Symfony 按角色查找用户(JSON 数组 Doctrine 属性)
Symfony find user by role (JSON array Doctrine property)
我正在做一个小项目,我有一个实体,其角色 属性 由一个数组组成。
我想做的是,在某些控制器中,找到一个在角色数组中具有特定角色的现有实体。
我正在尝试使用 findOneBy()
方法,但我似乎无法让它工作,它总是 returns null 即使我正在尝试寻找具有特定角色的实体存在。
这是我的实体及其属性:
/**
* @ORM\Entity(repositoryClass=SalarieRepository::class)
*/
class Salarie
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $nom;
/**
* @ORM\Column(type="string", length=255)
*/
private $prenom;
/**
* @ORM\Column(type="string", length=255)
*/
private $email;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $telephone;
/**
* @ORM\Column(type="string", length=255)
*/
private $service;
/**
* @ORM\Column(type="json")
*/
private $roles = [];
// Getters & setters
}
这是我在控制器中使用 findOneBy()
尝试的示例,即 returns null
:
$rolecheck = $this->salarieRepository->findOneBy(["roles" => ["ROLE_RESPONSABLE_RH"]]);
当我尝试使用不是数组的任何其他 属性 实体时,它运行良好,如果我这样做:
$rolecheck = $this->salarieRepository->findOneBy(["nom" => "test"]);
dd($rolecheck);
它将显示正确的实体:
SalarieController.php on line 47:
App\Entity\Salarie {#1501 ▼
-id: 6
-nom: "test"
-prenom: "test"
-email: "test@test.test"
-telephone: null
-service: "Graphisme"
-roles: array:3 [▼
0 => "ROLE_RESPONSABLE_RH"
1 => "ROLE_RESPONSABLE_SERVICE"
2 => "ROLE_SALARIE"
]
}
我们还可以看到它确实有角色数组,其中包含我试图在其中找到的角色。
关于我如何尝试找到一个具有特定角色的实体的任何线索"ROLE_RESPONSABLE_RH"
?
您的 $roles
属性 是 json
类型,这意味着它在您的数据库中存储为:
["ROLE_RESPONSABLE_RH", "ROLE_RESPONSABLE_SERVICE", "ROLE_SALARIE"]
如果 JSON 数组包含该角色,你需要询问 Doctrine,但你不能用 findOneBy()
方法做到这一点。
当您达到 ORM 限制时,您可以使用 Native Query with ResultSetMapping。它允许您使用 DBMS 的特定功能编写纯 SQL 查询,但仍然可以获得实体对象。
在您的 SalarieRepository
class:
中创建此方法
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();
}
然后你需要根据DBMS替换我在WHERE
子句中的注释:
MariaDB - JSON_SEARCH():
SELECT %s
FROM salarie s
WHERE JSON_SEARCH(s.roles, 'one', :role) IS NOT NULL
MySQL - JSON_CONTAINS():
SELECT %s
FROM salarie s
WHERE JSON_CONTAINS(s.roles, :role, '$')
警告:您必须用双引号将 role
参数括起来:
$query->setParameter('role', sprintf('"%s"', $role));
PostgreSQL - jsonb escaped "?" operator:
SELECT %s
FROM salarie s
WHERE s.roles::jsonb ?? :role
警告: 需要 PHP 7.4+。见 RFC
- CAST JSON 到 TEXT
class JSONText extends FunctionNode
{
private $expr1;
public function getSql(SqlWalker $sqlWalker)
{
return sprintf(
"CAST(%s AS TEXT)",
$this->expr1->dispatch($sqlWalker)
);
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->expr1 = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
- 添加到您的 Doctrine DQL:
dql:
string_functions:
JSON_TEXT: YOUR_NAMESPACE\JSONText
- 使用你的转换函数
$qb->andWhere("JSON_TEXT(d.topics) LIKE '%$role%'")
我正在做一个小项目,我有一个实体,其角色 属性 由一个数组组成。
我想做的是,在某些控制器中,找到一个在角色数组中具有特定角色的现有实体。
我正在尝试使用 findOneBy()
方法,但我似乎无法让它工作,它总是 returns null 即使我正在尝试寻找具有特定角色的实体存在。
这是我的实体及其属性:
/**
* @ORM\Entity(repositoryClass=SalarieRepository::class)
*/
class Salarie
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $nom;
/**
* @ORM\Column(type="string", length=255)
*/
private $prenom;
/**
* @ORM\Column(type="string", length=255)
*/
private $email;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $telephone;
/**
* @ORM\Column(type="string", length=255)
*/
private $service;
/**
* @ORM\Column(type="json")
*/
private $roles = [];
// Getters & setters
}
这是我在控制器中使用 findOneBy()
尝试的示例,即 returns null
:
$rolecheck = $this->salarieRepository->findOneBy(["roles" => ["ROLE_RESPONSABLE_RH"]]);
当我尝试使用不是数组的任何其他 属性 实体时,它运行良好,如果我这样做:
$rolecheck = $this->salarieRepository->findOneBy(["nom" => "test"]);
dd($rolecheck);
它将显示正确的实体:
SalarieController.php on line 47:
App\Entity\Salarie {#1501 ▼
-id: 6
-nom: "test"
-prenom: "test"
-email: "test@test.test"
-telephone: null
-service: "Graphisme"
-roles: array:3 [▼
0 => "ROLE_RESPONSABLE_RH"
1 => "ROLE_RESPONSABLE_SERVICE"
2 => "ROLE_SALARIE"
]
}
我们还可以看到它确实有角色数组,其中包含我试图在其中找到的角色。
关于我如何尝试找到一个具有特定角色的实体的任何线索"ROLE_RESPONSABLE_RH"
?
您的 $roles
属性 是 json
类型,这意味着它在您的数据库中存储为:
["ROLE_RESPONSABLE_RH", "ROLE_RESPONSABLE_SERVICE", "ROLE_SALARIE"]
如果 JSON 数组包含该角色,你需要询问 Doctrine,但你不能用 findOneBy()
方法做到这一点。
当您达到 ORM 限制时,您可以使用 Native Query with ResultSetMapping。它允许您使用 DBMS 的特定功能编写纯 SQL 查询,但仍然可以获得实体对象。
在您的 SalarieRepository
class:
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();
}
然后你需要根据DBMS替换我在WHERE
子句中的注释:
MariaDB - JSON_SEARCH():
SELECT %s
FROM salarie s
WHERE JSON_SEARCH(s.roles, 'one', :role) IS NOT NULL
MySQL - JSON_CONTAINS():
SELECT %s
FROM salarie s
WHERE JSON_CONTAINS(s.roles, :role, '$')
警告:您必须用双引号将 role
参数括起来:
$query->setParameter('role', sprintf('"%s"', $role));
PostgreSQL - jsonb escaped "?" operator:
SELECT %s
FROM salarie s
WHERE s.roles::jsonb ?? :role
警告: 需要 PHP 7.4+。见 RFC
- CAST JSON 到 TEXT
class JSONText extends FunctionNode
{
private $expr1;
public function getSql(SqlWalker $sqlWalker)
{
return sprintf(
"CAST(%s AS TEXT)",
$this->expr1->dispatch($sqlWalker)
);
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->expr1 = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
- 添加到您的 Doctrine DQL:
dql:
string_functions:
JSON_TEXT: YOUR_NAMESPACE\JSONText
- 使用你的转换函数
$qb->andWhere("JSON_TEXT(d.topics) LIKE '%$role%'")