Symfony 按角色查找用户(JSON 数组 Doctrine 属性)

Sol*_*BPS 8 php symfony doctrine-orm

我正在做一个小项目,其中有一个具有角色属性的实体,该属性由数组组成。

\n

我想做的是,在某个控制器中,找到一个在角色数组中具有特定角色的现有实体。

\n

我正在尝试使用findOneBy()方法,但我似乎无法使其工作,它总是返回 null,即使具有我试图找到的特定角色的实体存在。

\n

这是我的实体及其属性:

\n
/**\n * @ORM\\Entity(repositoryClass=SalarieRepository::class)\n */\nclass Salarie\n{\n    /**\n     * @ORM\\Id\n     * @ORM\\GeneratedValue\n     * @ORM\\Column(type="integer")\n     */\n    private $id;\n\n    /**\n     * @ORM\\Column(type="string", length=255)\n     */\n    private $nom;\n\n    /**\n     * @ORM\\Column(type="string", length=255)\n     */\n    private $prenom;\n\n    /**\n     * @ORM\\Column(type="string", length=255)\n     */\n    private $email;\n\n    /**\n     * @ORM\\Column(type="string", length=255, nullable=true)\n     */\n    private $telephone;\n\n    /**\n     * @ORM\\Column(type="string", length=255)\n     */\n    private $service;\n\n    /**\n     * @ORM\\Column(type="json")\n     */\n    private $roles = [];\n\n    // Getters & setters\n}\n
Run Code Online (Sandbox Code Playgroud)\n

findOneBy()这是我在控制器内部尝试的一个示例,它返回null,它返回:

\n
$rolecheck = $this->salarieRepository->findOneBy(["roles" => ["ROLE_RESPONSABLE_RH"]]);\n
Run Code Online (Sandbox Code Playgroud)\n

当我尝试使用不是数组的实体的任何其他属性时,如果我执行以下操作,它会很好地工作:

\n
$rolecheck = $this->salarieRepository->findOneBy(["nom" => "test"]);\ndd($rolecheck);\n
Run Code Online (Sandbox Code Playgroud)\n

它将显示正确的实体:

\n
SalarieController.php on line 47:\nApp\\Entity\\Salarie {#1501 \xe2\x96\xbc\n  -id: 6\n  -nom: "test"\n  -prenom: "test"\n  -email: "test@test.test"\n  -telephone: null\n  -service: "Graphisme"\n  -roles: array:3 [\xe2\x96\xbc\n    0 => "ROLE_RESPONSABLE_RH"\n    1 => "ROLE_RESPONSABLE_SERVICE"\n    2 => "ROLE_SALARIE"\n  ]\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我们还可以看到它确实有角色数组,其中包含我试图在其中找到的角色。

\n

有关我如何尝试找到具有特定角色的实体的任何线索吗"ROLE_RESPONSABLE_RH"

\n

Aym*_*Dev 12

您的$roles属性的类型为json,这意味着它在数据库中存储如下:

["ROLE_RESPONSABLE_RH", "ROLE_RESPONSABLE_SERVICE", "ROLE_SALARIE"]
Run Code Online (Sandbox Code Playgroud)

您需要询问 Doctrine JSON 数组是否包含该角色,但您不能使用该findOneBy()方法来做到这一点。

当您遇到 ORM 限制时,您可以将本机查询与 ResultSetMapping 结合使用。它允许您使用 DBMS 的特定功能编写纯 SQL 查询,但仍然获取实体对象。

在您的类中创建此方法SalarieRepository

public function findByRole(string $role): array
{
    // The ResultSetMapping maps the SQL result to entities
    $rsm = $this->createResultSetMappingBuilder('s');

    $rawQuery = sprintf(
        'SELECT %s
        FROM salarie s 
        WHERE /* your WHERE clause depending on the DBMS */',
        $rsm->generateSelectClause()
    );

    $query = $this->getEntityManager()->createNativeQuery($rawQuery, $rsm);
    $query->setParameter('role', $role);
    return $query->getResult();
}
Run Code Online (Sandbox Code Playgroud)

WHERE然后,您需要根据 DBMS 替换我在子句中放置的注释:

MariaDB - JSON_SEARCH()

SELECT %s
FROM salarie s 
WHERE JSON_SEARCH(s.roles, 'one', :role) IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

MySQL - JSON_CONTAINS()

SELECT %s
FROM salarie s 
WHERE JSON_CONTAINS(s.roles, :role, '$')
Run Code Online (Sandbox Code Playgroud)

警告:您必须role用双引号将参数引起来:

$query->setParameter('role', sprintf('"%s"', $role));
Run Code Online (Sandbox Code Playgroud)

PostgreSQL - jsonb 转义“?” 操作员

SELECT %s
FROM salarie s 
WHERE s.roles::jsonb ?? :role
Run Code Online (Sandbox Code Playgroud)

警告:需要 PHP 7.4+。请参阅RFC