у меня есть Category
сущность, которая содержит кучу Assets
, Категория имеет getCount
метод, который возвращает количество активов в нем.
Я использую FosRestBundle и, следовательно, JMSSerializerBundle, чтобы сериализовать актив Category в json. Теперь произошла смена функций, которая привела к появлению различных видов активов, например, external
а также internal
из них.
Я все еще хочу использовать сериализацию объекта, и я подумал, создав PreSerializeEvent
Я действительно мог бы сделать это.
Все же документы для компонента сериализатора неясны, ссылаясь на соответствующую часть как do something
Как я на самом деле должен что-то здесь делать?
Чего я хочу добиться — это изменить метод, который вызывается, если установлен флаг. Обычным случаем для сериализатора должно быть использование getCount
метод, с другой стороны, getExternalCountOnly
метод объекта Category, если getCount
сериализуется.
Это действительно возможно сделать здесь, или я на неправильном пути?
См мой CategorySerializationSubscriber
:
<?php
namespace Hn\AssetDbBundle\Listener;
use Hn\AssetDbBundle\Entity\Category;
use Hn\UserBundle\Entity\User;
use JMS\Serializer\Annotation\PostSerialize;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;
use JMS\Serializer\EventDispatcher\PreSerializeEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;
/**
* Class CategorySerializationSubscriber
* @package Hn\AssetDbBundle\Listener
*/
class CategorySerializationSubscriber implements EventSubscriberInterface
{
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var User $user
*/
private $user;
/**
* @param LoggerInterface $logger
*/
public function __construct(LoggerInterface $logger, SecurityContextInterface $context)
{
$this->user = $context->getToken()->getUser();
$this->logger = $logger;
$logger->critical($this->user->getFullNameOrEmail());
}
/**
* @return array
*/
public static function getSubscribedEvents()
{
return [
[
'event' => 'serializer.pre_serialize',
'method' => 'onPreSerialize'
],
];
}
/**
* @param PreSerializeEvent $event
*/
public function onPreSerialize(PreSerializeEvent $event)
{
$category = $this->getCategoryFromEvent($event);
if (!$category) {
$this->logger->info('is not a category, aborting');
return;
}
$userCanViewInternalAsset = $this->user->isAllowedToViewInternalAssets();
/**
* How to actually do something?
*
* Pseudocode follows:
*/
if ($userCanViewInternalAsset) {
$seriaization->replaceMethod($category, 'getCount', 'getExternalAssetCount');
} else {
/**
* $category->getCount(); remains intact
*/
}
}
/**
* @param PreSerializeEvent $event
* @return Category|null
*/
protected function getCategoryFromEvent(PreSerializeEvent $event) {
/**
* @var Category $category
*/
$category = $event->getObject();
if (!$category instanceof Category) {
return null;
}
return $category;
}
}
Как насчет исключения по умолчанию и последующего использования подписчика postSerialize (), чтобы добавить его с нужной вам функцией? Например:
Определить в services.yml (или под services
в config.yml):
category_serialization_subscriber:
class: Hn\AssetDbBundle\Listener\CategorySerializationSubscriber
tags:
- { name: jms_serializer.event_subscriber }
Затем следующее, которое модифицируется из вашего класса выше:
public static function getSubscribedEvents()
{
return array(array(
'event' => 'serializer.post_serialize',
'class' => 'Hn\AssetDbBundle\Entity\Category',
'method' => 'onPostSerialize'
));
}
public function onPostSerialize(ObjectEvent $event)
{
$category = $event->getObject();
$visitor = $event->getVisitor();
if ($this->user->isAllowedToViewInternalAssets()) {
$visitor->addData('count', $category->getExternalAssetCount());
} else {
$visitor->addData('count', $category->getCount());
}
}
Других решений пока нет …