Добавление дополнительных полей с помощью пакета сериализатора JMS
Я сущность, я обычно сериализовать объекты JMS сериализатор пакет. Я должен добавить в сериализацию некоторые поля, которые не находятся в самой сущности, но собраны с некоторыми запросами БД.
моя идея заключалась в том, чтобы создать пользовательский объект, заполнить поля с поля и добавить пользовательский. Но это кажется немного сложным и дорогостоящим для каждого варианта (я использую много групп сериализации) класса.
есть ли лучше/стандартный способ сделать это? Используя фабрику? События до / после сериализации?
может быть, я могу прослушать сериализацию и проверить тип сущности и группы сериализации добавить пользовательские поля? Но вместо того, чтобы делать запрос для каждой сущности, было бы лучше собрать все данные из смежных структур, а затем добавить к ним. Любая помощь приветствуется
5 ответов
Я нашел решение сам,
чтобы добавить настраиваемое поле после сериализации, мы должны создать класс прослушивателя следующим образом:
<?php
namespace Acme\DemoBundle\Listener;
use JMS\DiExtraBundle\Annotation\Service;
use JMS\DiExtraBundle\Annotation\Tag;
use JMS\DiExtraBundle\Annotation\Inject;
use JMS\DiExtraBundle\Annotation\InjectParams;
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
use Acme\DemoBundle\Entity\Team;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\PreSerializeEvent;
use JMS\Serializer\EventDispatcher\ObjectEvent;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\JsonSerializationVisitor;
/**
* Add data after serialization
*
* @Service("acme.listener.serializationlistener")
* @Tag("jms_serializer.event_subscriber")
*/
class SerializationListener implements EventSubscriberInterface
{
/**
* @inheritdoc
*/
static public function getSubscribedEvents()
{
return array(
array('event' => 'serializer.post_serialize', 'class' => 'Acme\DemoBundle\Entity\Team', 'method' => 'onPostSerialize'),
);
}
public function onPostSerialize(ObjectEvent $event)
{
$event->getVisitor()->addData('someKey','someValue');
}
}
таким образом, вы можете добавить данные в сериализованный элемент.
вместо этого, если вы хотите изменить объект непосредственно перед сериализацией, используйте событие pre_serialize, имейте в виду, что вам уже нужно иметь переменную (и правильные группы сериализации), если вы хотите использовать pre_serialize для добавления значение.
меня удивляет, почему никто не предложил гораздо более простой способ. Вам нужно просто использовать @VirtualProperty:
<?php
// ...
/**
* @JMS\VirtualProperty
* @JMS\SerializedName("someField")
*/
public function getSomeField()
{
return $this->getTitle() . $this->getPromo();
}
для дальнейшего ответа на исходный вопрос. Вот как вы ограничиваете добавленные данные для некоторых сериализованных групп (в этом примере some_data
добавляется только тогда, когда мы не используем list
группа:
public function onPostSerializeSomeEntityJson(ObjectEvent $event) {
$entity = $event->getObject();
if (!in_array('list', (array)$event->getContext()->attributes->get('groups'))) {
$event->getVisitor()->addData('user_access', array(
'some_data' => 'some_value'
));
}
}
(array)$event->getContext()->attributes->get('groups')
содержит массив используемых сериализованных групп.
принятый ответ работает только тогда, когда посетитель получен из \JMS\Serializer\GenericSerializationVisitor
. Это означает, что он будет работать для JSON, но не для XML.
вот пример метода, который будет справляться с XML. Он смотрит на интерфейсы, которые поддерживает объект посетителя, и действует соответствующим образом. Он показывает, как можно добавить элемент link в сериализованные объекты JSON и XML...
public function onPostSerialize(ObjectEvent $event)
{
//obtain some data we want to add
$link=array(
'rel'=>'self',
'href'=>'http://example.org/thing/1',
'type'=>'application/thing+xml'
);
//see what our visitor supports...
$visitor= $event->getVisitor();
if ($visitor instanceof \JMS\Serializer\XmlSerializationVisitor)
{
//do XML things
$doc=$visitor->getDocument();
$element = $doc->createElement('link');
foreach($link as $name => $value) {
$element->setAttribute($name, $value);
}
$doc->documentElement->appendChild($element);
} elseif ($visitor instanceof \JMS\Serializer\GenericSerializationVisitor)
{
$visitor->addData('link', $link);
}
}
как насчет этого: http://jmsyst.com/libs/serializer/master/handlers
В общем, вы определяете класс, который получает объект и возвращает текст или массив (который будет преобразован в json).
у вас есть класс "IndexedStuff", который содержит странное вычисляемое поле, которое по какой-то причине должно быть вычислено во время сериализации.
<?php
namespace Project/Model;
class IndexedStuff
{
public $name;
public $value;
public $rawData;
}
Теперь создайте обработчик
<?php
namespace Project/Serializer;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\JsonSerializationVisitor;
use JMS\Serializer\Context;
class MyHandler implements SubscribingHandlerInterface
{
public function setEntityManager(Registry $registry) {
// Inject registry instead of entity manager to avoid circular dependency
$this->em = $registry->getEntityManager();
}
public static function getSubscribingMethods()
{
return array(
array(
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => 'Project/Model/IndexedStuff',
'method' => 'serializeIndexedStuffToJson',
),
);
}
public function serializeIndexedStuffToJson(JsonSerializationVisitor $visitor, Project/Model/IndexedStuff $stuff, array $type, Context $context)
{
// Build your object here and return it
$score = $this->em->find("ProjectBundle:Calculator", $stuff->value)
return array("score" => $score->getIndexScore(), "name"=> $score->name
}
}
наконец-то зарегистрировать сервис
services:
project.serializer.stuff:
class: Project\Serializer\MyHandler
calls:
- [setEntityManager, ["@doctrine"]]
теперь везде, где вы хотите сериализовать объект типа "IndexedStuff", вы получите json, подобный этому
{"name": "myName", "score" => 0.3432}
таким образом, вы можете полностью настроить, как ваша сущность сериализуется