【问题标题】:Custom ItemDataProvider with Api Platform使用 Api 平台自定义 ItemDataProvider
【发布时间】:2019-07-02 16:54:44
【问题描述】:

我尝试用 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

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

【问题讨论】:

    标签: php symfony symfony4 api-platform.com


    【解决方案1】:

    我认为是关于逻辑的,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);
        }
    }
    

    【讨论】:

    • 为我的实体添加构造函数并没有解决问题,现在没有之前的IRI错误,但是除了id之外的所有字段都是null。所以它仍然没有检索到数据。
    • @RaKoDev Symfony 有一个自动连接,在某些情况下你需要启用该服务,所以基本上你需要这样做,对不起,我要修改我的答案
    • @RaKoDev 基本上是一个 DTO 将一个实体或一组实体转换为分组数据,在这种情况下,您可以在 Api 中启用类型或类,但不生成表或类是实体,并手动设置数据。
    • 是的,这就是我最终所做的。我在此处遵循 API 平台文档中的示例:api-platform.com/docs/core/data-providers 我想知道为什么它不像我的示例那样工作。
    【解决方案2】:

    添加标识符

    @ApiProperty(identifier=true)
    

    【讨论】:

    • 请在您的答案中添加一些解释,以便其他人可以从中学习
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-06
    • 2020-10-22
    • 1970-01-01
    相关资源
    最近更新 更多