Symfony 4 Doctrine 多个 table 加入一个 属性

Symfony 4 Doctrine multiple table joins in one property

symfony 和 Doctrine 的新手。我的数据库中有以下 tables。

mo_user

id   |    email      |   password
__________________________________
9144 | summer@h.com  |   !password! 

mo_user_角色

user_id| role_id
_________________
9144   | 5

mo_permission

id | namespace            | name | description
______________________________________________
1  | admin                | -    |   -
2  | users                | -    |   -
3  | view_summary_report  | -    |   -
4  | view_user_statement  | -    |   -

mo_role_permission

role_id  | permission_id
________________________
    5    | 3
    5    | 4    

我正在尝试 return 当前用户的权限数组,在本例中,id = 9144 的用户应该是 array('view_summary_report','view_user_statement')

我已将所有 table 映射到它们对应的实体 class。在对应于 mo_user table 的 MoUser.php 实体 class 中,我有一个 应该 return 数组的权限方法,但我从注释中加入失败,

我的 getPermissions() 方法 MoUser.php

/**
 * @var Collection|MoPermission[]
 * @ORM\ManyToMany(targetEntity="App\Entity\MoPermission")
 * @ORM\JoinTable(
 *     name="mo_user_role",
 *     joinColumns={@ORM\JoinColumn(name="user_id",referencedColumnName="id")},
 *     inverseJoinColumns={@ORM\JoinColumn(name="role_id",referencedColumnName="id")}
 * )
 */
private $permissions;

 public function getPermissions()
{
    $currentPermissions = array();
    foreach ($this->permissions->toArray() as $index => $permission) {
        $currentPermissions[] = $permission->getNamespace();
    }

    //Return default role if Roles are not assigned to this user.
    if(count($currentPermissions)>0) {
        return $currentPermissions;
    } else {
        return array('DEFAULT_PERMISSION');
    }
}

所以我想出了原始 sql 来实现下面我想要的,但我想知道实现以下原始 SQL 的 Symfony/Doctrine 注释方法。

 SELECT t0.id AS id_1, t0.namespace AS namespace_2, t0.name AS name_3, t0.description AS description_4 

 FROM mo_permission t0 

 LEFT JOIN mo_role_permission ON t0.id = mo_role_permission.permission_id 

 LEFT JOIN mo_user_role ON  mo_role_permission.role_id = mo_user_role.role_id

 WHERE mo_user_role.user_id = 9144;

我认为没有合适的方法可以直接通过 属性 注释和您当前的设置来实现您想要做的事情。

您可以使用以下解决方案之一实现您想要的效果:

  • 不需要 mo_user_rolemo_role_permission 之一,因为其中 none 有附加字段。您应该只拥有一个由 MoUserMoPermission 之间的 ManyToMany 关系生成的 mo_user_permission table,这将授予您直接访问 MoPermission 的权限MoUsergetPermissions()

  • 另一种方法是创建一个具有 GetPermissionsFromUser(MoUser $moUser) 方法(例如)的服务,从实体的存储库中调用适当的查询,您可以在需要时调用该查询。

  • 您仍然可以使用当前设置在 getPermissions() 方法中实现您想要的结果,但是您必须遍历每个关系的项目以手动构建新的结果数组。

例如最后一点:

public function getPermissions() {
    $permissions = [];
    foreach($this->roles as $role) {
        foreach($role->getPermissions() as $permission) {
            permissions[] = $permission->getNamespace();
        }
    }
    return $permissions;
}

这假设您有一个 MoRole 实体,这对您当前的设置很有意义,但您没有提到它。否则,仍然可以应用相同的逻辑,这只是命名问题。

我很确定您可以使用 Doctrine(和 QueryBuilder)来执行该查询,例如...

use Doctrine\ORM\EntityRepository

class PermissionRepository extends EntityRepository
{
    //....

    /**
     * @param UserInterface $user
     * @return array|Permission[]
     */
    public function getPermissionsForUser(UserInterface $user)
    {
        $queryBuilder = $this->createQueryBuilder('permission');

        /**
         * permissions will be in a multi-dimensional array
         * with a single key per array of 'namespace'
         */
        $permissions = $queryBuilder
            ->select('permission.namespace')
            ->join('permission.role', 'role')
            ->join('role.user', 'user')
            ->where($queryBuilder->expr()->eq('user', ':user'))
            ->setParameter('user', $user)
            ->getQuery()
            ->getArrayResult();

        if (count($permissions) > 0) {
            /**
             * If there are any permissions found just return
             * the 'namespace' property from each "sub-array"
             */
            return array_column($permissions, 'namespace');
        }

        return ['DEFAULT_PERMISSION'];
    }

    //...
}

然后你会这样称呼它..

$permissions = $repository->getPermissionsForUser($user);