Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 101 |
Query | |
0.00% |
0 / 1 |
|
0.00% |
0 / 6 |
1190 | |
0.00% |
0 / 101 |
__construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
condition | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
execute | |
0.00% |
0 / 1 |
56 | |
0.00% |
0 / 20 |
|||
anonymous function | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
loadRecords | |
0.00% |
0 / 1 |
552 | |
0.00% |
0 / 58 |
|||
getConfigKeyStore | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\Core\Config\Entity\Query\Query. | |
*/ | |
namespace Drupal\Core\Config\Entity\Query; | |
use Drupal\Core\Config\ConfigFactoryInterface; | |
use Drupal\Core\Entity\EntityTypeInterface; | |
use Drupal\Core\Entity\Query\QueryBase; | |
use Drupal\Core\Entity\Query\QueryInterface; | |
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; | |
/** | |
* Defines the entity query for configuration entities. | |
*/ | |
class Query extends QueryBase implements QueryInterface { | |
/** | |
* Information about the entity type. | |
* | |
* @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface | |
*/ | |
protected $entityType; | |
/** | |
* The config factory used by the config entity query. | |
* | |
* @var \Drupal\Core\Config\ConfigFactoryInterface | |
*/ | |
protected $configFactory; | |
/** | |
* The key value factory. | |
* | |
* @var \Drupal\Core\KeyValueStore\KeyValueFactoryInterface | |
*/ | |
protected $keyValueFactory; | |
/** | |
* Constructs a Query object. | |
* | |
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type | |
* The entity type definition. | |
* @param string $conjunction | |
* - AND: all of the conditions on the query need to match. | |
* - OR: at least one of the conditions on the query need to match. | |
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory | |
* The config factory. | |
* @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory | |
* The key value factory. | |
* @param array $namespaces | |
* List of potential namespaces of the classes belonging to this query. | |
*/ | |
function __construct(EntityTypeInterface $entity_type, $conjunction, ConfigFactoryInterface $config_factory, KeyValueFactoryInterface $key_value_factory, array $namespaces) { | |
parent::__construct($entity_type, $conjunction, $namespaces); | |
$this->configFactory = $config_factory; | |
$this->keyValueFactory = $key_value_factory; | |
} | |
/** | |
* 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); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
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 = $this->entityType->getConfigPrefix() . '.'; | |
$prefix_length = strlen($prefix); | |
// Search the conditions for restrictions on configuration object names. | |
$names = FALSE; | |
$id_condition = NULL; | |
$id_key = $this->entityType->getKey('id'); | |
if ($this->condition->getConjunction() == 'AND') { | |
$lookup_keys = $this->entityType->getLookupKeys(); | |
$conditions = $this->condition->conditions(); | |
foreach ($conditions as $condition_key => $condition) { | |
$operator = $condition['operator'] ?: (is_array($condition['value']) ? 'IN' : '='); | |
if (is_string($condition['field']) && ($operator == 'IN' || $operator == '=')) { | |
// Special case ID lookups. | |
if ($condition['field'] == $id_key) { | |
$ids = (array) $condition['value']; | |
$names = array_map(function ($id) use ($prefix) { | |
return $prefix . $id; | |
}, $ids); | |
} | |
elseif (in_array($condition['field'], $lookup_keys)) { | |
// If we don't find anything then there are no matches. No point in | |
// listing anything. | |
$names = array(); | |
$keys = (array) $condition['value']; | |
$keys = array_map(function ($value) use ($condition) { | |
return $condition['field'] . ':' . $value; | |
}, $keys); | |
foreach ($this->getConfigKeyStore()->getMultiple($keys) as $list) { | |
$names = array_merge($names, $list); | |
} | |
} | |
} | |
// Save the first ID condition that is not an 'IN' or '=' for narrowing | |
// down later. | |
elseif (!$id_condition && $condition['field'] == $id_key) { | |
$id_condition = $condition; | |
} | |
// We stop at the first restricting condition on name. In the case where | |
// there are additional restricting conditions, results will be | |
// eliminated when the conditions are checked on the loaded records. | |
if ($names !== FALSE) { | |
// If the condition has been responsible for narrowing the list of | |
// configuration to check there is no point in checking it further. | |
unset($conditions[$condition_key]); | |
break; | |
} | |
} | |
} | |
// If no restrictions on IDs were found, we need to parse all records. | |
if ($names === FALSE) { | |
$names = $this->configFactory->listAll($prefix); | |
} | |
// In case we have an ID condition, try to narrow down the list of config | |
// objects to load. | |
if ($id_condition && !empty($names)) { | |
$value = $id_condition['value']; | |
$filter = NULL; | |
switch ($id_condition['operator']) { | |
case '<>': | |
$filter = function ($name) use ($value, $prefix_length) { | |
$id = substr($name, $prefix_length); | |
return $id !== $value; | |
}; | |
break; | |
case 'STARTS_WITH': | |
$filter = function ($name) use ($value, $prefix_length) { | |
$id = substr($name, $prefix_length); | |
return strpos($id, $value) === 0; | |
}; | |
break; | |
case 'CONTAINS': | |
$filter = function ($name) use ($value, $prefix_length) { | |
$id = substr($name, $prefix_length); | |
return strpos($id, $value) !== FALSE; | |
}; | |
break; | |
case 'ENDS_WITH': | |
$filter = function ($name) use ($value, $prefix_length) { | |
$id = substr($name, $prefix_length); | |
return strrpos($id, $value) === strlen($id) - strlen($value); | |
}; | |
break; | |
} | |
if ($filter) { | |
$names = array_filter($names, $filter); | |
} | |
} | |
// Load the corresponding records. | |
$records = array(); | |
foreach ($this->configFactory->loadMultiple($names) as $config) { | |
$records[substr($config->getName(), $prefix_length)] = $config->get(); | |
} | |
return $records; | |
} | |
/** | |
* Gets the key value store used to store fast lookups. | |
* | |
* @return \Drupal\Core\KeyValueStore\KeyValueStoreInterface | |
* The key value store used to store fast lookups. | |
*/ | |
protected function getConfigKeyStore() { | |
return $this->keyValueFactory->get(QueryFactory::CONFIG_LOOKUP_PREFIX . $this->entityTypeId); | |
} | |
} |