function TemporaryQueryGuard::secureQuery

Same name and namespace in other branches
  1. 9 core/modules/jsonapi/src/Access/TemporaryQueryGuard.php \Drupal\jsonapi\Access\TemporaryQueryGuard::secureQuery()
  2. 8.9.x core/modules/jsonapi/src/Access/TemporaryQueryGuard.php \Drupal\jsonapi\Access\TemporaryQueryGuard::secureQuery()
  3. 11.x core/modules/jsonapi/src/Access/TemporaryQueryGuard.php \Drupal\jsonapi\Access\TemporaryQueryGuard::secureQuery()

Applies tags, metadata and conditions to secure an entity query.

Parameters

\Drupal\Core\Entity\Query\QueryInterface $query: The query to be secured.

string $entity_type_id: An entity type ID.

array $tree: A tree of field specifiers in an entity query condition. The tree is a multi-dimensional array where the keys are field specifiers and the values are multi-dimensional array of the same form, containing only subsequent specifiers. @see ::buildTree().

\Drupal\Core\Cache\CacheableMetadata $cacheability: Collects cacheability for the query.

string|null $field_prefix: Internal use only. Contains a string representation of the previously visited field specifiers.

\Drupal\Core\Field\FieldStorageDefinitionInterface $field_storage_definition: Internal use only. The current field storage definition, if known.

See also

\Drupal\Core\Database\Query\AlterableInterface::addTag()

\Drupal\Core\Database\Query\AlterableInterface::addMetaData()

\Drupal\Core\Database\Query\ConditionInterface

1 call to TemporaryQueryGuard::secureQuery()
TemporaryQueryGuard::applyAccessControls in core/modules/jsonapi/src/Access/TemporaryQueryGuard.php
Applies access controls to an entity query.

File

core/modules/jsonapi/src/Access/TemporaryQueryGuard.php, line 122

Class

TemporaryQueryGuard
Adds sufficient access control to collection queries.

Namespace

Drupal\jsonapi\Access

Code

protected static function secureQuery(QueryInterface $query, $entity_type_id, array $tree, CacheableMetadata $cacheability, $field_prefix = NULL, FieldStorageDefinitionInterface $field_storage_definition = NULL) {
    $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
    // Config entity types are not fieldable, therefore they do not have field
    // access restrictions, nor entity references to other entity types.
    if ($entity_type instanceof ConfigEntityTypeInterface) {
        return;
    }
    foreach ($tree as $specifier => $children) {
        // The field path reconstructs the entity condition fields.
        // E.g. `uid.0` would become `uid.0.name` if $specifier === 'name'.
        $child_prefix = is_null($field_prefix) ? $specifier : "{$field_prefix}.{$specifier}";
        if (is_null($field_storage_definition)) {
            // When the field storage definition is NULL, this specifier is the
            // first specifier in an entity query field path or the previous
            // specifier was a data reference that has been traversed. In both
            // cases, the specifier must be a field name.
            $field_storage_definitions = static::$fieldManager->getFieldStorageDefinitions($entity_type_id);
            static::secureQuery($query, $entity_type_id, $children, $cacheability, $child_prefix, $field_storage_definitions[$specifier]);
            // When $field_prefix is NULL, this must be the first specifier in the
            // entity query field path and a condition for the query's base entity
            // type must be applied.
            if (is_null($field_prefix)) {
                static::applyAccessConditions($query, $entity_type_id, NULL, $cacheability);
            }
        }
        else {
            // When the specifier is an entity reference, it can contain an entity
            // type specifier, like so: `entity:node`. This extracts the `entity`
            // portion. JSON:API will have already validated that the property
            // exists.
            $split_specifier = explode(':', $specifier, 2);
            [
                $property_name,
                $target_entity_type_id,
            ] = array_merge($split_specifier, count($split_specifier) === 2 ? [] : [
                NULL,
            ]);
            // The specifier is either a field property or a delta. If it is a data
            // reference or a delta, then it needs to be traversed to the next
            // specifier. However, if the specific is a simple field property, i.e.
            // it is neither a data reference nor a delta, then there is no need to
            // evaluate the remaining specifiers.
            $property_definition = $field_storage_definition->getPropertyDefinition($property_name);
            if ($property_definition instanceof DataReferenceDefinitionInterface) {
                // Because the filter is following an entity reference, ensure
                // access is respected on those targeted entities.
                // Examples:
                // - node_query_node_access_alter()
                $target_entity_type_id = $target_entity_type_id ?: $field_storage_definition->getSetting('target_type');
                $query->addTag("{$target_entity_type_id}_access");
                static::applyAccessConditions($query, $target_entity_type_id, $child_prefix, $cacheability);
                // Keep descending the tree.
                static::secureQuery($query, $target_entity_type_id, $children, $cacheability, $child_prefix);
            }
            elseif (is_null($property_definition)) {
                assert(is_numeric($property_name), 'The specifier is not a property name, it must be a delta.');
                // Keep descending the tree.
                static::secureQuery($query, $entity_type_id, $children, $cacheability, $child_prefix, $field_storage_definition);
            }
        }
    }
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.