API-Platform自定义过滤集合作为属性

时间:2017-04-11 07:21:48

标签: php symfony api-platform.com

我正在为我的网站使用api-platform(https://api-platform.com/)框架,我试图用不同的标准多次序列化一个实体的集合。我创建了以下示例实体:

EntityWithFilteredCollection

namespace AppBundle\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ApiResource(attributes={"normalization_context"={"groups"={"get"}}})
 * @ORM\Entity()
 */
class EntityWithFilteredCollection
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     * @Groups({"get"})
     */
    private $id;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\FilteredCollectionRelatedEntity", mappedBy="relatedEntity")
     */
    private $relatedEntities;

    /**
     * @Groups({"get"})
     */
    private $filteredEntities;

    public function __construct()
    {
        $this->relatedEntities = new ArrayCollection();
    }

    public function getId()
    {
        return $this->id;
    }

    public function getRelatedEntities()
    {
        return $this->relatedEntities;
    }

    public function setRelatedEntities($relatedEntities)
    {
        $this->relatedEntities = $relatedEntities;
    }

    public function getFilteredEntities()
    {
        return $this->filteredEntities;
    }

    public function setFilteredEntities($filteredEntities)
    {
        $this->filteredEntities = $filteredEntities;
    }
}

FilteredCollectionRelatedEntity

namespace AppBundle\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ApiResource(attributes={"normalization_context"={"groups"={"get"}}})
 * @ORM\Entity()
 */
class FilteredCollectionRelatedEntity
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     * @Groups({"get"})
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\RelatedEntity", inversedBy="relatedEntites")
     */
    protected $relatedEntity;

    /**
     * @ORM\Column(type="integer")
     * @Groups({"get"})
     */
    protected $value;

    /**
     * @ORM\Column(type="boolean")
     * @Groups({"get"})
     */
    protected $condition;

    public function getId()
    {
        return $this->id;
    }

    public function getRelatedEntity()
    {
        return $this->relatedEntity;
    }

    public function setRelatedEntity($relatedEntity)
    {
        $this->relatedEntity = $relatedEntity;
    }

    public function getValue()
    {
        return $this->value;
    }

    public function setValue($value)
    {
        $this->value = $value;
    }

    public function getCondition()
    {
        return $this->condition;
    }

    public function setCondition($condition)
    {
        $this->condition = $condition;
    }
}

Doctrine Post Load Event的事件订阅者:

namespace AppBundle\EventSubscriber;


use AppBundle\Entity\EntityWithFilteredCollection;
use AppBundle\Entity\FilteredCollectionRelatedEntity;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;

class FilterCollectionSubscriber implements EventSubscriber
{
    /** @var  RequestStack */
    private $requestStack;

    public function __construct(TokenStorage $tokenStorage, RequestStack $requestStack)
    {
        $this->tokenStorage = $tokenStorage;
        $this->requestStack = $requestStack;
    }


    public function postLoad(LifecycleEventArgs $event)
    {
        $entity = $event->getEntity();
        $method = $this->requestStack->getCurrentRequest()->getMethod();


        if (!$entity instanceof EntityWithFilteredCollection || Request::METHOD_GET !== $method) {
            return;
        }

        $entity->setFilteredEntities($entity->getRelatedEntities()->filter(function (FilteredCollectionRelatedEntity $entity) {
            return $entity->getCondition();
        }));

    }

    /**
     * Returns an array of events this subscriber wants to listen to.
     *
     * @return array
     */
    public function getSubscribedEvents()
    {
        return [
            'postLoad'
        ];
    }
}

当我尝试检索一个EntityWithFilteredCollection时,它有一些FilteredCollectionRelatedEntity实体,其条件值设置为true,我得到以下异常:

No resource class found for object of type "AppBundle\Entity\FilteredCollectionRelatedEntity"

我走错了路吗?我错过了什么吗? 当我没有尝试序列化已过滤的集合但原始的集合可行时,但我得到了所有实体。

1 个答案:

答案 0 :(得分:0)

您应该使用自定义API平台的过滤器而不是Doctrine监听器:https://api-platform.com/docs/core/filters#creating-custom-filters

实现起来更容易,执行速度更快(数据将在DBMS端而不是PHP端进行过滤)。