Symfony REST API 实体的哈希 ID
Sysmfony REST API hash id of entities
我正在使用带有 FOSRestBundle 和 JMSSerializerBundle 的 Symfony 2.7.9 构建一个多租户后端。
当通过 API 返回对象时,我想对返回对象的所有 ID 进行散列处理,所以不是返回 { id: 5 }
它应该变成类似 { id: 6uPQF1bVzPA }
这样的东西我可以在前端使用散列 id(可能使用 http://hashids.org)
我正在考虑配置 JMSSerializer 以使用自定义 getter 方法在我的实体上设置虚拟 属性(例如“_id”)-计算 id 的哈希值,但我没有无法访问容器/任何服务。
我该如何正确处理这个问题?
您可以使用 Doctrine postLoad
侦听器生成哈希并在 class 中设置 hashId
属性。然后你可以在序列化程序中调用公开 属性 但将 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
# ...
非常感谢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()));
}
}
我正在使用带有 FOSRestBundle 和 JMSSerializerBundle 的 Symfony 2.7.9 构建一个多租户后端。
当通过 API 返回对象时,我想对返回对象的所有 ID 进行散列处理,所以不是返回 { id: 5 }
它应该变成类似 { id: 6uPQF1bVzPA }
这样的东西我可以在前端使用散列 id(可能使用 http://hashids.org)
我正在考虑配置 JMSSerializer 以使用自定义 getter 方法在我的实体上设置虚拟 属性(例如“_id”)-计算 id 的哈希值,但我没有无法访问容器/任何服务。
我该如何正确处理这个问题?
您可以使用 Doctrine postLoad
侦听器生成哈希并在 class 中设置 hashId
属性。然后你可以在序列化程序中调用公开 属性 但将 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
# ...
非常感谢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()));
}
}