2015-11-13 32 views
0

我有這個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串行選擇退出的系列化這種動態特性。我嘗試在JMS串行器上創建onPostSerialize事件訂戶,但是沒有明確的方法來檢查這是否是GET ONEGET COLLECTION請求。我不需要GET COLLECTION上的這種行爲,也會導致集合序列化的巨大性能。另外我不想創建任何具有permission屬性的基礎實體類。

也許有一些其他的方式來處理這種情況?

回答

0

我能想象是虛擬財產和序列化集團的組合:

屬性添加到您的實體,如:

/** 
* @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,你可以在序列化之前設置一個控制器/服務的實體權限屬性它。

編輯

這一點更多的代碼來證明我的意思是通過包裝你的實體一起使用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); 
+0

我想ro避免改變或耦合我的實體 – nn4n4s

+0

那麼如何包裝您的實體然後在一個具有虛擬屬性?例如通過擴展你的ViewHandler或類似的東西?那麼你不需要玩一個事件監聽器。 – LBA

+0

也許你可以把一些代碼示例建議 – nn4n4s