【问题标题】:Relationships between entities using Resolve Target Entity in Symfony2 when the referencedColumnName is different to "id"当 referencedColumnName 与“id”不同时,使用 Symfony2 中的 Resolve Target Entity 的实体之间的关系
【发布时间】:2016-05-21 22:09:51
【问题描述】:

我正在处理我的第一个可分发包,我对如何在我的包中重用“现有用户实体”有一些疑问。我的捆绑包的目的是将票证实体与用户实体相关联。

当 TargetEntity 的“referencedColumnName”与“id”不同时,我正在尝试将不同包之间的实体关联起来。

我正在关注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”,我的bundle和这个实体之间的关系正常。

// 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") 中指定外键的值,这会很好用,但是从我的包中,我无法通过我的实际配置知道外键的名称。

  1. 有没有什么方法可以在两个实体之间建立关系,而不管这些主键的名称是什么?

  2. 也许我可以请求用户在 app/config/config.yml 中指定他“用户实体”的主键的名称,并以某种方式指定该值以创建正确的关系我的包的实体和安装我的包的用户的实体。但是,我该怎么做呢?

谢谢。 问候

非常感谢!

更多细节:

我的可分发包的存储库是:https://github.com/KdrMkLabs/TicketBundle

【问题讨论】:

    标签: symfony doctrine-orm


    【解决方案1】:

    在分析这个问题几个小时后,我得出结论,在彼此未知的实体之间创建关系的正确方法是使用原则事件监听器。我将在下面解释如何做到这一点。


    您可以使用 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 的类属性名称的值。上面的映射数组类似于使用注解做教义 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 实体之间的关系

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-30
      • 2012-07-23
      • 2014-12-30
      • 1970-01-01
      • 1970-01-01
      • 2013-04-07
      • 1970-01-01
      相关资源
      最近更新 更多