Search by

ik-oss / doctrine-dynamic-discriminator-map

fduarte42

Dynamic discriminator map for Doctrine ORM

1.0.0 2026-09-22 16:14 UTC

This package is auto-updated.

Last update: 2026-09-22 16:24:12 UTC


README

CI Latest Stable Version License

Adds the ability to declare a Doctrine ORM entity discriminator map from configuration, instead of having to list every child entity in the parent's #[DiscriminatorMap] attribute.

Entries coming from configuration are merged on top of the ones declared via the #[DiscriminatorMap] attribute, so configuration wins on key collisions.

Requirements

  • PHP 8.5
  • Doctrine ORM 3.6+

Installation

$ composer require ik-oss/doctrine-dynamic-discriminator-map

Usage

Entities

Declare the parent entity with an inheritance type, a discriminator column and (optionally) a discriminator map containing only itself:

<?php

declare(strict_types=1);

namespace My\Namespace\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'person')]
#[ORM\InheritanceType('SINGLE_TABLE')]
#[ORM\DiscriminatorColumn(name: 'type', type: 'string')]
#[ORM\DiscriminatorMap(['person' => Person::class])]
class Person
{
    // ...
}

The children need no discriminator entry of their own:

<?php

declare(strict_types=1);

namespace My\Namespace\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Student extends Person
{
    // ...
}

#[ORM\Entity]
class Teacher extends Person
{
    // ...
}

Register the listener on the Doctrine event manager

<?php

declare(strict_types=1);

use Doctrine\Common\EventManager;
use Doctrine\DBAL\DriverManager;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\ORMSetup;
use Ikoss\DoctrineDDM\Factory\MetadataConfigFactory;
use Ikoss\DoctrineDDM\MetadataListener;
use My\Namespace\Entity;

$metadataConfig = (new MetadataConfigFactory())->createMetadata([
    Entity\Person::class => [ // parent class
        'discriminator_map' => [
            'teacher' => Entity\Teacher::class, // child class
            'student' => Entity\Student::class, // child class
        ],
    ],
]);

$eventManager = new EventManager();
$eventManager->addEventSubscriber(new MetadataListener($metadataConfig));

$config = ORMSetup::createAttributeMetadataConfiguration([__DIR__ . '/src'], true);
$config->enableNativeLazyObjects(true);

$connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'memory' => true]);

$entityManager = new EntityManager($connection, $config, $eventManager);

That's it — Person now resolves student and teacher discriminator values:

$entityManager->getClassMetadata(Entity\Person::class)->discriminatorMap;
// [
//     'person'  => My\Namespace\Entity\Person::class,   // from the attribute
//     'teacher' => My\Namespace\Entity\Teacher::class,  // from configuration
//     'student' => My\Namespace\Entity\Student::class,  // from configuration
// ]

Note: ORMSetup requires symfony/cache to build its default metadata cache. Either add it to your project or pass your own PSR-6 pool as the fourth argument. enableNativeLazyObjects(true) uses PHP 8.4+ native lazy objects instead of requiring symfony/var-exporter.

Framework integration

Invokable factories

Ikoss\DoctrineDDM\Factory\MetadataConfigFactory and Ikoss\DoctrineDDM\Factory\MetadataListenerFactory both expose an __invoke(ContainerInterface $container) method usable with any PSR-11 container.

MetadataConfigFactory reads the config service and looks for a Ikoss\DoctrineDDM\Factory\MetadataConfigFactory::class key holding the discriminator map configuration, returning a Ikoss\DoctrineDDM\Configuration\Metadata instance.

MetadataListenerFactory reads the Ikoss\DoctrineDDM\Configuration\Metadata service and returns a configured Ikoss\DoctrineDDM\MetadataListener.

Laminas and Mezzio

The package ships a ConfigProvider (Mezzio) and a Module (Laminas MVC), both registering the factories above. With DoctrineORMModule:

<?php

declare(strict_types=1);

use Ikoss\DoctrineDDM\Configuration\Metadata;
use Ikoss\DoctrineDDM\Factory\MetadataConfigFactory;
use Ikoss\DoctrineDDM\Factory\MetadataListenerFactory;
use Ikoss\DoctrineDDM\MetadataListener;
use My\Namespace\Entity;

return [
    'service_manager' => [ // or "dependencies" for Mezzio
        'factories' => [
            Metadata::class => MetadataConfigFactory::class,
            MetadataListener::class => MetadataListenerFactory::class,
        ],
    ],
    'doctrine' => [
        'eventmanager' => [
            'orm_default' => [
                'subscribers' => [
                    MetadataListener::class,
                ],
            ],
        ],
    ],
    // discriminator map configuration read by MetadataConfigFactory
    MetadataConfigFactory::class => [
        Entity\Person::class => [ // parent class
            'discriminator_map' => [
                'teacher' => Entity\Teacher::class, // child class
                'student' => Entity\Student::class, // child class
            ],
        ],
    ],
];

Development

$ composer install
$ composer test       # PHPUnit
$ composer cs-check   # phpcs
$ composer cs-fix     # phpcbf
$ composer check      # cs-check + test

Credits

This package is a continuation of facile-it/doctrine-dynamic-discriminator-map by Thomas Vargiu, maintained by INTERLIGENT kommunizieren GmbH under the ik-oss namespace as the upstream project is no longer maintained.

License

MIT — see LICENSE.md.