Skip to content
Snippets Groups Projects
Commit cc037df7 authored by Nick Dickinson-Wilde's avatar Nick Dickinson-Wilde
Browse files

Merge branch '8.x-1.x' into 3183368-clone-config-translations

# Conflicts:
#	src/EntityClone/Config/ConfigWithFieldEntityClone.php
parents fbc158d1 d4fb1ba7
No related branches found
No related tags found
1 merge request!3Clone ConfigEntity translations
Showing with 438 additions and 15 deletions
<?php
/**
* @file
* Entity Clone hooks and events.
*/
/**
* Event subscribers for Entity Clone.
*
* Service definition for my_module.services.yml:
* <code>
* ```yaml
* my_module.my_event_subscriber:
* class: Drupal\my_module\EventSubscriber\MyEntityCloneEventSubscriber
* tags:
* - { name: event_subscriber }
* ```
* </code>
*
* Code for src/EventSubscriber/MyEntityCloneEventSubscriber.php
* <code>
* <?php
* namespace Drupal\my_module\EventSubscriber;
* ?>
* </code>
*/
class MyEntityCloneEventSubscriber implements \Symfony\Component\EventDispatcher\EventSubscriberInterface {
/**
* An example event subscriber.
*
* Dispatched before an entity is cloned and saved.
*
* @see \Drupal\entity_clone\Event\EntityCloneEvents::PRE_CLONE
*/
public function myPreClone(\Drupal\entity_clone\Event\EntityCloneEvent $event): void {
$original = $event->getEntity();
$newEntity = $event->getClonedEntity();
}
/**
* An example event subscriber.
*
* Dispatched after an entity is cloned and saved.
*
* @see \Drupal\entity_clone\Event\EntityCloneEvents::POST_CLONE
*/
public function myPostClone(\Drupal\entity_clone\Event\EntityCloneEvent $event): void {
$original = $event->getEntity();
$newEntity = $event->getClonedEntity();
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
$events[\Drupal\entity_clone\Event\EntityCloneEvents::PRE_CLONE][] = ['myPreClone'];
$events[\Drupal\entity_clone\Event\EntityCloneEvents::POST_CLONE][] = ['myPostClone'];
return $events;
}
}
...@@ -22,6 +22,7 @@ use Drupal\entity_clone\EntityClone\Content\ContentEntityCloneFormBase; ...@@ -22,6 +22,7 @@ use Drupal\entity_clone\EntityClone\Content\ContentEntityCloneFormBase;
use Drupal\entity_clone\EntityClone\Content\FileEntityClone; use Drupal\entity_clone\EntityClone\Content\FileEntityClone;
use Drupal\entity_clone\EntityClone\Content\TaxonomyTermEntityClone; use Drupal\entity_clone\EntityClone\Content\TaxonomyTermEntityClone;
use Drupal\entity_clone\EntityClone\Content\UserEntityClone; use Drupal\entity_clone\EntityClone\Content\UserEntityClone;
use Drupal\entity_clone\EntityClone\Config\LayoutBuilderEntityClone;
/** /**
* Implements hook_help(). * Implements hook_help().
...@@ -77,6 +78,9 @@ function entity_clone_entity_type_build(array &$entity_types) { ...@@ -77,6 +78,9 @@ function entity_clone_entity_type_build(array &$entity_types) {
'taxonomy_vocabulary' => [ 'taxonomy_vocabulary' => [
'entity_clone' => ConfigWithFieldEntityClone::class, 'entity_clone' => ConfigWithFieldEntityClone::class,
], ],
'entity_view_display' => [
'entity_clone' => \Drupal::moduleHandler()->moduleExists('layout_builder') ? LayoutBuilderEntityClone::class : NULL,
],
]; ];
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */ /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
...@@ -122,7 +126,8 @@ function entity_clone_entity_operation(EntityInterface $entity) { ...@@ -122,7 +126,8 @@ function entity_clone_entity_operation(EntityInterface $entity) {
'clone' => [ 'clone' => [
'title' => t('Clone'), 'title' => t('Clone'),
'weight' => 50, 'weight' => 50,
'url' => $entity->toUrl('clone-form'), 'url' => $entity->toUrl('clone-form')
->mergeOptions(['query' => \Drupal::destination()->getAsArray()]),
], ],
]; ];
} }
......
...@@ -7,3 +7,6 @@ services: ...@@ -7,3 +7,6 @@ services:
arguments: ['@entity_type.manager'] arguments: ['@entity_type.manager']
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
entity_clone.service_provider:
class: Drupal\entity_clone\Services\EntityCloneServiceProvider
arguments: [ ]
...@@ -20,16 +20,16 @@ class ConfigWithFieldEntityClone extends ConfigEntityCloneBase { ...@@ -20,16 +20,16 @@ class ConfigWithFieldEntityClone extends ConfigEntityCloneBase {
$this->cloneFields($entity->id(), $cloned_entity->id(), $bundle_of, $translate); $this->cloneFields($entity->id(), $cloned_entity->id(), $bundle_of, $translate);
} }
$view_displays = \Drupal::service('entity_display.repository')->getViewModes($bundle_of); $view_displays = \Drupal::service('entity_display.repository')->getFormModes($bundle_of);
$view_displays = array_merge($view_displays, ['default' => 'default']); $view_displays = array_merge($view_displays, ['default' => 'default']);
if (!empty($view_displays)) { if (!empty($view_displays)) {
$this->cloneDisplays('view', $entity->id(), $cloned_entity->id(), $view_displays, $bundle_of, $translate); $this->cloneDisplays('form', $entity->id(), $cloned_entity->id(), $view_displays, $bundle_of, $translate);
} }
$view_displays = \Drupal::service('entity_display.repository')->getFormModes($bundle_of); $view_displays = \Drupal::service('entity_display.repository')->getViewModes($bundle_of);
$view_displays = array_merge($view_displays, ['default' => 'default']); $view_displays = array_merge($view_displays, ['default' => 'default']);
if (!empty($view_displays)) { if (!empty($view_displays)) {
$this->cloneDisplays('form', $entity->id(), $cloned_entity->id(), $view_displays, $bundle_of, $translate); $this->cloneDisplays('view', $entity->id(), $cloned_entity->id(), $view_displays, $bundle_of, $translate);
} }
return $cloned_entity; return $cloned_entity;
......
<?php
namespace Drupal\entity_clone\EntityClone\Config;
use Drupal\Component\Plugin\DerivativeInspectionInterface;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\layout_builder\SectionComponent;
use Drupal\layout_builder\Section;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Class LayoutBuilderEntityView.
*/
class LayoutBuilderEntityClone extends ConfigEntityCloneBase {
/**
* Uuid generator service.
*
* @var \Drupal\Component\Uuid\UuidInterface
*/
protected $uuidGenerator;
/**
* LayoutBuilderEntityClone constructor.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, $entity_type_id, UuidInterface $uuid) {
parent::__construct($entity_type_manager, $entity_type_id);
$this->uuidGenerator = $uuid;
}
/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static(
$container->get('entity_type.manager'),
$entity_type->id(),
$container->get('uuid')
);
}
/**
* {@inheritdoc}
*/
public function cloneEntity(EntityInterface $entity, EntityInterface $cloned_entity, array $properties = []) {
/** @var $cloned_entity \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface */
/** @var $entity \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface */
// We need to create an entity, save it, then adjust layout builder settings
// and save it again, because for new entities layout_builder module stacks
// all fields into display.
// @see \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::preSave()
$cloned_entity = parent::cloneEntity($entity, $cloned_entity, $properties);
if ($cloned_entity->isLayoutBuilderEnabled()) {
$cloned_entity->removeAllSections();
foreach ($entity->getSections() as $section) {
$cloned_components = [];
foreach ($section->getComponents() as $section_component) {
$plugin = $section_component->getPlugin();
$component_array = $section_component->toArray();
$deriver_id = $plugin->getPluginDefinition()['id'];
switch ($deriver_id) {
case 'field_block':
case 'extra_field_block':
$full_id = explode(PluginBase::DERIVATIVE_SEPARATOR, $plugin->getPluginId());
$field_name = end($full_id);
$derivative_id = $cloned_entity->getTargetEntityTypeId() . PluginBase::DERIVATIVE_SEPARATOR . $cloned_entity->getTargetBundle() . PluginBase::DERIVATIVE_SEPARATOR . $field_name;
break;
case 'inline_block':
$derivative_id = $plugin->getDerivativeId();
break;
default:
if ($plugin instanceof DerivativeInspectionInterface) {
$derivative_id = $plugin->getDerivativeId();
}
else {
$derivative_id = '';
}
break;
}
$cloned_plugin_id = $deriver_id . (!empty($derivative_id) ? PluginBase::DERIVATIVE_SEPARATOR . $derivative_id : '');
$component_array['uuid'] = $this->uuidGenerator->generate();
$component_array['configuration']['id'] = $cloned_plugin_id;
$cloned_components[] = SectionComponent::fromArray($component_array);
}
// We don't expect here third-party settings, but just in case.
$third_party_settings = [];
foreach ($section->getThirdPartyProviders() as $third_party_provider) {
$third_party_settings[$third_party_provider] = $section->getThirdPartySettings($third_party_provider);
}
$cloned_section = new Section($section->getLayoutId(), $section->getLayoutSettings(), $cloned_components, $third_party_settings);
$cloned_entity->appendSection($cloned_section);
}
$cloned_entity->save();
}
return $cloned_entity;
}
}
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
namespace Drupal\entity_clone\EntityClone\Content; namespace Drupal\entity_clone\EntityClone\Content;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Entity\EntityHandlerInterface; use Drupal\Core\Entity\EntityHandlerInterface;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityTypeInterface;
...@@ -10,6 +11,7 @@ use Drupal\Core\Entity\FieldableEntityInterface; ...@@ -10,6 +11,7 @@ use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldConfigInterface; use Drupal\Core\Field\FieldConfigInterface;
use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\entity_clone\EntityClone\EntityCloneInterface; use Drupal\entity_clone\EntityClone\EntityCloneInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
...@@ -32,6 +34,20 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter ...@@ -32,6 +34,20 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
*/ */
protected $entityTypeId; protected $entityTypeId;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* A service for obtaining the system's time.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $timeService;
/** /**
* Constructs a new ContentEntityCloneBase. * Constructs a new ContentEntityCloneBase.
* *
...@@ -39,10 +55,16 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter ...@@ -39,10 +55,16 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
* The entity type manager. * The entity type manager.
* @param string $entity_type_id * @param string $entity_type_id
* The entity type ID. * The entity type ID.
* @param \Drupal\Core\Session\AccountProxyInterface $currentUser
* The current user.
* @param \Drupal\Component\Datetime\TimeInterface $time_service
* A service for obtaining the system's time.
*/ */
public function __construct(EntityTypeManagerInterface $entity_type_manager, $entity_type_id) { public function __construct(EntityTypeManagerInterface $entity_type_manager, $entity_type_id, TimeInterface $time_service, AccountProxyInterface $currentUser) {
$this->entityTypeManager = $entity_type_manager; $this->entityTypeManager = $entity_type_manager;
$this->entityTypeId = $entity_type_id; $this->entityTypeId = $entity_type_id;
$this->timeService = $time_service;
$this->currentUser = $currentUser;
} }
/** /**
...@@ -51,7 +73,9 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter ...@@ -51,7 +73,9 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static( return new static(
$container->get('entity_type.manager'), $container->get('entity_type.manager'),
$entity_type->id() $entity_type->id(),
$container->get('datetime.time'),
$container->get('current_user')
); );
} }
...@@ -59,6 +83,9 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter ...@@ -59,6 +83,9 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
* {@inheritdoc} * {@inheritdoc}
*/ */
public function cloneEntity(EntityInterface $entity, EntityInterface $cloned_entity, array $properties = [], array &$already_cloned = []) { public function cloneEntity(EntityInterface $entity, EntityInterface $cloned_entity, array $properties = [], array &$already_cloned = []) {
if (isset($properties['take_ownership']) && $properties['take_ownership'] === 1) {
$cloned_entity->setOwnerId($this->currentUser->id());
}
// Clone referenced entities. // Clone referenced entities.
$cloned_entity->save(); $cloned_entity->save();
$already_cloned[$entity->getEntityTypeId()][$entity->id()] = $cloned_entity; $already_cloned[$entity->getEntityTypeId()][$entity->id()] = $cloned_entity;
...@@ -75,6 +102,16 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter ...@@ -75,6 +102,16 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
} }
$this->setClonedEntityLabel($entity, $cloned_entity); $this->setClonedEntityLabel($entity, $cloned_entity);
// For now, check that the cloned entity has a 'setCreatedTime' method, and
// if so, try to call it. This condition can be replaced with a more-robust
// check whether $cloned_entity is an instance of
// Drupal\Core\Entity\EntityCreatedInterface once
// https://www.drupal.org/project/drupal/issues/2833378 lands.
if (method_exists($cloned_entity, 'setCreatedTime')) {
$cloned_entity->setCreatedTime($this->timeService->getRequestTime());
}
$cloned_entity->save(); $cloned_entity->save();
return $cloned_entity; return $cloned_entity;
} }
...@@ -86,7 +123,7 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter ...@@ -86,7 +123,7 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
* The field definition. * The field definition.
* *
* @return bool * @return bool
* TRUE if th field is clonable; FALSE otherwise. * TRUE if the field is clonable; FALSE otherwise.
*/ */
protected function fieldIsClonable(FieldDefinitionInterface $field_definition) { protected function fieldIsClonable(FieldDefinitionInterface $field_definition) {
$clonable_field_types = [ $clonable_field_types = [
...@@ -117,7 +154,7 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter ...@@ -117,7 +154,7 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
} }
/** /**
* Clone referenced entities. * Clones referenced entities.
* *
* @param \Drupal\Core\Field\FieldItemListInterface $field * @param \Drupal\Core\Field\FieldItemListInterface $field
* The field item. * The field item.
......
...@@ -16,6 +16,9 @@ class FileEntityClone extends ContentEntityCloneBase { ...@@ -16,6 +16,9 @@ class FileEntityClone extends ContentEntityCloneBase {
public function cloneEntity(EntityInterface $entity, EntityInterface $cloned_entity, array $properties = [], array &$already_cloned = []) { public function cloneEntity(EntityInterface $entity, EntityInterface $cloned_entity, array $properties = [], array &$already_cloned = []) {
/** @var \Drupal\file\FileInterface $cloned_entity */ /** @var \Drupal\file\FileInterface $cloned_entity */
$cloned_file = file_copy($cloned_entity, $cloned_entity->getFileUri(), FileSystemInterface::EXISTS_RENAME); $cloned_file = file_copy($cloned_entity, $cloned_entity->getFileUri(), FileSystemInterface::EXISTS_RENAME);
if (isset($properties['take_ownership']) && $properties['take_ownership'] === 1) {
$cloned_file->setOwnerId(\Drupal::currentUser()->id());
}
return parent::cloneEntity($entity, $cloned_file, $properties); return parent::cloneEntity($entity, $cloned_file, $properties);
} }
......
...@@ -6,6 +6,7 @@ use Drupal\Core\DependencyInjection\ContainerInjectionInterface; ...@@ -6,6 +6,7 @@ use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\TranslationManager; use Drupal\Core\StringTranslation\TranslationManager;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\entity_clone\Services\EntityCloneServiceProvider;
/** /**
* Provides dynamic permissions of the entity_clone module. * Provides dynamic permissions of the entity_clone module.
...@@ -26,6 +27,13 @@ class EntityClonePermissions implements ContainerInjectionInterface { ...@@ -26,6 +27,13 @@ class EntityClonePermissions implements ContainerInjectionInterface {
*/ */
protected $translationManager; protected $translationManager;
/**
* The Service Provider that verifies if entity has ownership.
*
* @var \Drupal\entity_clone\Services\EntityCloneServiceProvider
*/
protected $serviceProvider;
/** /**
* Constructs a new EntityClonePermissions instance. * Constructs a new EntityClonePermissions instance.
* *
...@@ -33,10 +41,13 @@ class EntityClonePermissions implements ContainerInjectionInterface { ...@@ -33,10 +41,13 @@ class EntityClonePermissions implements ContainerInjectionInterface {
* The entity type manager. * The entity type manager.
* @param \Drupal\Core\StringTranslation\TranslationManager $string_translation * @param \Drupal\Core\StringTranslation\TranslationManager $string_translation
* The string translation manager. * The string translation manager.
* @param \\Drupal\entity_clone\Services\EntityCloneServiceProvider $service_provider
* The Service Provider that verifies if entity has ownership.
*/ */
public function __construct(EntityTypeManagerInterface $entity_manager, TranslationManager $string_translation) { public function __construct(EntityTypeManagerInterface $entity_manager, TranslationManager $string_translation, EntityCloneServiceProvider $service_provider) {
$this->entityTypeManager = $entity_manager; $this->entityTypeManager = $entity_manager;
$this->translationManager = $string_translation; $this->translationManager = $string_translation;
$this->serviceProvider = $service_provider;
} }
/** /**
...@@ -45,7 +56,8 @@ class EntityClonePermissions implements ContainerInjectionInterface { ...@@ -45,7 +56,8 @@ class EntityClonePermissions implements ContainerInjectionInterface {
public static function create(ContainerInterface $container) { public static function create(ContainerInterface $container) {
return new static( return new static(
$container->get('entity_type.manager'), $container->get('entity_type.manager'),
$container->get('string_translation') $container->get('string_translation'),
$container->get('entity_clone.service_provider')
); );
} }
...@@ -62,6 +74,12 @@ class EntityClonePermissions implements ContainerInjectionInterface { ...@@ -62,6 +74,12 @@ class EntityClonePermissions implements ContainerInjectionInterface {
$permissions['clone ' . $entity_type_id . ' entity'] = $this->translationManager->translate('Clone all <em>@label</em> entities.', [ $permissions['clone ' . $entity_type_id . ' entity'] = $this->translationManager->translate('Clone all <em>@label</em> entities.', [
'@label' => $entity_type->getLabel(), '@label' => $entity_type->getLabel(),
]); ]);
if ($this->serviceProvider->entityTypeHasOwnerTrait($entity_type)) {
$permissions['take_ownership_on_clone ' . $entity_type_id . ' entity'] = $this->translationManager->translate('Allow user to take ownership of <em>@label</em> cloned entities', [
'@label' => $entity_type->getLabel(),
]);
}
} }
return $permissions; return $permissions;
......
...@@ -146,4 +146,21 @@ class EntityCloneSettingsManager { ...@@ -146,4 +146,21 @@ class EntityCloneSettingsManager {
return FALSE; return FALSE;
} }
/**
* Set the take ownership setting.
*
* @param int $setting
* The settings from the form.
*/
public function setTakeOwnershipSettings(int $setting) {
$this->editableConfig->set('take_ownership', $setting)->save();
}
/**
* Get the take ownership settings.
*/
public function getTakeOwnershipSetting() {
return $this->config->get('take_ownership') ?? FALSE;
}
} }
...@@ -8,7 +8,10 @@ use Drupal\Core\Form\FormBase; ...@@ -8,7 +8,10 @@ use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\Messenger; use Drupal\Core\Messenger\Messenger;
use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\TranslationManager; use Drupal\Core\StringTranslation\TranslationManager;
use Drupal\entity_clone\Services\EntityCloneServiceProvider;
use Drupal\entity_clone\EntityCloneSettingsManager;
use Drupal\entity_clone\Event\EntityCloneEvent; use Drupal\entity_clone\Event\EntityCloneEvent;
use Drupal\entity_clone\Event\EntityCloneEvents; use Drupal\entity_clone\Event\EntityCloneEvents;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
...@@ -61,6 +64,27 @@ class EntityCloneForm extends FormBase { ...@@ -61,6 +64,27 @@ class EntityCloneForm extends FormBase {
*/ */
protected $messenger; protected $messenger;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The entity clone settings manager service.
*
* @var \Drupal\entity_clone\EntityCloneSettingsManager
*/
protected $entityCloneSettingsManager;
/**
* The Service Provider that verifies if entity has ownership.
*
* @var \Drupal\entity_clone\Services\EntityCloneServiceProvider
*/
protected $serviceProvider;
/** /**
* Constructs a new Entity Clone form. * Constructs a new Entity Clone form.
* *
...@@ -74,10 +98,16 @@ class EntityCloneForm extends FormBase { ...@@ -74,10 +98,16 @@ class EntityCloneForm extends FormBase {
* The event dispatcher service. * The event dispatcher service.
* @param \Drupal\Core\Messenger\Messenger $messenger * @param \Drupal\Core\Messenger\Messenger $messenger
* The messenger service. * The messenger service.
* @param \Drupal\Core\Session\AccountProxyInterface $currentUser
* The current user.
* @param \Drupal\entity_clone\EntityCloneSettingsManager $entity_clone_settings_manager
* The entity clone settings manager.
* @param \Drupal\entity_clone\Services\EntityCloneServiceProvider $service_provider
* The Service Provider that verifies if entity has ownership.
* *
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/ */
public function __construct(EntityTypeManagerInterface $entity_type_manager, RouteMatchInterface $route_match, TranslationManager $string_translation, EventDispatcherInterface $eventDispatcher, Messenger $messenger) { public function __construct(EntityTypeManagerInterface $entity_type_manager, RouteMatchInterface $route_match, TranslationManager $string_translation, EventDispatcherInterface $eventDispatcher, Messenger $messenger, AccountProxyInterface $currentUser, EntityCloneSettingsManager $entity_clone_settings_manager, EntityCloneServiceProvider $service_provider) {
$this->entityTypeManager = $entity_type_manager; $this->entityTypeManager = $entity_type_manager;
$this->stringTranslationManager = $string_translation; $this->stringTranslationManager = $string_translation;
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
...@@ -87,6 +117,9 @@ class EntityCloneForm extends FormBase { ...@@ -87,6 +117,9 @@ class EntityCloneForm extends FormBase {
$this->entity = $route_match->getParameter($parameter_name); $this->entity = $route_match->getParameter($parameter_name);
$this->entityTypeDefinition = $entity_type_manager->getDefinition($this->entity->getEntityTypeId()); $this->entityTypeDefinition = $entity_type_manager->getDefinition($this->entity->getEntityTypeId());
$this->currentUser = $currentUser;
$this->entityCloneSettingsManager = $entity_clone_settings_manager;
$this->serviceProvider = $service_provider;
} }
/** /**
...@@ -98,7 +131,10 @@ class EntityCloneForm extends FormBase { ...@@ -98,7 +131,10 @@ class EntityCloneForm extends FormBase {
$container->get('current_route_match'), $container->get('current_route_match'),
$container->get('string_translation'), $container->get('string_translation'),
$container->get('event_dispatcher'), $container->get('event_dispatcher'),
$container->get('messenger') $container->get('messenger'),
$container->get('current_user'),
$container->get('entity_clone.settings.manager'),
$container->get('entity_clone.service_provider')
); );
} }
...@@ -120,6 +156,15 @@ class EntityCloneForm extends FormBase { ...@@ -120,6 +156,15 @@ class EntityCloneForm extends FormBase {
$entity_clone_form_handler = $this->entityTypeManager->getHandler($this->entityTypeDefinition->id(), 'entity_clone_form'); $entity_clone_form_handler = $this->entityTypeManager->getHandler($this->entityTypeDefinition->id(), 'entity_clone_form');
$form = array_merge($form, $entity_clone_form_handler->formElement($this->entity)); $form = array_merge($form, $entity_clone_form_handler->formElement($this->entity));
} }
$entityType = $this->getEntity()->getEntityTypeId();
if ($this->serviceProvider->entityTypeHasOwnerTrait($this->getEntity()->getEntityType()) && $this->currentUser->hasPermission('take_ownership_on_clone ' . $entityType . ' entity')) {
$form['take_ownership'] = [
'#type' => 'checkbox',
'#title' => $this->stringTranslationManager->translate('Take ownership'),
'#default_value' => $this->entityCloneSettingsManager->getTakeOwnershipSetting(),
'#description' => $this->stringTranslationManager->translate('Take ownership of the newly created cloned entity.'),
];
}
$form['actions'] = ['#type' => 'actions']; $form['actions'] = ['#type' => 'actions'];
$form['actions']['clone'] = [ $form['actions']['clone'] = [
...@@ -130,7 +175,7 @@ class EntityCloneForm extends FormBase { ...@@ -130,7 +175,7 @@ class EntityCloneForm extends FormBase {
$form['actions']['abort'] = [ $form['actions']['abort'] = [
'#type' => 'submit', '#type' => 'submit',
'#value' => $this->stringTranslationManager->translate('Abort'), '#value' => $this->stringTranslationManager->translate('Cancel'),
'#submit' => ['::cancelForm'], '#submit' => ['::cancelForm'],
]; ];
} }
...@@ -193,7 +238,7 @@ class EntityCloneForm extends FormBase { ...@@ -193,7 +238,7 @@ class EntityCloneForm extends FormBase {
} }
/** /**
* Set a redirect on form state. * Sets a redirect on form state.
* *
* @param \Drupal\Core\Form\FormStateInterface $form_state * @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form. * The current state of the form.
......
...@@ -111,6 +111,13 @@ class EntityCloneSettingsForm extends ConfigFormBase implements ContainerInjecti ...@@ -111,6 +111,13 @@ class EntityCloneSettingsForm extends ConfigFormBase implements ContainerInjecti
]; ];
} }
$form['take_ownership'] = [
'#type' => 'checkbox',
'#title' => $this->t('Take ownership'),
'#description' => $this->t('Whether the "Take ownership" option should be checked by default on the entity clone form.'),
'#default_value' => $this->entityCloneSettingsManager->getTakeOwnershipSetting(),
];
return parent::buildForm($form, $form_state); return parent::buildForm($form, $form_state);
} }
...@@ -119,6 +126,7 @@ class EntityCloneSettingsForm extends ConfigFormBase implements ContainerInjecti ...@@ -119,6 +126,7 @@ class EntityCloneSettingsForm extends ConfigFormBase implements ContainerInjecti
*/ */
public function submitForm(array &$form, FormStateInterface $form_state) { public function submitForm(array &$form, FormStateInterface $form_state) {
$this->entityCloneSettingsManager->setFormSettings($form_state->getValue('form_settings')); $this->entityCloneSettingsManager->setFormSettings($form_state->getValue('form_settings'));
$this->entityCloneSettingsManager->setTakeOwnershipSettings($form_state->getValue('take_ownership'));
parent::submitForm($form, $form_state); parent::submitForm($form, $form_state);
} }
......
<?php
namespace Drupal\entity_clone\Services;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\user\EntityOwnerTrait;
/**
* Service Provider Class.
*/
class EntityCloneServiceProvider {
/**
* Constructs a new ServiceProvider object.
*/
public function __construct() {}
/**
* Checks if the given entity implements has owner trait.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity
* Entity to be tested.
*
* @return bool
* Returns boolean for the owner trait test.
*/
public function entityTypeHasOwnerTrait(EntityTypeInterface $entityType) {
try {
$reflectionClass = new \ReflectionClass($entityType->getOriginalClass());
} catch (\ReflectionException $e) {
return FALSE;
}
return in_array(
EntityOwnerTrait::class,
array_keys($reflectionClass->getTraits())
);
}
}
<?php
namespace Drupal\Tests\entity_clone\Functional;
use Drupal\Core\Url;
use Drupal\node\Entity\Node;
use Drupal\Tests\node\Functional\NodeTestBase;
/**
* Test whether cloning an entity also clones its created date.
*
* @group entity_clone
*/
class EntityCloneContentCreatedDate extends NodeTestBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
public static $modules = ['entity_clone', 'node'];
/**
* The user that we will use to execute the functional test.
*
* @var \Drupal\user\UserInterface
*/
protected $sutUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->sutUser = $this->drupalCreateUser([
'bypass node access',
'administer nodes',
'clone node entity',
]);
}
/**
* Test that an entity's created date is not cloned.
*/
public function testCreatedDateIsNotCloned() {
// Log in.
$this->drupalLogin($this->sutUser);
// Create the original node.
$originalNodeCreatedDate = new \DateTimeImmutable('1 year 1 month 1 day ago');
$originalNode = $this->drupalCreateNode([
'created' => $originalNodeCreatedDate->getTimestamp(),
]);
$this->assertEquals($originalNodeCreatedDate->getTimestamp(), $originalNode->getCreatedTime());
// Clone the node.
$this->drupalGet(Url::fromRoute('entity.node.clone_form', [
'node' => $originalNode->id(),
])->toString());
$this->getSession()->getPage()->pressButton('Clone');
// Find the cloned node.
$originalNodeClones = \Drupal::entityTypeManager()
->getStorage('node')
->loadByProperties([
'title' => sprintf('%s - Cloned', $originalNode->label()),
]);
$this->assertGreaterThanOrEqual(1, count($originalNodeClones));
$clonedNode = reset($originalNodeClones);
// Validate the cloned node's created time is more recent than the original
// node.
$this->assertNotEquals($originalNode->getCreatedTime(), $clonedNode->getCreatedTime());
$this->assertGreaterThanOrEqual($originalNode->getCreatedTime(), $clonedNode->getCreatedTime());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment