【问题标题】:Doctrine ORM: use interface as relation for different entities?Doctrine ORM:使用接口作为不同实体的关系?
【发布时间】:2017-07-27 17:38:48
【问题描述】:

如何在多对多关系中使用接口?

在我的应用中有 3 个实体:用户、汽车和司机。用户可以将汽车和司机添加为收藏夹。所以我做了这个结构(简化):

喜欢功能的用户:

namespace Acme\AppBundle\Entities;

use Acme\AppBundle\Interfaces\HasFavorites;

/** @ORM\Entity */
class User implements HasFavorites
{
    /** @ORM\ManyToMany(targetEntity="Acme\AppBundle\Entities\Favorite") */
    protected $favorites;

    public function getFavorites() : ArrayCollection
    {
        return $this->favorites;
    }

    public function addFavorite(Favorite $favorite)
    {
        $this->favorites->add($favorite);
    }
}

最喜欢的对象模型:

namespace Acme\AppBundle\Entities;

use Acme\AppBundle\Interfaces\Favoritable;

/** @ORM\Entity */
class Favorite
{
    /** @ORM\ManyToOne(targetEntity="Acme\AppBundle\Entities\User") */
    private $owner;

    /** @ORM\ManyToOne(targetEntity="Acme\AppBundle\Interfaces\Favoritable") */
    private $target;

    public function __construct(User $owner, Favoritable $target)
    {
        $this->owner  = $owner;
        $this->target = $target;
    }

    public function getOwner() : User
    {
        return $this->owner;
    }

    public function getTarget() : Favoritable
    {
        return $this->target;
    }
}

汽车和司机 - 可以添加到收藏夹的实体:

namespace Acme\AppBundle\Entities;

use Acme\AppBundle\Interfaces\Favoritable;

/** @ORM\Entity */
class Car implements Favoritable { /* ... */ }

/** @ORM\Entity */
class Driver implements Favoritable { /* ... */ }

但是当我使用命令./bin/console doctrine:schema:update --force 更新我的架构时,我会得到错误

[Doctrine\Common\Persistence\Mapping\MappingException]
Class 'Acme\AppBundle\Interfaces\Favoritable' does not exist

我测试中的这段代码也可以正常工作(如果我不使用数据库),所以命名空间和文件路径是正确的:

$user = $this->getMockUser();
$car  = $this->getMockCar();
$fav  = new Favorite($user, $car);
$user->addFavorite($fav);
static::assertCount(1, $user->getFavorites());
static::assertEquals($user, $fav->getUser());

如何做这种关系?我在搜索中发现的只是汽车/司机在逻辑上基本相同的情况。

我在数据库中需要的只是这样的(想要的),但它并不那么重要:

+ ––––––––––––– +   + ––––––––––––– +   + –––––––––––––––––––––––––––––––––– +
|     users     |   |      cars     |   |            favorites               |
+ –– + –––––––– +   + –– + –––––––– +   + –––––––– + ––––––––– + ––––––––––– +
| id |   name   |   | id |   name   |   | owner_id | target_id | target_type |
+ –– + –––––––– +   + –– + –––––––– +   + –––––––– + ––––––––– + ––––––––––– +
| 42 | John Doe |   | 17 | BMW      |   |       42 |        17 | car         |
+ –– + –––––––– +   + –– + –––––––– +   + –––––––– + ––––––––– + ––––––––––– +

【问题讨论】:

    标签: php doctrine-orm doctrine symfony


    【解决方案1】:

    不确定您是如何生成架构的,但我想该接口不在范围内。

    添加您用来生成的命令,以便重现。

    更新 除非 Favoritable 是数据库表,否则这将不起作用
    @ORM\ManyToOne(targetEntity="Acme\AppBundle\Interfaces\Favoritable")

    我建议在 User 中映射 Car 和 Driver 实体,然后实现 getFavorites 从中返回 Cars 和/或 Drivers。

    这应该会让你继续前进

    /** @ORM\ManyToOne(targetEntity="Acme\AppBundle\Entities\Car" mappedBy="favorites" ????) */ private $favoriteCars;

    http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html

    【讨论】:

    • 我用有关命令和简单测试的附加信息更新了我的问题(不涉及数据库或实体管理器)。
    • 猜测 Doctrine(也许?)想要真正的类或抽象类用作 targetEntity 但得到了接口。我不能从一个抽象类继承 Car 和 Driver,因为它们是非常不同的实体。
    【解决方案2】:

    看起来您在之后的注释中缺少 JoinColumns 语句:

    ** @ORM\ManyToOne(targetEntity="Acme\AppBundle\Entities\User") */

     * @ORM\JoinColumns({
     *  @ORM\JoinColumn(name="owner_id", referencedColumnName="id")
     * })
    

    【讨论】:

    • 谢谢。但是没有任何改变——我认为这是因为 Doctrine 不支持与接口的关系。这个问题给了我一个线索,它根本不起作用)-:github.com/doctrine/DoctrineBundle/issues/328 但现在我不明白如何重构我的代码以实现“收藏夹功能”。
    【解决方案3】:

    使用 Doctrine 的 ResolveTargetEntityListener,您可以按照您的方式注释与目标interface 的关系,然后将其解析为特定实体。

    Doctrine 文档中的更多内容:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/resolve-target-entity-listener.html

    或者在这里,如果你使用 Symfony 框架:http://symfony.com/doc/current/doctrine/resolve_target_entity.html

    但是,您无法通过此实现您想要的 - 一个接口被解析为使用“鉴别器”实现此接口的多个实体。这是不可能的AFAIK。您只能将一个接口解析为一个实体,以便在一个表中使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多