Symfony2 - 在具有不同关系的Bundle之间共享实体

时间:2015-06-04 17:46:09

标签: symfony doctrine-orm

如何在具有不同关系的多个捆绑包之间共享实体?

例如,ZooAnimalBundle和FarmAnimalBundle都需要用户实体。第三个Bundle AccountUserBundle具有用户实体。

在Zoo和Farm AnimalBundles中,我创建了一个用户实体,如下所示:

Select * FROM [Backbone_ASPIDER].[dbo].[vw_CFGsvr_Con]
WHERE [Backbone_ASPIDER].[dbo].[vw_CFGsvr_Con].[NodeName] = 'Database' AND [Backbone_ASPIDER].[dbo].[vw_CFGsvr_Con].[EnvironmentName]  IS NOT NULL
ORDER BY [Backbone_ASPIDER].[dbo].[vw_CFGsvr_Con].[EnvironmentName] asc 

然后我在动物园里有一个医院实体:

use Account\UserBundle\Entity\User as BaseUser;


class User extends BaseUser 
{
}

Farm中的Room实体:

class Hospital {
/**
 * @ORM\ManyToMany(targetEntity="Zoo\AnaimalBundle\Entity\User")
 * @ORM\JoinTable(name="users_zoo_animals")
 */
protected $users; 

到目前为止一切正常,我可以调用Zoo.Room-> getUsers()或Farm.Hospital-> getUsers()

但问题是我不确定如何在各自的用户实体中设置反向关系。

例如,如果我更新FarmAnimal用户实体并运行doctrine:generate:entities

class Room {
/**
 * @ORM\ManyToMany(targetEntity="Farm\AnaimalBundle\Entity\User")
 * @ORM\JoinTable(name="users_farm_animals")
 */
protected $users; 

它将从BaseUser复制受保护的$属性并创建所有不是我想要的set和get方法。建立这些关系的正确方法是什么?

更新

如果您没有设置反向关系,您将如何选择hospital.id = 1

的所有用户?
/**
 * @ORM\Entity
 */
class User extends BaseUser
{
    /**
     * @ORM\ManyToMany(targetEntity="Room", mappedBy="users", cascade={"persist"})
     */
    protected $rooms;
}

这给出了错误:

    $qb = $this->getEntityManager()->createQueryBuilder()
        ->select(
            'u'
        )
        ->from('Account\UserBundle\Entity\User','u')
        ->leftJoin('u.hospitals', 'h')
        ->andWhere('h.id = :hospital_id')
            ->setParameter('hospital_id',$hospital_id);

我知道我可以从医院中选择并加入用户,因为该关系确实存在,但我需要选择用户,因为我使用它们与Doctrine \ ORM \ Tools \ Pagination \ Paginator

查询将是

   Class Account\UserBundle\Entity\User has no association named hospitals 

问题是Paginator只看到一个结果医院,因为用户已附加到它。

2 个答案:

答案 0 :(得分:3)

您可以定义abstract entity dependencies并使用其他捆绑包实现它们。

首先,每个捆绑包取决于用户实体应该定义用户界面。例如:

namespace Foo\BarBundle\Entity;

interface UserInterface
{
    public function getId();

    public function getEmail();

    // other getters
}

然后,在每个实体中,取决于用户,定义关系,例如:

namespace Foo\BarBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 */
class Something
{
    /**
     * @ORM\ManyToOne(targetEntity="UserInterface")
     * @Assert\NotNull
     */
    protected $User;

    // add other fields as required
}

现在您需要将User实体注册为UserInterfaces的实现:

namespace Foo\UserBundle\Entity;

use Foo\BarBundle\Entity\UserInterface as BarUserInterface;
use Foo\FoobarBundle\Entity\UserInterface as FoobarUserInterface;

/**
 * @ORM\Entity
 */
class User implements BarUserInterface, FoobarUserInterface
{
    // implement the demanded methods
}

然后将以下内容添加到app/config/config.yml

doctrine:
    orm:
        resolve_target_entities:
            Foo\BarBundle\Entity\UserInterface: Foo\UserBundle\Entity\User
            Foo\FooarBundle\Entity\UserInterface: Foo\UserBundle\Entity\User

(抬头:通常会有一个doctrine.orm节点,你必须扩展它。)

这不是一个完美的解决方案,因为你无法真正说明用户实体应该拥有哪些字段。另一方面,它是严格的OOP,因为您不必了解User实现的内部 - 您只需要它来返回正确的值。

答案 1 :(得分:0)

创建帐户的多个定义是错误的方法,除非你想创建3个单独的用户表(即使那样最好不要这样做)。

您真的希望其他实体映射到帐户包中的用户实体。

即,

class Hospital {
   /**
    * @ORM\ManyToMany(targetEntity="Zoo\AccountBundle\Entity\User")
    */
   protected $users; 

现在,无需创建反向关系。事实上,这是一种不好的做法,因为你有双向依赖。用户不了解医院,但医院知道它的用户。现在,任何bundle都可以映射到用户实体并重用它。