Переменная или функция среды в аннотации DiscriminatorMap - PullRequest
0 голосов
/ 11 января 2020

Как мне получить карту дискриминатора, установленную на основе текущей среды?

У меня есть объект, использующий наследование одной таблицы со столбцом дискриминатора:

@ORM\DiscriminatorMap({1="Product", 2="User"})

Значения дискриминатора (1, 2) отличаются в моей среде производства и разработки, поэтому значения должны быть установлены динамически. К сожалению, это не вариант в документации Doctrine .

Использование окружения непосредственно в аннотации, похоже, не работает. Например, я попытался:

@ORM\DiscriminatorMap('%discrimination_array%')

и затем определить discrimination_array в doctrine.yaml:

discrimination_array: '{%env(PRODUCT)%="Product", %env(USER)%="User"}'

вместе с соответствующими переменными среды в .env:

PRODUCT=1
USER=2

Однако Doctrine выдает такие ошибки, как

Преобразование не удалось при преобразовании значения varchar '% env (PRODUCT)%' в тип данных smallint.

Можно ли установить карту дискриминации классов в зависимости от текущей среды?

1 Ответ

1 голос
/ 11 января 2020

Это можно сделать, расширив отображение данных для указанного c объекта. Когда аннотации анализируются, Doctrine запускает событие :

Когда считывается информация о сопоставлении для объекта, он заполняется в экземпляре ClassMetadataInfo. Вы можете подключиться к этому процессу и управлять экземпляром.

Подписавшись на это событие, можно установить значение DiscriminatorMap для объекта после его загрузки.

Вот общий пример. Сначала реализуем подписчика. При загрузке соответствующего объекта (Item::class) добавьте соответствующий DiscriminatorMap.

<?php

namespace App\Doctrine\Listener;

use App\Entity\Item;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;

class LoadClassMetadataSubscriber implements EventSubscriber
{
    private $discriminatorMap;

    public function __construct( $discriminatorMap)
    {
        $this->discriminatorMap = $discriminatorMap;
    }

    public function getSubscribedEvents()
    {
        return [
            Events::loadClassMetadata
        ];
    }

    /**
     * @param LoadClassMetadataEventArgs $eventArgs
     */
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        /**
         * @var \Doctrine\ORM\Mapping\ClassMetadata $classMetadata
         */
        $classMetadata = $eventArgs->getClassMetadata();

        if ($classMetadata->name !== Item::class) {
            return;
        }

        $map = [];
        foreach ($this->discriminatorMap as $value) {
            $partial = explode('=', $value);
            $map[$partial[0]] = $partial[1];
        }

        $classMetadata->setDiscriminatorMap($map);
    }
}

Поскольку карта дискриминатора добавляется после анализа класса, Entity\Item не требуется аннотация DiscriminatorMap:

<?php

namespace App\Entity;

use App\Map;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(...)
 * @ORM\Table(...)
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 */
abstract class Item {

в среду должно быть добавлено сопоставление (.env или аналогичное):

DISCRIMINATOR_MAP=one=App\Entity\Item\One,two=App\Entity\Item\Two

Зарегистрируйте подписчика на правильное событие (config/services.yaml):

services:
    ...

    # Set up the custom subscriber. It'll take the environmental variable as
    # an argument, and subscribe to the `loadClassMetadata` event. 
    App\Doctrine\Listener\LoadClassMetadataSubscriber:
        public: true
        arguments:
            - '%env(csv:MAP)%'
        tags:
            - { name: doctrine.event_listener, event: loadClassMetadata, lazy: true }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...