Сопоставление имени класса в доктрине

#php #doctrine-orm #doctrine

#php #doctrine-orm #доктрина

Вопрос:

Я создаю приложение, у которого есть вызываемый объект Element . Класс состоит из 2 полей (на самом деле их больше, но остальные не имеют значения):

  • ElementData — набор данных (ключ — значение) с некоторыми дополнительными функциями
  • ElementType — интерфейс с несколькими реализациями. Инкапсулированный набор бизнес-правил и валидаторов — не получает никаких значений

Упрощенная диаграмма классов:

введите описание изображения здесь

У меня есть несколько классов, реализующих ElementType interfce:

 class Type1 implements ElementType {/*...*/}
class Type2 implements ElementType {/*...*/}
class Type3 implements ElementType {/*...*/}
 

Моя таблица базы данных для элементов также очень проста и имеет только 2 соответствующих поля (остальные удалены из скриншота):

введите описание изображения здесь

Здесь возникает проблема. Я понятия не имею, как сопоставить класс (Type1, Type2 …) и сохранить его в виде строки (type1, type2 …) в elements таблице (как обычный встроенный элемент). Я просмотрел документацию и не нашел ничего полезного. Мой текущий файл сопоставления выглядит следующим образом:

 <doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                   https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
    <entity name="AppDomainElement" table="elements" repository-class="AppRepositoryElementRepository">
        <embedded name="id" class="AppDomainElementId" use-column-prefix="false" />
        <!--Missing mapping here-->
    </entity>
</doctrine-mapping>
 

Ответ №1:

В конце концов я понял это. Возможно, мое решение будет кому-то полезно. Решение основано на пользовательском типе сопоставления.

 <?php

namespace AppMapping;

use AppDomainElementType;
use AppDomainType1;
use AppDomainTypeFactory;
use DoctrineDBALTypesType;
use DoctrineDBALPlatformsAbstractPlatform;

class ElementType extends Type
{
    const NAME = 'element_type';

    public function getSQLDeclaration(array $column, AbstractPlatform $platform)
    {
        return $platform->getVarcharTypeDeclarationSQL($column);
    }

    public function convertToPHPValue($value, AbstractPlatform $platform)
    {
        return TypeFactory::getTypeByString($value);
    }

    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        if (!$value instanceof ElementType) {
            throw new Exception('Wrong type');
        }

        return TypeFactory::getStringByType($value);
    }

    public function getName(): string
    {
        return self::NAME;
    }
}

 

TypeFactory это просто простой оператор switch, поэтому я не буду вставлять его здесь.

 # config/packages/doctrine.yml
doctrine:
    dbal:
        types:
            element_type:  AppMappingElementType
 

Когда был создан мой пользовательский тип сопоставления, все, что мне нужно было сделать, это реализовать его в моем mapper:

 <doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                   https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
    <entity name="AppDomainElement" table="elements" repository-class="AppRepositoryElementRepository">
        <embedded name="id" class="AppDomainElementId" use-column-prefix="false" />
        <field name="type" type="element_type" />
    </entity>
</doctrine-mapping>