首页 > 解决方案 > 使用 Api 平台自定义 ItemDataProvider

问题描述

我尝试用 Symfony 4.3 & Api Platform 做一个演示应用

我创建了一个名为 Event 的实体:

/**
 * @ApiResource(
 *     itemOperations={
 *          "put"={"denormalization_context"={"groups"={"event:update"}}},
 *          "get"={
 *              "normalization_context"={"groups"={"event:read", "event:item:get"}}
 *          },
 *          "delete"
 *     },
 *     collectionOperations={"get", "post"},
 *     normalizationContext={"groups"={"event:read"}, "swagger_definition_name"="Read"},
 *     denormalizationContext={"groups"={"event:write"}, "swagger_definition_name"="Write"},
 *     shortName="Event",
 *     attributes={
 *          "pagination_items_per_page"=10,
 *          "formats"={"jsonld", "json", "csv", "jsonhal"}
 *     }
 * )
 * @ORM\Entity(repositoryClass="App\Repository\EventRepository")
 * @ORM\HasLifecycleCallbacks()
 */
class Event
{

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Groups({"event:read", "event:item:get"})
     */
    private $id;

    ...

    public function getId(): ?int
    {
        return $this->id;
    }
    ...

还有一个 EventItemDataProvider 类,我的目标是在将实体发送到响应之前执行其他操作。

<?php

namespace App\DataProvider;

use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
use App\Entity\Event;

final class EventItemDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
{
    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return Event::class === $resourceClass;
    }

    public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?Event
    {
        // Retrieve the blog post item from somewhere then return it or null if not found
        return new Event($id);
//        return null;
    }
}

当谈到 Event($id) 我有这个错误:

无法为 \"App\Entity\Event\" 类型的项目生成 IRI

你觉得我的代码有什么问题?

标签: phpsymfonysymfony4api-platform.com

解决方案


我认为是关于逻辑,api平台使用了一个restfull组件。当您拦截 getItem 时,基本上您正在使用此路线:

http://example/api/event/id

在这部分中,我们需要尝试弄清楚正在发生的事情

public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?Event
    {
        return new Event($id);
    }

在问题的前面代码中,您没有提到 Event 类有一个构造函数,所以基本上当 ApiPlatform 尝试提取 index 或 id 属性时,响应为空,然后 restfull 结构被破坏。他们不能像这样生成 restfull url:

http://example/api/event/null ????

尝试在构造函数中设置 $id 参数,例如:

class
{
     private $id;
     public function __constructor($id)
     {
         $this->id = $id;
     }
}

同样作为注释不是强制性的,在 ApiPlatform 的 getItem 中返回确切的类,您可以尝试以下操作:

public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
    {
        return ['id'=> $id]
    }

更新:

<?php

namespace App\DataProvider;

use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Event;

final class EventItemDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
{
    private $repository;
    /**
     * UserDataProvider constructor.
     */
    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->repository = $entityManager->getRepository(Event::class);
    }
    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return Event::class === $resourceClass;
    }

    public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?Event
    {
        // Retrieve the blog post item from somewhere then return it or null if not found
        return $this->repository->find($id);
    }
}

推荐阅读