在Doctrine 2.6中覆盖特征属性的关联映射

先决条件:

  • PHP 7.1.8
  • Symfony 3.3.9
  • Doctrine 2.6.x-dev
  • 我想知道是否可以重写属性关联映射的inversedBy属性,该属性取自特征。

    我用作具体用户实体占位符的接口:

    ReusableBundle ModelEntrantInterface.php

    interface EntrantInterface
    {
        public function getEmail();
    
        public function getFirstName();
    
        public function getLastName();
    }
    
  • 以下架构工作得很好(需要创建实现EntrantInterface User实体以及派生自AppBundle这些抽象类的所有其他实体):
  • ReusableBundle 实体 Entry.php

    /**
     * @ORMMappedSuperclass
     */
    abstract class Entry
    {
        /**
         * @var EntrantInterface
         *
         * @ORMManyToOne(targetEntity="ReusableBundleModelEntrantInterface", inversedBy="entries")
         * @ORMJoinColumn(name="user_id")
         */
        protected $user;
    
        // getters/setters...
    }
    

    ReusableBundle 实体 Timestamp.php

    /**
     * @ORMMappedSuperclass
     */
    abstract class Timestamp
    {
        /**
         * @var EntrantInterface
         *
         * @ORMManyToOne(targetEntity="ReusableBundleModelEntrantInterface", inversedBy="timestamps")
         * @ORMJoinColumn(name="user_id")
         */
        protected $user;
    
        // getters/setters...
    }
    

    还有更多使用EntranInterface具有相似结构的实体

  • 这就是我想要实现的 - UserAwareTrait可以跨几个实体重用:
  • ReusableBundle 实体特征 UserAwareTrait.php

    trait UserAwareTrait
    {
        /**
         * @var EntrantInterface
         *
         * @ORMManyToOne(targetEntity="ReusableBundleModelEntrantInterface")
         * @ORMJoinColumn(name="user_id")
         */
        protected $user;
    
        // getter/setter...
    }
    

    在Doctrine 2.6中,如果我会使用超类,并希望覆盖它的属性,我会这样做:

    /**
     * @ORMMappedSuperclass
     * @ORMAssociationOverrides({
     *     @ORMAssociationOverride({name="property", inversedBy="entities"})
     * })
     */
    abstract class Entity extends SuperEntity
    {
        // code...
    }
    

    但是如果我希望该实体使用UserAwareTrait并覆盖属性的关联映射......

    /**
     * @ORMMappedSuperclass
     * @ORMAssociationOverrides({
     *     @ORMAssociationOverride({name="user", inversedBy="entries"})
     * })
     */
    abstract class Entry
    {
        use UserAwareTrait;
        // code...
    }
    

    ...并运行php bin/console doctrine:schema:validate我在控制台中看到这个错误:

    [学说 ORM 映射 MappingException]
    对于'ReusableBundle Entity Entry'类,名为'user'的字段覆盖无效。

    有没有一种解决方法可以实现预期的效果?

  • 使用trait来存储共享属性

  • 覆盖使用该特征的类中的assotiation映射或(可能)属性映射


  • TL; DR您应该将访问修改从protected更改为private 。 不要忘记,你将无法直接操作子类中的私有属性,并需要一个getter。

    这个异常是由于AnnotationDriver的错误(我相信,或者是一个怪癖)而出现的。

    foreach ($class->getProperties() as $property) {
        if ($metadata->isMappedSuperclass && ! $property->isPrivate()
            ||
            ...) {
            continue;
        }
    

    它跳过MappedSuperclass所有非私有属性,让它们在子类解析中MappedSuperclass元数据。 但是当涉及重写驱动程序试图在MappedSuperclass级别执行它时,它不记得该属性被跳过,无法在元数据中找到它并引发异常。

    我在这个问题上做了详细的解释。 你也可以在那里找到单元测试的链接来突出显示案例。


    你必须在你自己的代码中试试看,但它可能是可能的。

    作为一个实验,我重写了一个类的特征,然后使用class_uses()检查特征http://php.net/manual/en/function.class-uses.php

    <?php
    
    trait CanWhatever
    {
        public function doStuff()
        {
            return 'result!';
        }
    }
    
    class X
    {
        use CanWhatever;
    
        public function doStuff()
        {
            return 'overridden!';
        }
    }
    
    $x = new X();
    echo $x->doStuff();
    echo "n$x has ";
    echo (class_uses($x, 'CanWhatever')) ? 'the trait' : 'no trait';
    

    这输出:

    overridden! 
    $x has the trait
    

    你可以在这里看到https://3v4l.org/Vin2H

    然而,Doctrine Annotations仍然可能会从适当的特性中挑选出DocBlock,而不是重写的方法,这就是为什么我不能给你一个确定的答案。 你只需要尝试一下,看看!


    我有一个类似的问题,并通过覆盖它自己的属性来解决它:

    use UserAwareTrait;
    /**
     * @var EntrantInterface
     * @ORMManyToOne(targetEntity="ReusableBundleModelEntrantInterface"inversedBy="entries")
     */
    protected $user;
    
    链接地址: http://www.djcxy.com/p/69387.html

    上一篇: Override association mapping of a trait property in Doctrine 2.6

    下一篇: FOSUserBundle form extension