Skip to content

Commit

Permalink
Prohibits class typo in the discriminator map (#8122)
Browse files Browse the repository at this point in the history
* Prevents incorrect table aliases to be generated

When a defined subclass has a case typo, the query builder will be lost
and will generate exotic table alias. This commit fixes the issue at the
root by prohibiting case typo in discriminator map.

See #8112 for the consequence of
such typo.

* Controls growing rate of the abstract test class

* Fixes incorrect test case

The Cube class must be autoloaded with the correct case, otherwise
composer autoloader will complain.

* Removes non architecture compliant code

See https://github.com/doctrine/orm/pull/8122/files#r423952247

* Ensures discriminator map is case sensitive
  • Loading branch information
gquemener authored Jul 5, 2020
1 parent 2a2a0b2 commit 64c3f68
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 1 deletion.
6 changes: 6 additions & 0 deletions lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
use Doctrine\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Persistence\Mapping\ReflectionService;
use ReflectionClass;
use ReflectionException;
use function assert;
use function interface_exists;
Expand Down Expand Up @@ -278,6 +279,11 @@ protected function validateRuntimeMetadata($class, $parent)
if ( ! $class->discriminatorColumn) {
throw MappingException::missingDiscriminatorColumn($class->name);
}
foreach ($class->subClasses as $subClass) {
if ((new ReflectionClass($subClass))->name !== $subClass) {
throw MappingException::invalidClassInDiscriminatorMap($subClass, $class->name);
}
}
}
} else if ($class->isMappedSuperclass && $class->name == $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
// second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
Expand Down
10 changes: 10 additions & 0 deletions tests/Doctrine/Tests/Models/CaseSensitiveDiscriminatorMap/Cube.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\Models\CaseSensitiveDiscriminatorMap;

/** @Entity */
final class Cube extends Shape
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\Models\CaseSensitiveDiscriminatorMap;

use Doctrine\ORM\Mapping\ClassMetadataInfo;

/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorMap({"cube" = cube::class})
* @DiscriminatorColumn(name="discr", length=32, type="string")
*/
abstract class Shape
{
/** @Id @Column(type="string") @GeneratedValue(strategy="AUTO") */
public $id;

public static function loadMetadata(ClassMetadataInfo $metadata)
{
$metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE);
$metadata->setDiscriminatorColumn([
'name' => 'discr',
'type' => 'string',
'length' => 32,
]);
$metadata->setDiscriminatorMap([
'cube' => cube::class,
]);
$metadata->mapField([
'fieldName' => 'id',
'type' => 'string',
'length' => null,
'precision' => 0,
'scale' => 0,
'nullable' => false,
'unique' => false,
'id' => true,
'columnName' => 'id',
]);
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
}
}
14 changes: 13 additions & 1 deletion tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
use Doctrine\Persistence\Mapping\RuntimeReflectionService;
use Doctrine\Tests\Models\Cache\City;
use Doctrine\Tests\Models\CaseSensitiveDiscriminatorMap;
use Doctrine\Tests\Models\CMS\CmsAddress;
use Doctrine\Tests\Models\CMS\CmsAddressListener;
use Doctrine\Tests\Models\CMS\CmsUser;
Expand All @@ -37,6 +38,7 @@
use Doctrine\Tests\Models\DDC964\DDC964Admin;
use Doctrine\Tests\Models\DDC964\DDC964Guest;
use Doctrine\Tests\OrmTestCase;
use function class_exists;

abstract class AbstractMappingDriverTest extends OrmTestCase
{
Expand Down Expand Up @@ -1079,6 +1081,17 @@ public function testDiscriminatorColumnDefaultName()
$this->assertEquals('dtype', $class->discriminatorColumn['name']);
}

public function testInvalidSubClassCase()
{
class_exists(CaseSensitiveDiscriminatorMap\Cube::class);

$this->expectException(MappingException::class);
$this->expectExceptionMessage('Entity class \'Doctrine\Tests\Models\CaseSensitiveDiscriminatorMap\cube\' used in the discriminator map of class \'Doctrine\Tests\Models\CaseSensitiveDiscriminatorMap\Shape\' does not exist.');

$em = $this->_getTestEntityManager();
$factory = $this->createClassMetadataFactory($em);
$factory->getMetadataFor(CaseSensitiveDiscriminatorMap\Shape::class);
}
}

/**
Expand Down Expand Up @@ -1344,7 +1357,6 @@ public static function loadMetadata(ClassMetadataInfo $metadata)
}
}


/**
* @Entity
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\Tests\Models\CaseSensitiveDiscriminatorMap\cube;

$metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE);
$metadata->setDiscriminatorColumn([
'name' => 'discr',
'type' => 'string',
'length' => 32,
]);
$metadata->setDiscriminatorMap([
'cube' => cube::class,
]);
$metadata->mapField([
'fieldName' => 'id',
'type' => 'string',
'length' => null,
'precision' => 0,
'scale' => 0,
'nullable' => false,
'unique' => false,
'id' => true,
'columnName' => 'id',
]);
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?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\Models\CaseSensitiveDiscriminatorMap\Shape" inheritance-type="SINGLE_TABLE">
<discriminator-column name="discr" type="string" length="32" />
<discriminator-map>
<discriminator-mapping value="cube" class="Doctrine\Tests\Models\CaseSensitiveDiscriminatorMap\cube" />
</discriminator-map>
<id name="id" type="integer" column="id">
<generator strategy="AUTO" />
</id>
</entity>
</doctrine-mapping>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Doctrine\Tests\Models\CaseSensitiveDiscriminatorMap\Shape:
type: entity
inheritanceType: SINGLE_TABLE
discriminatorMap:
cube: Doctrine\Tests\Models\CaseSensitiveDiscriminatorMap\cube
discriminatorColumn:
type: string
name: discr
length: 32
id:
id:
type: integer
generator:
strategy: AUTO

0 comments on commit 64c3f68

Please sign in to comment.