contentserialize-8.x-1.x-dev/src/MissingReferenceFixer.php

src/MissingReferenceFixer.php
<?php

namespace Drupal\contentserialize;

use Drupal\bulkentity\EntityLoaderInterface;
use Drupal\Core\Entity\ContentEntityInterface;

/**
 * Tracks references between entities that can't be set on import.
 *
 * It's possible that an entity is imported before all its dependencies (eg. if
 * there's a cyclic refrence it can't be avoided). This object will track which
 * entities are missing references to which others and will call a custom
 * callback when the import's finished.
 *
 * @todo Add tests.
 */
class MissingReferenceFixer {

  /**
   * The batch size to use when loading referenced entities.
   *
   * @var int
   */
  const BATCH_SIZE = 50;

  /**
   * @var array
   */
  protected $targets = [];

  /**
   * Callbacks to fix missing entity references keyed by entity type and UUID.
   *
   * @var array
   */
  protected $callbacks = [];

  /**
   * The entity loader
   *
   * @var \Drupal\bulkentity\EntityLoaderInterface
   */
  protected $entityLoader;

  /**
   * Creates a new missing reference fixer.
   *
   * @param \Drupal\bulkentity\EntityLoaderInterface $entity_loader
   *   The bulk entity loader.
   */
  public function __construct(EntityLoaderInterface $entity_loader) {
    $this->entityLoader = $entity_loader;
  }

  /**
   * Register that an imported entity has a reference to a non-existent entity.
   *
   * @param string $type
   *   The entity type ID of the referencing entity;
   * @param string $uuid
   *   The UUID of the referencing entity;
   * @param string $target_type
   *   The entity type ID of the missing referenced entity;
   * @param $target_uuid
   *   The UUId of the missing referenced entity;
   * @param callable $callback
   *   A callback that will fix the missing dependency; it takes three
   *   arguments:
   *   - the loaded referencing entity object;
   *   - the entity ID of the referenced entity;
   *   - the revision ID of the referenced entity (may be NULL).
   */
  public function register($type, $uuid, $target_type, $target_uuid, callable $callback) {
    $this->callbacks[$type][$uuid][] = [$callback, $target_type, $target_uuid];
    $this->targets[$target_type][] = $target_uuid;
  }

  /**
   * Fix all registered missing references.
   */
  public function fix() {
    $map = [];
    $vids = [];
    foreach ($this->loadReferencedEntities() as $entity) {
      $map[$entity->uuid()] = $entity->id();

      // @todo Remove the special casing of entity reference revisions once
      //   #2667748 lands.
      $vid = $entity->getRevisionId();
      if ($vid) {
        $vids[$entity->uuid()] = $vid;
      }
    }

    // @todo Verify that the referenced entity types match.
    foreach ($this->loadReferencingEntities() as $entity) {
      try {
        foreach ($this->callbacks[$entity->getEntityTypeId()][$entity->uuid()] as $callback_data) {
          list($callback,, $target_uuid) = $callback_data;
          $callback($entity, $map[$target_uuid], $vids[$target_uuid] ?? NULL);
        }

        $entity->save();
      }
      catch (\Exception $e) {
        watchdog_exception('contentserialize', $e);
      }
    }
  }

  /**
   * Batch load referencing entities.
   *
   * @return \Generator|\Drupal\Core\Entity\ContentEntityInterface[]
   */
  protected function loadReferencingEntities() {
    // Although you can query by UUID with an entity query, the results won't
    // map the serial ID to UUID so we need to load the entities.
    foreach ($this->callbacks as $entity_type_id => $entities_data) {
      $query = \Drupal::entityQuery($entity_type_id)
        ->condition('uuid', array_keys($entities_data), 'IN');
      yield from $this->entityLoader->byQuery( static::BATCH_SIZE, $query);
    }
  }

  /**
   * Batch load referenced entities.
   *
   * @return \Generator|\Drupal\Core\Entity\ContentEntityInterface[]
   */
  protected function loadReferencedEntities() {
    foreach ($this->targets as $target_type => $uuids) {
      $query = \Drupal::entityQuery($target_type)
        ->condition('uuid', $uuids, 'IN');
      yield from $this->entityLoader->byQuery( static::BATCH_SIZE, $query);
    }
  }

  /**
   * Get the callbacks to run for a referencing entity.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   The referencing entity
   *
   * @return \Generator
   */
  protected function getCallbacks(ContentEntityInterface $entity) {
    yield from $this->callbacks[$entity->getEntityTypeId()][$entity->uuid()];
  }

}

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

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