entity_value_inheritance-1.3.0/src/Services/InheritanceUpdater.php

src/Services/InheritanceUpdater.php
<?php

namespace Drupal\entity_value_inheritance\Services;

use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\entity_value_inheritance\Entity\InheritanceInterface;
use Drupal\entity_value_inheritance\EntityValueInheritanceUpdaterPluginInterface;
use Drupal\entity_value_inheritance\EntityValueInheritanceUpdaterPluginManager;
use Drupal\entity_value_inheritance\Event\InheritanceAlterUpdateListEvent;
use Drupal\entity_value_inheritance\Event\InheritanceEvents;
use Drupal\entity_value_inheritance\Event\InheritancePostUpdateEvent;
use Drupal\entity_value_inheritance\Event\InheritancePreUpdateEvent;
use Drupal\entity_value_inheritance\Event\InheritanceSaveEntityEvent;

/**
 * Inheritance Updater.
 */
final class InheritanceUpdater {

  use StringTranslationTrait;

  /**
   * Array of plugins used.
   */
  protected \SplObjectStorage $plugins;

  /**
   * Constructs a new \Drupal\entity_value_inheritance\Services\InheritanceUpdater object.
   *
   * @param \Drupal\entity_value_inheritance\EntityValueInheritanceUpdaterPluginManager $pluginManager
   *   Entity Value Inheritance Updater Plugin Manager Service.
   * @param \Drupal\entity_value_inheritance\Services\Helper $helper
   *   Helper Class Service.
   */
  public function __construct(protected EntityValueInheritanceUpdaterPluginManager $pluginManager, protected Helper $helper) {
    $this->plugins = new \SplObjectStorage();
  }

  /**
   * Modify the form for the destination entity.
   *
   * @param array $form
   *   Form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state to use.
   *
   * @return array
   *   Form element.
   */
  public function alterForm(array &$form, FormStateInterface $form_state): array {
    // Do not continue if the form_state is not an EntityForm.
    if (!($form_state->getFormObject() instanceof EntityFormInterface)) {
      return $form;
    }

    /** @var \Drupal\Core\Entity\EntityInterface $entity */
    $entity = $form_state->getFormObject()->getEntity();

    // If there are no active records exit.
    if (!$this->helper->hasActiveRecords($entity->getEntityTypeId())) {
      return $form;
    }

    /** @var string[] $fields */
    $fields = Element::getVisibleChildren($form);

    // Loop through all the fields on the form.
    foreach ($fields as $field) {
      $inheritances = $this->helper->getDestinationsByField(
        $entity->getEntityTypeId(),
        $entity->bundle(),
        $field
      );

      // Return the field.
      $field_definition = $this->helper->getEntityBundleField($entity->getEntityTypeId(), $entity->bundle(), $field);
      if ($field_definition === NULL) {
        continue;
      }

      foreach ($inheritances as $inheritance) {
        try {
          $updaterPlugin = $this->createInstance($inheritance);

          $form = $updaterPlugin->alterForm($form, $form_state, $entity, $field_definition);
          $form[$field] = $updaterPlugin->alterFormField($form[$field], $form_state, $entity, $field_definition);
        }
        catch (PluginException | PluginNotFoundException $pluginNotFoundException) {
          // If there is some sort of error log it.
          $this->helper->logger()->error('Error trying to alter form field. <pre>@message</pre>', ['@message' => $pluginNotFoundException->getMessage()]);
        }
      }
    }

    return $form;
  }

  /**
   * Insert the new destination entity.
   *
   * @param \Drupal\Core\Entity\EntityInterface $destinationEntity
   *   Destination being created.
   */
  public function insertDestination(EntityInterface $destinationEntity): void {
    $inheritanceGroup = $this->helper->groupByProperty(
      $this->helper->getInheritanceItemsByDestination($destinationEntity),
      'destination_entity_referencing_field'
    );

    foreach ($inheritanceGroup as $referenceField => $inheritances) {
      // Get referenced entities for field.
      $sourceEntities = $destinationEntity
        ->get($referenceField)
        ->referencedEntities();

      foreach ($sourceEntities as $sourceEntity) {
        foreach ($inheritances as $inheritance) {
          $this->updateEntity($inheritance, $sourceEntity, $destinationEntity);
        }
      }

      $this->helper->dispatchEvent(
        new InheritanceSaveEntityEvent($inheritances, [$destinationEntity]),
        InheritanceEvents::SAVE_ENTITIES
      );
    }
  }

  /**
   * Update the destination entity types.
   *
   * @param \Drupal\Core\Entity\EntityInterface $sourceEntity
   *   Source entity to run updates on.
   *
   * @see entity_value_inheritance_entity_update
   */
  public function updateDestination(EntityInterface $sourceEntity): void {
    $inheritanceGroup = $this->helper->groupByProperty(
      $this->helper->getInheritanceItemsBySource($sourceEntity),
      'destination_entity_type'
    );

    foreach ($inheritanceGroup as $entityType => $inheritances) {
      $destinationEntities = $this->getListOfDestinationEntities(
        $sourceEntity,
        $entityType,
        $inheritances
      );

      foreach ($destinationEntities as $destinationEntity) {
        foreach ($inheritances as $inheritance) {
          $this->updateEntity($inheritance, $sourceEntity, $destinationEntity);
        }
      }

      $this->helper->dispatchEvent(
        new InheritanceSaveEntityEvent($inheritances, $destinationEntities),
        InheritanceEvents::SAVE_ENTITIES
      );
    }
  }

  /**
   * Try to update the provided entity.
   *
   * @param \Drupal\entity_value_inheritance\Entity\InheritanceInterface $inheritance
   *   Inheritance configuration.
   * @param \Drupal\Core\Entity\EntityInterface $sourceEntity
   *   Entity providing the information.
   * @param \Drupal\Core\Entity\EntityInterface $destinationEntity
   *   Entity being updated.
   *
   * @return bool
   *   Return TRUE to continue update.
   */
  protected function updateEntity(InheritanceInterface $inheritance, EntityInterface $sourceEntity, EntityInterface $destinationEntity): bool {
    // Check if the update process can continue.
    /** @var \Drupal\entity_value_inheritance\Event\InheritancePreUpdateEvent $dispatchedEvent */
    $dispatchedEvent = ($this->helper->dispatchEvent(
      new InheritancePreUpdateEvent($inheritance, $sourceEntity, $destinationEntity),
      InheritanceEvents::PRE_UPDATE
    ));
    if (!$dispatchedEvent->canContinue()) {
      return FALSE;
    }

    $this->tryUpdating($inheritance, $sourceEntity, $destinationEntity);

    // Dispatch that the following items have completed update.
    $this->helper->dispatchEvent(
      new InheritancePostUpdateEvent($inheritance, $sourceEntity, $destinationEntity),
      InheritanceEvents::POST_UPDATE
    );
    return TRUE;
  }

  /**
   * Get the list of entities that need to be updated.
   *
   * @param \Drupal\Core\Entity\EntityInterface $sourceEntity
   *   Source entity to search for.
   * @param string $destinationEntityType
   *   Destination Entity Type.
   * @param \Drupal\entity_value_inheritance\Entity\InheritanceInterface[] $inheritances
   *   Inheritance entity to get criteria for.
   *
   * @return \Drupal\Core\Entity\EntityInterface[]
   *   List of entities that need to be processed.
   */
  protected function getListOfDestinationEntities(EntityInterface $sourceEntity, string $destinationEntityType, array $inheritances): array {
    $updateEntities = $this->helper->queryEntities($destinationEntityType, $inheritances, $sourceEntity);
    /** @var \Drupal\entity_value_inheritance\Event\InheritanceAlterUpdateListEvent $event */
    $event = $this->helper->dispatchEvent(
      new InheritanceAlterUpdateListEvent($sourceEntity, $updateEntities),
      InheritanceEvents::ALTER_UPDATE_LIST
    );
    return $event->getList();
  }

  /**
   * Try to update the destination using the source entity.
   *
   * @param \Drupal\entity_value_inheritance\Entity\InheritanceInterface $inheritance
   *   Inheritance configuration.
   * @param \Drupal\Core\Entity\EntityInterface $sourceEntity
   *   Entity providing the information.
   * @param \Drupal\Core\Entity\EntityInterface $destinationEntity
   *   Entity being updated.
   *
   * @return \Drupal\Core\Entity\EntityInterface
   *   Return the entity being updated.
   */
  protected function tryUpdating(InheritanceInterface $inheritance, EntityInterface $sourceEntity, EntityInterface $destinationEntity): EntityInterface {
    try {
      $plugin = $this->createInstance($inheritance);
      // Update the destination.
      $altered = $plugin->updateDestination($sourceEntity, $destinationEntity);
      // Mark if the entity is altered.
      $destinationEntity->altered =
        isset($destinationEntity->altered) &&
        $destinationEntity->altered === TRUE ||
        $altered;
    }
    catch (PluginNotFoundException | PluginException $pluginNotFoundException) {
      // Add attribute that entity was altered.
      $destinationEntity->altered = FALSE;
      // If there is an issue log the message.
      $this->helper->logger()->error(
        implode('</br>', [
          'Instance encountered an error.',
          'Inheritance: @instance_id',
          'Updater Plugin ID: @plugin_id',
          'Source Entity ID: @source_entity_id',
          'Destination Entity ID: @destination_entity_id',
          'Error Message: <pre>@message</pre>',
        ]),
        [
          '@instanced_id' => $inheritance->id(),
          '@plugin' => $inheritance->getStrategy(),
          '@source_entity_id' => $sourceEntity->id(),
          '@destination_entity_id' => $destinationEntity->id(),
          '@message' => $pluginNotFoundException->getMessage(),
        ]
      );
    }
    return $destinationEntity;
  }

  /**
   * Hook to modify or work with entities before saving.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   Entity to alter before saving.
   *
   * @see hook_entity_presave()
   */
  public function preSaveEntity(EntityInterface $entity): void {
    $list = array_merge(
      $this->helper->getInheritanceItemsBySource($entity),
      $this->helper->getInheritanceItemsByDestination($entity)
    );

    foreach ($list as $inheritance) {
      $plugin = $this->createInstance($inheritance);
      $plugin->preSaveEntity($entity);
    }
  }

  /**
   * Hook to modify or work with entities before saving.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   Entity to alter before saving.
   *
   * @see hook_entity_delete()
   */
  public function deleteEntity(EntityInterface $entity): void {
    $list = array_merge(
      $this->helper->getInheritanceItemsBySource($entity),
      $this->helper->getInheritanceItemsByDestination($entity)
    );

    foreach ($list as $inheritance) {
      $plugin = $this->createInstance($inheritance);
      $plugin->deleteEntity($entity);
    }
  }

  /**
   * Modify or alter any of the entities that are being loaded.
   *
   * @param \Drupal\Core\Entity\EntityInterface[] $entities
   *   Entities to alter during the load process.
   * @param string $entity_type_id
   *   Entity Type being loaded.
   *
   * @see hook_entity_load()
   */
  public function entityLoad(array $entities, string $entity_type_id): void {
    // Group the entities by entity type then bundle.
    $bundles = [];
    foreach ($entities as $entity) {
      $bundles[$entity->bundle()][] = $entity;
    }

    // Loop through the group.
    foreach ($bundles as $bundle_type => $entities) {
      $list = array_merge(
        $this->helper->getSourceItems($entity_type_id, $bundle_type),
        $this->helper->getDestinationItems($entity_type_id, $bundle_type)
      );

      foreach ($list as $inheritance) {
        $plugin = $this->createInstance($inheritance);
        $plugin->entityLoadProperties($entity_type_id, $entities);
        foreach ($entities as $entity) {
          $plugin->entityLoad($entity);
        }
      }
    }
  }

  /**
   * Alter the processed build of groups.
   *
   * @param array $element
   *   The element being processed.
   * @param object $group
   *   The group info.
   * @param object $complete_form
   *   The complete form.
   *
   * @see hook_field_group_form_process_alter()
   */
  public function fieldGroupFormProcessAlter(array &$element, object &$group, array &$complete_form) {
    $fields = $group->children;
    $entityType = $group->entity_type;
    $bundleType = $group->bundle;

    foreach ($fields as $field) {
      $inheritances = $this->helper->getDestinationsByField($entityType, $bundleType, $field);
      if (!empty($inheritances)) {
        $inheritance = array_pop($inheritances);
        $plugin = $this->createInstance($inheritance);
        $plugin->fieldGroupFormProcessAlter($element, $group, $complete_form);
      }
    }
  }

  /**
   * Helper Method for creating inheritance methods and storing a version of it.
   *
   * @param \Drupal\entity_value_inheritance\Entity\InheritanceInterface $inheritance
   *   Inheritance to create a plugin for.
   *
   * @return \Drupal\entity_value_inheritance\EntityValueInheritanceUpdaterPluginInterface
   *   Plugin Instance.
   *
   * @throws \Drupal\Component\Plugin\Exception
   *   Throws exception if can't find or create plugin.
   */
  protected function createInstance(InheritanceInterface $inheritance): EntityValueInheritanceUpdaterPluginInterface {
    if (!$this->plugins->contains($inheritance)) {
      $this->plugins->offsetSet($inheritance, ($this->pluginManager->createInstance($inheritance->getStrategy(), $inheritance->getSettings()))->setInheritance($inheritance));
    }
    return $this->plugins->offsetGet($inheritance);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc