Sysmfony REST API хеш-идентификатор сущностей
Я создаю многопользовательский бэкэнд, используя Symfony 2.7.9 с FOSRestBundle и JMSSerializerBundle.
При возврате объектов через API я хотел бы хэшировать все идентификаторы возвращаемых объектов, поэтому вместо возврата { id: 5 }
это должно стать чем-то вроде { id: 6uPQF1bVzPA }
так что я могу работать с хэшированными идентификаторами во внешнем интерфейсе (возможно, используя http://hashids.org/)
Я думал о настройке JMSSerializer для установки виртуального свойства (например, _id) для моих сущностей с помощью специального метода getter, который вычисляет хэш для идентификатора, но у меня нет доступа к контейнеру / какой-либо службе.
Как я мог правильно справиться с этим?
2 ответа
Большое спасибо за ваш подробный ответ qooplmao.
Тем не менее, мне не очень нравится этот подход, потому что я не собираюсь хранить хеш в сущности. Теперь я подписался на сериализатор onPostSerialize
событие, в котором я могу добавить хэшированный идентификатор следующим образом:
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;
class MySubscriber implements EventSubscriberInterface
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public static function getSubscribedEvents()
{
return array(
array('event' => 'serializer.post_serialize', 'method' => 'onPostSerialize'),
);
}
/**
* @param ObjectEvent $event
*/
public function onPostSerialize(ObjectEvent $event)
{
$service = $this->container->get('myservice');
$event->getVisitor()->addData('_id', $service->hash($event->getObject()->getId()));
}
}
Вы могли бы использовать Доктрину postLoad
слушатель генерировать хэш и установить hashId
недвижимость в вашем классе. Затем вы можете вызвать expose для свойства в сериализаторе, но установить serialized_name
как id
(или вы можете просто оставить его на hash_id
).
Из-за хеширования, происходящего в postLoad
вам нужно обновить ваш объект, если вы только что создали его с помощью $manager->refresh($entity)
для этого вступают в силу.
AppBundle \ Doctrine \ Слушатель \ HashIdListener
class HashIdListsner
{
private $hashIdService;
public function postLoad(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$reflectionClass = new \ReflectionClass($entity);
// Only hash the id if the class has a "hashId" property
if (!$reflectionClass->hasProperty('hashId')) {
return;
}
// Hash the id
$hashId = $this->hashIdService->encode($entity->getId());
// Set the property through reflection so no need for a setter
// that could be used incorrectly in future
$property = $reflectionClass->getProperty('hashId');
$property->setAccessible(true);
$property->setValue($entity, $hashId);
}
}
services.yml
services:
app.doctrine_listsner.hash_id:
class: AppBundle\Doctrine\Listener\HashIdListener
arguments:
# assuming your are using cayetanosoriano/hashids-bundle
- "@hashids"
tags:
- { name: doctrine.event_listener, event: postLoad }
AppBundle \ Resources \ Config \ сериализатору \Entity.User.yml
AppBundle\Entity\User:
exclusion_policy: ALL
properties:
# ...
hashId:
expose: true
serialized_name: id
# ...