#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>