我正在使用我的第一个可分发的包中,我对如何在我的包中重用“存在的用户实体”有一些疑问。我的捆绑包的目的是将故障单实体与用户实体相关联。
当TargetEntity的'referencedColumnName'与'id'不同时,我正试图在不同的bundle之间关联实体。
我正在关注Resolve Target Entity Docs并且对我有用只有当“targetEntity”的主键被命名为“id”时才能正常工作。
示例:
// file: vendor\Kdrmklabs\Bundle\TicketBundle\Entity\Ticket.php
class Ticket {
/**
* @ORM\ManyToOne(targetEntity="\Kdrmklabs\Bundle\TicketBundle\Model\UserInterface")
*/
private $user;
}
// file: vendor\Kdrmklabs\Bundle\TicketBundle\Model\UserInterface.php;
interface UserInterface {
public function getId();
}
# file: app/config/config.yml
doctrine:
orm:
auto_mapping: true
resolve_target_entities:
Kdrmklabs\Bundle\TicketBundle\Model\UserInterface: AppBundle\Entity\User
如果实体AppBundle/Entity/User
的主键名为“id”,则我的捆绑包与此实体之间的关系可以正常工作。
// file: src/AppBundle/Entity/User.php
class User implements \Kdrmklabs\Bundle\TicketBundle\Model\UserInterface
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
}
但是否则会发生异常:
// file: src/AppBundle/Entity/User.php
class User implements \Kdrmklabs\Bundle\TicketBundle\Model\UserInterface
{
/**
* @var integer
*
* @ORM\Column(name="id_customer", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
}
Column name 'id' referenced for relation from \Kdrmklabs\Bundle\TicketBundle\Entity\Ticket towards AppBundle\Entity\User does not exists.
我知道如果你在注释@ORM\JoinColumn(referencedColumnName="id_of_the_external_user_entity")
中指定外键的值,这将很有效,但是从我的包中我无法通过实际配置知道外键的名称。
有没有办法在两个实体之间创建关系,而不管这些主键的名称是什么?
可能是我可以请求用户在app / config / config.yml中指定他的主键名称“用户实体”并以某种方式指定这个值为doctrine来创建正确的关系我的包的实体和安装我的包的用户的实体。但是,我该怎么做呢?
谢谢。 问候
更多详情:
我的可分发包的存储库是:https://github.com/KdrMkLabs/TicketBundle
答案 0 :(得分:1)
在分析了这个问题几个小时之后,我得出结论,在彼此不知道的实体之间创建关系的正确方法是使用doctrine eventlisteners。我将在下面解释如何做到这一点。
您可以使用Doctrine事件侦听器解决冲突,以使用PHP而不是注释来映射实体。
EntityManager和UnitOfWork在其注册实体的生命周期内触发一系列事件。
Here you have a list of Lifecycle Events that you can use
在这种情况下,我们将监听事件loadClassMetadata
以进行正确的学说映射,并在用户实体和捆绑实体之间建立良好的关系。
<强> 1。在捆绑包中创建Doctrine EventListener
// file: Kdrmklabs\Bundle\TicketBundle\EventListener\LoadMetadata.php
namespace Kdrmklabs\Bundle\TicketBundle\EventListener;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
class LoadMetadata {
protected $userRepository;
protected $primary_key;
public function __construct($userRepository, $primary_key)
{
$this->userRepository = $userRepository;
$this->primary_key = $primary_key;
}
public function getSubscribedEvents()
{
return ['loadClassMetadata',];
}
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$classMetadata = $eventArgs->getClassMetadata();
$class_name = $classMetadata->getName();
if($class_name == "Kdrmklabs\Bundle\TicketBundle\Entity\Ticket") {
// The following is to map ORM with PHP
$mapping = array(
'targetEntity' => $this->userRepository,
'fieldName' => 'user',
'joinColumns' => array(
array(
'name' => 'user_id',
'referencedColumnName' => $this->primary_key
)
)
);
$classMetadata->mapManyToOne($mapping);
}
}
}
请注意,'fieldName'的值对应于引用Ticket实体中$ user的class属性的名称。上面的映射数组与使用注释的doctrine ORM映射类似,如下所示:
class Ticket {
/**
* @ORM\ManyToOne(targetEntity="\Kdrmklabs\Bundle\TicketBundle\Model\UserInterface")
* @ORM\JoinColumn(name="user_id", referencedColumnName="?id_from_external_entity?")
*/
private $user;
}
Here is more information about mapping in doctrine 2 with PHP
<强> 2。将eventListener注册为服务
# file: Kdrmklabs\Bundle\TicketBundle\Resources\config\services.yml
services:
kdrmklabs_ticket.listener:
class: Kdrmklabs\Bundle\TicketBundle\EventListener\LoadMetadata
arguments:
- %kdrmklabs_ticket.model.user.class%
- %kdrmklabs_ticket.model.user.primary_key%
tags:
- { name: doctrine.event_listener, event: loadClassMetadata }
不要忘记从 DependencyInjection 中注入新参数kdrmklabs_ticket.model.user.primary_key
,例如:
// file: Kdrmklabs\Bundle\TicketBundle\DependencyInjection\Configuration.php
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('kdrmklabs_ticket');
$rootNode->children()
->scalarNode('user_class')->isRequired()->cannotBeEmpty()->end()
->scalarNode('user_primay_key')->isRequired()->cannotBeEmpty()->end()
->end();
return $treeBuilder;
}
}
// file: Kdrmklabs\Bundle\TicketBundle\DependencyInjection\KdrmklabsTicketExtension.php
class KdrmklabsTicketExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
$container->setParameter('kdrmklabs_ticket.model.user.class', $config['user_class']);
$container->setParameter('kdrmklabs_ticket.model.user.primary_key', $config['user_primay_key']);
}
}
第3。最后,从项目config.yml文件中注入参数'user_primay_key'。
# file: app\config\config.yml
kdrmklabs_ticket:
user_class: AppBundle\Entity\User
user_primay_key: id
就是这样。每当您更新学说方案时,Doctrine都会自动创建Ticket实体与项目config.yml(app / config / config.yml)中指定的外部User实体之间的关系