Skip to content

Commit

Permalink
Merge pull request #11776 from curry684/issue-9558
Browse files Browse the repository at this point in the history
Respect referencedColumnName defaults in custom naming strategies
  • Loading branch information
greg0ire authored Dec 24, 2024
2 parents 8ebd98e + a9873c8 commit 9f2b367
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/Mapping/JoinColumnMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function __construct(
* @param array<string, mixed> $mappingArray
* @phpstan-param array{
* name: string,
* referencedColumnName: string,
* referencedColumnName: string|null,
* unique?: bool|null,
* quoted?: bool|null,
* fieldName?: string|null,
Expand Down
2 changes: 1 addition & 1 deletion src/Mapping/JoinColumnProperties.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ trait JoinColumnProperties
/** @param array<string, mixed> $options */
public function __construct(
public readonly string|null $name = null,
public readonly string $referencedColumnName = 'id',
public readonly string|null $referencedColumnName = null,
public readonly bool $unique = false,
public readonly bool $nullable = true,
public readonly mixed $onDelete = null,
Expand Down
10 changes: 8 additions & 2 deletions src/Mapping/ManyToManyOwningSideMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,27 @@ public static function fromMappingArrayAndNamingStrategy(array $mappingArray, Na
{
if (isset($mappingArray['joinTable']['joinColumns'])) {
foreach ($mappingArray['joinTable']['joinColumns'] as $key => $joinColumn) {
if (empty($joinColumn['referencedColumnName'])) {

Check failure on line 64 in src/Mapping/ManyToManyOwningSideMapping.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

Expected 1 line after "if", found 0.
$mappingArray['joinTable']['joinColumns'][$key]['referencedColumnName'] = $namingStrategy->referenceColumnName();
}
if (empty($joinColumn['name'])) {
$mappingArray['joinTable']['joinColumns'][$key]['name'] = $namingStrategy->joinKeyColumnName(
$mappingArray['sourceEntity'],
$joinColumn['referencedColumnName'] ?? null,
$joinColumn['referencedColumnName'] ?? $namingStrategy->referenceColumnName(),
);
}
}
}

if (isset($mappingArray['joinTable']['inverseJoinColumns'])) {
foreach ($mappingArray['joinTable']['inverseJoinColumns'] as $key => $joinColumn) {
if (empty($joinColumn['referencedColumnName'])) {

Check failure on line 78 in src/Mapping/ManyToManyOwningSideMapping.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

Expected 1 line after "if", found 0.
$mappingArray['joinTable']['inverseJoinColumns'][$key]['referencedColumnName'] = $namingStrategy->referenceColumnName();
}
if (empty($joinColumn['name'])) {
$mappingArray['joinTable']['inverseJoinColumns'][$key]['name'] = $namingStrategy->joinKeyColumnName(
$mappingArray['targetEntity'],
$joinColumn['referencedColumnName'] ?? null,
$joinColumn['referencedColumnName'] ?? $namingStrategy->referenceColumnName(),
);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/Mapping/ToOneOwningSideMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ public static function fromMappingArrayAndName(
if (empty($joinColumn['name'])) {

Check failure on line 107 in src/Mapping/ToOneOwningSideMapping.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

Expected 1 line after "if", found 0.
$mappingArray['joinColumns'][$index]['name'] = $namingStrategy->joinColumnName($mappingArray['fieldName'], $name);
}
if (empty($joinColumn['referencedColumnName'])) {
$mappingArray['joinColumns'][$index]['referencedColumnName'] = $namingStrategy->referenceColumnName();
}
}
}

Expand Down
57 changes: 57 additions & 0 deletions tests/Tests/ORM/Mapping/MappingDriverTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
use Doctrine\Tests\Models\TypedProperties\UserTypedWithCustomTypedField;
use Doctrine\Tests\Models\Upsertable\Insertable;
use Doctrine\Tests\Models\Upsertable\Updatable;
use Doctrine\Tests\ORM\Mapping\NamingStrategy\CustomPascalNamingStrategy;
use Doctrine\Tests\OrmTestCase;
use PHPUnit\Framework\Attributes\Depends;
use stdClass;
Expand Down Expand Up @@ -946,6 +947,16 @@ public function testEnumType(): void

self::assertEquals(Suit::class, $metadata->fieldMappings['suit']->enumType);
}

public function testCustomNamingStrategyIsRespected(): void
{
$ns = new CustomPascalNamingStrategy();

Check failure on line 953 in tests/Tests/ORM/Mapping/MappingDriverTestCase.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

Equals sign not aligned with surrounding assignments; expected 7 spaces but found 1 space
$metadata = $this->createClassMetadata(BlogPostComment::class, $ns);

self::assertEquals('id', $metadata->fieldNames['Id']);
self::assertEquals('Id', $metadata->associationMappings['blogPost']->joinColumns[0]->referencedColumnName);
self::assertFalse($metadata->associationMappings['blogPost']->joinColumns[0]->nullable);
}
}

#[ORM\Entity()]
Expand Down Expand Up @@ -1547,3 +1558,49 @@ public static function loadMetadata(ClassMetadata $metadata): void
class GH10288EnumTypeBoss extends GH10288EnumTypePerson
{
}

/**
* Two small related entities to test default namings with barebone attributes
*/
#[Entity]
class BlogPost
{
#[Id, Column, GeneratedValue(strategy: 'NONE')]

Check failure on line 1568 in tests/Tests/ORM/Mapping/MappingDriverTestCase.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

3 attributes are joined.
public int $id;
}

#[Entity]
class BlogPostComment
{
#[Id, Column, GeneratedValue(strategy: 'AUTO')]

Check failure on line 1575 in tests/Tests/ORM/Mapping/MappingDriverTestCase.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

3 attributes are joined.
public int $id;

#[ORM\ManyToOne, ORM\JoinColumn(nullable: false)]

Check failure on line 1578 in tests/Tests/ORM/Mapping/MappingDriverTestCase.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

2 attributes are joined.
public BlogPost $blogPost;

public static function loadMetadata(ClassMetadata $metadata): void
{
$metadata->mapField(
[
'id' => true,
'fieldName' => 'id',
'type' => 'integer',
],
);
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);

$metadata->mapManyToOne(
[
'fieldName' => 'blogPost',
'targetEntity' => BlogPost::class,
'joinColumns' =>
[
0 =>
[

Check failure on line 1599 in tests/Tests/ORM/Mapping/MappingDriverTestCase.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

Multi-line array contains a single value; use single-line array instead
'nullable' => false,
],
],
]

Check failure on line 1603 in tests/Tests/ORM/Mapping/MappingDriverTestCase.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

Multi-line function calls must have a trailing comma after the last parameter.
);
}
}
101 changes: 101 additions & 0 deletions tests/Tests/ORM/Mapping/NamingStrategy/CustomPascalNamingStrategy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Mapping\NamingStrategy;

use Doctrine\ORM\Mapping\NamingStrategy;

/**
* Fully customized naming strategy changing all namings to a PascalCase model. Included to test some behaviours
* regarding fully custom naming strategies.
*/
class CustomPascalNamingStrategy implements NamingStrategy
{
/**
* Returns a table name for an entity class.
*
* @param string $className The fully-qualified class name

Check failure on line 18 in tests/Tests/ORM/Mapping/NamingStrategy/CustomPascalNamingStrategy.php

View workflow job for this annotation

GitHub Actions / coding-standards / Coding Standards (PHP: 8.4)

Incorrect annotations group.
* @return string A table name
*/
public function classToTableName(string $className): string
{
if (str_contains($className, '\\')) {
return substr($className, strrpos($className, '\\') + 1);
}

return $className;
}

/**
* Returns a column name for a property.
*
* @param string $propertyName A property name
* @param string|null $className The fully-qualified class name
*
* @return string A column name
*/
public function propertyToColumnName(string $propertyName, ?string $className = null): string
{
if (null !== $className && strtolower($propertyName) == strtolower($this->classToTableName($className)) . 'id') {
return 'Id';
}

return ucfirst($propertyName);
}

/**
* Returns a column name for an embedded property.
*/
public function embeddedFieldToColumnName(string $propertyName, string $embeddedColumnName, ?string $className = null, $embeddedClassName = null): string
{
throw new \LogicException(sprintf('Method %s is not implemented', __METHOD__));
}

/**
* Returns the default reference column name.
*
* @return string A column name
*/
public function referenceColumnName(): string
{
return 'Id';
}

/**
* Returns a join column name for a property.
*
* @return string A join column name
*/
public function joinColumnName(string $propertyName, string $className): string
{
return ucfirst($propertyName) . $this->referenceColumnName();
}

/**
* Returns a join table name.
*
* @param string $sourceEntity The source entity
* @param string $targetEntity The target entity
* @param string|null $propertyName A property name
*
* @return string A join table name
*/
public function joinTableName(string $sourceEntity, string $targetEntity, ?string $propertyName = null): string
{
return $this->classToTableName($sourceEntity) . $this->classToTableName($targetEntity);
}

/**
* Returns the foreign key column name for the given parameters.
*
* @param string $entityName An entity
* @param string|null $referencedColumnName A property
*
* @return string A join column name
*/
public function joinKeyColumnName(string $entityName, ?string $referencedColumnName = null): string
{
return $this->classToTableName($entityName) . ($referencedColumnName ?: $this->referenceColumnName());
}
}
17 changes: 17 additions & 0 deletions tests/Tests/ORM/Mapping/NamingStrategyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Doctrine\ORM\Mapping\DefaultNamingStrategy;
use Doctrine\ORM\Mapping\NamingStrategy;
use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
use Doctrine\Tests\ORM\Mapping\NamingStrategy\CustomPascalNamingStrategy;
use Doctrine\Tests\ORM\Mapping\NamingStrategy\JoinColumnClassNamingStrategy;
use Doctrine\Tests\OrmTestCase;
use PHPUnit\Framework\Attributes\DataProvider;
Expand All @@ -33,6 +34,11 @@ private static function underscoreNamingUpper(): UnderscoreNamingStrategy
return new UnderscoreNamingStrategy(CASE_UPPER);
}

private static function customNaming(): CustomPascalNamingStrategy
{
return new CustomPascalNamingStrategy();
}

/**
* Data Provider for NamingStrategy#classToTableName
*
Expand All @@ -56,6 +62,10 @@ public static function dataClassToTableName(): array
[self::underscoreNamingUpper(), 'NAME', '\Some\Class\Name'],
[self::underscoreNamingUpper(), 'NAME2_TEST', '\Some\Class\Name2Test'],
[self::underscoreNamingUpper(), 'NAME2TEST', '\Some\Class\Name2test'],

// CustomPascalNamingStrategy
[self::customNaming(), 'SomeClassName', 'SomeClassName'],
[self::customNaming(), 'Name2Test', '\Some\Class\Name2Test'],
];
}

Expand Down Expand Up @@ -89,6 +99,10 @@ public static function dataPropertyToColumnName(): array
[self::underscoreNamingUpper(), 'SOME_PROPERTY', 'SOME_PROPERTY', 'Some\Class'],
[self::underscoreNamingUpper(), 'BASE64_ENCODED', 'base64Encoded', 'Some\Class'],
[self::underscoreNamingUpper(), 'BASE64ENCODED', 'base64encoded', 'Some\Class'],

// CustomPascalNamingStrategy
[self::customNaming(), 'SomeProperty', 'someProperty', 'Some\Class'],
[self::customNaming(), 'Base64Encoded', 'base64Encoded', 'Some\Class'],
];
}

Expand Down Expand Up @@ -116,6 +130,9 @@ public static function dataReferenceColumnName(): array
// UnderscoreNamingStrategy
[self::underscoreNamingLower(), 'id'],
[self::underscoreNamingUpper(), 'ID'],

// CustomPascalNamingStrategy
[self::customNaming(), 'Id'],
];
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>

<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

<entity name="Doctrine\Tests\ORM\Mapping\BlogPost">

<id name="id" type="integer" column="id">
<generator strategy="NONE"/>
</id>

</entity>

</doctrine-mapping>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>

<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

<entity name="Doctrine\Tests\ORM\Mapping\BlogPostComment">

<id name="id" type="integer">
<generator strategy="NONE"/>
</id>

<many-to-one field="blogPost" target-entity="Doctrine\Tests\ORM\Mapping\BlogPost">
<join-columns>
<join-column nullable="false"/>
</join-columns>
</many-to-one>

</entity>

</doctrine-mapping>

0 comments on commit 9f2b367

Please sign in to comment.