Code Coverage  | 
     ||||||||||
Classes and Traits  | 
      Functions and Methods  | 
      Lines  | 
     ||||||||
| Total |         | 
      0.00%  | 
      0 / 1  | 
              | 
      16.67%  | 
      1 / 6  | 
      CRAP |         | 
      20.63%  | 
      13 / 63  | 
     
| MigrationStorage |         | 
      0.00%  | 
      0 / 1  | 
              | 
      16.67%  | 
      1 / 6  | 
      241.46 |         | 
      20.63%  | 
      13 / 63  | 
     
| __construct |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 3  | 
     |||
| createInstance |         | 
      0.00%  | 
      0 / 1  | 
      2 |         | 
      0.00%  | 
      0 / 5  | 
     |||
| loadMultiple |         | 
      0.00%  | 
      0 / 1  | 
      12 |         | 
      0.00%  | 
      0 / 7  | 
     |||
| getVariantIds |         | 
      100.00%  | 
      1 / 1  | 
      3 |         | 
      100.00%  | 
      13 / 13  | 
     |||
| buildDependencyMigration |         | 
      0.00%  | 
      0 / 1  | 
      110 |         | 
      0.00%  | 
      0 / 30  | 
     |||
| addDependency |         | 
      0.00%  | 
      0 / 1  | 
      12 |         | 
      0.00%  | 
      0 / 5  | 
     |||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\migrate\MigrationStorage. | |
| */ | |
| namespace Drupal\migrate; | |
| use Drupal\Component\Graph\Graph; | |
| use Drupal\Component\Uuid\UuidInterface; | |
| use Drupal\Core\Config\ConfigFactoryInterface; | |
| use Drupal\Core\Config\Entity\ConfigEntityStorage; | |
| use Drupal\Core\Entity\EntityTypeInterface; | |
| use Drupal\Core\Entity\Query\QueryFactoryInterface; | |
| use Drupal\Core\Language\LanguageManagerInterface; | |
| use Symfony\Component\DependencyInjection\ContainerInterface; | |
| /** | |
| * Storage for migration entities. | |
| */ | |
| class MigrationStorage extends ConfigEntityStorage implements MigrateBuildDependencyInterface { | |
| /** | |
| * The entity query factory service. | |
| * | |
| * @var \Drupal\Core\Entity\Query\QueryFactoryInterface | |
| */ | |
| protected $queryFactory; | |
| /** | |
| * Constructs a MigrationStorage object. | |
| * | |
| * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type | |
| * An entity type definition. | |
| * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory | |
| * The config factory service. | |
| * @param \Drupal\Component\Uuid\UuidInterface $uuid_service | |
| * The UUID service. | |
| * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager | |
| * The language manager. | |
| * @param \Drupal\Core\Entity\Query\QueryFactoryInterface $query_factory | |
| * The entity query factory service. | |
| */ | |
| public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, QueryFactoryInterface $query_factory) { | |
| parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager); | |
| $this->queryFactory = $query_factory; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { | |
| return new static( | |
| $entity_type, | |
| $container->get('config.factory'), | |
| $container->get('uuid'), | |
| $container->get('language_manager'), | |
| $container->get('entity.query.config') | |
| ); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function loadMultiple(array $ids = NULL) { | |
| if ($ids) { | |
| $ids = $this->getVariantIds($ids); | |
| } | |
| /** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */ | |
| $migrations = parent::loadMultiple($ids); | |
| foreach ($migrations as $migration) { | |
| $dependencies = array_map([$this, 'getVariantIds'], $migration->getMigrationDependencies()); | |
| $migration->set('migration_dependencies', $dependencies); | |
| } | |
| // Build an array of dependencies and set the order of the migrations. | |
| return $this->buildDependencyMigration($migrations, []); | |
| } | |
| /** | |
| * Splices variant IDs into a list of migration IDs. | |
| * | |
| * IDs which match the template_id:* pattern are shorthand for every variant | |
| * of template_id. This method queries for those variant IDs and splices them | |
| * into the original list. | |
| * | |
| * @param string[] $ids | |
| * A set of migration IDs. | |
| * | |
| * @return string[] | |
| * The expanded list of IDs. | |
| */ | |
| public function getVariantIds(array $ids) { | |
| // Re-index the array numerically, since we need to limit the loop by size. | |
| $ids = array_values($ids); | |
| $index = 0; | |
| while ($index < count($ids)) { | |
| if (substr($ids[$index], -2) == ':*') { | |
| $template_id = substr($ids[$index], 0, -2); | |
| $variants = $this->queryFactory->get($this->entityType, 'OR') | |
| ->condition('id', $template_id) | |
| ->condition('template', $template_id) | |
| ->execute(); | |
| array_splice($ids, $index, 1, $variants); | |
| $index += count($variants); | |
| } | |
| else { | |
| $index++; | |
| } | |
| } | |
| return $ids; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function buildDependencyMigration(array $migrations, array $dynamic_ids) { | |
| // Migration dependencies defined in the migration storage can be | |
| // optional or required. If an optional dependency does not run, the current | |
| // migration is still OK to go. Both optional and required dependencies | |
| // (if run at all) must run before the current migration. | |
| $dependency_graph = array(); | |
| $requirement_graph = array(); | |
| $different = FALSE; | |
| foreach ($migrations as $migration) { | |
| /** @var \Drupal\migrate\Entity\MigrationInterface $migration */ | |
| $id = $migration->id(); | |
| $requirements[$id] = array(); | |
| $dependency_graph[$id]['edges'] = array(); | |
| $migration_dependencies = $migration->getMigrationDependencies(); | |
| if (isset($migration_dependencies['required'])) { | |
| foreach ($migration_dependencies['required'] as $dependency) { | |
| if (!isset($dynamic_ids[$dependency])) { | |
| $this->addDependency($requirement_graph, $id, $dependency, $dynamic_ids); | |
| } | |
| $this->addDependency($dependency_graph, $id, $dependency, $dynamic_ids); | |
| } | |
| } | |
| if (isset($migration_dependencies['optional'])) { | |
| foreach ($migration_dependencies['optional'] as $dependency) { | |
| $different = TRUE; | |
| $this->addDependency($dependency_graph, $id, $dependency, $dynamic_ids); | |
| } | |
| } | |
| } | |
| $graph_object = new Graph($dependency_graph); | |
| $dependency_graph = $graph_object->searchAndSort(); | |
| if ($different) { | |
| $graph_object = new Graph($requirement_graph); | |
| $requirement_graph = $graph_object->searchAndSort(); | |
| } | |
| else { | |
| $requirement_graph = $dependency_graph; | |
| } | |
| $weights = array(); | |
| foreach ($migrations as $migration_id => $migration) { | |
| // Populate a weights array to use with array_multisort later. | |
| $weights[] = $dependency_graph[$migration_id]['weight']; | |
| if (!empty($requirement_graph[$migration_id]['paths'])) { | |
| $migration->set('requirements', $requirement_graph[$migration_id]['paths']); | |
| } | |
| } | |
| array_multisort($weights, SORT_DESC, SORT_NUMERIC, $migrations); | |
| return $migrations; | |
| } | |
| /** | |
| * Add one or more dependencies to a graph. | |
| * | |
| * @param array $graph | |
| * The graph so far, passed by reference. | |
| * @param int $id | |
| * The migration ID. | |
| * @param string $dependency | |
| * The dependency string. | |
| * @param array $dynamic_ids | |
| * The dynamic ID mapping. | |
| */ | |
| protected function addDependency(array &$graph, $id, $dependency, $dynamic_ids) { | |
| $dependencies = isset($dynamic_ids[$dependency]) ? $dynamic_ids[$dependency] : array($dependency); | |
| if (!isset($graph[$id]['edges'])) { | |
| $graph[$id]['edges'] = array(); | |
| } | |
| $graph[$id]['edges'] += array_combine($dependencies, $dependencies); | |
| } | |
| } |