In Doctrine 2 ORM I have an abstract "Communication" entity that uses SINGLE_TABLE inheritance to decide which type of communication it is:

Communication.orm.yaml:

App\Entity\Communication:

    type: entity
    table: communication

    inheritanceType: SINGLE_TABLE
    discriminatorColumn:
        name: mode
        type: string
    discriminatorMap:
        push: App\Entity\Communication\Push
        notice: App\Entity\Communication\Notice
        email: App\Entity\Communication\Email

# ...

So there are 3 communication types (push, notice, and email) that all use the "communication" table.

Each "Communication" is translatable. Previously, I had 3 entities containing these translations. Each of these i18n entities uses the same "i18n_communication" table, and contains a bi-directional many-to-one relationship with their respective type of Communication:

  • App\Entity\I18n\Communication\Push
  • App\Entity\I18n\Communication\Notice
  • App\Entity\I18n\Communication\Email

Since having multiple entities using the same table without table inheritance is illegal in Doctrine 2, I made all of the I18n entities extend a base I18nCommunication class, similar to the non-i18n entities that they translate:

I18nCommunication.orm.yaml:

App\Entity\I18N\Communication\I18nCommunication:

    type: entity
    table: i18n_communication
    inheritanceType: SINGLE_TABLE
    discriminatorColumn:
        name: communication.mode    ******
        type: string
    discriminatorMap:
        push: App\Entity\I18N\Communication\Push
        notice: App\Entity\I18N\Communication\Notice
        email: App\Entity\I18N\Communication\Email
# ...

This doesn't work. All entities that extend I18nCommunication have a "communication" field that references the Communication entity they translate, but Doctrine doesn't know that what to do with the "name: communication.mode" line.

My question is this: How do I use a field from a related entity as the discriminator column?

I tried using inheritanceType: JOINED and extending I18nCommunication from Communication so I had access to the parent's mode field. However, that doesn't work because of Communication's inheritanceType: SINGLE_TABLE, it thinks that I18nCommunication should then reside in the communication table.

Is there a way to do this? Or will I have to resort to combining my I18nCommunication entities into a single entity?

Thank you.

1 Answers

0
rkeet On

This won't work. The DiscriminatorColumn is declared inside the currently being configured Entity. The annotation too, it's a "EntityAnnotation", not an "PropertyAnnotation".

Any particular reason you don't have something like:

class I18nCommunication { ... }
class Push extends I18nCommunication { ... }
class Notice extends I18nCommunication { ... }
class Email extends I18nCommunication { ... }
App\Entity\I18N\Communication\I18nCommunication:

    type: entity
    table: i18n_communication
    inheritanceType: SINGLE_TABLE
    discriminatorColumn:
        name: discr
        type: string

As you're using Single Table Inheritance all of the data would be there anyway.

Next, do not declare a DiscriminatorMap, Doctrine will handle that for you automagically. See the last bullet point under STI link above:

If no discriminator map is provided, then the map is generated automatically. The automatically generated discriminator map the lowercase short name of each class as key.

Also, you ask in your question title:

Use a field in a joined table as the discriminator

This could never happen, simple because: that joined table would be the only one which knows about that data. It would not be available to the siblings, thus they'd never know they're part of something else.

As such, this is also never built as something to be made available.

The discriminator, being class annotation, must always happen on the "parent" of the lot being discriminated. In your case: I18nCommunication.