如何使用 JMS Serializer EventSubscriberInterface (php, symfony) 将对象序列化为它自己的 属性(数组)
How to serialize object as its own property (array) using JMS Serializer EventSubscriberInterface (php, symfony)
我需要将一个对象序列化为它自己的属性(它的类型是数组),我的意思是该对象有一个数组属性 books
,并且在转换它之后我想跳过books
键,这样结构会更扁平[book1, book2]
(不是[books => [book1, book2]]
。我有以下类:
<?php
class Store
{
private ?BooksCollection $booksCollection = null;
public function __construct(?BooksCollection $booksCollection = null)
{
$this->booksCollection = $booksCollection;
}
public function getBooksCollection(): ?BooksCollection
{
return $this->booksCollection;
}
}
class BooksCollection
{
/** @var Book[] */
private array $books;
public function __construct(Book ...$books)
{
$this->books = $books;
}
public function getBooks(): array
{
return $this->books;
}
}
class Book
{
private string $title;
public function __construct(string $title)
{
$this->title = $title;
}
public function getTitle(): string
{
return $this->title;
}
}
和序列化配置:
Store:
exclusion_policy: ALL
properties:
booksCollection:
type: BooksCollection
BooksCollection:
exclusion_policy: ALL
properties:
books:
type: array<int, Book>
Book:
exclusion_policy: ALL
properties:
title:
type: string
我想通过的考试:
<?php
use JMS\Serializer\ArrayTransformerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class StoreSerializeTest extends KernelTestCase
{
/** @var ArrayTransformerInterface */
private $serializer;
protected function setUp(): void
{
self::bootKernel();
$this->serializer = self::$kernel->getContainer()->get('jms_serializer');
}
public function testSerialization(): void
{
$store = new Store(new BooksCollection(new Book('Birdy'), new Book('Lotr')));
$serializedStore = $this->serializer->toArray($store);
$storeUnserialized = $this->serializer->fromArray($serializedStore, Store::class);
self::assertSame(
[
'books_collection' => [
['title' => 'Birdy'],
['title' => 'Lotr']
]
],
$serializedStore
);
self::assertEquals($store, $storeUnserialized);
}
}
如下所示,测试失败。我怎样才能去掉一个嵌套'books'?
我的主要想法是使用 EventSubscriberInterface
和 onPreSerialize
事件,但我真的不知道如何用数组替换对象 BooksCollection
它自己的 属性 books
。有没有人已经知道怎么做了?
我终于明白了。我实现了 SubscribingHandlerInterface
<?php
use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigatorInterface;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\JsonSerializationVisitor;
use Book;
use BooksCollection;
class BooksCollectionHandler implements SubscribingHandlerInterface
{
public static function getSubscribingMethods(): array
{
return [
[
'type' => BooksCollection::class,
'format' => 'json',
'method' => 'serialize',
'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
],
[
'type' => BooksCollection::class,
'format' => 'json',
'method' => 'deserialize',
'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
]
];
}
public function serialize(
JsonSerializationVisitor $visitor,
BooksCollection $booksCollection,
array $type,
Context $context
) {
return $visitor->visitArray($booksCollection->getBooks(), ['name' => 'array'], $context);
}
public function deserialize(
JsonDeserializationVisitor $visitor,
array $data,
array $type,
Context $context
): BooksCollection {
$collection = [];
foreach ($data as $book) {
$collection[] =
$visitor->getNavigator()->accept($book, ['name' => Book::class], $context);
}
return new BooksCollection(...$collection);
}
}
服务配置:
books_handler:
class: BooksCollectionHandler
tags:
- { name: jms_serializer.subscribing_handler }
我需要将一个对象序列化为它自己的属性(它的类型是数组),我的意思是该对象有一个数组属性 books
,并且在转换它之后我想跳过books
键,这样结构会更扁平[book1, book2]
(不是[books => [book1, book2]]
。我有以下类:
<?php
class Store
{
private ?BooksCollection $booksCollection = null;
public function __construct(?BooksCollection $booksCollection = null)
{
$this->booksCollection = $booksCollection;
}
public function getBooksCollection(): ?BooksCollection
{
return $this->booksCollection;
}
}
class BooksCollection
{
/** @var Book[] */
private array $books;
public function __construct(Book ...$books)
{
$this->books = $books;
}
public function getBooks(): array
{
return $this->books;
}
}
class Book
{
private string $title;
public function __construct(string $title)
{
$this->title = $title;
}
public function getTitle(): string
{
return $this->title;
}
}
和序列化配置:
Store:
exclusion_policy: ALL
properties:
booksCollection:
type: BooksCollection
BooksCollection:
exclusion_policy: ALL
properties:
books:
type: array<int, Book>
Book:
exclusion_policy: ALL
properties:
title:
type: string
我想通过的考试:
<?php
use JMS\Serializer\ArrayTransformerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class StoreSerializeTest extends KernelTestCase
{
/** @var ArrayTransformerInterface */
private $serializer;
protected function setUp(): void
{
self::bootKernel();
$this->serializer = self::$kernel->getContainer()->get('jms_serializer');
}
public function testSerialization(): void
{
$store = new Store(new BooksCollection(new Book('Birdy'), new Book('Lotr')));
$serializedStore = $this->serializer->toArray($store);
$storeUnserialized = $this->serializer->fromArray($serializedStore, Store::class);
self::assertSame(
[
'books_collection' => [
['title' => 'Birdy'],
['title' => 'Lotr']
]
],
$serializedStore
);
self::assertEquals($store, $storeUnserialized);
}
}
如下所示,测试失败。我怎样才能去掉一个嵌套'books'?
我的主要想法是使用 EventSubscriberInterface
和 onPreSerialize
事件,但我真的不知道如何用数组替换对象 BooksCollection
它自己的 属性 books
。有没有人已经知道怎么做了?
我终于明白了。我实现了 SubscribingHandlerInterface
<?php
use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigatorInterface;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\JsonSerializationVisitor;
use Book;
use BooksCollection;
class BooksCollectionHandler implements SubscribingHandlerInterface
{
public static function getSubscribingMethods(): array
{
return [
[
'type' => BooksCollection::class,
'format' => 'json',
'method' => 'serialize',
'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
],
[
'type' => BooksCollection::class,
'format' => 'json',
'method' => 'deserialize',
'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
]
];
}
public function serialize(
JsonSerializationVisitor $visitor,
BooksCollection $booksCollection,
array $type,
Context $context
) {
return $visitor->visitArray($booksCollection->getBooks(), ['name' => 'array'], $context);
}
public function deserialize(
JsonDeserializationVisitor $visitor,
array $data,
array $type,
Context $context
): BooksCollection {
$collection = [];
foreach ($data as $book) {
$collection[] =
$visitor->getNavigator()->accept($book, ['name' => Book::class], $context);
}
return new BooksCollection(...$collection);
}
}
服务配置:
books_handler:
class: BooksCollectionHandler
tags:
- { name: jms_serializer.subscribing_handler }