实体的Sysmfony REST API哈希id

时间:2016-01-17 12:19:06

标签: symfony fosrestbundle jmsserializerbundle jms-serializer

我使用带有FOSRestBundle和JMSSerializerBundle的Symfony 2.7.9构建多租户后端。

通过API返回对象时,我想要对返回对象的所有ID进行哈希处理,因此它不应该返回{ id: 5 },而应该像{ id: 6uPQF1bVzPA }那样我可以使用前端的哈希id(可能使用http://hashids.org

我正在考虑配置JMSSerializer以使用自定义getter方法在我的实体上设置虚拟属性(例如' _id'),该方法计算id的哈希值,但我没有访问容器/任何服务。

我怎么能正确处理这个?

2 个答案:

答案 0 :(得分:1)

您可以使用Doctrine postLoad侦听器生成哈希并在您的类中设置hashId属性。然后你可以调用在序列化程序中公开属性,但将serialized_name设置为id(或者你可以将它保留在hash_id)。

由于在postLoad内进行散列,如果您刚刚使用$manager->refresh($entity)创建对象,则需要刷新对象才能生效。

的appbundle \学说\监听\ 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 \资源\配置\串行\ Entity.User.yml

AppBundle\Entity\User:
    exclusion_policy: ALL
    properties:
        # ...
        hashId:
            expose: true
            serialized_name: id
        # ...

答案 1 :(得分:1)

非常感谢您详细解答qooplmao。

但是,我并不特别喜欢这种方法,因为我并不打算将哈希存储在实体中。我现在最终订阅了序列化程序的onPostSerialize事件,我可以在其中添加哈希id,如下所示:

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()));
    }
}