使用苗条的框架和理论来查询多对多关系

时间:2019-01-25 14:34:01

标签: doctrine-orm doctrine slim

我正在将Slim Framework与Doctrine结合使用。我有三个桌子

id | username | password | name
--------------------------------
1  | Lorel    | ******** | Lorel

id | permission  | description
-------------------------------
2  | READ_ACCESS | Lorel Ipsum


id | user_id | permission_id
-----------------------------
X  | 1       | 2

无论如何,假设用户“ 1”是否具有权限“ 2”,是否有使用我可以通过其找到的理论。

1 个答案:

答案 0 :(得分:0)

我假设您正在寻求授权。我在Zend Framework 3中使用Doctrine 2进行了设置。两者之间的关系相同,只是不确定如何将其转换为Slim Framework。但是这里什么都没有;-)

用户:实体与角色有关:

/**
 * @var Collection|ArrayCollection|Role[]
 * @ORM\ManyToMany(targetEntity="User\Entity\Role", inversedBy="users", fetch="LAZY")
 * @ORM\JoinTable(
 *     name="user_user_roles",
 *     joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
 *     inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")}
 * )
 *
 */
protected $roles;

角色:实体具有路由,且与用户

相反
/**
 * @var Collection|ArrayCollection|Route[]
 * @ORM\ManyToMany(targetEntity="User\Entity\Route", inversedBy="roles", fetch="EAGER")
 * @ORM\JoinTable(
 *     name="user_role_routes",
 *     joinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")},
 *     inverseJoinColumns={@ORM\JoinColumn(name="route_id", referencedColumnName="id")}
 * )
 */
protected $routes;

/**
 * @var Collection|ArrayCollection|User[]
 * @ORM\ManyToMany(targetEntity="User\Entity\User", mappedBy="roles", fetch="LAZY")
 */
protected $users;

路线实体与角色

相反
/**
 * @var Collection|ArrayCollection|Role[]
 * @ORM\ManyToMany(targetEntity="User\Entity\Role", mappedBy="routes", fetch="LAZY")
 */
protected $roles;

关于它与 2 关系有关的通知:

  • 用户<->角色
  • 角色<->路线

确保初始化__construct中的每个Collection,如下所示:

// Initialize only those within the Entity
public function __construct()
{ 
    $this->users = new ArrayCollection();
}

生成您的 getter 方法(不需要设置!)。创建Adder / Remover方法而不是setter,就像这样(在 Route 实体中):

/**
 * @param Collection|ArrayCollection|Role[] $roles
 *
 * @return Route
 */
public function addRoles(Collection $roles) : Route
{
    foreach ($roles as $role) {
        if ( ! $this->getRoles()->contains($role)) {
            $this->getRoles()->add($role);
        }

        if ( ! $role->getRoutes()->contains($this)) {
            $role->getRoutes()->add($this);
        }
    }

    return $this;
}

/**
 * @param Collection|ArrayCollection|Role[] $roles
 *
 * @return Route
 */
public function removeRoles(Collection $roles) : Route
{
    foreach ($roles as $role) {
        if ($this->getRoles()->contains($role)) {
            $this->getRoles()->remove($role);
        }

        if ($role->getRoutes()->contains($this)) {
            $role->getRoutes()->remove($this);
        }
    }

    return $this;
}

那么,到那里,就是设置。我建议您加入Gedmo Doctrine extensions并将@Gedmo\Tree(type="nested")应用于您的角色实体。使管理(嵌套/继承)角色变得容易。参见Managing Hierarchical Data in MySQL(和Gedmo Tree docs


接下来要检查用户是否有权访问某个路由,您需要某种形式的AuthenticationService。因为我不了解Slim,所以请确保使用该框架中的内容进行填充。逻辑是一样的。我使用要包含在/用于路由访问的服务,该服务检查用户是否已知(已认证),如果没有,则分配来宾角色,然后检查所分配的任何角色是否都知道要访问的路由。

/**
 * @param string $route
 *
 * @return bool
 * @throws Exception
 */
public function isGranted(string $route) : bool
{
    // Get assigned Role[] array or set Guest Role
    if ($this->getAuthenticationService()->hasIdentity()) {
        /** @var User $user */
        $user = $this->getAuthenticationService()->getIdentity();

        /** @var Collection|Role[] $roles */
        $roles = $user->getRoles();
    } else {
        $roles = new ArrayCollection(
            [
                $this->getObjectManager()->getRepository(Role::class)->findOneBy(['name' => Role::NO_ACCOUNT_ROLE]),
            ]
        );
    }

    foreach ($roles as $role) {
        if ($this->checkRoutes($role, $route)) {

            return true;
        }
    }

    return false;
}

因此,以上所有内容都可以为您带来更多收益。

GL和HF