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

时间:2017-09-21 23:54:01

标签: php symfony doctrine-orm doctrine symfony-3.3

先决条件:

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

    的类似结构的更多实体
    1. 这就是我想要实现的目标 - UserAwareTrait可以在多个实体之间重复使用:
    2. ReusableBundle \实体\性状\ 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我在控制台中看到此错误:

        

      [学说\ ORM \映射\ MappingException]
        名为' user'的字段覆盖无效。 for class' ReusableBundle \ Entity \ Entry'。

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

      1. 使用特征存储共享属性

      2. 在使用该特征的类中覆盖关联映射或(可能)属性映射

3 个答案:

答案 0 :(得分:2)

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

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

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

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

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

答案 1 :(得分:0)

您必须在自己的代码中尝试使用此功能才能看到,但可能可能。

作为一项实验,我在课程中覆盖了特征,然后使用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,这就是为什么我无法给出明确的答案。你只需要试一试,看看!

答案 2 :(得分:0)

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

<button md-raised-button type="submit" [disabled]="!myForm.get('emailPass').valid">Siguiente</button>