content_sync-8.x-2.x-dev/src/DependencyResolver/ImportQueueResolver.php
src/DependencyResolver/ImportQueueResolver.php
<?php namespace Drupal\content_sync\DependencyResolver; use Drupal\Core\Serialization\Yaml; /** * Class ImportQueueResolver. * * @package Drupal\content_sync\DependencyResolver */ class ImportQueueResolver implements ContentSyncResolverInterface { /** * The normalized data. * @var array */ protected $normalizedEntities; /** * Entities with references to ancestors. * @var array */ protected $rebuild; /** * Queue variable. * @var array */ protected $q; /** * Constructs an ImportQueueResolver object. * * @param array $normalized_entities * The normalized data. */ public function __construct(array $normalized_entities) { $this->normalizedEntities = $normalized_entities; $this->rebuild = []; $this->q = []; } /** * Creates a queue. * * @return array * Queue to be processed within a batch process. */ public function resolve() { $ancestors = []; foreach ($this->normalizedEntities as $identifier => $entity) { $this->processEntity($identifier, $entity, $ancestors); } return array_reverse(array_merge($this->q, $this->rebuild)); } /** * Get entities dependencies - it considers redundancies. */ public function processEntity(string $identifier, array $entity, array $ancestors) { $q = array_column($this->q, 'identifier'); if (in_array($identifier, $q)) { return; } $ancestors[] = $identifier; $dependencies = $this->getDependencies($entity); foreach ($dependencies as $dependency) { $dependency_entity = $this->fetchEntity($dependency); if (in_array($dependency, $ancestors)) { $this->rebuild[] = [ 'identifier' => $identifier, 'entity_type_id' => $entity['_content_sync']['entity_type'], 'decoded_entity' => $entity, ]; } else { $this->processEntity($dependency, $dependency_entity, $ancestors); } } $this->q[] = [ 'identifier' => $identifier, 'entity_type_id' => $entity['_content_sync']['entity_type'], 'decoded_entity' => $entity, ]; } /** * Get dependencies of a given entity. * * @return array * Dependencies of an entity. */ public function getDependencies($entity) { $dependencies = []; if (!empty($entity['_content_sync']['entity_dependencies'])) { foreach ($entity['_content_sync']['entity_dependencies'] as $ref_entity_type_id => $references) { $dependencies = array_merge($dependencies, $references); } } return $dependencies; } /** * Fetch an entity - normalized data. * * @return array * Entity normalized data. */ public function fetchEntity($identifier) { try { $entity = $this->getEntity($identifier, $this->normalizedEntities); } catch (\Exception $e) { $entity = []; // TODO: notice/log of what entity is missing. // TODO: should the import of the parent entity abort? } return $entity; } /** * Gets an entity. * * @param $identifier * An entity identifier to process. * @param $normalized_entities * An array of entity identifiers to process. * * @return bool|mixed * Decoded entity or FALSE if an entity already exists and doesn't require to be imported. * * @throws \Exception */ protected function getEntity($identifier, $normalized_entities) { if (!empty($normalized_entities[$identifier])) { $entity = $normalized_entities[$identifier]; return $entity; } else { // Check the entity in the content directory. [$entity_type_id, $bundle, $uuid] = explode('.', $identifier); $file_path = content_sync_get_content_directory('sync') . "/entities/" . $entity_type_id . "/" . $bundle . "/" . $identifier . ".yml"; $raw_entity = file_get_contents($file_path); // Problems to open the .yml file. if (!$raw_entity) { throw new \Exception("Dependency {$identifier} is missing."); } $entity = Yaml::decode($raw_entity); } // TODO: else if Check the entity exists in the snapshot // TODO: else if Check if the entity exist in the site. // TODO: better notice about missing dependency // - should the parent import be aborted or not? return $entity; } /** * Checks if a dependency exists in the site. * * @param $identifier * An entity identifier to process. * * @return bool */ protected function entityExists($identifier) { return (bool) \Drupal::database() ->queryRange('SELECT 1 FROM {cs_db_snapshot} WHERE name = :name', 0, 1, [ ':name' => $identifier]) ->fetchField(); } }