X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=web%2Fmodules%2Fcontrib%2Fentity%2Fsrc%2FQueryAccess%2FViewsQueryAlter.php;fp=web%2Fmodules%2Fcontrib%2Fentity%2Fsrc%2FQueryAccess%2FViewsQueryAlter.php;h=3d660fdaae85f87940d29a528c9eafebce2d67f8;hp=0000000000000000000000000000000000000000;hb=f3baf763d342a5f82576890e2a8111a5aaf139dc;hpb=059867c3f96750652c80f39e44c442a58c2549ee diff --git a/web/modules/contrib/entity/src/QueryAccess/ViewsQueryAlter.php b/web/modules/contrib/entity/src/QueryAccess/ViewsQueryAlter.php new file mode 100644 index 000000000..3d660fdaa --- /dev/null +++ b/web/modules/contrib/entity/src/QueryAccess/ViewsQueryAlter.php @@ -0,0 +1,251 @@ +connection = $connection; + $this->entityFieldManager = $entity_field_manager; + $this->entityTypeManager = $entity_type_manager; + $this->renderer = $renderer; + $this->requestStack = $request_stack; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('database'), + $container->get('entity_field.manager'), + $container->get('entity_type.manager'), + $container->get('renderer'), + $container->get('request_stack') + ); + } + + /** + * Alters the given views query. + * + * @param \Drupal\views\Plugin\views\query\Sql $query + * The views query. + * @param \Drupal\views\ViewExecutable $view + * The view. + */ + public function alter(Sql $query, ViewExecutable $view) { + $table_info = $query->getEntityTableInfo(); + $base_table = reset($table_info); + if (empty($base_table['entity_type']) || $base_table['relationship_id'] != 'none') { + return; + } + $entity_type_id = $base_table['entity_type']; + $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); + if (!$entity_type->hasHandlerClass('query_access')) { + return; + } + $storage = $this->entityTypeManager->getStorage($entity_type_id); + if (!$storage instanceof SqlContentEntityStorage) { + return; + } + + /** @var \Drupal\entity\QueryAccess\QueryAccessHandlerInterface $query_access */ + $query_access = $this->entityTypeManager->getHandler($entity_type_id, 'query_access'); + $conditions = $query_access->getConditions('view'); + if ($conditions->isAlwaysFalse()) { + $query->addWhereExpression(0, '1 = 0'); + } + elseif (count($conditions)) { + // Store the data table, in case mapConditions() needs to join it in. + $base_table['data_table'] = $entity_type->getDataTable(); + $field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type_id); + /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */ + $table_mapping = $storage->getTableMapping(); + $sql_conditions = $this->mapConditions($conditions, $query, $base_table, $field_storage_definitions, $table_mapping); + $query->addWhere(0, $sql_conditions); + } + + $this->applyCacheability(CacheableMetadata::createFromObject($conditions)); + } + + /** + * Maps an entity type's access conditions to views SQL conditions. + * + * @param \Drupal\entity\QueryAccess\ConditionGroup $conditions + * The access conditions. + * @param \Drupal\views\Plugin\views\query\Sql $query + * The views query. + * @param array $base_table + * The base table information. + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $field_storage_definitions + * The field storage definitions. + * @param \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping + * The table mapping. + * + * @return \Drupal\Core\Database\Query\ConditionInterface + * The SQL conditions. + */ + protected function mapConditions(ConditionGroup $conditions, Sql $query, array $base_table, array $field_storage_definitions, DefaultTableMapping $table_mapping) { + $sql_condition = new SqlCondition($conditions->getConjunction()); + foreach ($conditions->getConditions() as $condition) { + if ($condition instanceof ConditionGroup) { + $nested_sql_conditions = $this->mapConditions($condition, $query, $base_table, $field_storage_definitions, $table_mapping); + $sql_condition->condition($nested_sql_conditions); + } + else { + $field = $condition->getField(); + $property_name = NULL; + if (strpos($field, '.') !== FALSE) { + list($field, $property_name) = explode('.', $field); + } + // Skip unknown fields. + if (!isset($field_storage_definitions[$field])) { + continue; + } + $field_storage_definition = $field_storage_definitions[$field]; + if (!$property_name) { + $property_name = $field_storage_definition->getMainPropertyName(); + } + + $column = $table_mapping->getFieldColumnName($field_storage_definition, $property_name); + if ($table_mapping->requiresDedicatedTableStorage($field_storage_definitions[$field])) { + if ($base_table['revision']) { + $dedicated_table = $table_mapping->getDedicatedRevisionTableName($field_storage_definition); + } + else { + $dedicated_table = $table_mapping->getDedicatedDataTableName($field_storage_definition); + } + // Views defaults to LEFT JOIN. For simplicity, we don't try to + // use an INNER JOIN when it's safe to do so (AND conjunctions). + $alias = $query->ensureTable($dedicated_table); + } + elseif ($base_table['revision'] && !$field_storage_definition->isRevisionable()) { + // Workaround for #2652652, which causes $query->ensureTable() + // to not work in this case, due to a missing relationship. + if ($data_table = $query->getTableInfo($base_table['data_table'])) { + $alias = $data_table['alias']; + } + else { + $configuration = [ + 'type' => 'INNER', + 'table' => $base_table['data_table'], + 'field' => 'id', + 'left_table' => $base_table['alias'], + 'left_field' => 'id', + ]; + /** @var \Drupal\Views\Plugin\views\join\JoinPluginBase $join */ + $join = Views::pluginManager('join')->createInstance('standard', $configuration); + $alias = $query->addRelationship($base_table['data_table'], $join, $data_table); + } + } + else { + $alias = $base_table['alias']; + } + + $value = $condition->getValue(); + $operator = $condition->getOperator(); + // Using LIKE/NOT LIKE ensures a case insensitive comparison. + // @see \Drupal\Core\Entity\Query\Sql\Condition::translateCondition(). + $property_definitions = $field_storage_definition->getPropertyDefinitions(); + $case_sensitive = $property_definitions[$property_name]->getSetting('case_sensitive'); + $operator_map = [ + '=' => 'LIKE', + '<>' => 'NOT LIKE', + ]; + if (!$case_sensitive && isset($operator_map[$operator])) { + $operator = $operator_map[$operator]; + $value = $this->connection->escapeLike($value); + } + + $sql_condition->condition("$alias.$column", $value, $operator); + } + } + + return $sql_condition; + } + + /** + * Applies the cacheablity metadata to the current request. + * + * @param \Drupal\Core\Cache\CacheableMetadata $cacheable_metadata + * The cacheability metadata. + */ + protected function applyCacheability(CacheableMetadata $cacheable_metadata) { + $request = $this->requestStack->getCurrentRequest(); + if ($request->isMethodCacheable() && $this->renderer->hasRenderContext()) { + $build = []; + $cacheable_metadata->applyTo($build); + $this->renderer->render($build); + } + } + +}