Chris@17: workspaceManager = \Drupal::service('workspaces.manager'); Chris@17: Chris@17: // The join between the first 'workspace_association' table and base table Chris@17: // of the query is done in Chris@17: // \Drupal\workspaces\EntityQuery\QueryTrait::prepare(), so we need to Chris@17: // initialize its entry manually. Chris@17: if ($this->sqlQuery->getMetaData('active_workspace_id')) { Chris@17: $this->contentWorkspaceTables['base_table'] = 'workspace_association'; Chris@17: $this->baseTablesEntityType['base_table'] = $this->sqlQuery->getMetaData('entity_type'); Chris@17: } Chris@17: } Chris@17: Chris@17: /** Chris@17: * {@inheritdoc} Chris@17: */ Chris@17: public function addField($field, $type, $langcode) { Chris@17: // The parent method uses shared and dedicated revision tables only when the Chris@17: // entity query is instructed to query all revisions. However, if we are Chris@17: // looking for workspace-specific revisions, we have to force the parent Chris@17: // method to always pick the revision tables if the field being queried is Chris@17: // revisionable. Chris@17: if ($active_workspace_id = $this->sqlQuery->getMetaData('active_workspace_id')) { Chris@17: $previous_all_revisions = $this->sqlQuery->getMetaData('all_revisions'); Chris@17: $this->sqlQuery->addMetaData('all_revisions', TRUE); Chris@17: } Chris@17: Chris@17: $alias = parent::addField($field, $type, $langcode); Chris@17: Chris@17: // Restore the 'all_revisions' metadata because we don't want to interfere Chris@17: // with the rest of the query. Chris@17: if (isset($previous_all_revisions)) { Chris@17: $this->sqlQuery->addMetaData('all_revisions', $previous_all_revisions); Chris@17: } Chris@17: Chris@17: return $alias; Chris@17: } Chris@17: Chris@17: /** Chris@17: * {@inheritdoc} Chris@17: */ Chris@17: protected function addJoin($type, $table, $join_condition, $langcode, $delta = NULL) { Chris@17: if ($this->sqlQuery->getMetaData('active_workspace_id')) { Chris@17: // The join condition for a shared or dedicated field table is in the form Chris@17: // of "%alias.$id_field = $base_table.$id_field". Whenever we join a field Chris@17: // table we have to check: Chris@17: // 1) if $base_table is of an entity type that can belong to a workspace; Chris@17: // 2) if $id_field is the revision key of that entity type or the special Chris@17: // 'revision_id' string used when joining dedicated field tables. Chris@17: // If those two conditions are met, we have to update the join condition Chris@17: // to also look for a possible workspace-specific revision using COALESCE. Chris@17: $condition_parts = explode(' = ', $join_condition); Chris@17: list($base_table, $id_field) = explode('.', $condition_parts[1]); Chris@17: Chris@17: if (isset($this->baseTablesEntityType[$base_table])) { Chris@17: $entity_type_id = $this->baseTablesEntityType[$base_table]; Chris@18: $revision_key = $this->entityTypeManager->getActiveDefinition($entity_type_id)->getKey('revision'); Chris@17: Chris@17: if ($id_field === $revision_key || $id_field === 'revision_id') { Chris@17: $workspace_association_table = $this->contentWorkspaceTables[$base_table]; Chris@17: $join_condition = "{$condition_parts[0]} = COALESCE($workspace_association_table.target_entity_revision_id, {$condition_parts[1]})"; Chris@17: } Chris@17: } Chris@17: } Chris@17: Chris@17: return parent::addJoin($type, $table, $join_condition, $langcode, $delta); Chris@17: } Chris@17: Chris@17: /** Chris@17: * {@inheritdoc} Chris@17: */ Chris@17: protected function addNextBaseTable(EntityType $entity_type, $table, $sql_column, FieldStorageDefinitionInterface $field_storage) { Chris@17: $next_base_table_alias = parent::addNextBaseTable($entity_type, $table, $sql_column, $field_storage); Chris@17: Chris@17: $active_workspace_id = $this->sqlQuery->getMetaData('active_workspace_id'); Chris@17: if ($active_workspace_id && $this->workspaceManager->isEntityTypeSupported($entity_type)) { Chris@17: $this->addWorkspaceAssociationJoin($entity_type->id(), $next_base_table_alias, $active_workspace_id); Chris@17: } Chris@17: Chris@17: return $next_base_table_alias; Chris@17: } Chris@17: Chris@17: /** Chris@17: * Adds a new join to the 'workspace_association' table for an entity base table. Chris@17: * Chris@17: * This method assumes that the active workspace has already been determined Chris@17: * to be a non-default workspace. Chris@17: * Chris@17: * @param string $entity_type_id Chris@17: * The ID of the entity type whose base table we are joining. Chris@17: * @param string $base_table_alias Chris@17: * The alias of the entity type's base table. Chris@17: * @param string $active_workspace_id Chris@17: * The ID of the active workspace. Chris@17: * Chris@17: * @return string Chris@17: * The alias of the joined table. Chris@17: */ Chris@17: public function addWorkspaceAssociationJoin($entity_type_id, $base_table_alias, $active_workspace_id) { Chris@17: if (!isset($this->contentWorkspaceTables[$base_table_alias])) { Chris@18: $entity_type = $this->entityTypeManager->getActiveDefinition($entity_type_id); Chris@17: $id_field = $entity_type->getKey('id'); Chris@17: Chris@17: // LEFT join the Workspace association entity's table so we can properly Chris@17: // include live content along with a possible workspace-specific revision. Chris@17: $this->contentWorkspaceTables[$base_table_alias] = $this->sqlQuery->leftJoin('workspace_association', NULL, "%alias.target_entity_type_id = '$entity_type_id' AND %alias.target_entity_id = $base_table_alias.$id_field AND %alias.workspace = '$active_workspace_id'"); Chris@17: Chris@17: $this->baseTablesEntityType[$base_table_alias] = $entity_type->id(); Chris@17: } Chris@17: return $this->contentWorkspaceTables[$base_table_alias]; Chris@17: } Chris@17: Chris@17: }