Хэш-идентификатор Sysmfony REST API сущностей

Я создаю многопользовательскую серверную часть, используя Symfony 2.7.9 с FOSRestBundle и JMSSerializerBundle.

При возврате объектов через API я хотел бы хэшировать все идентификаторы возвращаемых объектов, поэтому вместо возврата { id: 5 } он должен стать чем-то вроде { id: 6uPQF1bVzPA }, чтобы я мог работать с хэшированными идентификаторами во внешнем интерфейсе (возможно, с помощью http://hashids.org)

Я думал о настройке JMSSerializer для установки виртуального свойства (например, «_id») для моих объектов с помощью специального метода получения, который вычисляет хэш для идентификатора, но у меня нет доступа к контейнеру/какой-либо службе.

Как я мог правильно справиться с этим?


person bacbos    schedule 17.01.2016    source источник


Ответы (2)


Вы можете использовать прослушиватель Doctrine postLoad для генерации хэша и установки свойства hashId в своем классе. Затем вы можете вызвать свойство expose в сериализаторе, но установить serialized_name как id (или вы можете просто оставить его равным hash_id).

Из-за хеширования, происходящего в postLoad, вам нужно будет обновить свой объект, если вы только что создали его с помощью $manager->refresh($entity), чтобы он вступил в силу.

AppBundle\Doctrine\Listener\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\serializer\Entity.User.yml

AppBundle\Entity\User:
    exclusion_policy: ALL
    properties:
        # ...
        hashId:
            expose: true
            serialized_name: id
        # ...
person qooplmao    schedule 17.01.2016

Большое спасибо за подробный ответ 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()));
    }
}
person bacbos    schedule 18.01.2016