pri*_*spy 5 php pagination symfony api-platform.com
我们实现了一个RolePermissionChecker,它应该控制特定资源的安全性/可访问性 ( Offer) 比较资源的访问者和创建者的属性。因为itemOperations我们正在使用Voter(https://api-platform.com/docs/core/security/#hooking-custom-permission-checks-using-voters),它工作得很好。
根据https://api-platform.com/docs/core/security/#filtering-collection-according-to-the-current-user-permissions应该collectionOperations DataProvider使用 - 所以我们实现了一个。
我们现在遇到的问题是OfferCollectionDataProvider首先调用它的父级ApiPlatform\Core\Bridge\Doctrine\Orm\CollectionDataProvider::getCollection函数以应用所有扩展并检索集合。然后我们过滤用户无权读取的实体。但是,当我们在准备好的页面上使用分页和过滤时,分页随后就会被破坏,例如一半的页面条目将被过滤,对于用户来说,看起来好像没有更多数据了。
有谁知道如何在不破坏分页且不使用扩展的情况下过滤集合,因为我们的权限检查有点复杂并且很难转换为查询?
<?php
namespace App\DataProvider;
use ApiPlatform\Core\Bridge\Doctrine\Orm\CollectionDataProvider;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Paginator;
use App\Entity\Offer;
use App\Entity\User;
use App\Service\RolePermissionChecker;
use ArrayIterator;
use Doctrine\Persistence\ManagerRegistry;
use ReflectionProperty;
use Symfony\Component\Security\Core\Security;
/**
* Class OfferCollectionDataProvider
*
* @package App\DataProvider
*/
class OfferCollectionDataProvider extends CollectionDataProvider
{
/**
* @var RolePermissionChecker
*/
protected RolePermissionChecker $rolePermissionChecker;
/**
* @var Security $security
*/
protected Security $security;
/**
* @param RolePermissionChecker $rolePermissionChecker
* @param Security $security
* @param ManagerRegistry $managerRegistry
* @param iterable $collectionExtensions
*/
public function __construct(
RolePermissionChecker $rolePermissionChecker,
Security $security,
ManagerRegistry $managerRegistry,
iterable $collectionExtensions = []
)
{
parent::__construct(
$managerRegistry,
$collectionExtensions
);
$this->rolePermissionChecker = $rolePermissionChecker;
$this->security = $security;
}
/**
* @param string $resourceClass
* @param string|null $operationName
* @param array $context
*
* @return bool
*/
public function supports(
string $resourceClass,
string $operationName = null,
array $context = []
): bool
{
return Offer::class === $resourceClass;
}
/**
* @inheritdoc
*/
public function getCollection(
string $resourceClass,
string $operationName = null,
array $context = []
): iterable
{
$collection = parent::getCollection(
$resourceClass,
$operationName,
$context
);
$user = $this->security->getUser();
if ($user instanceof User) {
$hasReadPermissionsOnOffer = fn($offer) => $this->rolePermissionChecker->hasReadPermission(
$offer,
$user
);
if ($collection instanceof Paginator) {
$newIteratorArray = [];
foreach ($collection->getIterator() as $offer) {
if ($hasReadPermissionsOnOffer($offer)) {
$newIteratorArray[] = $offer;
}
}
$paginatorReflectionProperty = new ReflectionProperty(
Paginator::class,
'paginator'
);
$paginatorReflectionProperty->setAccessible(true);
$paginator = $paginatorReflectionProperty->getValue($collection);
return new FilteredPaginator(
$paginator,
new ArrayIterator(
$newIteratorArray
),
$collection->getCurrentPage(),
$collection->getItemsPerPage(),
$collection->getLastPage(),
$collection->getTotalItems(),
);
} else if (
is_array($collection)
) {
$collection = array_filter(
$collection,
$hasReadPermissionsOnOffer,
);
}
}
return $collection;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1081 次 |
| 最近记录: |