Symfony 4中用Doctrine注解实现多表关联获取用户权限
用Symfony/Doctrine注解实现用户权限获取
咱们先理清楚四张表的关联逻辑:mo_user和mo_role通过中间表mo_user_role是多对多关系(一个用户可以拥有多个角色),mo_role和mo_permission通过中间表mo_role_permission也是多对多关系(一个角色可以关联多个权限)。要实现获取指定用户的权限数组,核心是通过Doctrine注解正确配置这些关联,然后在MoUser实体中封装获取权限的方法。
第一步:配置实体类的多对多关联注解
1. MoUser 实体关联 MoRole
在MoUser类中,添加与MoRole的多对多关联,指定中间表和关联字段:
// src/Entity/MoUser.php namespace App\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: MoUserRepository::class)] #[ORM\Table(name: 'mo_user')] class MoUser { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: 'integer')] private ?int $id = null; // 其他业务字段... /** * 多对多关联MoRole,对应中间表mo_user_role */ #[ORM\ManyToMany(targetEntity: MoRole::class, inversedBy: 'users')] #[ORM\JoinTable(name: 'mo_user_role')] #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id')] #[ORM\InverseJoinColumn(name: 'role_id', referencedColumnName: 'id')] private Collection $roles; public function __construct() { $this->roles = new ArrayCollection(); } // 生成roles的基础操作方法 public function getRoles(): Collection { return $this->roles; } }
2. MoRole 实体关联 MoPermission
接着在MoRole类中,添加与MoPermission的多对多关联:
// src/Entity/MoRole.php namespace App\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: MoRoleRepository::class)] #[ORM\Table(name: 'mo_role')] class MoRole { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: 'integer')] private ?int $id = null; // 其他业务字段... /** * 反向关联MoUser(可选,若需要从角色维度查询用户则保留) */ #[ORM\ManyToMany(targetEntity: MoUser::class, mappedBy: 'roles')] private Collection $users; /** * 多对多关联MoPermission,对应中间表mo_role_permission */ #[ORM\ManyToMany(targetEntity: MoPermission::class, inversedBy: 'roles')] #[ORM\JoinTable(name: 'mo_role_permission')] #[ORM\JoinColumn(name: 'role_id', referencedColumnName: 'id')] #[ORM\InverseJoinColumn(name: 'permission_id', referencedColumnName: 'id')] private Collection $permissions; public function __construct() { $this->users = new ArrayCollection(); $this->permissions = new ArrayCollection(); } // 生成permissions的基础操作方法 public function getPermissions(): Collection { return $this->permissions; } }
3. MoPermission 实体
确保MoPermission中有存储权限标识的字段(比如code,对应你需要的view_summary_report这类值):
// src/Entity/MoPermission.php namespace App\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: MoPermissionRepository::class)] #[ORM\Table(name: 'mo_permission')] class MoPermission { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: 'integer')] private ?int $id = null; /** * 权限唯一标识,如'view_summary_report' */ #[ORM\Column(type: 'string', length: 255, unique: true)] private ?string $code = null; // 其他业务字段(如权限名称、描述等)... /** * 反向关联MoRole(可选) */ #[ORM\ManyToMany(targetEntity: MoRole::class, mappedBy: 'permissions')] private Collection $roles; public function __construct() { $this->roles = new ArrayCollection(); } // 生成code的getter方法 public function getCode(): ?string { return $this->code; } }
第二步:在MoUser中实现getPermissions()方法
现在可以在MoUser类中添加一个方法,遍历所有关联角色的权限,提取code并去重(避免不同角色重复权限):
// 在MoUser类中新增以下方法 public function getPermissions(): array { $permissionCodes = []; foreach ($this->getRoles() as $role) { foreach ($role->getPermissions() as $permission) { $code = $permission->getCode(); if (!in_array($code, $permissionCodes)) { $permissionCodes[] = $code; } } } return $permissionCodes; }
第三步:查询用户并获取权限
在业务代码(比如Controller或Service)中,你可以这样获取ID为9144的用户权限:
use App\Entity\MoUser; use Doctrine\ORM\EntityManagerInterface; // 注入EntityManagerInterface public function getUserPermissions(EntityManagerInterface $em) { $user = $em->getRepository(MoUser::class)->find(9144); if (!$user) { // 处理用户不存在的场景 return []; } // 这里就能得到你预期的权限数组 $userPermissions = $user->getPermissions(); }
性能优化提示
如果担心懒加载导致的N+1查询问题(比如加载用户后,每个角色都要单独查询权限),可以在MoUserRepository中添加自定义查询方法,一次性加载关联数据:
// src/Repository/MoUserRepository.php namespace App\Repository; use App\Entity\MoUser; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; class MoUserRepository extends ServiceEntityRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, MoUser::class); } /** * 加载用户并一次性加载关联的角色和权限 */ public function findUserWithPermissions(int $userId): ?MoUser { return $this->createQueryBuilder('u') ->leftJoin('u.roles', 'r') ->leftJoin('r.permissions', 'p') ->addSelect('r', 'p') // 主动选择关联数据,避免懒加载 ->where('u.id = :id') ->setParameter('id', $userId) ->getQuery() ->getOneOrNullResult(); } }
使用这个方法查询:
$user = $em->getRepository(MoUser::class)->findUserWithPermissions(9144); $userPermissions = $user->getPermissions();
这样就可以避免多次查询数据库,提升整体性能。
内容的提问来源于stack exchange,提问作者ShanjayG
相关产品推荐
相关产品推荐

