Add custom property to serialized object

2019-05-24 08:16发布

问题:

I'm developing RESTful API for a web service. And I need to expose some properties that do not belong to an entity itself.

For example I have a Pizza entity object, it has it's own size and name properties. I'm outputting it in JSON format with FOSRestBundle and JMSSerializer. I've setup properties annotations for this entity to expose needed properties via serialization groups and it's working great.

But I need to add some properties that do not belong to the entity itself. For example I want my pizza to have property: isFresh that is determined by some PizzaService::isFresh(Pizza $pizza) service. How do I do this?

  • Should I inject some additional logic to serialization process (if so how)?
  • Should I create a wrapper entity with properties that I want to expose from original entity plus additional external properties?
  • Should I add property isFresh to the original Pizza entity and populate in in the controller before serialization?
  • Should I return additional data independent of entity data (in a sibling JSON properties for example)?

In other words: what are the best practices around this issue? Could you provide examples? Thank you.

回答1:

I think you can do that with the VirtualProperty annotation :

/**
 * @JMS\VirtualProperty
 * @return boolean
 */
public function isFresh (){
     ...
}

Edit : another solution with the Accessor annotation

/** @Accessor(getter="getIsFresh",setter="setIsFresh") */
private $isFresh;

// ...
public function getIsFresh()
{
    return $this->isFresh;
}

public function setIsFresh($isFresh)
{
    $this->isFresh= $isFresh;
}

In your controller, you call the setIsFresh method

(See http://jmsyst.com/libs/serializer/master/reference/annotation)



回答2:

I've decided to create my own class to serialize an entity.

Here's the example:

class PizzaSerializer implements ObjectSerializerInterface
{
    /** @var PizzaService */
    protected $pizzaService;

    /**
     * @param PizzaService $pizzaService
     */
    public function __construct(PizzaService $pizzaService)
    {
        $this->pizzaService = $pizzaService;
    }

    /**
     * @param Pizza $pizza
     * @return array
     */
    public function serialize(Pizza $pizza)
    {
        return [
            'id'      => $pizza->getId(),
            'size'    => $pizza->getSize(),
            'name'    => $pizza->getName(),
            'isFresh' => $this->pizzaService->isFresh($pizza),
        ];
    }
}

You just have to configure DC to inject PizzaService into the object serializer and then just call it like this from the controller:

$pizza = getPizzaFromSomewhere();

$pizzaSerializer = $this->get('serializer.pizza');

return $pizzaSerializer->serialize($pizza);

The object serializer will return an array that can be easily converted to JSON, XML, YAML or any other format by using real serializer like JMS Serializer. FOSRestBundle will do this automatically if you configured it so.