Search code examples
phpsymfonydoctrine-ormfosrestbundlejms-serializer

serialize array of objects using Doctrine and JMSSerializer annotations


I have a model

    /**
     * @ORM\Table(name="polygon")
     * @ORM\Entity(repositoryClass="MyBundle\Repository\PolygonRepository")
     * @JMS\ExclusionPolicy("none")
     */
    class Polygon {
         /**
          * @var string
          *
          * @ORM\Column(name="polygon", type="json_array")
          * @JMS\Type("array<MyBundle\Model\Point>")
          */
          private $points;

          /***/
    }

in DB it's stored like text '[{"x":1, "y":1} ...]'

in controller I have

/**
 * Matches /polygon exactly
 *
 * @Route("/", name="polygon_list")
 * @Method("GET")
 *
 * @Rest\Get("/")
 *
 */
public function listAction()
{
    return $this->container->get('doctrine.orm.entity_manager')
        ->getRepository('MyBundle:Polygon')
        ->findAll();
}

so I'm getting ReflectionProperty::getValue() expects parameter 1 to be object, array given

in ...vendor/jms/metadata/src/Metadata/PropertyMetadata.php:51

If it were only to get result, it could be solved by using virtual property

/**
 * @JMS\Exclude
 */
private $points;

/**
 * @JMS\VirtualProperty
 * @JMS\Type("array<MyBundle\Model\Point>")
 * @JMS\SerializedName("points")
 * @JMS\Groups({"common"})
 *
 * @return array
 */
public function getMyPoints() {
    return [new Point(), new Point()]
}

But I need to receive this points as JSON from POST so the only way I found so far is Doctrine custom type similar to https://github.com/sonata-project/sonata-doctrine-extensions

with only difference that in convertToPHPValue method I'm addind additional typecast to receive objects instead of assoc array:

// pass my [{"x":1, "y":1} ...]
public function convertToPHPValue($value, AbstractPlatform $platform)
    {
       return array_map(function($a){ return (object)$a;}, json_decode($value));
    }

Is there is a more clean solution, without adding custom Doctrine serialization?

if only this ...vendor/jms/metadata/src/Metadata/PropertyMetadata.php:51 had

return $this->reflection->getValue((object)$obj);

but it's

return $this->reflection->getValue($obj); // :(

Solution

  • My problem was in using @JMS\Type at all

        class Polygon {
             /**
              * @ORM\Column(name="polygon", type="json_array")
              */
              private $points;
    
              public function getPoints() { return $this->points;}
              public function setPoints($points) {
                   $this->points = $points;
                   return $this;
              }
              /***/
        }
    

    Works just fine, thanks @Matteo for pointing out that I'm complicating a things :)