You are here

protected static function TemporaryQueryGuard::secureQuery in JSON:API 8

Same name and namespace in other branches
  1. 8.2 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 src/Access/TemporaryQueryGuard.php
Applies access controls to an entity query.

File

src/Access/TemporaryQueryGuard.php, line 113

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);
      list($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);
      }
    }
  }
}