Alternative DiscriminatorMap declaration #6961

Open
opened 2026-01-22 15:42:10 +01:00 by admin · 7 comments
Owner

Originally created by @michnovka on GitHub (Apr 18, 2022).

Feature Request

I have a custom DBAL type and I wish to use it as a discriminator column for JOINED inheritance type

Q A
New Feature yes
RFC no
BC Break no

Summary

In my case I use custom type that works with enums. But any custom type using any non-scalar PHP value would cause the same issues:

#[ORM\InheritanceType("JOINED")]
#[ORM\DiscriminatorColumn(name:"type", type: PaymentGatewayType::class)]
#[ORM\DiscriminatorMap([
    PaymentGatewayType::PAYSSION => Payssion::class,
    PaymentGatewayType::PAYMENTASIA => PaymentAsia::class
])]
abstract class PaymentGateway
{

The issue is that while any type can be used for DiscriminatorColumn, the DiscriminatorMap definition accepts only format like

#[ORM\DiscriminatorMap([
    VALUE_OF_COLUMN => SUB_CLASS,
])]

The VALUE_OF_COLUMN is the actual PHP value used by the Type thats converted to DB value with Type::convertToDatabaseValue().

And here lies the problem

in PHP as of 8.1 we cannot use objects as array keys. Therefore no objects / enums can be used inside DiscriminatorMap solely for this limitation. The JoinedSubclassPersister handles the conversion through DBAL Type correctly, but the PHP limitation makes it impossible to use any non-scalar keys.

Proposed solution

I propose an alternative declaration of DiscriminatorMap, but keep the old one for simplicity and BC.

#[ORM\DiscriminatorMapItem(VALUE_OF_COLUMN, SUB_CLASS)]

So my code would look:

#[ORM\InheritanceType("JOINED")]
#[ORM\DiscriminatorColumn(name:"type", type: PaymentGatewayType::class)]
#[ORM\DiscriminatorMapItem(PaymentGatewayType::PAYSSION, Payssion::class)]
#[ORM\DiscriminatorMapItem(PaymentGatewayType::PAYMENTASIA, PaymentAsia::class])]
abstract class PaymentGateway
{

This would allow any custom type to be used as discriminator

Originally created by @michnovka on GitHub (Apr 18, 2022). ### Feature Request I have a custom DBAL type and I wish to use it as a discriminator column for JOINED inheritance type <!-- Fill in the relevant information below to help triage your issue. --> | Q | A |------------ | ------ | New Feature | yes | RFC | no | BC Break | no #### Summary In my case I use custom type that works with enums. But any custom type using any non-scalar PHP value would cause the same issues: ```php #[ORM\InheritanceType("JOINED")] #[ORM\DiscriminatorColumn(name:"type", type: PaymentGatewayType::class)] #[ORM\DiscriminatorMap([ PaymentGatewayType::PAYSSION => Payssion::class, PaymentGatewayType::PAYMENTASIA => PaymentAsia::class ])] abstract class PaymentGateway { ``` The issue is that while any type can be used for `DiscriminatorColumn`, the `DiscriminatorMap` definition accepts only format like ```php #[ORM\DiscriminatorMap([ VALUE_OF_COLUMN => SUB_CLASS, ])] ``` The `VALUE_OF_COLUMN` is the actual PHP value used by the `Type` thats converted to DB value with `Type::convertToDatabaseValue()`. *And here lies the problem* in PHP as of 8.1 we cannot use objects as array keys. Therefore no objects / enums can be used inside `DiscriminatorMap` solely for this limitation. The `JoinedSubclassPersister` handles the conversion through DBAL Type correctly, but the PHP limitation makes it impossible to use any non-scalar keys. #### Proposed solution I propose an alternative declaration of `DiscriminatorMap`, but keep the old one for simplicity and BC. ```php #[ORM\DiscriminatorMapItem(VALUE_OF_COLUMN, SUB_CLASS)] ``` So my code would look: ```php #[ORM\InheritanceType("JOINED")] #[ORM\DiscriminatorColumn(name:"type", type: PaymentGatewayType::class)] #[ORM\DiscriminatorMapItem(PaymentGatewayType::PAYSSION, Payssion::class)] #[ORM\DiscriminatorMapItem(PaymentGatewayType::PAYMENTASIA, PaymentAsia::class])] abstract class PaymentGateway { ``` This would allow any custom type to be used as discriminator
admin added the New Feature label 2026-01-22 15:42:10 +01:00
Author
Owner

@derrabus commented on GitHub (Apr 19, 2022):

Sounds reasonable, especially if we want to support backed enumerations as discriminators.

@derrabus commented on GitHub (Apr 19, 2022): Sounds reasonable, especially if we want to support backed enumerations as discriminators.
Author
Owner

@michnovka commented on GitHub (Apr 19, 2022):

This will require redesign of internal ClassMetadataInfo::$discriminatorMap as right now it also uses same structure with array key being the actual discriminator. Thats a public property, so there is a BC break. Otherwise wed have to copy lot of code to handle this special case, to keep BC.

@michnovka commented on GitHub (Apr 19, 2022): This will require redesign of internal `ClassMetadataInfo::$discriminatorMap` as right now it also uses same structure with array key being the actual discriminator. Thats a public property, so there is a BC break. Otherwise wed have to copy lot of code to handle this special case, to keep BC.
Author
Owner

@michnovka commented on GitHub (Apr 19, 2022):

@beberlei would like your input on this too, please.

@michnovka commented on GitHub (Apr 19, 2022): @beberlei would like your input on this too, please.
Author
Owner

@michnovka commented on GitHub (Apr 19, 2022):

How about we call the getDatabaseValue when constructing the discriminator map? And then when it is inserted into SQL, we no longer need to do that. This would allow us to keep the same ClassMetadataInfo::$discriminatorMap . I dont think BC would be broken, as currently it cannot work for any non-scalar types, and those have the same PHP value as DB value

@michnovka commented on GitHub (Apr 19, 2022): How about we call the `getDatabaseValue` when constructing the discriminator map? And then when it is inserted into SQL, we no longer need to do that. This would allow us to keep the same `ClassMetadataInfo::$discriminatorMap` . I dont think BC would be broken, as currently it cannot work for any non-scalar types, and those have the same PHP value as DB value
Author
Owner

@Gabb1995 commented on GitHub (Jan 20, 2023):

is it at all possible to have php 8.1 enums as discriminator maps? I tried using the ->value method but it gives Constant expiression contains invalid operations.

@Gabb1995 commented on GitHub (Jan 20, 2023): is it at all possible to have php 8.1 enums as discriminator maps? I tried using the ->value method but it gives Constant expiression contains invalid operations.
Author
Owner

@michnovka commented on GitHub (Jan 20, 2023):

@Gabb1995 this question does not belong here, but since you already asked, the answer is no. Using Enum::enumCase->value inside attributes is a PHP 8.2 feature.

@michnovka commented on GitHub (Jan 20, 2023): @Gabb1995 this question does not belong here, but since you already asked, the answer is no. Using `Enum::enumCase->value` inside attributes is a PHP 8.2 feature.
Author
Owner

@whataboutpereira commented on GitHub (Jan 18, 2025):

I see DiscriminatorColumn takes enumType and I tried to use an enum there.

enum CommentType: string
{
    case One = 'one';
    case Two = 'two';
    case Three = 'three';
}
#[ORM\DiscriminatorColumn(name: 'Type', type: Types::ENUM, enumType: CommentType::class)]
#[ORM\DiscriminatorMap([
    'one' => CommentOne::class,
    'two' => CommentTwo::class,
    'three' => CommentThree::class,
])]

The entities actually work, but generating migration fails with:

This yields Doctrine\DBAL\Platforms\MySQL80Platform requires the values of a ENUM column to be specified.

Is this still unsupported or am I missing something else?

Ideally it would be nice to return the whole discriminator map from the enum.

@whataboutpereira commented on GitHub (Jan 18, 2025): I see DiscriminatorColumn takes enumType and I tried to use an enum there. ``` enum CommentType: string { case One = 'one'; case Two = 'two'; case Three = 'three'; } ``` ``` #[ORM\DiscriminatorColumn(name: 'Type', type: Types::ENUM, enumType: CommentType::class)] #[ORM\DiscriminatorMap([ 'one' => CommentOne::class, 'two' => CommentTwo::class, 'three' => CommentThree::class, ])] ``` The entities actually work, but generating migration fails with: `This yields Doctrine\DBAL\Platforms\MySQL80Platform requires the values of a ENUM column to be specified.` Is this still unsupported or am I missing something else? Ideally it would be nice to return the whole discriminator map from the enum.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6961