You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在API Platform中统一将自定义Url对象类型设为字符串?

问题

项目中使用自定义Doctrine类型处理URL,实体中的URL字符串会返回App\Util\Url对象,已实现归一化器/反归一化器,旧API中该类型以字符串形式传输。

接入API Platform后,OpenAPI文档将Url字段描述为对象:

Url.jsonld{
    @context {...}
    @id    [...]
    @type  [...]
    schema [...]
    domain [...]
    path   [...]
}

但实际API响应中Url字段是正常的字符串格式:

{
  "@context": "/api/contexts/Company",
  "@id": "/api/companies",
  "@type": "hydra:Collection",
  "hydra:member": [
    {
      "@id": "/api/companies/1",
      "@type": "Company",
      "name": "company name",
      "description": "company description",
      "id": 1,
      "url": "http://test.com"
    }
  ],
  "hydra:totalItems": 1
}

虽然可以通过#[ApiProperty(openapiContext: [])]单独配置每个字段,但项目中Url字段数量较多,不想逐个配置。希望实现像DateTime对象那样,让API Platform统一将所有Url对象在OpenAPI文档中显示为字符串类型。

解决方案

可以通过以下几种方式实现全局统一处理App\Util\Url类型的OpenAPI描述:

方法一:自定义OpenAPI类型映射扩展

创建一个装饰器类,修改API Platform生成的OpenAPI文档,将所有指向Url类型的属性替换为字符串类型:

<?php

namespace App\OpenApi;

use ApiPlatform\Core\OpenApi\Factory\OpenApiFactoryInterface;
use ApiPlatform\Core\OpenApi\Model\Schema;
use ApiPlatform\Core\OpenApi\OpenApi;

class UrlTypeOpenApiExtension implements OpenApiFactoryInterface
{
    private $decorated;

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

    public function __invoke(array $context = []): OpenApi
    {
        $openApi = $this->decorated->__invoke($context);
        
        // 遍历所有Schema,替换Url类型的属性定义
        foreach ($openApi->getComponents()->getSchemas() as $schema) {
            if (!$schema->getProperties()) {
                continue;
            }
            
            foreach ($schema->getProperties() as $propertyName => $propertySchema) {
                if ($propertySchema->getRef() === '#/components/schemas/Url') {
                    // 替换为URI格式的字符串类型
                    $newSchema = new Schema(type: 'string', format: 'uri');
                    $schema->setProperty($propertyName, $newSchema);
                }
            }
        }

        // 移除自动生成的Url Schema定义
        $openApi->getComponents()->getSchemas()->offsetUnset('Url');

        return $openApi;
    }
}

在services.yaml中注册该服务:

services:
    App\OpenApi\UrlTypeOpenApiExtension:
        decorates: 'api_platform.open_api.factory'
        arguments: ['@.inner']

方法二:通过元数据扩展全局设置属性配置

实现属性元数据工厂的装饰器,为所有App\Util\Url类型的属性自动添加openapiContext配置:

<?php

namespace App\Metadata;

use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
use App\Util\Url;
use Symfony\Component\PropertyInfo\Type;

class UrlPropertyMetadataFactory implements PropertyMetadataFactoryInterface
{
    private $decorated;

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

    public function create(string $resourceClass, string $property, array $options = []): PropertyMetadata
    {
        $propertyMetadata = $this->decorated->create($resourceClass, $property, $options);
        
        $type = $propertyMetadata->getType();
        if ($type instanceof Type && $type->getClassName() === Url::class) {
            // 为Url类型属性设置统一的OpenAPI描述
            $propertyMetadata = $propertyMetadata->withOpenapiContext([
                'type' => 'string',
                'format' => 'uri'
            ]);
        }

        return $propertyMetadata;
    }
}

注册服务:

services:
    App\Metadata\UrlPropertyMetadataFactory:
        decorates: 'api_platform.metadata.property.metadata_factory'
        arguments: ['@.inner']

内容的提问来源于stack exchange,提问作者marv255

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 17:45:45