Abstract subclass discriminator value is null #7301

Closed
opened 2026-01-22 15:49:34 +01:00 by admin · 8 comments
Owner

Originally created by @plantas on GitHub (Jan 20, 2024).

Bug Report

Q A
BC Break no
Version 2.17.3

Summary

In case we use single table inheritance we might have intermediate abstract class that is part of the discriminator map but value in that case is null.

Current behavior

SqlWalker (1ae74b8ec5/lib/Doctrine/ORM/Query/SqlWalker.php (L479)) does not check if value is null and the following deprecation is emitted:

vendor/doctrine/dbal/src/Driver/PDO/Connection.php:89
PDO::quote(): Passing null to parameter #1 ($string) of type string is deprecated

Expected behavior

Skip null values in the map.
I believe fix can be adding a not null check:

foreach ($class->subClasses as $subclassName) {
    if ($this->em->getClassMetadata($subclassName)->discriminatorValue !== null) {
        $values[] = $conn->quote($this->em->getClassMetadata($subclassName)->discriminatorValue);
    }
}

I'am not familiar with the internals and there might be more places in the code that should be checked. If someone more experienced would like to give a suggestion, I can open a PR with the fix.
Thanks

Originally created by @plantas on GitHub (Jan 20, 2024). ### Bug Report | Q | A |------------ | ------ | BC Break | no | Version | 2.17.3 #### Summary In case we use single table inheritance we might have intermediate abstract class that is part of the discriminator map but value in that case is null. #### Current behavior SqlWalker (https://github.com/htto/doctrine-orm/blob/1ae74b8ec56e8749d6c85c2845d64294ba34dd66/lib/Doctrine/ORM/Query/SqlWalker.php#L479) does not check if value is null and the following deprecation is emitted: ``` vendor/doctrine/dbal/src/Driver/PDO/Connection.php:89 PDO::quote(): Passing null to parameter #1 ($string) of type string is deprecated ``` #### Expected behavior Skip null values in the map. I believe fix can be adding a not null check: ``` foreach ($class->subClasses as $subclassName) { if ($this->em->getClassMetadata($subclassName)->discriminatorValue !== null) { $values[] = $conn->quote($this->em->getClassMetadata($subclassName)->discriminatorValue); } } ``` I'am not familiar with the internals and there might be more places in the code that should be checked. If someone more experienced would like to give a suggestion, I can open a PR with the fix. Thanks
admin closed this issue 2026-01-22 15:49:34 +01:00
Author
Owner

@mpdude commented on GitHub (Jan 20, 2024):

When the class is abstract, how can an entity exist that is of this type?

@mpdude commented on GitHub (Jan 20, 2024): When the class is abstract, how can an entity exist that is of this type?
Author
Owner

@plantas commented on GitHub (Jan 20, 2024):

When the class is abstract, how can an entity exist that is of this type?

@mpdude it does not exist. Abstract class A (contains discriminator map definition), abstract class B extends A, class C extends B. Only class C has value in a discriminator map. It seems like class metadata returns class B in the list of subclasses and it's discriminator value is null.

@plantas commented on GitHub (Jan 20, 2024): > When the class is abstract, how can an entity exist that is of this type? @mpdude it does not exist. Abstract class A (contains discriminator map definition), abstract class B extends A, class C extends B. Only class C has value in a discriminator map. It seems like class metadata returns class B in the list of subclasses and it's discriminator value is null.
Author
Owner

@mpdude commented on GitHub (Jan 21, 2024):

Is there any particular reason why you want that class to be in the discriminator map, and use null as the discriminator value?

@mpdude commented on GitHub (Jan 21, 2024): Is there any particular reason why you want that class to be in the discriminator map, and use `null` as the discriminator value?
Author
Owner

@plantas commented on GitHub (Jan 21, 2024):

Is there any particular reason why you want that class to be in the discriminator map, and use null as the discriminator value?

@mpdude abstract class A and B aren't part of the discriminator map. The only class in the map is class C.
When we iterate over subclasses of A we get B and C (https://github.com/doctrine/orm/blob/2.17.x/lib/Doctrine/ORM/Query/SqlWalker.php#L478). B should be skipped because it is not part of the discriminator map and expression $this->em->getClassMetadata($subclassName)->discriminatorValue evaluates to null.

@plantas commented on GitHub (Jan 21, 2024): > Is there any particular reason why you want that class to be in the discriminator map, and use `null` as the discriminator value? @mpdude abstract class A and B aren't part of the discriminator map. The only class in the map is class C. When we iterate over subclasses of A we get B and C (https://github.com/doctrine/orm/blob/2.17.x/lib/Doctrine/ORM/Query/SqlWalker.php#L478). B should be skipped because it is not part of the discriminator map and expression `$this->em->getClassMetadata($subclassName)->discriminatorValue` evaluates to null.
Author
Owner

@yard-mschwartz commented on GitHub (Jan 26, 2024):

You are describing the same problem I'm currently facing, am I right?

I'm not allowed to do this:

#[ORM\InheritanceType('SINGLE_TABLE')]
#[ORM\DiscriminatorColumn(name: 'discr', type: 'string')]
abstract class Field
{
}

abstract class ChoiceField extends Field
{
}

#[ORM\Entity]
class SingleChoiceField extends ChoiceField
{
}

#[ORM\Entity]
class MultipleChoiceField extends ChoiceField
{
}

Because Doctrine will tell me this:

$ symfony console doctrine:migrations:diff

In MappingException.php line 357:

  Class "App\Modules\Forms\Entity\ChoiceField" sub class of "App\Modules\Forms\Entity\Field" is not a valid entity or mapped super class.

Explicitly adding the following code block to Field doesn't help

#[ORM\DiscriminatorMap([
    'single_choice' => SingleChoiceField::class,
    'multiple_choice' => MultipleChoiceField::class,
])]

Workaround for now is to make ChoiceField an entity that I just won't be using.

@yard-mschwartz commented on GitHub (Jan 26, 2024): You are describing the same problem I'm currently facing, am I right? I'm not allowed to do this: ``` #[ORM\InheritanceType('SINGLE_TABLE')] #[ORM\DiscriminatorColumn(name: 'discr', type: 'string')] abstract class Field { } abstract class ChoiceField extends Field { } #[ORM\Entity] class SingleChoiceField extends ChoiceField { } #[ORM\Entity] class MultipleChoiceField extends ChoiceField { } ``` Because Doctrine will tell me this: ``` $ symfony console doctrine:migrations:diff In MappingException.php line 357: Class "App\Modules\Forms\Entity\ChoiceField" sub class of "App\Modules\Forms\Entity\Field" is not a valid entity or mapped super class. ``` Explicitly adding the following code block to `Field` doesn't help ``` #[ORM\DiscriminatorMap([ 'single_choice' => SingleChoiceField::class, 'multiple_choice' => MultipleChoiceField::class, ])] ``` Workaround for now is to make `ChoiceField` an entity that I just won't be using.
Author
Owner

@mpdude commented on GitHub (Feb 2, 2024):

You might want to subscribe to #11200

@mpdude commented on GitHub (Feb 2, 2024): You might want to subscribe to #11200
Author
Owner

@mpdude commented on GitHub (Feb 2, 2024):

Please report in #11200 whether it fixes this issue

@mpdude commented on GitHub (Feb 2, 2024): Please report in #11200 whether it fixes this issue
Author
Owner

@mpdude commented on GitHub (Feb 3, 2024):

Fixed by #11200

@mpdude commented on GitHub (Feb 3, 2024): Fixed by #11200
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#7301