diff --git a/src/Mapping/ClassMetadata.php b/src/Mapping/ClassMetadata.php index 0d9889b6e77..1082e5150d0 100644 --- a/src/Mapping/ClassMetadata.php +++ b/src/Mapping/ClassMetadata.php @@ -2199,6 +2199,35 @@ public function addDiscriminatorMapClass(int|string $name, string $className): v $this->addSubClass($className); } + /** + * @internal + * + * @return list + * + * @psalm-internal Doctrine\ORM + */ + public function getDiscriminatorValuesForClassAndSubclasses(): array + { + $values = []; + $valueByClass = array_flip($this->discriminatorMap); + + // Even if this class is part of an inheritance hierarchy, the discriminator + // value may be null in case the class is abstract. + if ($this->discriminatorValue !== null) { + $values[] = $this->discriminatorValue; + } + + foreach ($this->subClasses as $subClass) { + // Abstract entity classes show up in the list of subClasses, + // but may be omitted from the discriminator map. + if (isset($valueByClass[$subClass])) { + $values[] = $valueByClass[$subClass]; + } + } + + return $values; + } + /** @param array $classes */ public function addSubClasses(array $classes): void { diff --git a/src/Persisters/Entity/SingleTablePersister.php b/src/Persisters/Entity/SingleTablePersister.php index 4a4d9998266..949d82ac25e 100644 --- a/src/Persisters/Entity/SingleTablePersister.php +++ b/src/Persisters/Entity/SingleTablePersister.php @@ -10,10 +10,7 @@ use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Utility\PersisterHelper; -use function array_flip; -use function array_intersect; use function array_map; -use function array_unshift; use function implode; use function strval; @@ -138,19 +135,12 @@ protected function getSelectConditionCriteriaSQL(Criteria $criteria): string protected function getSelectConditionDiscriminatorValueSQL(): string { - $values = array_map($this->conn->quote(...), array_map( - strval(...), - array_flip(array_intersect($this->class->discriminatorMap, $this->class->subClasses)), - )); - - if ($this->class->discriminatorValue !== null) { // discriminators can be 0 - array_unshift($values, $this->conn->quote((string) $this->class->discriminatorValue)); - } - + $tableAlias = $this->getSQLTableAlias($this->class->name); $discColumnName = $this->class->getDiscriminatorColumn()->name; - - $values = implode(', ', $values); - $tableAlias = $this->getSQLTableAlias($this->class->name); + $values = implode(', ', array_map( + $this->conn->quote(...), + array_map(strval(...), $this->class->getDiscriminatorValuesForClassAndSubclasses()) + )); return $tableAlias . '.' . $discColumnName . ' IN (' . $values . ')'; } diff --git a/src/Query/SqlWalker.php b/src/Query/SqlWalker.php index f6f94347e36..6d6acfeee1e 100644 --- a/src/Query/SqlWalker.php +++ b/src/Query/SqlWalker.php @@ -368,6 +368,7 @@ private function generateOrderedCollectionOrderByItems(): string private function generateDiscriminatorColumnConditionSQL(array $dqlAliases): string { $sqlParts = []; + $conn = $this->em->getConnection(); foreach ($dqlAliases as $dqlAlias) { $class = $this->getMetadataForDqlAlias($dqlAlias); @@ -376,22 +377,20 @@ private function generateDiscriminatorColumnConditionSQL(array $dqlAliases): str continue; } - $conn = $this->em->getConnection(); - $values = []; - - if ($class->discriminatorValue !== null) { // discriminators can be 0 - $values[] = $conn->quote($class->discriminatorValue); - } - - foreach ($class->subClasses as $subclassName) { - $values[] = $conn->quote((string) $this->em->getClassMetadata($subclassName)->discriminatorValue); - } - $sqlTableAlias = $this->useSqlTableAliases ? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.' : ''; - $sqlParts[] = $sqlTableAlias . $class->getDiscriminatorColumn()->name . ' IN (' . implode(', ', $values) . ')'; + $discriminatorValues = array_map( + $conn->quote(...), + array_map(strval(...), $class->getDiscriminatorValuesForClassAndSubclasses()) + ); + + if ($discriminatorValues !== []) { + $sqlParts[] = $sqlTableAlias . $class->getDiscriminatorColumn()->name . ' IN (' . implode(', ', $discriminatorValues) . ')'; + } else { + $sqlParts[] = '1=0'; // impossible condition + } } $sql = implode(' AND ', $sqlParts);