Doctrine ORM:如何在不同实体之间使用接口作为关系?

4

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

我的应用程序有3个实体:User(用户)、Car(汽车)和Driver(司机)。用户可以将汽车和司机添加为收藏夹。所以我创建了这个结构(简化版):

用户,具有收藏功能:

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;
    }
}

Car and Driver - 可添加到收藏夹的实体:

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         |
+ –– + –––––––– +   + –– + –––––––– +   + –––––––– + ––––––––– + ––––––––––– +
3个回答

3
使用Doctrine的ResolveTargetEntityListener,你可以像以前一样注释一个关系并将其指向所需的接口,然后将其解析为特定的实体。
更多关于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 然而,使用“鉴别器”无法做到想要的效果,即将一个接口解析成实现该接口的多个实体。据我所知,这是不可能的。您只能将一个接口解析为一个实体,并在一个表内使用。

0

不确定您是如何生成模式的,但我想象接口不在范围内。

请添加您正在使用的命令以便进行复制。

更新 除非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


我更新了我的问题,并提供了有关命令和简单测试的附加信息(没有涉及数据库或实体管理器)。 - trogwar
猜测Doctrine(也许?)想要真正的类或抽象类作为targetEntity,但得到了接口。我无法将Car和Driver从一个抽象类继承,因为它们是非常不同的实体。 - trogwar

0

看起来在此注释之后缺少JoinColumns语句:

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

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

谢谢。但是什么都没有改变 - 我认为这是因为Doctrine不支持与接口的关系。 这个问题给了我一个线索,它根本不起作用)-:https://github.com/doctrine/DoctrineBundle/issues/328 但现在我不明白如何重构我的代码来实现“收藏夹功能”。 - trogwar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接