首页 文章

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

提问于
浏览
10

先决条件:

  • 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();
}
  • 以下架构工作正常(需要创建实现 EntrantInterfaceUser 实体以及_1773123中从这些抽象类派生的所有其他实体):

ReusableBundle\Entity\Entry.php

/**
 * @ORM\MappedSuperclass
 */
abstract class Entry
{
    /**
     * @var EntrantInterface
     *
     * @ORM\ManyToOne(targetEntity="ReusableBundle\Model\EntrantInterface", inversedBy="entries")
     * @ORM\JoinColumn(name="user_id")
     */
    protected $user;

    // getters/setters...
}

ReusableBundle\Entity\Timestamp.php

/**
 * @ORM\MappedSuperclass
 */
abstract class Timestamp
{
    /**
     * @var EntrantInterface
     *
     * @ORM\ManyToOne(targetEntity="ReusableBundle\Model\EntrantInterface", inversedBy="timestamps")
     * @ORM\JoinColumn(name="user_id")
     */
    protected $user;

    // getters/setters...
}

并结合使用 EntranInterface 类似结构的更多实体

  • 这就是我想要实现的目标 - UserAwareTrait 可以跨多个实体重复使用:

ReusableBundle\Entity\Traits\UserAwareTrait.php

trait UserAwareTrait
{
    /**
     * @var EntrantInterface
     *
     * @ORM\ManyToOne(targetEntity="ReusableBundle\Model\EntrantInterface")
     * @ORM\JoinColumn(name="user_id")
     */
    protected $user;

    // getter/setter...
}

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

/**
 * @ORM\MappedSuperclass
 * @ORM\AssociationOverrides({
 *     @ORM\AssociationOverride({name="property", inversedBy="entities"})
 * })
 */
abstract class Entity extends SuperEntity
{
    // code...
}

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

/**
 * @ORM\MappedSuperclass
 * @ORM\AssociationOverrides({
 *     @ORM\AssociationOverride({name="user", inversedBy="entries"})
 * })
 */
abstract class Entry
{
    use UserAwareTrait;
    // code...
}

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

[Doctrine \ ORM \ Mapping \ MappingException]类'ReusableBundle \ Entity \ Entry'的名为'user'的字段覆盖无效 .

有没有可以遵循的解决方法来达到预期的效果?

  • 使用特征存储共享属性

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

3 回答

  • 1

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

    由于 AnnotationDriver 中的错误(我相信或行为的怪癖)而出现异常 .

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

    它会跳过 MappedSuperclass 的所有非私有属性,让它们在子类解析上组合元数据 . 但是当涉及到覆盖驱动程序尝试在 MappedSuperclass 级别执行时,它不记得该属性被跳过,无法在元数据中找到它并引发异常 .

    我在the issue做了详细解释 . 您还可以找到突出显示案例的单元测试的链接 .

  • 0

    您必须在自己的代码中尝试这一点才能看到,但它可以实现.177144可能 .

    作为一个实验,我重写了一个类中的特征,然后使用 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,这就是为什么我不能给你一个明确的答案 . 你只需要尝试一下,看看!

  • 0

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

    use UserAwareTrait;
    /**
     * @var EntrantInterface
     * @ORM\ManyToOne(targetEntity="ReusableBundle\Model\EntrantInterface"inversedBy="entries")
     */
    protected $user;
    

相关问题