为了解释我的问题,我设置了一个非常简单的ApiResource,它使用自定义状态提供程序.

#[ApiResource(
    types: 'https://schema.org/UpdateAction',
    provider: TransitionStateProvider::class,
)]
class Transition
{
    #[ApiProperty(
        identifier: true,
        types: ['https://schema.org/identifier'],
    )]
    public int $id;
}

我的州供应商:

class TransitionStateProvider implements ProviderInterface
{
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
    {
        $transition = new Transition();
        $transition->id = 1;
        
        return $transition;
    }
}

当我发送GET请求时,@CONTEXT、@ID、@TYPE没有按照我想要的方式设置. 我得到了:

{
    "@context": {
        "@vocab": "https://localhost/docs.jsonld#",
        "hydra": "http://www.w3.org/ns/hydra/core#"
    },
    "@type": "Transition",
    "@id": "/.well-known/genid/66dae3d5fb3332ca13ee",
    "id": 1
}

我想要的是:

{
    "@context": "/contexts/Transition",
    "@id": "/transitions/1",
    "@type": "https://schema.org/UpdateAction",
    "id": 1
}

它与我的其他资源一起工作,但它们使用stateOptions链接到一个教义实体.这个Transition资源并非如此.

我试着在ApiProperty中设置identifier:true,我试着用uriTemplate,urivariableshydraContext玩,但没有成功.

我错过了什么-配置?

推荐答案

您可以try 创建一个custom normalizer来修改序列化过程,并确保@context@id@type的设置符合您的要求.

namespace App\Serializer;

use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

class TransitionNormalizer implements ContextAwareNormalizerInterface
{
    private $decorated;

    public function __construct(NormalizerInterface $decorated)
    {
        $this->decorated = $decorated;
    }

    public function normalize($object, string $format = null, array $context = [])
    {
        $data = $this->decorated->normalize($object, $format, $context);
        $data['@context'] = '/contexts/Transition';
        $data['@id'] = '/transitions/' . $object->id;
        $data['@type'] = 'https://schema.org/UpdateAction';

        return $data;
    }

    public function supportsNormalization($data, string $format = null, array $context = []): bool
    {
        return $data instanceof Transition;
    }
}

将自定义规范化器as a servicetag it定义为serializer.normalizer.这将确保它是在Symfony Serializer component注册.

# config/services.yaml
services:
    App\Serializer\TransitionNormalizer:
        decorates: 'serializer.normalizer.object'
        tags: ['serializer.normalizer']

https://symfony.com/doc/current/_images/components/serializer/serializer_workflow.svg

并更新Transition类上的ApiResource annotation以利用自定义规范化器.

#[ApiResource(
    types: 'https://schema.org/UpdateAction',
    provider: TransitionStateProvider::class,
    normalizationContext: ['groups' => ['transition']]
)]
class Transition
{
    #[ApiProperty(
        identifier: true,
        types: ['https://schema.org/identifier'],
    )]
    public int $id;
}

你得到的工作流程:

+---------------+     +----------------------+     +-----------------------+     +-------------------+
| API Resource  |     | Custom Normalizer    |     |   Service Definition  |     | Desired JSON-LD   |
| Transition    | --> | TransitionNormalizer | --> | serializer.normalizer | --> |   @context Setup  |
+---------------+     +----------------------+     +-----------------------+     +-------------------+

你更新的代码与上面的建议:

namespace App\Serializer;

use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

class TransitionNormalizer implements ContextAwareNormalizerInterface
{
    private $decorated;

    public function __construct(NormalizerInterface $decorated)
    {
        $this->decorated = $decorated;
    }

    public function normalize($object, string $format = null, array $context = [])
    {
        $data = $this->decorated->normalize($object, $format, $context);
        $data['@context'] = '/contexts/Transition';
        $data['@id'] = '/transitions/' . $object->id;
        $data['@type'] = 'https://schema.org/UpdateAction';

        return $data;
    }

    public function supportsNormalization($data, string $format = null, array $context = []): bool
    {
        return $data instanceof Transition;
    }
}

// config/services.yaml
services:
    App\Serializer\TransitionNormalizer:
        decorates: 'serializer.normalizer.object'
        tags: ['serializer.normalizer']

// Your ApiResource and Provider remains the same
#[ApiResource(
    types: 'https://schema.org/UpdateAction',
    provider: TransitionStateProvider::class,
    normalizationContext: ['groups' => ['transition']]
)]
class Transition
{
    #[ApiProperty(
        identifier: true,
        types: ['https://schema.org/identifier'],
    )]
    public int $id;
}

class TransitionStateProvider implements ProviderInterface
{
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
    {
        $transition = new Transition();
        $transition->id = 1;
        
        return $transition;
    }
}

Php相关问答推荐

419注册期间Laravel 11中的错误

PHP邮件表单无法识别重音/特殊字符

WooCommerce购物车中仅允许一个可下载产品

MySQLi是否在事务错误时删除保存点(并且仅删除保存点)?

将购买限制在WooCommerce中具有相同产品属性的项目

将一个按钮添加到WooCommerce产品的管理视图中,该按钮链接到一个自定义的WebHook,并在末尾附加产品ID

如何在PHP中组合日期范围

使用CODIGNITER3中的OR和AND子句进行查询

如何使用PHP从TXM(XML)标记中读取特定属性

将自定义字段添加到管理产品 在 WooCommerce 3.2+ 中批量编辑

laravel Eloquent 模型的问题

如何在 Phpunit 的静态提供程序中创建测试双打?

我的功能以舒适的方式显示数组 struct

批量作业(job)提交错误无法处理所有文档,uris 似乎正确?

在 PHP 中验证签名

显示时间范围内的可用空位,同时考虑已预订的空位

Symfony 6 中的入口点 (public/index.php) - 它是如何工作的?

为什么可以从 PHP 类访问 PHP Trait 的私有成员?

Symfony 自定义注销

如何使用先前 SELECT 的结果来 SELECT SQL 数据