wayofdev/laravel-symfony-serializer

📦 Laravel 对 Symfony Serializer 的封装。


README



构建
Build Status

项目
Total Downloads Latest Stable Version Commits since latest release PHP Version Require

质量
Codecov Mutation testing badge PHP Stan Level 6 of 9

社区
Discord Follow on Twitter (X)


Laravel Symfony Serializer

此包将 Symfony Serializer 组件集成到 Laravel 中,提供了一个强大的工具,可以将对象序列化和反序列化为各种格式,如 JSON、XML、CSV 和 YAML。

有关 Symfony Serializer 的详细文档可以在其 官方页面 上找到。


🗂️ 目录


🤔 目的

此包将 Symfony Serializer 组件的强大功能带入 Laravel。虽然 Laravel 没有内置的序列化器,通常依赖于数组或 JSON 转换,但此包提供了更高级的序列化功能。这包括对象归一化、处理循环引用、属性分组和特定格式的编码器。

如果您正在构建 REST API、处理队列或具有复杂的序列化需求,此包将特别有用。它允许您使用对象而不是简单的数组作为有效负载,并支持各种格式,如 JSON、XML、CSV 和 YAML。此文档将指导您完成安装过程,并提供如何使用此包进行对象序列化和反序列化的示例。


🙏 如果您认为此存储库很有用,请考虑给它一个 ⭐️。谢谢!


💿 安装

将包作为依赖项要求

composer require wayofdev/laravel-symfony-serializer

您可以使用以下命令发布配置文件

$ php artisan vendor:publish \
  --provider="WayOfDev\Serializer\Bridge\Laravel\Providers\SerializerServiceProvider" \
  --tag="config"

🔧 配置

包配置文件允许您自定义序列化过程的各个方面。

以下是包提供的默认配置

<?php

declare(strict_types=1);

use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface;
use WayOfDev\Serializer\Contracts\EncoderRegistrationStrategy;
use WayOfDev\Serializer\Contracts\NormalizerRegistrationStrategy;
use WayOfDev\Serializer\DefaultEncoderRegistrationStrategy;
use WayOfDev\Serializer\DefaultNormalizerRegistrationStrategy;

/**
 * @return array{
 *     default: string,
 *     debug: bool,
 *     normalizerRegistrationStrategy: class-string<NormalizerRegistrationStrategy>,
 *     encoderRegistrationStrategy: class-string<EncoderRegistrationStrategy>,
 *     metadataLoader: class-string<LoaderInterface>|null,
 * }
 */
return [
    'default' => env('SERIALIZER_DEFAULT_FORMAT', 'symfony-json'),

    'debug' => env('SERIALIZER_DEBUG_MODE', env('APP_DEBUG', false)),

    'normalizerRegistrationStrategy' => DefaultNormalizerRegistrationStrategy::class,

    'encoderRegistrationStrategy' => DefaultEncoderRegistrationStrategy::class,

    'metadataLoader' => null,
];

→ 配置选项

  • default:指定默认序列化器格式。可以通过设置 SERIALIZER_DEFAULT_FORMAT 环境变量来覆盖。默认为 symfony-json
  • debug:为 ProblemNormalizer 启用调试模式。可以使用 SERIALIZER_DEBUG_MODE 环境变量设置。默认为 APP_DEBUG 的值。
  • normalizerRegistrationStrategy:指定注册归一化器的策略类。默认策略为 WayOfDev\Serializer\DefaultNormalizerRegistrationStrategy
  • encoderRegistrationStrategy:指定注册编码器的策略类。默认策略为 WayOfDev\Serializer\DefaultEncoderRegistrationStrategy
  • metadataLoader:允许注册自定义元数据加载器。默认情况下,使用 Symfony\Component\Serializer\Mapping\Loader\AttributeLoader

→ 自定义策略

由于 Laravel 的缓存限制,其中配置无法实例化对象,因此此包使用策略来注册归一化器和编码器。[链接](https://elliotderhay.com/blog/caching-laravel-configs-that-use-objects)

您可以通过实现相应的接口来创建自定义的标准化器或编码器注册策略。

标准化器注册策略

要创建自定义的标准化器注册策略

  1. 实现 NormalizerRegistrationStrategy 接口

    <?php
    
    declare(strict_types=1);
    
    namespace Infrastructure\Serializer;
    
    use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface;
    use Symfony\Component\Serializer\Normalizer;
    use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
    use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
    use WayOfDev\Serializer\Contracts\NormalizerRegistrationStrategy;
    // ...
    
    final readonly class CustomNormalizerRegistrationStrategy implements NormalizerRegistrationStrategy
    {
        public function __construct(
            private LoaderInterface $loader,
            private bool $debugMode = false,
        ) {
        }
    
        /**
         * @return iterable<array{normalizer: NormalizerInterface|DenormalizerInterface, priority: int<0, max>}>
         */
        public function normalizers(): iterable
        {
            // ...
        }
    }
  2. 修改 serializer.php 配置以使用您的自定义策略

    'normalizerRegistrationStrategy' => CustomNormalizerRegistrationStrategy::class,

编码器注册策略

要创建自定义的编码器注册策略

  1. 实现 EncoderRegistrationStrategy 接口

    <?php
    
    declare(strict_types=1);
    
    namespace Infrastructure\Serializer;
    
    use Symfony\Component\Serializer\Encoder;
    use Symfony\Component\Serializer\Encoder\DecoderInterface;
    use Symfony\Component\Serializer\Encoder\EncoderInterface;
    use Symfony\Component\Yaml\Dumper;
    
    use function class_exists;
    
    final class CustomEncoderRegistrationStrategy implements Contracts\EncoderRegistrationStrategy
    {
        /**
         * @return iterable<array{encoder: EncoderInterface|DecoderInterface}>
         */
        public function encoders(): iterable
        {
            // Register your encoders here...
          
            yield ['encoder' => new Encoder\JsonEncoder()];
            yield ['encoder' => new Encoder\CsvEncoder()];
            yield ['encoder' => new Encoder\XmlEncoder()];
    
            if (class_exists(Dumper::class)) {
                yield ['encoder' => new Encoder\YamlEncoder()];
            }
        }
    }
  2. 修改 serializer.php 配置以使用您的自定义策略

    'encoderRegistrationStrategy' => CustomEncoderRegistrationStrategy::class,

💻 使用方法

该软件包提供了一系列序列化器,可用于序列化和反序列化对象。

本软件包中可用的默认序列化器有:symfony-jsonsymfony-csvsymfony-xmlsymfony-yaml

警告

要使用 yaml 编码器,需要安装 symfony/yaml 包,且在包未安装时默认禁用。安装 symfony/yaml 包后,编码器将自动启用。

→ 组件

SerializerManager

SerializerManager 处理本软件包中可用的不同序列化器。它可以用于序列化和反序列化对象。

ResponseFactory

ResponseFactory 用于在 Laravel 控制器中创建响应,使将序列化数据包含在 HTTP 响应中变得简单。

Facades

本软件包包括两个 Laravel Facades

  • Manager - 用于访问底层的 SerializerManager
  • Serializer - 用于访问绑定和配置的原始 Symfony 序列化器实例。

→ 示例 DTO

我们将使用此示例 DTO 进行序列化

<?php

namespace Application\User;

use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\SerializedName;

class UserDTO
{
    #[Groups(['public'])]
    #[SerializedName('id')]
    private int $id;

    #[Groups(['public'])]
    #[SerializedName('name')]
    private string $name;

    #[Groups(['private', 'public'])]
    #[SerializedName('emailAddress')]
    private string $email;

    public function __construct(int $id, string $name, string $email)
    {
        $this->id = $id;
        $this->name = $name;
        $this->email = $email;
    }

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

    public function name(): string
    {
        return $this->name;
    }

    public function email(): string
    {
        return $this->email;
    }
}

→ 在服务类中使用 SerializerManager

<?php

namespace Application\Services;

use WayOfDev\Serializer\Manager\SerializerManager;
use Application\User\UserDTO;

class ProductService
{
    public function __construct(
        private readonly SerializerManager $serializer,
    ) {
    }

    public function someMethod(): void
    {
        $serializer = $this->serializer->serializer('symfony-json');
        $dto = new UserDTO(1, 'John Doe', 'john@example.com');

        $serialized = $serializer->serialize(
            payload: $dto,
            context: ['groups' => ['private']]
        );
    }
}

→ 在 Laravel 控制器中使用 ResponseFactory

以下是如何在 Laravel 控制器中使用 ResponseFactory 的示例

示例控制器

<?php

namespace Bridge\Laravel\Public\Product\Controllers;

use Application\User\UserDTO;
use Illuminate\Http\Request;
use WayOfDev\Serializer\Bridge\Laravel\Http\HttpCode;
use WayOfDev\Serializer\Bridge\Laravel\Http\ResponseFactory;

class UserController extends Controller
{
    public function __construct(private ResponseFactory $response)
    {
    }

    public function index()
    {
        $dto = new UserDTO(1, 'John Doe', 'john@example.com');

        $this->response->withContext(['groups' => ['private']]);
        $this->response->withStatusCode(HttpCode::HTTP_OK);
      
        return $this->response->create($dto);
    }
}

→ 在 Laravel 队列中使用

要切换到 Laravel 默认序列化与该实现之间的队列,您可以在您的队列作业中覆盖 __serialize__unserialize 方法。以下是一个示例

<?php

declare(strict_types=1);

namespace Bridge\Laravel\Public\Product\Jobs;

use Domain\Product\Models\Product;
use Domain\Product\ProductProcessor;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use WayOfDev\Serializer\Bridge\Laravel\Facades\Manager;

/**
 * This Job class shows how Symfony Serializer can be used with Laravel Queues.
 */
class ProcessProductJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public Product $product;

    public function __construct(Product $product)
    {
        $this->product = $product;
    }

    public function handle(ProductProcessor $processor): void
    {
        $processor->process($this->product);
    }

    public function __serialize(): array
    {
        return [
            'product' => Manager::serialize($this->product),
        ];
    }

    public function __unserialize(array $values): void
    {
        $this->product = Manager::deserialize($values['product'], Product::class);
    }
}

🔒 安全策略

该项目有一个 安全策略


🙌 想要贡献?

感谢您考虑为 wayofdev 社区做出贡献!我们欢迎所有类型的贡献。如果您想

您非常欢迎。在贡献之前,请查看我们的 贡献指南

Conventional Commits


🫡 贡献者

Contributors Badge

🌐 社交链接


📜 许可证

License


🧱 信用和有用资源

此存储库受到以下项目的启发