【问题标题】:API Platform : search filter with group's fieldsAPI 平台:使用组字段的搜索过滤器
【发布时间】:2019-08-07 12:16:53
【问题描述】:

我正在使用 API 平台,我正在寻找一些东西。 我做了一个这样的人实体:

class Person
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $name;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $firstname;

    /**
     * @ORM\Column(type="datetime")
     */
    private $birthdate;
}

为字段定义组:

App\Entity\Person:
  attributes:
    id:
      groups: ['private']
    name:
      groups: ['public']
    firstname:
      groups: ['public']
    birthdate:
      groups: ['public']

我还明确指出,如果我想要该资源的所有集合,则只应序列化公共字段:

App\Entity\Person:
    collectionOperations:
      get:
        filters: ['search_filter']
        normalization_context:
          groups: ['public']
        formats: ['json']

如您所见,我应用了搜索过滤器。在这种情况下,我可以从精确为查询参数的字段中检索资源。

但是,我想仅对公共字段应用此过滤器。 所以我不希望http://localhost/api/people?id=1 请求有效,因为 id 字段是私有

我发现可以将想要作为 SearchFilter 参数的字段精确化,但改为精确化组名会更有用,因为我打算与更多组合作。

我试图查看 GroupFilters,但它对我没有帮助,因为它是一个序列化器过滤器...

你有什么推荐给我的?

【问题讨论】:

    标签: symfony serialization api-platform.com


    【解决方案1】:

    经过几个小时的挖掘,我终于找到了答案:

    • 我创建了自己的过滤器,它注入了一个 SearchFilter 实例。
    • 为了比较发送到 QueryParam 的字段组,我不得不使用 AbstractContextAwareFilter 类扩展我的过滤器。

    • 我将这些组与 ClassMetadataFactory 类提供的资源/实体元数据信息进行比较。 我必须改用注释语法来编写我的组而不是 yaml,否则它们将不会被检测到。

      如果一个组不在规范化组中,我抛出一个异常,否则我离开 SearchFilter 来执行过滤过程。

    这是我的工作:

    use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter;
    use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractFilter;
    use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
    use Doctrine\Common\Persistence\ManagerRegistry;
    use Doctrine\ORM\QueryBuilder;
    use http\Exception\RuntimeException;
    use Psr\Log\LoggerInterface;
    use Symfony\Component\HttpFoundation\RequestStack;
    use Symfony\Component\Serializer\Mapping\ClassMetadata;
    use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
    
    /**
     * Class RestrictGroupFilter
     * @package App\Filters
     */
    class RestrictGroupFilter extends AbstractContextAwareFilter
    {
        /**
         * @var $decorated AbstractFilter
         */
        private $filter;
        private $metadataFactory;
    
        public function __construct(AbstractFilter $filter, ClassMetadataFactory $metadataFactory,ManagerRegistry $managerRegistry, ?RequestStack $requestStack = null, LoggerInterface $logger = null, array $properties = null)
        {
            parent::__construct($managerRegistry, $requestStack, $logger, $properties);
            $this->filter = $filter;
            $this->metadataFactory = $metadataFactory;
        }
    
        protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null, array $context = [])
        {
            /**
             * @var $classMetadata ClassMetadata
             */
            $classMetadata = $this->metadataFactory->getMetadataFor($resourceClass); #retrieve of Entity's class's attribute metadata
            #prepare to check context's group with normalization ones
            foreach ($context["groups"] as $group)
            {
                if(!in_array($group,$classMetadata->attributesMetadata[$property]->getGroups())){ //if one group is not found in normalization groups
    
                    throw new RuntimeException("$property's group denied." /*Groups authorized : ".implode(", ",$context["groups"])*/);
                }
            }
            //Filter is enabled if all is good
            $this->filter->filterProperty($property,$value,$queryBuilder,$queryNameGenerator,$resourceClass,$operationName);
    
        }
    
        public function getDescription(string $resourceClass): array
        {
            // TODO: Implement getDescription() method.
            return $this->filter->getDescription($resourceClass);
        }
    }
    

    对于服务:

        search_filter:
            parent: 'api_platform.doctrine.orm.search_filter'
            tags:   ['api_platform.filter']
            autowire: false
            autoconfigure: false
    
    
        'App\Filters\RestrictGroupFilter':
            arguments: [ '@search_filter','@serializer.mapping.class_metadata_factory']
    
    

    【讨论】:

      猜你喜欢
      • 2021-11-06
      • 2020-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多