class Query in Apigee Edge 8
Defines the entity query for Apigee Edge entities.
Query loader always tries to use the best Apigee Edge endpoint for retrieving already filtered results from Apigee Edge and only do the necessary filtering in the PHP side. It does it in the getFromStorage() method by filtering conditions to find those that can used directly on Apigee Edge. This process does not work on group conditions (OR, AND) it only supports direct field conditions added to the query. Group conditions always evaluated on the PHP side.
// This works.
$query
->condition('developerId', 'XY');
// But this does not.
$or = $query
->orConditionGroup() . $or
->condition('developerId', 'XY')
->condition('developerId', 'YX');
$query
->condition($or);
Hierarchy
- class \Drupal\Core\Entity\Query\QueryBase implements QueryInterface
- class \Drupal\apigee_edge\Entity\Query\Query implements QueryInterface
Expanded class hierarchy of Query
File
- src/
Entity/ Query/ Query.php, line 48
Namespace
Drupal\apigee_edge\Entity\QueryView source
class Query extends QueryBase implements QueryInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* 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 array $namespaces
* List of potential namespaces of the classes belonging to this query.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeInterface $entity_type, string $conjunction, array $namespaces, EntityTypeManagerInterface $entity_type_manager) {
parent::__construct($entity_type, $conjunction, $namespaces);
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public function execute() {
// We have to allow getFromStorage() to remove unnecessary query conditions
// so we have to run it before compile(). Example: DeveloperAppQuery
// can load only apps of a specific developer by developerId or email.
// If it does that by email then the email condition should be removed
// because developer apps do not have email property only developerId.
// Basically, DeveloperAppQuery already applies a condition on the returned
// result because this function gets called.
$all_records = $this
->getFromStorage();
$filter = $this->condition
->compile($this);
$result = array_filter($all_records, $filter);
if ($this->count) {
return count($result);
}
if ($this->sort) {
uasort($result, function (EntityInterface $entity0, EntityInterface $entity1) : int {
foreach ($this->sort as $sort) {
$value0 = Condition::getProperty($entity0, $sort['field']);
$value1 = Condition::getProperty($entity1, $sort['field']);
$cmp = $value0 <=> $value1;
if ($cmp === 0) {
continue;
}
if ($sort['direction'] === 'DESC') {
$cmp *= -1;
}
return $cmp;
}
return 0;
});
}
$this
->initializePager();
if ($this->range) {
$result = array_slice($result, $this->range['start'], $this->range['length']);
}
return array_map(function (EntityInterface $entity) : string {
return (string) $entity
->id();
}, $result);
}
/**
* Returns an array of properties that should be considered as entity ids.
*
* Usually one entity has one primary id, but in case of Apigee Edge
* entities one entity could have multiple ids (primary keys).
* Ex.: Developer => ['email', 'developerId'].
*
* @return string[]
* Array of property names that should be considered as unique entity ids.
*/
protected function getEntityIdProperties() : array {
$storage = $this->entityTypeManager
->getStorage($this->entityTypeId);
/** @var \Drupal\apigee_edge\Entity\EdgeEntityInterface $entity */
$entity = $storage
->create();
return $entity::uniqueIdProperties();
}
/**
* Loads entities from the entity storage for querying.
*
* @return \Drupal\Core\Entity\EntityInterface[]
* Array of matching entities.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
*/
protected function getFromStorage() : array {
$storage = $this->entityTypeManager
->getStorage($this->entityTypeId);
// The worst case: load all entities from Apigee Edge.
$ids = NULL;
$original_conditions =& $this->condition
->conditions();
$filtered_conditions = [];
foreach ($original_conditions as $key => $condition) {
$filtered_conditions[$key] = $condition;
$id = NULL;
// Indicates whether we found a single entity id in this condition
// or not.
$id_found = FALSE;
// \Drupal\Core\Entity\EntityStorageBase::buildPropertyQuery() always adds
// conditions with IN this is the reason why the last part of this
// condition is needed.
if (in_array($condition['field'], $this
->getEntityIdProperties()) && (in_array($condition['operator'], [
NULL,
'=',
]) || $condition['operator'] === 'IN' && is_array($condition['value']) && count($condition['value']) === 1)) {
if (is_array($condition['value'])) {
$id = reset($condition['value']);
$id_found = TRUE;
}
else {
$id = $condition['value'];
$id_found = TRUE;
}
}
// We have to handle propertly when a developer probably unintentionally
// passed an empty value (null, false, "", etc.) as a value of a condition
// for a primary entity id. In this case we should return empty result
// immediately because this condition can not be evaluated Apigee Edge
// and we should not load all entities unnecessarily to get same result
// after filtered the results in the PHP side.
if ($id_found) {
if (empty($id)) {
return [];
}
else {
$ids = [
$id,
];
unset($filtered_conditions[$key]);
// If we found an id field in the query do not look for an another
// because that would not make any sense to query one entity by
// both id fields. (Where in theory both id field could refer to a
// different entity.)
break;
}
}
}
// Remove conditions that is going to be applied on Apigee Edge
// (by calling the proper API with the proper parameters).
// We do not want to apply the same filters on the result in execute()
// again.
$original_conditions = $filtered_conditions;
return $storage
->loadMultiple($ids);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
Query:: |
protected | property | The entity type manager. | |
Query:: |
public | function |
Execute the query. Overrides QueryInterface:: |
|
Query:: |
protected | function | Returns an array of properties that should be considered as entity ids. | |
Query:: |
protected | function | Loads entities from the entity storage for querying. | 1 |
Query:: |
public | function |
Constructs a Query object. Overrides QueryBase:: |
|
QueryBase:: |
protected | property | Whether access check is requested or not. Defaults to TRUE. | |
QueryBase:: |
protected | property | The list of aggregate expressions. | |
QueryBase:: |
protected | property | Flag indicating whether to query the current revision or all revisions. | |
QueryBase:: |
protected | property | The query metadata for alter purposes. | |
QueryBase:: |
protected | property | The query tags. | |
QueryBase:: |
protected | property | Conditions. | 1 |
QueryBase:: |
protected | property | Aggregate Conditions | |
QueryBase:: |
protected | property | TRUE if this is a count query, FALSE if it isn't. | |
QueryBase:: |
protected | property | Information about the entity type. | 1 |
QueryBase:: |
protected | property | The entity type this query runs against. | |
QueryBase:: |
protected | property | The list of columns to group on. | |
QueryBase:: |
protected | property | Flag indicating whether to query the latest revision. | |
QueryBase:: |
protected | property | List of potential namespaces of the classes belonging to this query. | |
QueryBase:: |
protected | property | The query pager data. | |
QueryBase:: |
protected | property | The query range. | |
QueryBase:: |
protected | property | The list of sorts. | |
QueryBase:: |
protected | property | The list of sorts over the aggregate results. | |
QueryBase:: |
public | function |
Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Adds additional metadata to the query. Overrides AlterableInterface:: |
|
QueryBase:: |
public | function |
Adds a tag to a query. Overrides AlterableInterface:: |
|
QueryBase:: |
public | function | ||
QueryBase:: |
public | function |
Queries all the revisions. Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Creates a new group of conditions ANDed together. Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Add a condition to the query or a condition group. Overrides QueryInterface:: |
1 |
QueryBase:: |
public | function | ||
QueryBase:: |
protected | function | Creates an object holding a group of conditions. | |
QueryBase:: |
public | function |
Makes this a count query. Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Queries the current revision. Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Queries for a non-empty value on a field. Overrides QueryInterface:: |
|
QueryBase:: |
protected | function | Generates an alias for a field and its aggregated function. | |
QueryBase:: |
public static | function | Finds a class in a list of namespaces. | |
QueryBase:: |
public | function |
Gets the ID of the entity type for this query. Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Retrieves a given piece of metadata. Overrides AlterableInterface:: |
|
QueryBase:: |
public static | function | Gets a list of namespaces of the ancestors of a class. | |
QueryBase:: |
public | function | ||
QueryBase:: |
public | function |
Determines if a given query has all specified tags. Overrides AlterableInterface:: |
|
QueryBase:: |
public | function |
Determines if a given query has any specified tag. Overrides AlterableInterface:: |
|
QueryBase:: |
public | function |
Determines if a given query has a given tag. Overrides AlterableInterface:: |
|
QueryBase:: |
protected | function | Gets the total number of results and initialize a pager for the query. | |
QueryBase:: |
public | function |
Queries the latest revision. Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Queries for an empty field. Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Creates a new group of conditions ORed together. Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Enables a pager for the query. Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Overrides QueryInterface:: |
|
QueryBase:: |
public | function |
Overrides QueryInterface:: |
|
QueryBase:: |
public | function | ||
QueryBase:: |
public | function |
Enables sortable tables for this query. Overrides QueryInterface:: |
|
QueryBase:: |
public | function | Makes sure that the Condition object is cloned as well. | 1 |