Hoi,

Ik heb een nieuw Symfony2-project waarbij ik een bestaande database automatisch heb laten mappen naar entiteiten. Ik wil graag een RESTapi gaan maken met dit Symfony-project, dus heb ik de volgende controller:
<?php
namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

class APIController extends Controller
{
    /**
     * @Route("/api/{type}/{id}", name="get")
     * @Method("GET")
     */
    public function getAction($type, $id, Request $request)
    {
        $response = null;

        $serializer = new Serializer(
            array(
                new ObjectNormalizer()
            ),
            array(
                new XmlEncoder(),
                new JsonEncoder()
            )
        );

        $repository = $this->getDoctrine()->getRepository('AppBundle:' . $type);

        $entity = $repository->find($id);
        $test = $serializer->serialize($entity, 'json');

        $response = new Response($serializer->serialize($entity, 'json'));
        $response->headers->set('Content-Type', 'application/json');

        return $response;
    }
}
?>

Ik heb wel een deel weggelaten, het gaat namelijk om het volgende. Als ik nu /api/Ride/1 opvraag, dan krijg ik de volgende exception:
Runtime Notice: Accessing static property Proxies\__CG__\AppBundle\Entity\Route::$lazyPropertiesDefaults as non static

Deze Ride heeft een referentie naar Route. Deze entiteiten zien er zo uit: (getters en setters weggelaten)
<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Ride
 *
 * @ORM\Table(name="ride", indexes={@ORM\Index(name="route", columns={"route"})})
 * @ORM\Entity
 */
class Ride
{
    /**
     * @var \DateTime
     *
     * @ORM\Column(name="date", type="date", nullable=false)
     */
    private $date;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="string", length=50, nullable=true)
     */
    private $description;

    /**
     * @var boolean
     *
     * @ORM\Column(name="retour", type="boolean", nullable=true)
     */
    private $retour;

    /**
     * @var boolean
     *
     * @ORM\Column(name="active", type="boolean", nullable=false)
     */
    private $active;

    /**
     * @var integer
     *
     * @ORM\Column(name="ridenumber", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $ridenumber;

    /**
     * @var \AppBundle\Entity\Route
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Route")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="route", referencedColumnName="routenumber")
     * })
     */
    private $route;
}
?>

<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Route
 *
 * @ORM\Table(name="route")
 * @ORM\Entity
 */
class Route
{
    /**
     * @var string
     *
     * @ORM\Column(name="from", type="string", length=50, nullable=false)
     */
    private $from;

    /**
     * @var string
     *
     * @ORM\Column(name="addressfrom", type="string", length=50, nullable=false)
     */
    private $addressfrom;

    /**
     * @var string
     *
     * @ORM\Column(name="postalcodefrom", type="string", length=7, nullable=false)
     */
    private $postalcodefrom;

    /**
     * @var string
     *
     * @ORM\Column(name="to", type="string", length=50, nullable=false)
     */
    private $to;

    /**
     * @var string
     *
     * @ORM\Column(name="addressto", type="string", length=50, nullable=false)
     */
    private $addressto;

    /**
     * @var string
     *
     * @ORM\Column(name="postalcodeto", type="string", length=7, nullable=false)
     */
    private $postalcodeto;

    /**
     * @var string
     *
     * @ORM\Column(name="distance", type="decimal", precision=5, scale=2, nullable=false)
     */
    private $distance;

    /**
     * @var boolean
     *
     * @ORM\Column(name="active", type="boolean", nullable=false)
     */
    private $active;

    /**
     * @var integer
     *
     * @ORM\Column(name="routenumber", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $routenumber;
}
?>

Ik vind het vooral een vage foutmelding aangezien deze uit Symfony zelf komt. Deze foutmelding krijg ik bij andere entiteiten ook (zoals Cursist die een Person is).

Weet iemand wat ik moet doen om dit op te lossen?

Roel
Thx, dat doet het hem!
Zo val je van het ene probleem in het andere, haha.
Wat ik nu wil doen is een JSON-string weer deserializen naar een object. Ik heb even gauw een controller aangemaakt voor dit proces.
<?php
/**
     * @Route("/api/{type}/{id}", name="post")
     */
    public function postAction($type, $id, Request $request)
    {
        $response = null;

        $content = '{"date":{"lastErrors":{"warning_count":0,"warnings":[],"error_count":0,"errors":[]},"timezone":{"name":"Europe\/Paris","location":{"country_code":"FR","latitude":48.86666,"longitude":2.33333,"comments":""}},"offset":7200,"timestamp":1442440800},"description":"Mada","retour":true,"active":true,"ridenumber":1,"route":{"from":"Roel","addressfrom":"Burgemeester de Roocklaan 15","postalcodefrom":"4611LA","to":"Niels","addressto":"Oudlandsestraat 194","postalcodeto":"4651MG","distance":"7.00","active":true,"routenumber":1}}';
        //$content = $request->getContent();

        $normalizer = new GetSetMethodNormalizer(null, null);

        $serializer = new Serializer(
            array(
                $normalizer
            ),
            array(
                //new XmlEncoder(),
                new JsonEncoder()
            )
        );

        if ($id > 0) {
            $repository = $this->getDoctrine()->getRepository('AppBundle:' . $type);

            $entity = $repository->find($id);
        } else {
            if (!empty($content)) {
                $entity = $serializer->deserialize($content, 'AppBundle\Entity\Ride', 'json');
            }
        }

        $response = new Response($serializer->serialize($entity, 'json'));
        $response->headers->set('Content-Type', 'application/json');

        return $response;
    }
?>

Na wat geprutst te hebben, kwam ik erachter dat ik een implementatie van een ObjectNormalizer moest meegeven aan de serializer, in dit geval een GetSetMethodNormalizer. Dit werkt goed, totdat 'ie bij Route aankomt. Dan krijg ik deze mooie foutmelding:
Catchable Fatal Error: Argument 1 passed to AppBundle\Entity\Ride::setRoute() must be an instance of AppBundle\Entity\Route, array given, called in H:\wamp\www\hs\vendor\symfony\symfony\src\Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer.php on line 118 and defined

De melding is op zich logisch. Wat is hier een goede oplossing? Zelf setRoute aanpassen om ook een array aan te nemen en vervolgens daar handmatig deserializen, of zie ik een handig component over het hoofd? De magie gebeurt overigens op regel 30.
Jazeker. Maar als ik i.p.v. een GetSetMethodNormalizer een ObjectNormalizer meegeef, dan krijg ik een volgende soort fout:
Could not denormalize object of type ..., no supporting normalizer found.
Dat is inderdaad iets wat ik wil. Ik vraag me alleen af of er in Symfony 2.7 inmiddels geen ingebouwde mogelijkheid is hiervoor. Jouw artikel dateert uit 2012. Als er geen alternatief is, dan is dit inderdaad een mooie oplossing, maar ik ga eerst nog maar even verder zoeken. Het wiel opnieuw uitvinden heeft immers weinig zin!

Reageren