diff --git a/entity_clone.module b/entity_clone.module index 81faab0..03ce9a0 100644 --- a/entity_clone.module +++ b/entity_clone.module @@ -33,6 +33,9 @@ function entity_clone_help($route_name, RouteMatchInterface $route_match) { */ function entity_clone_entity_type_build(array &$entity_types) { $specific_handler = [ + 'field_collection_item' => [ + 'entity_clone' => '\Drupal\entity_clone\EntityClone\Content\FieldCollectionEntityClone', + ], 'file' => [ 'entity_clone' => '\Drupal\entity_clone\EntityClone\Content\FileEntityClone', ], diff --git a/entity_clone.services.yml b/entity_clone.services.yml index deb11ef..c7145a5 100644 --- a/entity_clone.services.yml +++ b/entity_clone.services.yml @@ -4,3 +4,13 @@ services: arguments: ['@entity_type.manager'] tags: - { name: event_subscriber } + entity_clone.entity_reference_revisions_clone: + class: Drupal\entity_clone\EventSubscriber\EntityReferenceRevisions + arguments: ['@entity_type.manager'] + tags: + - { name: event_subscriber } + entity_clone.field_collection_item_clone: + class: Drupal\entity_clone\EventSubscriber\FieldCollectionItem + arguments: ['@entity_type.manager'] + tags: + - { name: event_subscriber } diff --git a/src/EntityClone/Content/FieldCollectionEntityClone.php b/src/EntityClone/Content/FieldCollectionEntityClone.php new file mode 100644 index 0000000..40d3085 --- /dev/null +++ b/src/EntityClone/Content/FieldCollectionEntityClone.php @@ -0,0 +1,25 @@ +eventDispatcher->dispatch(EntityCloneEvents::PRE_SAVE, new EntityCloneEvent($entity, $cloned_entity, $properties)); + $cloned_entity->save(); + $this->eventDispatcher->dispatch(EntityCloneEvents::POST_SAVE, new EntityCloneEvent($entity, $cloned_entity, $properties)); + + return $cloned_entity; + } + +} diff --git a/src/EventSubscriber/EntityReferenceRevisions.php b/src/EventSubscriber/EntityReferenceRevisions.php new file mode 100644 index 0000000..1b274b1 --- /dev/null +++ b/src/EventSubscriber/EntityReferenceRevisions.php @@ -0,0 +1,68 @@ +entityTypeManager = $entity_type_manager; + } + + /** + * @inheritDoc + */ + public static function getSubscribedEvents() { + $events[EntityCloneEvents::PRE_SAVE][] = ['onEntityCloned']; + return $events; + } + + /** + * Clones entity reference revisions fields. + * + * @param \Drupal\entity_clone\Events\EntityCloneEvent $event + */ + public function onEntityCloned(EntityCloneEvent $event) { + $cloned_entity = $event->getClonedEntity(); + + foreach ($cloned_entity->getFieldDefinitions() as $field_id => $field_definition) { + // Always recurse for ERR fields. + if ($field_definition->getType() == 'entity_reference_revisions') { + $new_referenced_entities = []; + foreach ($cloned_entity->get($field_id)->referencedEntities() as $referenced_entity) { + if ($this->entityTypeManager->hasHandler($this->entityTypeManager->getDefinition($referenced_entity->getEntityTypeId())->id(), 'entity_clone')) { + $clone_handler = $this->entityTypeManager->getHandler($this->entityTypeManager->getDefinition($referenced_entity->getEntityTypeId())->id(), 'entity_clone'); + $cloned_reference_entity = $referenced_entity->createDuplicate(); + $cloned_reference_entity->isDefaultRevision(TRUE); + + // Recursively clone nested entities + $new_referenced_entity = $clone_handler->cloneEntity($referenced_entity, $cloned_reference_entity); + + $new_referenced_entities[] = [ + 'target_id' => $new_referenced_entity->id(), + 'target_revision_id' => $new_referenced_entity->getRevisionId(), + ]; + + $cloned_entity->set($field_id, $new_referenced_entities); + } + } + } + } + } +} diff --git a/src/EventSubscriber/FieldCollectionItem.php b/src/EventSubscriber/FieldCollectionItem.php new file mode 100644 index 0000000..33b6571 --- /dev/null +++ b/src/EventSubscriber/FieldCollectionItem.php @@ -0,0 +1,79 @@ +entityTypeManager = $entity_type_manager; + } + + /** + * @inheritDoc + */ + public static function getSubscribedEvents() { + // Field Collections need the host entity saved, so it uses POST_SAVE event. + $events[EntityCloneEvents::POST_SAVE][] = ['onEntityCloned']; + return $events; + } + + /** + * Clones field-collection fields. + * + * @param \Drupal\entity_clone\Events\EntityCloneEvent $event + */ + public function onEntityCloned(EntityCloneEvent $event) { + // Escape if 'field_collection_item' entity doesn't exist. + if (!$exists = \Drupal::service('entity_type.manager')->getDefinition('field_collection_item', FALSE)) { + return; + } + + $storage_field_collection = $this->entityTypeManager->getStorage('field_collection_item'); + $cloned_entity = $event->getClonedEntity(); + + foreach ($cloned_entity->getFieldDefinitions() as $field_id => $field_definition) { + if ($field_definition->getType() == 'field_collection') { + $items = $cloned_entity->get($field_id)->getValue(); + + // Delete reference to current items + $cloned_entity->{$field_id} = array(); + + foreach ($items as $delta => $referenced_entity) { + $field_collection_item = $storage_field_collection->load($referenced_entity['value']); + + if ($field_collection_item->id()) { + // Do not save when the host entity is being deleted. See + // \Drupal\field_collection\Plugin\Field\FieldType\FieldCollection::delete(). + if (empty($cloned_entity->field_collection_deleting)) { + $clone_handler = $this->entityTypeManager->getHandler($this->entityTypeManager->getDefinition($field_collection_item->getEntityTypeId())->id(), 'entity_clone'); + $cloned_reference_entity = $field_collection_item->createDuplicate(); + + // Assign Field collection to the host entity, and save the host. + $cloned_reference_entity->setHostEntity($cloned_entity); + + // Recursively clone nested entities + $clone_handler->cloneEntity($field_collection_item, $cloned_reference_entity); + } + } + } + } + } + } +}