diff --git a/core/lib/Drupal/Core/Config/Entity/Condition.php b/core/lib/Drupal/Core/Config/Entity/Condition.php new file mode 100644 index 0000000..0d30585 --- /dev/null +++ b/core/lib/Drupal/Core/Config/Entity/Condition.php @@ -0,0 +1,95 @@ +entityType); + $config_prefix = $info['config_prefix']; + // -H forces grep to print the filenames. + $options = '-H'; + $postfix = " $query->directory/$config_prefix.*.yml"; + + // The general idea is to build a list of grep commands via pipes to apply multiple search conditions. + foreach ($this->conditions as $condition) { + $field = '^ *' . $condition['field']; + // \Drupal\Core\Config\Config::castValue() casts to string. + $value = (string) $condition['value']; + // \Symfony\Component\Yaml\Inline::dump() does this. + $quote = ctype_digit($value) ? "'" : ''; + if (Escaper::requiresDoubleQuoting($value)) { + throw new \InvalidArgumentException('Invalid character in value.'); + } + elseif (Escaper::requiresSingleQuoting($value)) { + $value = str_replace("'", "''", $value); + $quote = "'"; + } + switch ($condition['operator']) { + case NULL: + case '=': + $value = "$quote$value$quote$"; + break; + + case 'CONTAINS': + $value = ".*$value"; + break; + + case 'STARTS_WITH': + $value = "$quote$value"; + break; + + case 'ENDS_WITH': + $value = ".*$value$quote$"; + break; + } + $subject = escapeshellarg("$field: $value"); + $commands[] = "grep $options $subject $postfix"; + $options = ''; + } + if (!empty($commands)) { + $command = implode('|', $commands); + } + else { + // @todo Find a better way to get all files matching a certain config_prefix. + $options .= ' -L'; + $command = "grep $options $postfix"; + } + exec($command, $output); + + // Get the actual entity IDs out of the filename using a regular expression. + $cut_length = strlen($query->directory) + strlen($config_prefix) + 2; + $ids = array(); + foreach ($output as $line) { + preg_match('/^([^.]+)\./', substr($line, $cut_length), $matches); + $ids[] = $matches[1]; + } + return $ids; + } + + /** + * Implements Drupal\Core\Entity\Query\ConditionInterface::exists(). + */ + public function exists($field, $langcode = NULL) { + } + + /** + * Implements Drupal\Core\Entity\Query\ConditionInterface::notExists(). + */ + public function notExists($field, $langcode = NULL) { + } + +} diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php index 6d0a3f4..8187dfc 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php @@ -428,6 +428,6 @@ protected function invokeHook($hook, EntityInterface $entity) { * Implements Drupal\Core\Entity\EntityStorageControllerInterface::getQueryServicename(). */ public function getQueryServicename() { - throw new \LogicException('Querying configuration entities is not supported.'); + return 'entity.query.config'; } } diff --git a/core/lib/Drupal/Core/Config/Entity/Query.php b/core/lib/Drupal/Core/Config/Entity/Query.php new file mode 100644 index 0000000..617d596 --- /dev/null +++ b/core/lib/Drupal/Core/Config/Entity/Query.php @@ -0,0 +1,46 @@ +directory = $directory; + } + + /** + * Implements Drupal\Core\Entity\Query\QueryInterface::conditionGroupFactory(). + */ + public function conditionGroupFactory($conjunction = 'AND') { + return new Condition($conjunction); + } + + /** + * Implements Drupal\Core\Entity\Query\QueryInterface::execute(). + */ + public function execute() { + $query = new \stdClass; + $query->directory = $this->directory; + $query->entityType = $this->entityType; + return drupal_map_assoc($this->condition->compile($query)); + } + +} diff --git a/core/lib/Drupal/Core/Config/Entity/QueryFactory.php b/core/lib/Drupal/Core/Config/Entity/QueryFactory.php new file mode 100644 index 0000000..bea2b27 --- /dev/null +++ b/core/lib/Drupal/Core/Config/Entity/QueryFactory.php @@ -0,0 +1,22 @@ +directory = $directory; + } + + function get($entity_type, $conjunction = 'AND') { + return new Query($entity_type, $conjunction, $this->directory); + } +} diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index e1147ac..51d2caa 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -127,6 +127,9 @@ public function build(ContainerBuilder $container) { // Add the entity query factory. $container->register('entity.query', 'Drupal\Core\Entity\Query\QueryFactory') ->addArgument(new Reference('service_container')); + // @todo: replace with active config storage refernece once it is in CoreBundle. + $container->register('entity.query.config', 'Drupal\Core\Config\Entity\QueryFactory') + ->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY)); $container->register('router.dumper', 'Drupal\Core\Routing\MatcherDumper') ->addArgument(new Reference('database')); diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityQueryTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityQueryTest.php new file mode 100644 index 0000000..a54738d --- /dev/null +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityQueryTest.php @@ -0,0 +1,165 @@ + 'Config Entity Query', + 'description' => 'Tests Config Entity Query functionality.', + 'group' => 'Configuration', + ); + } + + protected function setUp() { + parent::setUp(); + + $entity = entity_create('config_test', array( + 'label' => $this->randomName(), + 'id' => 1, + ) + ); + $this->entities[] = $entity; + $entity->enforceIsNew(); + $entity->save(); + + $entity = entity_create('config_test', array( + 'label' => $this->randomName(), + 'id' => 2, + ) + ); + $this->entities[] = $entity; + $entity->enforceIsNew(); + $entity->save(); + + $entity = entity_create('config_test', array( + 'label' => 'test_prefix_' . $this->randomName(), + 'id' => 3, + ) + ); + $this->entities[] = $entity; + $entity->enforceIsNew(); + $entity->save(); + + $entity = entity_create('config_test', array( + 'label' => $this->randomName() . '_test_suffix', + 'id' => 4, + ) + ); + $this->entities[] = $entity; + $entity->enforceIsNew(); + $entity->save(); + + $entity = entity_create('config_test', array( + 'label' => $this->randomName() . '_test_contains_' . $this->randomName(), + 'id' => 5, + ) + ); + $this->entities[] = $entity; + $entity->enforceIsNew(); + $entity->save(); + + // @todo This should be from the container. + $this->factory = new QueryFactory(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY)); + } + + + /** + * Test basic functionality. + */ + public function testConfigEntityQuery() { + //d Run a test without any condition. + $this->queryResults = $this->factory->get('config_test') + ->execute(); + + $this->assertEqual(count($this->queryResults), count($this->entities)); + + // Filter by ID with equality. + $this->queryResults = $this->factory->get('config_test') + ->condition('id', 3) + ->execute(); + + $this->assertEqual(count($this->queryResults), 1); + + // Filter by label with a known prefix. + $this->queryResults = $this->factory->get('config_test') + ->condition('label', 'test_prefix', 'STARTS_WITH') + ->execute(); + + $this->assertEqual(count($this->queryResults), 1); + $this->assertEqual($this->queryResults[3], '3'); + + // Filter by label with a known suffix. + $this->queryResults = $this->factory->get('config_test') + ->condition('label', 'test_suffix', 'ENDS_WITH') + ->execute(); + + $this->assertEqual(count($this->queryResults), 1); + $this->assertEqual($this->queryResults[4], 4); + + // Filter by label with a known containing word. + $this->queryResults = $this->factory->get('config_test') + ->condition('label', 'test_contains', 'CONTAINS') + ->execute(); + + $this->assertEqual(count($this->queryResults), 1); + $this->assertEqual($this->queryResults[5], 5); + + // Filter with an OR condition group. + $this->queryResults = $this->factory->get('config_test', 'OR') + ->condition('id', 1) + ->condition('id', 2) + ->execute(); + $this->assertEqual(count($this->queryResults), 2); + } + + /** + * Test entity count query. + */ + protected function testCount() { + $this->queryResults = $this->factory->get('config_test') + ->count() + ->execute(); + + $this->assertEqual(count($this->queryResults), 5); + } + +}