如何在条令中将关联限制为另一个关联的子集


How to restrict associations to a subset of another association in Doctrine?

我在Doctrine中遇到了同一对象的多个映射的问题。该应用程序是基于Symfony btw构建的,因此注释略有不同。

基本上我有以下对象:

  • 组织:掌握组织属性的保护伞
  • 部门:组织内的一个部门
  • User:通用用户对象

这些对象的关系如下:

  1. 一个组织总是只有一个所有者,即User
  2. 一个组织有很多成员,他们都是User
  3. 一个部门由许多User组成,但只允许Department所属的Organisation的成员

我有点拘泥于第三个要求。。。首先,这就是我的对象或多或少看起来像atm的方式:

/**
 * @ORM'Entity
 * @ORM'Table(name="organisations")
 */
class Organisation
{
    // ...
    /**
     * @ORM'OneToOne(targetEntity="User", inversedBy="organisation")
     */
    private $owner;
    /**
     * ORM'OneToMany(targetEntity="User", mappedBy="organisation")
     */
    private $members
}
/**
 * @ORM'Entity
 * @ORM'Table(name="departments")
 */
class Department
{
    // ...
    /**
     * @ORM'ManyToMany(targetEntity="User", mappedBy="departments")
     */
    private $members
    /**
     * @ORM'ManyToOne(targetEntity="Organisation", inversedBy="departments")
     */
    private $organisation;
}
/**
 * @ORM'Entity
 * @ORM'Table(name="users")
 */
class User
{
    // ...
    /**
     * The organisation this user "owns"
     *
     * @ORM'OneToOne(targetEntity="Organisation", mappedBy="owner", nullable=true)
     */
    private $owning_organisation;
    /**
     * @ORM'ManyToOne(targetEntity="Organisation", inversedBy="members")
     */
    private $organisations;
    /**
     * @ORM'ManyToMany(targetEntity="Department", inversedBy="members")
     * @ORM'JoinTable(name="users_departments")
     */
    private $departments;
}

现在,这基本上起作用了,如果并且仅在控制器中,我进行所有检查(类似于(if( $user->isPartOfOrganisation($department-getOrganisation()) { $department->addMember($user); })。

但是,有没有办法在设计层面上限制可能的对象关联?因此,基本上我想要的是,如果一个用户被添加到一个部门,那么只有当该用户已经是该部门所在组织的一部分时,才有可能。或者我应该在Department对象的addMember()方法中进行检查?我可以想象(但找不到)存在某种子集限制(Department::members is subset of Organisation::members)。

为了尽可能低级别(最接近数据库)实现此检查,我认为唯一的解决方案是一个Doctrine Event Listener,它在预持久化事件中检查您的自定义约束。阅读更多关于条令事件系统的信息。

顺便说一句,我认为你可以用一种更简单的方式来管理这种情况:我建议你将业务逻辑封装到一个服务中(这样你就可以更简单地重用它),并在自定义验证器中将其用于管理这种情况的表单中。

如果你需要更多的技巧来开发这种解决方案,或者你发现了更有用的东西,请告诉我。

希望这能帮助