DiscriminatorMap 注释中的环境变量或函数
Environmental variable or function in DiscriminatorMap annotation
我怎样才能有一个基于当前环境设置的鉴别器映射?
我有一个使用单table 继承和鉴别器列的实体:
@ORM\DiscriminatorMap({1="Product", 2="User"})
鉴别器值(1, 2
)在我的生产环境和开发环境中不同,因此需要动态设置这些值。不幸的是,这似乎不是 Doctrine annotation documentation 中的一个选项。
直接在注释中使用环境似乎不起作用。比如我试过:
@ORM\DiscriminatorMap('%discrimination_array%')
然后在doctrine.yaml
中定义discrimination_array
:
discrimination_array: '{%env(PRODUCT)%="Product", %env(USER)%="User"}'
以及 .env
中相应的环境变量:
PRODUCT=1
USER=2
但是,Doctrine 会抛出类似
的错误
Conversion failed when converting the varchar value '%env(PRODUCT)%' to data type smallint.
是否可以根据当前环境设置class判别图?
这可以通过扩展特定实体的数据映射来完成。解析注解时,Doctrine fires an event:
When the mapping information for an entity is read, it is populated in to a ClassMetadataInfo instance. You can hook in to this process and manipulate the instance.
通过订阅此事件,可以在加载实体后设置实体的 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);
}
}
因为在 class 解析后添加了鉴别器映射,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 }
我怎样才能有一个基于当前环境设置的鉴别器映射?
我有一个使用单table 继承和鉴别器列的实体:
@ORM\DiscriminatorMap({1="Product", 2="User"})
鉴别器值(1, 2
)在我的生产环境和开发环境中不同,因此需要动态设置这些值。不幸的是,这似乎不是 Doctrine annotation documentation 中的一个选项。
直接在注释中使用环境似乎不起作用。比如我试过:
@ORM\DiscriminatorMap('%discrimination_array%')
然后在doctrine.yaml
中定义discrimination_array
:
discrimination_array: '{%env(PRODUCT)%="Product", %env(USER)%="User"}'
以及 .env
中相应的环境变量:
PRODUCT=1
USER=2
但是,Doctrine 会抛出类似
的错误Conversion failed when converting the varchar value '%env(PRODUCT)%' to data type smallint.
是否可以根据当前环境设置class判别图?
这可以通过扩展特定实体的数据映射来完成。解析注解时,Doctrine fires an event:
When the mapping information for an entity is read, it is populated in to a ClassMetadataInfo instance. You can hook in to this process and manipulate the instance.
通过订阅此事件,可以在加载实体后设置实体的 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);
}
}
因为在 class 解析后添加了鉴别器映射,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 }