PHP项目Symfony serializer与组

wen PHP项目 1

本文目录导读:

PHP项目Symfony serializer与组

  1. 基础安装
  2. 核心组件配置
  3. 实体类配置
  4. 高级用法
  5. 控制器中使用
  6. 复杂场景处理
  7. 与API Platform集成
  8. 性能优化

我来帮你详细介绍PHP Symfony框架中Serializer组件的使用和配置。

基础安装

composer require symfony/serializer symfony/property-access symfony/property-info

核心组件配置

基本配置

// config/packages/framework.yaml
framework:
    serializer:
        enabled: true
        enable_annotations: true
        name_converter: 'serializer.name_converter.camel_case_to_snake_case'
        mapping:
            paths:
                - '%kernel.project_dir%/config/serializer'

在服务中配置

// config/services.yaml
services:
    App\Serializer\CustomNormalizer:
        tags:
            - { name: serializer.normalizer, priority: 64 }

实体类配置

使用注解

<?php
namespace App\Entity;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\MaxDepth;
use Symfony\Component\Serializer\Annotation\Ignore;
class User
{
    /**
     * @Groups({"user:read", "user:write", "list"})
     */
    private int $id;
    /**
     * @Groups({"user:read", "user:write", "list"})
     */
    private string $username;
    /**
     * @Groups({"user:write"})
     */
    private string $password;
    /**
     * @Groups({"user:read", "detail"})
     * @MaxDepth(1)
     */
    private array $roles;
    /**
     * @Groups({"user:read", "detail"})
     * @Ignore()
     */
    private string $internalNotes;
    // getters/setters...
}

使用YAML配置

# config/serializer/App.Entity.User.yaml
App\Entity\User:
    attributes:
        id:
            groups: ['user:read', 'user:write', 'list']
        username:
            groups: ['user:read', 'user:write', 'list']
        password:
            groups: ['user:write']
        email:
            groups: ['user:read', 'detail']
        createdAt:
            serialized_name: created_at
            groups: ['user:read', 'detail']

高级用法

自定义Normalizer

<?php
namespace App\Serializer;
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAwareInterface
{
    use NormalizerAwareTrait;
    public function supportsNormalization($data, string $format = null, array $context = []): bool
    {
        return $data instanceof \App\Entity\User;
    }
    public function normalize($object, string $format = null, array $context = []): array
    {
        $data = [
            'id' => $object->getId(),
            'username' => $object->getUsername(),
            'email' => $object->getEmail(),
        ];
        // 添加额外字段
        if (in_array('detail', $context['groups'] ?? [])) {
            $data['roles'] = $object->getRoles();
            $data['created_at'] = $object->getCreatedAt()->format('Y-m-d H:i:s');
        }
        return $data;
    }
}

自定义Denormalizer

<?php
namespace App\Serializer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use App\Entity\User;
class UserDenormalizer implements DenormalizerInterface
{
    public function denormalize($data, string $type, string $format = null, array $context = []): User
    {
        $user = new User();
        $user->setUsername($data['username']);
        $user->setEmail($data['email'] ?? null);
        if (isset($data['password'])) {
            $user->setPassword(password_hash($data['password'], PASSWORD_BCRYPT));
        }
        return $user;
    }
    public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool
    {
        return $type === User::class;
    }
}

控制器中使用

基础使用

<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
class UserController extends AbstractController
{
    public function show(int $id, SerializerInterface $serializer): JsonResponse
    {
        $user = $this->getDoctrine()->getRepository(User::class)->find($id);
        // 序列化为JSON
        $json = $serializer->serialize($user, 'json', [
            'groups' => ['user:read', 'detail'],
            'circular_reference_handler' => function ($object) {
                return $object->getId();
            }
        ]);
        return new JsonResponse($json, 200, [], true);
    }
    public function create(Request $request, SerializerInterface $serializer): JsonResponse
    {
        $data = $request->getContent();
        // 反序列化
        $user = $serializer->deserialize($data, User::class, 'json', [
            'groups' => ['user:write']
        ]);
        // 保存到数据库
        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->persist($user);
        $entityManager->flush();
        return new JsonResponse(['status' => 'created'], 201);
    }
}

使用对象规范化

<?php
namespace App\Controller;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
class ApiController extends AbstractController
{
    public function list(SerializerInterface $serializer): JsonResponse
    {
        $users = $this->getDoctrine()->getRepository(User::class)->findAll();
        $data = $serializer->normalize($users, null, [
            'groups' => ['list'],
            ObjectNormalizer::ENABLE_MAX_DEPTH => true,
            ObjectNormalizer::CIRCULAR_REFERENCE_LIMIT => 1,
            AbstractNormalizer::CALLBACKS => [
                'password' => function ($value) {
                    return null; // 隐藏密码
                }
            ]
        ]);
        return $this->json($data);
    }
}

复杂场景处理

递归引用处理

// 配置循环引用处理器
$context = [
    'circular_reference_handler' => function ($object) {
        return $object->getId();
    },
    'circular_reference_limit' => 2,
];
// 或者使用特定的处理器
$normalizer = new ObjectNormalizer();
$normalizer->setCircularReferenceHandler(function ($object) {
    return $object->getId();
});

自定义属性忽略

$context = [
    AbstractNormalizer::IGNORED_ATTRIBUTES => ['password', 'salt', 'internalNotes'],
    AbstractNormalizer::ATTRIBUTES => ['id', 'username', 'email', 'createdAt'],
];

属性重命名

$context = [
    AbstractNormalizer::ATTRIBUTES => [
        'id',
        'username',
        'email' => 'email_address', // 重命名属性
        'createdAt' => 'created_at', // 下划线命名
    ],
];

与API Platform集成

<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
/**
 * @ApiResource(
 *     normalizationContext={"groups"={"user:read"}},
 *     denormalizationContext={"groups"={"user:write"}},
 *     itemOperations={
 *         "get"={"method"="GET", "normalization_context"={"groups"={"detail"}}},
 *         "put"={"method"="PUT", "denormalization_context"={"groups"={"user:write"}}}
 *     }
 * )
 */
class User
{
    // ... entity definition
}

性能优化

缓存配置

// config/packages/framework.yaml
framework:
    serializer:
        cache: serializer.mapping.cache.symfony

使用指定编码器

// 只为特定格式配置
$encoders = [new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);

Symfony Serializer组件提供了强大的序列化/反序列化功能,通过组概念可以精细控制数据展示,配合自定义Normalizer可以处理复杂的业务逻辑,合理使用这些功能可以大大提高API开发的效率和灵活性。

抱歉,评论功能暂时关闭!