Skip to content

Commit

Permalink
Separate classes
Browse files Browse the repository at this point in the history
  • Loading branch information
greg0ire committed Feb 5, 2023
1 parent 5fc81fb commit 8296190
Show file tree
Hide file tree
Showing 13 changed files with 165 additions and 62 deletions.
51 changes: 9 additions & 42 deletions lib/Doctrine/ORM/Mapping/AssociationMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
namespace Doctrine\ORM\Mapping;

use ArrayAccess;
use Exception;

use function assert;
use function in_array;
use function property_exists;

/** @template-implements ArrayAccess<string, mixed> */
final class AssociationMapping implements ArrayAccess
class AssociationMapping implements ArrayAccess
{
/**
* required for bidirectional associations
Expand All @@ -35,39 +37,13 @@ final class AssociationMapping implements ArrayAccess
*/
public array|null $cascade = null;

/**
* one-to-many/many-to-many only
* A map of field names (of the target entity) to sorting directions
*
* @var array<string, 'asc'|'desc'>
*/
public array|null $orderBy = null;

/**
* The fetching strategy to use for the association, usually defaults to FETCH_LAZY.
*
* @var ClassMetadata::FETCH_EAGER|ClassMetadata::FETCH_LAZY
*/
public int|null $fetch = null;

/**
* many-to-many only
* Specification of the join table and its join columns (foreign keys).
* Only valid for many-to-many mappings. Note that one-to-many associations
* can be mapped through a join table by simply mapping the association as
* many-to-many with a unique constraint on the join table.
*/
public JoinTableMapping|null $joinTable = null;

/**
* to-many only
* Specification of a field on target-entity that is used to index the
* collection by. This field HAS to be either the primary key or a unique
* column. Otherwise the collection does not contain all the entities that
* are actually related.
*/
public string|null $indexBy = null;

/**
* This is set when the association is inherited by this class from another
* (inheritance) parent <em>entity</em> class. The value is the FQCN of the
Expand Down Expand Up @@ -122,15 +98,6 @@ final class AssociationMapping implements ArrayAccess

public bool|null $orphanRemoval = null;

public array|null $relationToSourceKeyColumns = null;
public array|null $relationToTargetKeyColumns = null;

/** @var array<string, string> */
public array|null $sourceToTargetKeyColumns = null;

/** @var array<string, string> */
public array|null $targetToSourceKeyColumns = null;

public bool|null $unique = null;

/**
Expand All @@ -150,7 +117,7 @@ final class AssociationMapping implements ArrayAccess
* be the same as the namespace of the
* source entity.
*/
public function __construct(
final public function __construct(
public int $type,
public string $fieldName,
public string $sourceEntity,
Expand All @@ -161,7 +128,7 @@ public function __construct(
/** @param array{fieldName: string, sourceEntity: class-string, targetEntity: class-string, type: int, joinColumns?: mixed[]|null, joinTable?: mixed[]|null, ...} $mappingArray */
public static function fromMappingArray(array $mappingArray): self
{
$mapping = new self(
$mapping = new static(
$mappingArray['type'],
$mappingArray['fieldName'],
$mappingArray['sourceEntity'],
Expand All @@ -188,6 +155,7 @@ public static function fromMappingArray(array $mappingArray): self
}

if ($key === 'joinTable') {
assert($mapping instanceof ManyToManyAssociationMapping);
if ($value === [] || $value === null) {
continue;
}
Expand All @@ -199,6 +167,8 @@ public static function fromMappingArray(array $mappingArray): self

if (property_exists($mapping, $key)) {
$mapping->$key = $value;
} else {
throw new Exception('Unknown property ' . $key . ' on class ' . static::class);
}
}

Expand Down Expand Up @@ -233,6 +203,7 @@ public function offsetSet($offset, $value): void
}

if ($offset === 'joinTable') {
assert($this instanceof ManyToManyAssociationMapping);
$value = JoinTableMapping::fromMappingArray($value);
}

Expand Down Expand Up @@ -261,10 +232,6 @@ public function toArray(): array
$array['joinColumns'] = $joinColumns;
}

if ($array['joinTable'] !== null) {
$array['joinTable'] = $array['joinTable']->toArray();
}

return $array;
}
}
43 changes: 34 additions & 9 deletions lib/Doctrine/ORM/Mapping/ClassMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Doctrine\ORM\Id\AbstractIdGenerator;
use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata;
use Doctrine\Persistence\Mapping\ReflectionService;
use Exception;
use InvalidArgumentException;
use LogicException;
use ReflectionClass;
Expand Down Expand Up @@ -1334,7 +1335,26 @@ protected function _validateAndCompleteAssociationMapping(array $mapping): Assoc
throw MappingException::missingTargetEntity($mapping['fieldName']);
}

$mapping = AssociationMapping::fromMappingArray($mapping);
switch ($mapping['type']) {
case self::ONE_TO_ONE:
$mapping = OneToOneAssociationMapping::fromMappingArray($mapping);
break;

case self::MANY_TO_ONE:
$mapping = ManyToOneAssociationMapping::fromMappingArray($mapping);
break;

case self::ONE_TO_MANY:
$mapping = OneToManyAssociationMapping::fromMappingArray($mapping);
break;

case self::MANY_TO_MANY:
$mapping = ManyToManyAssociationMapping::fromMappingArray($mapping);
break;

default:
throw new Exception('woops');
}

// Mandatory and optional attributes for either side
if (! $mapping['mappedBy']) {
Expand Down Expand Up @@ -1392,6 +1412,7 @@ protected function _validateAndCompleteAssociationMapping(array $mapping): Assoc
protected function _validateAndCompleteOneToOneMapping(array $mapping): AssociationMapping
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
assert($mapping instanceof OneToOneAssociationMapping || $mapping instanceof ManyToOneAssociationMapping);

if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
$mapping['isOwningSide'] = true;
Expand All @@ -1413,6 +1434,7 @@ protected function _validateAndCompleteOneToOneMapping(array $mapping): Associat
assert($mapping->joinColumns !== null);
foreach ($mapping->joinColumns as $joinColumn) {
if ($mapping['type'] === self::ONE_TO_ONE && ! $this->isInheritanceTypeSingleTable()) {
assert($mapping instanceof OneToOneAssociationMapping);
if (count($mapping['joinColumns']) === 1) {
if (empty($mapping['id'])) {
$joinColumn['unique'] = true;
Expand Down Expand Up @@ -1482,6 +1504,7 @@ protected function _validateAndCompleteOneToOneMapping(array $mapping): Associat
protected function _validateAndCompleteOneToManyMapping(array $mapping)
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
assert($mapping instanceof OneToManyAssociationMapping);

// OneToMany-side MUST be inverse (must have mappedBy)
if (! isset($mapping['mappedBy'])) {
Expand All @@ -1508,6 +1531,7 @@ protected function _validateAndCompleteOneToManyMapping(array $mapping)
protected function _validateAndCompleteManyToManyMapping(array $mapping)
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
assert($mapping instanceof ManyToManyAssociationMapping);

if ($mapping['isOwningSide']) {
// owning side MUST have a join table
Expand Down Expand Up @@ -1912,24 +1936,25 @@ public function setAssociationOverride(string $fieldName, array $overrideMapping
$mapping['fetch'] = $overrideMapping['fetch'];
}

$mapping['joinColumnFieldNames'] = null;
$mapping['joinTableColumns'] = null;
$mapping['sourceToTargetKeyColumns'] = null;
$mapping['relationToSourceKeyColumns'] = null;
$mapping['relationToTargetKeyColumns'] = null;
$mapping['joinColumnFieldNames'] = null;
$mapping['joinTableColumns'] = null;

switch ($mapping['type']) {
case self::ONE_TO_ONE:
$mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
$mapping['sourceToTargetKeyColumns'] = null;
$mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
break;
case self::ONE_TO_MANY:
$mapping = $this->_validateAndCompleteOneToManyMapping($mapping);
break;
case self::MANY_TO_ONE:
$mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
$mapping['sourceToTargetKeyColumns'] = null;
$mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
break;
case self::MANY_TO_MANY:
$mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
$mapping['relationToSourceKeyColumns'] = null;
$mapping['relationToTargetKeyColumns'] = null;
$mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
break;
}

Expand Down
30 changes: 30 additions & 0 deletions lib/Doctrine/ORM/Mapping/ManyToManyAssociationMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Mapping;

final class ManyToManyAssociationMapping extends AssociationMapping
{
use ToManyAssociationMapping;

/**
* Specification of the join table and its join columns (foreign keys).
* Only valid for many-to-many mappings. Note that one-to-many associations
* can be mapped through a join table by simply mapping the association as
* many-to-many with a unique constraint on the join table.
*/
public JoinTableMapping $joinTable;

public array|null $relationToSourceKeyColumns = null;
public array|null $relationToTargetKeyColumns = null;

public function toArray(): array
{
$array = parent::toArray();

$array['joinTable'] = $this->joinTable->toArray();

return $array;
}
}
10 changes: 10 additions & 0 deletions lib/Doctrine/ORM/Mapping/ManyToOneAssociationMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Mapping;

final class ManyToOneAssociationMapping extends AssociationMapping
{
use ToOneAssociationMapping;
}
10 changes: 10 additions & 0 deletions lib/Doctrine/ORM/Mapping/OneToManyAssociationMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Mapping;

final class OneToManyAssociationMapping extends AssociationMapping
{
use ToManyAssociationMapping;
}
10 changes: 10 additions & 0 deletions lib/Doctrine/ORM/Mapping/OneToOneAssociationMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Mapping;

final class OneToOneAssociationMapping extends AssociationMapping
{
use ToOneAssociationMapping;
}
23 changes: 23 additions & 0 deletions lib/Doctrine/ORM/Mapping/ToManyAssociationMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Mapping;

trait ToManyAssociationMapping
{
/**
* Specification of a field on target-entity that is used to index the
* collection by. This field HAS to be either the primary key or a unique
* column. Otherwise the collection does not contain all the entities that
* are actually related.
*/
public string|null $indexBy = null;

/**
* A map of field names (of the target entity) to sorting directions
*
* @var array<string, 'asc'|'desc'>
*/
public array|null $orderBy = null;
}
14 changes: 14 additions & 0 deletions lib/Doctrine/ORM/Mapping/ToOneAssociationMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Mapping;

trait ToOneAssociationMapping
{
/** @var array<string, string> */
public array|null $sourceToTargetKeyColumns = null;

/** @var array<string, string> */
public array|null $targetToSourceKeyColumns = null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use Doctrine\ORM\Internal\SQLResultCasing;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ManyToOneAssociationMapping;
use Doctrine\ORM\Mapping\OneToOneAssociationMapping;
use Doctrine\ORM\Utility\PersisterHelper;

use function array_combine;
Expand Down Expand Up @@ -480,6 +482,7 @@ protected function getInsertColumnList(): array
if (isset($this->class->associationMappings[$name])) {
$assoc = $this->class->associationMappings[$name];
if ($assoc->type & ClassMetadata::TO_ONE && $assoc['isOwningSide']) {
assert($assoc instanceof OneToOneAssociationMapping || $assoc instanceof ManyToOneAssociationMapping);
assert($assoc->targetToSourceKeyColumns !== null);
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
$columns[] = $sourceCol;
Expand Down
4 changes: 4 additions & 0 deletions lib/Doctrine/ORM/Query/SqlWalker.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ManyToOneAssociationMapping;
use Doctrine\ORM\Mapping\OneToOneAssociationMapping;
use Doctrine\ORM\Mapping\QuoteStrategy;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\Query;
Expand Down Expand Up @@ -597,6 +599,7 @@ public function walkPathExpression(AST\PathExpression $pathExpr): string
}

$assoc = $class->associationMappings[$fieldName];
assert($assoc instanceof OneToOneAssociationMapping || $assoc instanceof ManyToOneAssociationMapping);

if (! $assoc['isOwningSide']) {
throw QueryException::associationPathInverseSideNotSupported($pathExpr);
Expand Down Expand Up @@ -798,6 +801,7 @@ public function walkIndexBy(AST\IndexBy $indexBy): void
}

$association = $class->associationMappings[$fieldName];
assert($association instanceof OneToOneAssociationMapping || $association instanceof ManyToOneAssociationMapping);

if (! $association['isOwningSide']) {
throw QueryException::associationPathInverseSideNotSupported($pathExpression);
Expand Down
2 changes: 1 addition & 1 deletion tests/Doctrine/Tests/Models/DDC964/DDC964User.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public static function loadMetadata(ClassMetadata $metadata): void
'fieldName' => 'address',
'targetEntity' => 'DDC964Address',
'cascade' => ['persist','merge'],
'joinColumn' => ['name' => 'address_id', 'referencedColumnMame' => 'id'],
'joinColumns' => [['name' => 'address_id', 'referencedColumnMame' => 'id']],
],
);

Expand Down
Loading

0 comments on commit 8296190

Please sign in to comment.