CircleOfNice / DoctrineRestDriver

GNU General Public License v3.0
153 stars 44 forks source link

Fetch method doesn't work as expected. #40

Closed domgraziano closed 8 years ago

domgraziano commented 8 years ago

What is this feature about (expected vs actual behaviour)?

Hello! I'm trying to use this Bundle to try to implement a pluggable and adaptable architecture. Following the documentation I noticed that I can use DataSource annotation to specify my custom routes if I'm not following the convention {apiHost}/{pathToApi}/{tableName} but a 3rd party API with a different convention, which is exactly my case.

Everything is working fine for Select and Insert methods. But I'm getting different errors for Fetch and Update.

Fetch method is going to trigger this method in my controller(I'm using the FOSRestBundle as well to handle the final response):

  /**
     * @Rest\Get("/api/contacts")
     */
    public function getAllContactsAction(){
        $em = $this->getDoctrine()->getManager('restapi');
        $entities = $em->getRepository($this->contactApi)->findAll();

        $view = $this->view($entities, 200)
            ->setTemplate("ApiBundle:Users:contacts.html.twig");
        return $this->handleView($view);
    }

I expect the JSON data you find at the related DataSource annotation (see the entity below) But is returning and error: Invalid url given: localhost\/Contacts? That means that the call for some reason is the table name rather than the actual url.

Update method is going to trigger this method in my controller:

  /**
     * @Rest\Put("/api/contacts/{id}")
     */
    public function updateAction($id = 1) {
        $em = $this->getDoctrine()->getManager('restapi');
        $entity = $em->getRepository($this->contactApi)->find($id);
        $entity->setEmailAddress('something@something.uk');
        $em->flush();

        $view = $this->view($entity, 204)
            ->setTemplate("ApiBundle:Users:contacts.html.twig");
        return $this->handleView($view);

Again I expect the JSON data you find at the related DataSource annotation but I get "message": "An exception occurred while executing 'UPDATE Contacts SET email_address = ? WHERE contact_id = ?' with params [\"something@something.uk\", 1]:\n\nWarning: krsort() expects parameter 1 to be array, null given",

This is my Entity with DataSource annotations (the endpoints are publicly accessible and you can see the JSON returns).

namespace ApiBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Circle\DoctrineRestDriver\Annotations as DataSource;
/**
 * This annotation marks the class as managed entity:
 * @ORM\Entity
 * @ORM\Table("Contacts")
 * @DataSource\Select("http://private-f6d95-progressdom.apiary-mock.com/contacts/{id}")
 * @DataSource\Fetch("http://private-f6d95-progressdom.apiary-mock.com/contacts", method="GET")
 * @DataSource\Insert("http://private-f6d95-progressdom.apiary-mock.com/contacts", method="POST")
 * @DataSource\Update("http://private-f6d95-progressdom.apiary-mock.com/contacts/{id}", method="PUT", statusCode=204)
 */
class ProgressContact extends Contact
{{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    public $contact_id;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    public $email_address;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    public $firstname;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    public $surname;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    public $created_date;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    public $updated_date;

    /**
     * @param mixed $email_address
     */
    public function setEmailAddress($email_address)
    {
        $this->email_address = $email_address;
    }

    /**
     * @param mixed $firstname
     */
    public function setFirstname($firstname)
    {
        $this->firstname = $firstname;
    }

    /**
     * @param mixed $surname
     */
    public function setSurname($surname)
    {
        $this->surname = $surname;
    }

    /**
     * @param mixed $created_date
     */
    public function setCreatedDate($created_date)
    {
        $this->created_date = $created_date;
    }

    /**
     * @param mixed $updated_date
     */
    public function setUpdatedDate($updated_date)
    {
        $this->updated_date = $updated_date;
    }

How can I reproduce it?

Using the bundle with the above annotations.

domgraziano commented 8 years ago

I think I figured out why the fetch method is not working as expected in the case described above. What the bundle's documentation is asserting is that

By using this setting, the driver is performing a lot of magic under the hood:

But I think at this point it should specify that, because the bundle is using Doctrine, what is actually doing, is performing a data retrieving based on the Doctrine methods. In the code above the fetch case expects as return an array of Contacts objects, thus the correspondent findAll() doctrine method is going to fail in my case since the data is structured differently as a simple array of contact objects (eg. the 3rd party API I'm trying to map needs to follow HATEOAS constraint - https://spring.io/understanding/HATEOAS). This explains the krsort() error reported above.

Basically what I suggest is to: 1) Extend the bundle to support HATEOAS, that would probably means change the doctrine methods used. Or 2) Specify in the documentation that the data structure expected by using this bundle is highly coupled with whatever Doctrine methods are doing (Eg. fetch expects array of objects).

TobiasHauck commented 8 years ago

Hey domgrazio, thank you for the detailed information! I think we should support HATEOAS in future, but change the documentation as long as it hasn't been implemented.