在Symfony5安全角色是純字串。所以,一個User物體通常有一個$roles陣列來存盤角色名稱字串,例如:
class User {
/** @ORM\Column(type="json") */
protected array $roles = ['ROLE_USER'];
// ...
}
但是,在我的環境中,我想用描述和其他元資料豐富角色,所以我有一個Role類,我希望能夠使用框架為單個用戶獲取角色串列(注意:獲取角色集合不是問題,可以開箱即用)。api-platform
uj5u.com熱心網友回復:
這可以通過在 Api-Platform 中定義一個自定義的 Subresource DataProvider來完成。美麗的部分是所有過濾器和分頁都會自然地作業(但是,過濾器不會出現在 API 檔案中;我不知道如何解決這個問題)。
@ApiSubresource在您的 User::$roles 屬性上定義:
/**
* @ApiSubresource(maxDepth=1)
* @ORM\Column(type="json")
*/
protected array $roles = [];
- 創建您的資料提供者。這是我使用的,但可以使用一些改進來更通用。
<?php
namespace App\DataProvider;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryResultCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGenerator;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface;
use ApiPlatform\Core\Exception\InvalidResourceException;
use ApiPlatform\Core\Exception\RuntimeException;
use App\Entity\Role;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
/**
* Converts the User::$roles plain array into a collection of Role entities.
*/
class UserRoleDataProvider implements SubresourceDataProviderInterface, RestrictedDataProviderInterface
{
private iterable $collectionExtensions;
private ManagerRegistry $managerRegistry;
public function __construct(ManagerRegistry $managerRegistry, iterable $collectionExtensions = [])
{
$this->managerRegistry = $managerRegistry;
$this->collectionExtensions = $collectionExtensions;
}
public function getSubresource(string $resourceClass, array $identifiers, array $context, string $operationName = null)
{
$manager = $this->managerRegistry->getManagerForClass(Role::class);
$repository = $manager->getRepository(Role::class);
if (!method_exists($repository, 'createQueryBuilder')) {
throw new RuntimeException('The repository class must have a "createQueryBuilder" method.');
}
/** @var User $user */
$user = $this->managerRegistry->getManagerForClass(User::class)->getRepository(User::class)->find($identifiers['id']['id']);
if (!$user) {
throw new InvalidResourceException('Resource not found');
}
/** @var QueryBuilder $queryBuilder */
$queryBuilder = $repository->createQueryBuilder('o');
$queryNameGenerator = new QueryNameGenerator();
$param = $queryNameGenerator->generateParameterName('roleNames');
$queryBuilder->where(sprintf('o.name IN (:%s)', $param))->setParameter($param, $user->getRoles());
foreach ($this->collectionExtensions as $extension) {
$extension->applyToCollection($queryBuilder, $queryNameGenerator, Role::class, $operationName, $context);
if ($extension instanceof QueryResultCollectionExtensionInterface && $extension->supportsResult(Role::class, $operationName, $context)) {
return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context);
}
}
return $queryBuilder;
}
public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
{
return User::class === $resourceClass
&& $context['property'] === 'roles'
&& $this->managerRegistry->getManagerForClass($resourceClass) instanceof EntityManagerInterface;
}
}
- 配置服務
App\DataProvider\UserRoleDataProvider:
arguments:
$collectionExtensions: !tagged api_platform.doctrine.orm.query_extension.collection
- 您現在可以呼叫您的路線:
path('api_users_roles_get_subresource', {id: user.id})
我花了一點時間才弄清楚這一點,所以我希望這對某人有所幫助。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/507533.html
