使用api-platform为Symfony 5中的用户角色获取子资源

r3i60tvu  于 2022-11-25  发布在  其他
关注(0)|答案(1)|浏览(140)

Symfony5安全性中,角色是纯字串。因此,User实体通常会有一个$roles数组来储存角色名称字串,例如:

class User {
  /** @ORM\Column(type="json") */
  protected array $roles = ['ROLE_USER'];
  // ...
}

但是,在我的环境中,我希望使用描述和其他 meta数据丰富角色,因此我有一个Role类,我希望能够使用api-platform框架单个用户**获取角色列表(注意:获取角色集合不是问题,可以立即完成)*。

y53ybaqx

y53ybaqx1#

这可以通过在Api-Platform中定义一个自定义的子资源DataProvider来实现。我不知道如何解决这个问题)*。
1.在User::$roles属性上定义@ApiSubresource

/**
 * @ApiSubresource(maxDepth=1)
 * @ORM\Column(type="json")
 */
protected array $roles = [];

1.创建您的DataProvider。这是我使用的,但可以使用一些改进,使其更通用。

<?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;
    }
}

1.配置服务

App\DataProvider\UserRoleDataProvider:
    arguments:
        $collectionExtensions: !tagged api_platform.doctrine.orm.query_extension.collection

1.您现在可以调用您的路由:path('api_users_roles_get_subresource', {id: user.id})
我花了一点时间才弄明白这一点,所以我希望这对某些人有帮助。

相关问题