entity_hierarchy-8.x-2.24/src/Storage/QueryBuilderTrait.php
src/Storage/QueryBuilderTrait.php
<?php declare(strict_types=1); namespace Drupal\entity_hierarchy\Storage; use Drupal\Core\Entity\Sql\SqlContentEntityStorage; /** * Defines a trait for . */ trait QueryBuilderTrait { /** * Values in here are the table mappings for specific field. * * 'entity' - Main entity table. * 'entity_revision' - Revisions table if set, main entity table otherwise. * * @var array * Table names. */ protected $tables = []; /** * Mapping for the entity hierarchy schema to table column names for field. * * 'id' - the entity id column name. * 'revision_id' - the entity revision_id column name. * 'target_id' - the target_id column name from the entity hierarchy field. * 'weight' - the weight column name from the entity hierarchy field. * * @var array * Column names. */ protected $columns = []; /** * Sets up table and column information. * * @return $this */ protected function setupTablesAndColumns(): static { $entityTypeId = $this->fieldStorageDefinition->getTargetEntityTypeId(); $entityType = $this->entityTypeManager->getDefinition($entityTypeId); $storage = $this->entityTypeManager->getStorage($entityTypeId); assert($storage instanceof SqlContentEntityStorage); $tableMapping = $storage->getTableMapping(); // Get table definitions. $table_names = $tableMapping->getAllFieldTableNames($this->fieldStorageDefinition->getName()); $this->tables = [ 'entity' => $table_names[0], 'base' => $storage->getBaseTable(), 'data' => $storage->getDataTable(), ]; $this->tables['entity_revision'] = $table_names[1] ?? $table_names[0]; // Get column definitions. $base_field_id = $this->fieldStorageDefinition->isBaseField() ? $entityType->getKey('id') : 'entity_id'; $this->columns = [ 'id' => $base_field_id, 'entity_id' => $entityType->getKey('id'), 'revision_id_base' => $entityType->getKey('revision'), 'revision_id' => $this->fieldStorageDefinition->isRevisionable() ? 'revision_id' : $base_field_id, 'target_id' => $tableMapping->getFieldColumnName($this->fieldStorageDefinition, 'target_id'), 'weight' => $tableMapping->getFieldColumnName($this->fieldStorageDefinition, 'weight'), 'langcode' => $entityType->getKey('langcode'), ]; return $this; } /** * Build the CTE query that can traverse descendants. * * @return string * SQL to prefix descendants queries and define the 'descendants' table. */ protected function getDescendantSql(): string { $table_name = $this->tables['entity']; $column_id = $this->columns['id']; $column_revision_id = $this->columns['revision_id']; $column_target_id = $this->columns['target_id']; $column_weight = $this->columns['weight']; $sql = <<<CTESQL WITH RECURSIVE descendants AS ( SELECT $column_id as id, $column_revision_id as revisionId, $column_target_id as targetId, $column_weight as weight, 1 AS depth FROM {{$table_name}} WHERE $column_target_id = :targetId UNION ALL SELECT c.$column_id, c.$column_revision_id, c.$column_target_id, c.$column_weight, descendants.depth+1 FROM {{$table_name}} c JOIN descendants ON descendants.id=c.$column_target_id ) CTESQL; return $sql; } /** * Build the CTE query that can traverse ancestors. * * @return string * SQL to prefix ancestor queries and define the 'ancestors' table. */ protected function getAncestorSql(): string { $table_name = $this->tables['entity']; $revision_table_name = $this->tables['entity_revision']; $column_id = $this->columns['id']; $column_revision_id = $this->columns['revision_id']; $column_target_id = $this->columns['target_id']; $column_weight = $this->columns['weight']; $sql = <<<CTESQL WITH RECURSIVE ancestors AS ( SELECT $column_id AS id, $column_revision_id as revisionId, $column_target_id AS targetId, $column_weight AS weight, 0 AS depth FROM {{$revision_table_name}} WHERE $column_id = :id AND $column_revision_id = :revisionId UNION ALL SELECT c.$column_id, c.$column_revision_id, c.$column_target_id, c.$column_weight, ancestors.depth-1 FROM {{$table_name}} c JOIN ancestors ON c.$column_id=ancestors.targetId ) CTESQL; return $sql; } }