在要序列化的实体上添加动态属性

时间:2015-11-13 12:21:25

标签: symfony jms-serializer

我有这个REST API。每当请求通过id(/ resource / {id})获取资源时,我想在该对象上添加permissions数组(实体本身没有该字段)。

我想出的是这个事件监听器。它检查控制器返回的结果:

class PermissionFinderListener {
    ...

    public function onKernelView(GetResponseForControllerResultEvent $event)  {
        $object = $event->getControllerResult();

        if (!is_object($object) || !$this->isSupportedClass($object)) {
            return;
        }

        $permissions = $this->permissionFinder->getPermissions($object);
        $object->permissions = $permissions;

        $event->setControllerResult($object);
    }
    ....
}

问题是JMS Serializer在序列化时选择了这个动态属性。我尝试在JMS序列化程序上创建onPostSerialize事件订阅者,但是没有明确的方法来检查这是GET ONE还是GET COLLECTION请求。我不需要GET COLLECTION上的这种行为,也会导致收集序列化的巨大性能损失。此外,我不想创建任何具有permission属性的基本实体类。

也许还有其他方法来处理这种情况?

1 个答案:

答案 0 :(得分:-1)

我能想象的是虚拟财产和序列化组合的组合:

向您的实体添加属性,如:

 /**
 * @Serializer\VirtualProperty
 * @Serializer\SerializedName("permissions")
 * @Serializer\Groups({"includePermissions"}) */
 *
 * @return string
 */
public function getPermissions()
{
    return $permissionFinder->getPermissions($this);
}

你唯一需要做的就是序列化' includePermissions'仅在您的特殊情况下进行分组(请参阅http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies

如果您无法从您的实体访问$ permissionFinder,您也可以在序列化之前从Controller / Service设置实体的权限属性。

修改

通过包装您的实体并将VirtualProperty与SerializationGroups一起使用,这是一个更多的代码来演示我的意思。此代码根本未经过测试 - 它基本上是我们正在使用的手动复制和剥离版本。所以请将它作为一个想法使用!

1)为您的实体创建类似包装类的内容:

 <?php
 namespace Acquaim\ArcticBundle\Api;

 use JMS\Serializer\Annotation as JMS;

 /**
  * Class MyEntityApi
  *
  * @package My\Package\Api
  */
  class MyEntityApi
{
/**
 * The entity which is wrapped
 *
 * @var MyEntity
 * @JMS\Include()
 */
protected $entity;

protected $permissions;
/**
 * @param MyEntity     $entity
 * @param Permission[] $permissions
 */
public function __construct(
    MyEntity $entity,
    $permissions = null)
{
    $this->entity = $entity;
    $this->permissions = $permissions;
}

/**
 * @Serializer\VirtualProperty
 * @Serializer\SerializedName("permissions")
 * @Serializer\Groups({"includePermissions"})
 *
 * @return string
 */
public function getPermissions()
{
    if ($this->permissions !== null && count($this->permissions) > 0) {
        return $this->permissions;
    } else {
        return null;
    }
}

/**
 * @return object
 */
public function getEntity()
{
    return $this->entity;
}

}

2)在您的控制器中,不要返回原始实体,但获取您的权限并使用实体和权限创建包装类。 设置序列化上下文以包含权限,并让ViewHandler返回序列化对象。

如果您没有将序列化上下文设置为includePermissions,它将从序列化结果中排除。

 YourController:

 $myEntity = new Entity();

 $permissions = $this->get('permission_service')->getPermissions();

 $context =   SerializationContext::create()->setGroups(array('includePermissions'));

 $myEntityApi = new MyEntityApi($myEntity,$permissions);

 $view = $this->view($myEntityApi, 200);

 $view->setSerializationContext($context);

 return $this->handleView($view);