3

I have this REST API. Whenever request comes to get a resource by id ( /resource/{id}) I want to add a permissions array on that object on the fly (entity itself does not have that field).

What I came up with is this event listener. It checks the result the controller has returned:

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

The problem is that the JMS Serializer opts out this dynamic property on serialization. I tried making the onPostSerialize event subscriber on JMS serializer, but then there are no clear way to check if this is a GET ONE or GET COLLECTION request. I don't need this behaviour on GET COLLECTION and also it results a huge performance hit on collection serialization. Also I don't want to create any base entity class with permission property.

Maybe there is some other way to deal with this scenario?

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
andrius.k
  • 799
  • 1
  • 10
  • 26

1 Answers1

0

What I could imagine is a combination of Virtual Property and Serialization Group:

Add a property to your entity like:

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

Only thing you need to do then is to serialize 'includePermissions' group only in your special case (see http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies)

If you don't have access to $permissionFinder from your entity you could as well set the permission attribute of an entity from a Controller/Service before serializing it.

EDIT:

This is a bit more code to demonstrate what I mean by wrapping your entity and using VirtualProperty together with SerializationGroups. This code is not tested at all - it's basically a manually copied and stripped version of what we're using. So please use it just as an idea!

1) Create something like a wrapping class for your entity:

 <?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) In your controller don't return your original Entity, but get your permissions and create your wrapped class with entity and permissions. Set your Serialization Context to include permissions and let the ViewHandler return your serialized object.

If you don't set Serialization Context to includePermissions it will be excluded from the serialized result.

 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);
LBA
  • 3,859
  • 2
  • 21
  • 60