Skip to content

Commit

Permalink
Merge pull request #10635 from greg0ire/convenience-methods
Browse files Browse the repository at this point in the history
Introduce and leverage more convenience methods
  • Loading branch information
greg0ire committed Apr 15, 2023
2 parents eeae573 + b686032 commit 303baee
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 49 deletions.
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/Cache/DefaultQueryCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ private function storeAssociationCache(QueryCacheKey $key, AssociationMapping $a
$assocRegion = $assocPersister->getCacheRegion();

// Handle *-to-one associations
if ($assoc['type'] & ClassMetadata::TO_ONE) {
if ($assoc->isToOne()) {
$assocIdentifier = $this->uow->getEntityIdentifier($assocValue);
$entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier);

Expand Down Expand Up @@ -395,7 +395,7 @@ private function getAssociationPathValue(mixed $value, array $path): array|objec
}

// Handle *-to-one associations
if ($assoc['type'] & ClassMetadata::TO_ONE) {
if ($assoc->isToOne()) {
return $this->getAssociationPathValue($value, $path);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ protected function prepare(): void

$this->hints['fetched'][$parent][$assoc['fieldName']] = true;

if ($assoc['type'] === ClassMetadata::MANY_TO_MANY) {
if ($assoc->isManyToMany()) {
continue;
}

Expand Down
12 changes: 12 additions & 0 deletions lib/Doctrine/ORM/Mapping/AssociationMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,18 @@ final public function isOneToOne(): bool
return $this instanceof OneToOneAssociationMapping;
}

/** @psalm-assert-if-true OneToManyAssociationMapping $this */
final public function isOneToMany(): bool
{
return $this instanceof OneToManyAssociationMapping;
}

/** @psalm-assert-if-true ManyToOneAssociationMapping $this */
final public function isManyToOne(): bool
{
return $this instanceof ManyToOneAssociationMapping;
}

/** @psalm-assert-if-true ManyToManyAssociationMapping $this */
final public function isManyToMany(): bool
{
Expand Down
6 changes: 3 additions & 3 deletions lib/Doctrine/ORM/PersistentCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public function hydrateAdd(mixed $element): void

// If _backRefFieldName is set and its a one-to-many association,
// we need to set the back reference.
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
if ($this->backRefFieldName && $this->association->isOneToMany()) {
assert($this->typeClass !== null);
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
Expand All @@ -165,7 +165,7 @@ public function hydrateSet(mixed $key, mixed $element): void

// If _backRefFieldName is set, then the association is bidirectional
// and we need to set the back reference.
if ($this->backRefFieldName && $this->association !== null && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
if ($this->backRefFieldName && $this->association !== null && $this->association->isOneToMany()) {
assert($this->typeClass !== null);
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
Expand Down Expand Up @@ -587,7 +587,7 @@ public function matching(Criteria $criteria): Collection
}

assert($this->association !== null);
if ($this->association['type'] === ClassMetadata::MANY_TO_MANY) {
if ($this->association->isManyToMany()) {
$persister = $this->getUnitOfWork()->getCollectionPersister($this->association);

return new ArrayCollection($persister->loadCriteria($this, $criteria));
Expand Down
6 changes: 3 additions & 3 deletions lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,7 @@ public function getSelectSQL(
$joinSql = '';
$orderBySql = '';

if ($assoc !== null && $assoc['type'] === ClassMetadata::MANY_TO_MANY) {
if ($assoc !== null && $assoc->isManyToMany()) {
$joinSql = $this->getSelectManyToManyJoinSQL($assoc);
}

Expand Down Expand Up @@ -1619,7 +1619,7 @@ private function getSelectConditionStatementColumnSQL(
$columns = [];
$class = $this->class;

if ($association['type'] === ClassMetadata::MANY_TO_MANY) {
if ($association->isManyToMany()) {
if (! $association['isOwningSide']) {
$association = $assoc;
}
Expand Down Expand Up @@ -1835,7 +1835,7 @@ private function getTypes(string $field, mixed $value, ClassMetadata $class): ar
$class = $this->em->getClassMetadata($assoc['targetEntity']);
}

$columns = $assoc['type'] === ClassMetadata::MANY_TO_MANY
$columns = $assoc->isManyToMany()
? $assoc['relationToTargetKeyColumns']
: $assoc['sourceToTargetKeyColumns'];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ public function getSelectSQL(
$baseTableAlias = $this->getSQLTableAlias($this->class->name);
$joinSql = $this->getJoinSql($baseTableAlias);

if ($assoc !== null && $assoc['type'] === ClassMetadata::MANY_TO_MANY) {
if ($assoc !== null && $assoc->isManyToMany()) {
$joinSql .= $this->getSelectManyToManyJoinSQL($assoc);
}

Expand Down
8 changes: 4 additions & 4 deletions lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Doctrine\ORM\Query\AST\Functions;

use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\AST\PathExpression;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
Expand Down Expand Up @@ -39,8 +38,8 @@ public function getSql(SqlWalker $sqlWalker): string
$assoc = $class->associationMappings[$assocField];
$sql = 'SELECT COUNT(*) FROM ';

if ($assoc['type'] === ClassMetadata::ONE_TO_MANY) {
$targetClass = $entityManager->getClassMetadata($assoc['targetEntity']);
if ($assoc->isOneToMany()) {
$targetClass = $entityManager->getClassMetadata($assoc->targetEntity);
$targetTableAlias = $sqlWalker->getSQLTableAlias($targetClass->getTableName());
$sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias);

Expand All @@ -62,7 +61,8 @@ public function getSql(SqlWalker $sqlWalker): string
. $sourceTableAlias . '.' . $quoteStrategy->getColumnName($class->fieldNames[$targetColumn], $class, $platform);
}
} else { // many-to-many
$targetClass = $entityManager->getClassMetadata($assoc['targetEntity']);
assert($assoc->isManyToMany());
$targetClass = $entityManager->getClassMetadata($assoc->targetEntity);

$owningAssoc = $assoc->isOwningSide() ? $assoc : $targetClass->associationMappings[$assoc['mappedBy']];
$joinTable = $owningAssoc['joinTable'];
Expand Down
11 changes: 6 additions & 5 deletions lib/Doctrine/ORM/Query/SqlWalker.php
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ public function walkJoinAssociationDeclaration(
$assoc = ! $relation['isOwningSide'] ? $targetClass->associationMappings[$relation['mappedBy']] : $relation;

if ($this->query->getHint(Query::HINT_INTERNAL_ITERATION) === true && (! $this->query->getHint(self::HINT_DISTINCT) || isset($this->selectedClasses[$joinedDqlAlias]))) {
if ($relation['type'] === ClassMetadata::ONE_TO_MANY || $relation['type'] === ClassMetadata::MANY_TO_MANY) {
if ($relation->isToMany()) {
throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
}
}
Expand Down Expand Up @@ -945,7 +945,7 @@ public function walkJoinAssociationDeclaration(
];
break;

case $assoc['type'] === ClassMetadata::MANY_TO_MANY:
case $assoc->isManyToMany():
// Join relation table
$joinTable = $assoc['joinTable'];
$joinTableAlias = $this->getSQLTableAlias($joinTable['name'], $joinedDqlAlias);
Expand Down Expand Up @@ -1856,8 +1856,8 @@ public function walkCollectionMemberExpression(AST\CollectionMemberExpression $c

$assoc = $class->associationMappings[$fieldName];

if ($assoc['type'] === ClassMetadata::ONE_TO_MANY) {
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
if ($assoc->isOneToMany()) {
$targetClass = $this->em->getClassMetadata($assoc->targetEntity);
$targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName());
$sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias);

Expand All @@ -1882,7 +1882,8 @@ public function walkCollectionMemberExpression(AST\CollectionMemberExpression $c

$sql .= implode(' AND ', $sqlParts);
} else { // many-to-many
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
assert($assoc->isManyToMany());
$targetClass = $this->em->getClassMetadata($assoc->targetEntity);

$owningAssoc = $assoc['isOwningSide'] ? $assoc : $targetClass->associationMappings[$assoc['mappedBy']];
$joinTable = $owningAssoc['joinTable'];
Expand Down
18 changes: 9 additions & 9 deletions lib/Doctrine/ORM/Tools/SchemaValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public function validateClass(ClassMetadata $class): array
}
}

if ($assoc['inversedBy']) {
if ($assoc->inversedBy) {
if ($targetMetadata->hasField($assoc['inversedBy'])) {
$ce[] = 'The association ' . $class->name . '#' . $fieldName . ' refers to the inverse side ' .
'field ' . $assoc['targetEntity'] . '#' . $assoc['inversedBy'] . ' which is not defined as association.';
Expand All @@ -146,23 +146,23 @@ public function validateClass(ClassMetadata $class): array
}

// Verify inverse side/owning side match each other
if (array_key_exists($assoc['inversedBy'], $targetMetadata->associationMappings)) {
$targetAssoc = $targetMetadata->associationMappings[$assoc['inversedBy']];
if ($assoc['type'] === ClassMetadata::ONE_TO_ONE && $targetAssoc['type'] !== ClassMetadata::ONE_TO_ONE) {
if (array_key_exists($assoc->inversedBy, $targetMetadata->associationMappings)) {
$targetAssoc = $targetMetadata->associationMappings[$assoc->inversedBy];
if ($assoc->isOneToOne() && ! $targetAssoc->isOneToOne()) {
$ce[] = 'If association ' . $class->name . '#' . $fieldName . ' is one-to-one, then the inversed ' .
'side ' . $targetMetadata->name . '#' . $assoc['inversedBy'] . ' has to be one-to-one as well.';
} elseif ($assoc['type'] === ClassMetadata::MANY_TO_ONE && $targetAssoc['type'] !== ClassMetadata::ONE_TO_MANY) {
'side ' . $targetMetadata->name . '#' . $assoc->inversedBy . ' has to be one-to-one as well.';
} elseif ($assoc->isManyToOne() && ! $targetAssoc->isOneToMany()) {
$ce[] = 'If association ' . $class->name . '#' . $fieldName . ' is many-to-one, then the inversed ' .
'side ' . $targetMetadata->name . '#' . $assoc['inversedBy'] . ' has to be one-to-many.';
} elseif ($assoc['type'] === ClassMetadata::MANY_TO_MANY && $targetAssoc['type'] !== ClassMetadata::MANY_TO_MANY) {
'side ' . $targetMetadata->name . '#' . $assoc->inversedBy . ' has to be one-to-many.';
} elseif ($assoc->isManyToMany() && ! $targetAssoc->isManyToMany()) {
$ce[] = 'If association ' . $class->name . '#' . $fieldName . ' is many-to-many, then the inversed ' .
'side ' . $targetMetadata->name . '#' . $assoc['inversedBy'] . ' has to be many-to-many as well.';
}
}
}

if ($assoc->isOwningSide()) {
if ($assoc['type'] === ClassMetadata::MANY_TO_MANY) {
if ($assoc->isManyToMany()) {
$identifierColumns = $class->getIdentifierColumnNames();
foreach ($assoc['joinTable']['joinColumns'] as $joinColumn) {
if (! in_array($joinColumn['referencedColumnName'], $identifierColumns, true)) {
Expand Down
41 changes: 20 additions & 21 deletions tests/Doctrine/Tests/ORM/Functional/Ticket/GH10473Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Tools\ResolveTargetEntityListener;
use Doctrine\Tests\OrmTestCase;

Expand All @@ -32,37 +31,37 @@ public function testMappedSuperclassAssociationsCanBeResolvedToEntities(): void
self::assertTrue($userMetadata->isInheritanceTypeNone());

$socialMediaAccountsMapping = $userMetadata->getAssociationMapping('socialMediaAccounts');
self::assertArrayNotHasKey('inherited', $socialMediaAccountsMapping);
self::assertTrue((bool) ($socialMediaAccountsMapping['type'] & ClassMetadata::TO_MANY));
self::assertFalse($socialMediaAccountsMapping['isOwningSide']);
self::assertSame(GH10473SocialMediaAccount::class, $socialMediaAccountsMapping['targetEntity']);
self::assertSame('user', $socialMediaAccountsMapping['mappedBy']);
self::assertNull($socialMediaAccountsMapping->inherited);
self::assertTrue($socialMediaAccountsMapping->isToMany());
self::assertFalse($socialMediaAccountsMapping->isOwningSide());
self::assertSame(GH10473SocialMediaAccount::class, $socialMediaAccountsMapping->targetEntity);
self::assertSame('user', $socialMediaAccountsMapping->mappedBy);

$createdByMapping = $userMetadata->getAssociationMapping('createdBy');
self::assertArrayNotHasKey('inherited', $createdByMapping);
self::assertTrue((bool) ($createdByMapping['type'] & ClassMetadata::TO_ONE));
self::assertTrue($createdByMapping['isOwningSide']);
self::assertSame(GH10473UserImplementation::class, $createdByMapping['targetEntity']);
self::assertSame('createdUsers', $createdByMapping['inversedBy']);
self::assertNull($createdByMapping->inherited);
self::assertTrue($createdByMapping->isToOne());
self::assertTrue($createdByMapping->isOwningSide());
self::assertSame(GH10473UserImplementation::class, $createdByMapping->targetEntity);
self::assertSame('createdUsers', $createdByMapping->inversedBy);

$createdUsersMapping = $userMetadata->getAssociationMapping('createdUsers');
self::assertArrayNotHasKey('inherited', $createdUsersMapping);
self::assertTrue((bool) ($createdUsersMapping['type'] & ClassMetadata::TO_MANY));
self::assertFalse($createdUsersMapping['isOwningSide']);
self::assertSame(GH10473UserImplementation::class, $createdUsersMapping['targetEntity']);
self::assertSame('createdBy', $createdUsersMapping['mappedBy']);
self::assertNull($createdUsersMapping->inherited);
self::assertTrue($createdUsersMapping->isToMany());
self::assertFalse($createdUsersMapping->isOwningSide());
self::assertSame(GH10473UserImplementation::class, $createdUsersMapping->targetEntity);
self::assertSame('createdBy', $createdUsersMapping->mappedBy);

$socialMediaAccountMetadata = $em->getClassMetadata(GH10473SocialMediaAccount::class);

self::assertFalse($socialMediaAccountMetadata->isMappedSuperclass);
self::assertTrue($socialMediaAccountMetadata->isInheritanceTypeNone());

$userMapping = $socialMediaAccountMetadata->getAssociationMapping('user');
self::assertArrayNotHasKey('inherited', $userMapping);
self::assertTrue((bool) ($userMapping['type'] & ClassMetadata::TO_ONE));
self::assertTrue($userMapping['isOwningSide']);
self::assertSame(GH10473UserImplementation::class, $userMapping['targetEntity']);
self::assertSame('socialMediaAccounts', $userMapping['inversedBy']);
self::assertNull($userMapping->inherited);
self::assertTrue($userMapping->isToOne());
self::assertTrue($userMapping->isOwningSide());
self::assertSame(GH10473UserImplementation::class, $userMapping->targetEntity);
self::assertSame('socialMediaAccounts', $userMapping->inversedBy);
}
}

Expand Down

0 comments on commit 303baee

Please sign in to comment.