You are here

class Replicator in Replicate 8

Class Replicator. Manages the replication of an entity.

@package Drupal\replicate

Hierarchy

Expanded class hierarchy of Replicator

1 file declares its use of Replicator
ReplicatorTest.php in tests/src/Unit/ReplicatorTest.php
1 string reference to 'Replicator'
replicate.services.yml in ./replicate.services.yml
replicate.services.yml
1 service uses Replicator
replicate.replicator in ./replicate.services.yml
\Drupal\replicate\Replicator

File

src/Replicator.php, line 24

Namespace

Drupal\replicate
View source
class Replicator {
  use StringTranslationTrait;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The event dispatcher.
   *
   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
   */
  protected $eventDispatcher;

  /**
   * Creates a new Replicator instance.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
   *   The event dispatcher.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $event_dispatcher) {
    $this->entityTypeManager = $entity_type_manager;
    $this->eventDispatcher = $event_dispatcher;
  }

  /**
   * Replicate a entity by entity type ID and entity ID and save it.
   *
   * @param string $entity_type_id
   *   The entity type ID.
   * @param int $entity_id
   *   The entity ID.
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   *   The cloned entity.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   *   Thrown if the entity type doesn't exist.
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   *   Thrown if the storage handler couldn't be loaded.
   * @throws \Drupal\Core\Entity\EntityStorageException
   *   In case of failures, an exception is thrown.
   */
  public function replicateByEntityId($entity_type_id, $entity_id) {
    if ($entity = $this->entityTypeManager
      ->getStorage($entity_type_id)
      ->load($entity_id)) {
      return $this
        ->replicateEntity($entity);
    }
  }

  /**
   * Replicate a entity and save it.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity.
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   *   The cloned entity.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   *   Thrown if the entity type doesn't exist.
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   *   Thrown if the storage handler couldn't be loaded.
   * @throws \Drupal\Core\Entity\EntityStorageException
   *   In case of failures, an exception is thrown.
   */
  public function replicateEntity(EntityInterface $entity) {
    if ($clone = $this
      ->cloneEntity($entity)) {
      $this->entityTypeManager
        ->getStorage($entity
        ->getEntityTypeId())
        ->save($clone);
      $event = new AfterSaveEvent($clone);
      $this->eventDispatcher
        ->dispatch(ReplicatorEvents::AFTER_SAVE, $event);
      return $clone;
    }
  }

  /**
   * Clone a entity by entity type ID and entity ID without saving.
   *
   * @param string $entity_type_id
   *   The entity type ID.
   * @param int $entity_id
   *   The entity ID.
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   *   The cloned entity.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   *   Thrown if the entity type doesn't exist.
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   *   Thrown if the storage handler couldn't be loaded.
   */
  public function cloneByEntityId($entity_type_id, $entity_id) {
    if ($entity = $this->entityTypeManager
      ->getStorage($entity_type_id)
      ->load($entity_id)) {
      return $this
        ->cloneEntity($entity);
    }
  }

  /**
   * Clone a entity without saving.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity.
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   *   The cloned entity.
   */
  public function cloneEntity(EntityInterface $entity) {
    if ($clone = $entity
      ->createDuplicate()) {
      $event = new ReplicateEntityEvent($entity);
      $this->eventDispatcher
        ->dispatch(ReplicatorEvents::replicateEntityEvent($entity
        ->getEntityTypeId()), $event);
      if ($clone instanceof FieldableEntityInterface) {

        /** @var FieldableEntityInterface $clone */
        $this
          ->dispatchEventCloneEntityFields($clone);
      }
      $event = new ReplicateAlterEvent($clone, $entity);
      $this->eventDispatcher
        ->dispatch(ReplicatorEvents::REPLICATE_ALTER, $event);
      return $clone;
    }
  }

  /**
   * Clone an entity field to another.
   *
   * We can not create and return the target field here, because it needs to
   * know its parent entity, which can not be changed after creation.
   *
   * @param \Drupal\Core\Field\FieldItemListInterface $field
   *   The field to clone.
   * @param \Drupal\Core\Field\FieldItemListInterface $target_field
   *   The field to clone into.
   *
   * @throws \InvalidArgumentException
   *   If the value input is inappropriate.
   * @throws \Drupal\Core\TypedData\Exception\ReadOnlyException
   *   If the data is read-only.
   */
  public function cloneEntityField(FieldItemListInterface $field, FieldItemListInterface $target_field) {
    $target_field
      ->setValue($field
      ->getValue());
    $this
      ->postCloneEntityField($target_field);
  }

  /**
   * Postprocess a cloned entity field.
   *
   * A public API method so modules can e.g. clone a field partially.
   *
   * @param \Drupal\Core\Field\FieldItemListInterface $target_field
   *   The cloned field.
   */
  public function postCloneEntityField(FieldItemListInterface $target_field) {
    $entity = $target_field
      ->getEntity();
    if (!$entity instanceof FieldableEntityInterface) {

      // @todo Can this ever happen? The interface only assures EntityInterface.
      throw new FieldException($this
        ->t('Trying to clone into non fieldable Entity.'));
    }

    /** @var FieldableEntityInterface $entity */
    $violations = $target_field
      ->validate();
    if ($violations
      ->count()) {

      // This autocasts violations to string.
      $t_args = [
        '%violations' => implode(' & ', $violations),
      ];
      throw new FieldException($this
        ->t('Trying to clone into incompatible field: %violations', $t_args));
    }
    $this
      ->dispatchEventCloneEntityField($entity, $target_field
      ->getName(), $target_field
      ->getFieldDefinition());
  }

  /**
   * Fires events for each field of a fieldable entity.
   *
   * @param \Drupal\Core\Entity\FieldableEntityInterface $clone
   *   The cloned fieldable entity.
   */
  protected function dispatchEventCloneEntityFields(FieldableEntityInterface $clone) {
    foreach ($clone
      ->getFieldDefinitions() as $field_name => $field_definition) {
      $this
        ->dispatchEventCloneEntityField($clone, $field_name, $field_definition);
    }
  }

  /**
   * Fires events for a single field of a fieldable entity.
   *
   * @param \Drupal\Core\Entity\FieldableEntityInterface $clone
   *   The cloned fieldable entity.
   * @param $field_name
   *   The field name.
   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
   *   The field definition.
   */
  private function dispatchEventCloneEntityField(FieldableEntityInterface $clone, $field_name, FieldDefinitionInterface $field_definition) {
    $event = new ReplicateEntityFieldEvent($clone
      ->get($field_name), $clone);
    $this->eventDispatcher
      ->dispatch(ReplicatorEvents::replicateEntityField($field_definition
      ->getType()), $event);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Replicator::$entityTypeManager protected property The entity type manager.
Replicator::$eventDispatcher protected property The event dispatcher.
Replicator::cloneByEntityId public function Clone a entity by entity type ID and entity ID without saving.
Replicator::cloneEntity public function Clone a entity without saving.
Replicator::cloneEntityField public function Clone an entity field to another.
Replicator::dispatchEventCloneEntityField private function Fires events for a single field of a fieldable entity.
Replicator::dispatchEventCloneEntityFields protected function Fires events for each field of a fieldable entity.
Replicator::postCloneEntityField public function Postprocess a cloned entity field.
Replicator::replicateByEntityId public function Replicate a entity by entity type ID and entity ID and save it.
Replicator::replicateEntity public function Replicate a entity and save it.
Replicator::__construct public function Creates a new Replicator instance.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.