diff --git a/core/modules/migrate/migrate.services.yml b/core/modules/migrate/migrate.services.yml index 8b6bad7..a14da1d 100644 --- a/core/modules/migrate/migrate.services.yml +++ b/core/modules/migrate/migrate.services.yml @@ -6,6 +6,9 @@ services: factory_method: get factory_service: cache_factory arguments: [migrate] + entity.query.migrate: + class: Drupal\migrate\Entity\Query\QueryFactory + arguments: ['@config.storage'] plugin.manager.migrate.source: class: Drupal\migrate\Plugin\MigratePluginManager arguments: [source, '@container.namespaces', '@cache.discovery', '@module_handler', 'Drupal\migrate\Annotation\MigrateSource'] diff --git a/core/modules/migrate/src/Entity/Query/Condition.php b/core/modules/migrate/src/Entity/Query/Condition.php new file mode 100644 index 0000000..a1361ec --- /dev/null +++ b/core/modules/migrate/src/Entity/Query/Condition.php @@ -0,0 +1,18 @@ +storage = $migration_storage; + } + + /** + * Overrides \Drupal\Core\Entity\Query\QueryBase::condition(). + * + * Additional to the syntax defined in the QueryInterface you can use + * placeholders (*) to match all keys of an subarray. Let's take the follow + * yaml file as example: + * @code + * level1: + * level2a: + * level3: 1 + * level2b: + * level3: 2 + * @endcode + * Then you can filter out via $query->condition('level1.*.level3', 1). + */ + public function condition($property, $value = NULL, $operator = NULL, $langcode = NULL) { + return parent::condition($property, $value, $operator, $langcode); + } + + /** + * Implements \Drupal\Core\Entity\Query\QueryInterface::execute(). + */ + public function execute() { + // Load the relevant config records. + $configs = $this->loadRecords(); + + // Apply conditions. + $result = $this->condition->compile($configs); + + // Apply sort settings. + foreach ($this->sort as $sort) { + $direction = $sort['direction'] == 'ASC' ? -1 : 1; + $field = $sort['field']; + uasort($result, function($a, $b) use ($field, $direction) { + return ($a[$field] <= $b[$field]) ? $direction : -$direction; + }); + } + + // Let the pager do its work. + $this->initializePager(); + + if ($this->range) { + $result = array_slice($result, $this->range['start'], $this->range['length'], TRUE); + } + if ($this->count) { + return count($result); + } + + // Create the expected structure of entity_id => entity_id. Config + // entities have string entity IDs. + foreach ($result as $key => &$value) { + $value = (string) $key; + } + return $result; + } + + /** + * Loads the config records to examine for the query. + * + * @return array + * Config records keyed by entity IDs. + */ + protected function loadRecords() { + $prefix = 'migrate.migration.'; + $prefix_length = strlen($prefix); + + // Search the conditions for restrictions on entity IDs. + $ids = array(); + if ($this->condition->getConjunction() == 'AND') { + foreach ($this->condition->conditions() as $condition) { + if (is_string($condition['field']) && $condition['field'] == $this->entityType->getKey('id')) { + $operator = $condition['operator'] ?: (is_array($condition['value']) ? 'IN' : '='); + if ($operator == '=') { + $ids = array($condition['value']); + } + elseif ($operator == 'IN') { + $ids = $condition['value']; + } + // We stop at the first restricting condition on ID. In the (weird) + // case where there are additional restricting conditions, results + // will be eliminated when the conditions are checked on the loaded + // records. + if ($ids) { + break; + } + } + } + } + // If there are conditions restricting config ID, we can narrow the list of + // records to load and parse. + if ($ids) { + $names = array_map(function ($id) use ($prefix) { + return $prefix . $id; + }, $ids); + } + // If no restrictions on IDs were found, we need to parse all records. + else { + $names = $this->storage->listAll($prefix); + } + + // Load the corresponding records. + $records = array(); + foreach ($this->storage->readMultiple($names) as $id => $data) { + $records[substr($id, $prefix_length)] = $data; + } + return $records; + } + +} diff --git a/core/modules/migrate/src/Entity/Query/QueryFactory.php b/core/modules/migrate/src/Entity/Query/QueryFactory.php new file mode 100644 index 0000000..abee2e7 --- /dev/null +++ b/core/modules/migrate/src/Entity/Query/QueryFactory.php @@ -0,0 +1,56 @@ +storage = new ExtensionInstallStorage($config_storage, MigrationStorage::MIGRATION_DIRECTORY);; + $this->namespaces = QueryBase::getNamespaces($this); + } + + /** + * {@inheritdoc} + */ + public function get(EntityTypeInterface $entity_type, $conjunction) { + return new Query($entity_type, $conjunction, $this->storage, $this->namespaces); + } + + /** + * {@inheritdoc} + */ + public function getAggregate(EntityTypeInterface $entity_type, $conjunction) { + throw new QueryException('Aggregation over configuration entities is not supported'); + } + +} diff --git a/core/modules/migrate/src/MigrationStorage.php b/core/modules/migrate/src/MigrationStorage.php index 0d3aebf..5e5fab7 100644 --- a/core/modules/migrate/src/MigrationStorage.php +++ b/core/modules/migrate/src/MigrationStorage.php @@ -159,8 +159,7 @@ protected function has($id, EntityInterface $entity) { * {@inheritdoc} */ protected function getQueryServiceName() { - // @todo bit of a mess? - return 'entity.query.config'; + return 'entity.query.migrate'; } /**