1

I'm trying to make an API Rest in Symfony2 using Parse as cloud database.

If I try to retrieve the Parse users it works fine and returns the expected data.

Local url example: http://www.foo.local/app_dev.php/getUsers/

Here is the code I use in the Users controller (I use annotations in order to set the routes in the controller):

namespace Foo\ApiBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\RestBundle\Controller\Annotations\View;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Parse\ParseClient;
use Parse\ParseObject;
use Parse\ParseQuery;
use Parse\ParseUser;

class UsersController extends Controller
{
    /**
    * @return array
    * @View()
    * @Route("/getUsers/")
    */
    public function getUsersAction(Request $request) {
        ParseClient::initialize(<my Parse keys>);

        $query = ParseUser::query();     
        $results = $query->find();

        return array('users' => $results);
    } 
}

However if I try the same with my Products ParseObjects, I get the following error message:

error code="500" message="Internal Server Error" exception class="Doctrine\Common\Annotations\AnnotationException" message="[Semantical Error] The annotation "@returns" in method Parse\ParseFile::getData() was never imported. Did you maybe forget to add a "use" statement for this annotation?"

Local url example: http://www.foo.local/app_dev.php/getProducts/

The Products controller code:

namespace Foo\ApiBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\RestBundle\Controller\Annotations\View;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Parse\ParseClient;
use Parse\ParseObject;
use Parse\ParseQuery;
use Parse\ParseUser;
use Parse\ParseFile;

class ProductsController extends Controller 
{
    /**
     * @return array
     * @View()
     * @Route("/getProducts/")
     */
    public function getProductsAction(Request $request) {
        ParseClient::initialize(<my Parse keys>);

        $query = new ParseQuery("Products");
        $results = $query->find();

        return array('products' => $results);    
    }
}

If instead of returning $results I return other dummy data, like return array('products' => 'fooProducts'), I no longer get the error message.

Also if I make a var_dump of the $results variable, I get the expected array of ParseObjects.

Here is my routing.yml file in case there is something wrong with it:

api:
    resource: "@FooApiBundle/Controller/"
    type:     annotation
    prefix:   /

users:
    type: rest
    resource: Foo\ApiBundle\Controller\UsersController

products:
    type: rest
    resource: Foo\ApiBundle\Controller\ProductsController

By the error message it seems that the problem is related to Doctrine, but since I'm not using it, I don't know exactly how there can be a conflict or how to fix it. Any suggestions?

rfc1484
  • 9,441
  • 16
  • 72
  • 123
  • 2
    Seems they are using the wrong DocBlock `@returns` should be `@return` as far as I know. It seems to bounce between the two throughout the class. – qooplmao Oct 23 '14 at 20:07
  • Agreed with @Qoop, and I have no idea to work around that.. maybe try and put the `use` statements for `Parse` above the rest of the annotation classes? I'm going to make a pull request to fix the DocBlocks – sjagr Oct 23 '14 at 20:15
  • 1
    Try [using this fork](https://github.com/sjagr/parse-php-sdk) and see if it fixes your problem. I've made a pull request to the original devs – sjagr Oct 23 '14 at 20:23
  • Indeed your solution worked, thanks! May be you could create an answer with this solution? – rfc1484 Oct 23 '14 at 20:44

2 Answers2

1

There are a few DocBlock typos of @returns in the Parse\ParseFile class that is causing Doctrine's Annotations class to attempt to identify them as a class. This is not your fault but a bug in the Parse PHP SDK library.

I've made a fix in this commit and submitted a pull request back to the original devs, so it should be a simple matter of eventually running composer update to bring your Parse library to the latest correct version.

You can read more about DocBlock and the part specifically on Annotations here

Here is a copy/paste of the resulting diff for src/Parse/ParseFile.php:

@@ -31,7 +31,7 @@ class ParseFile implements \Parse\Internal\Encodable
   /**
    * Return the data for the file, downloading it if not already present.
    *
-   * @returns mixed
+   * @return mixed
    *
    * @throws ParseException
    */
 @@ -50,7 +50,7 @@ public function getData()
   /**
    * Return the URL for the file, if saved.
    *
-   * @returns string|null
+   * @return string|null
    */
   public function getURL()
   {
 @@ -112,7 +112,7 @@ public function getMimeType()
    * @param string $name The file name on Parse, can be used to detect mimeType
    * @param string $mimeType Optional, The mime-type to use when saving the file
    *
-   * @returns ParseFile
+   * @return ParseFile
    */
   public static function createFromData($contents, $name, $mimeType = null)
   {
 @@ -132,7 +132,7 @@ public static function createFromData($contents, $name, $mimeType = null)
    * @param string $name Filename to use on Parse, can be used to detect mimeType
    * @param string $mimeType Optional, The mime-type to use when saving the file
    *
-   * @returns ParseFile
+   * @return ParseFile
    */
   public static function createFromFile($path, $name, $mimeType = null)
   {
sjagr
  • 15,983
  • 5
  • 40
  • 67
0

The correct way to initialize Parse using Symfony, is on the setContainer method of your controller:

class BaseController extends Controller
{
    ....

    public function setContainer(ContainerInterface $container = null)
    {
        parent::setContainer( $container );
        ParseClient::initialize( $app_id, $rest_key, $master_key );
    }
}

Depending of your needs, you can create a BaseController and extend it in your rest of controllers.

class UsersController extends Controller 

In addition, you could add your keys in the parameters.yml file.

parameters:
    #your parameters...
    ParseAppId: your_id
    ParseRestKey: your_rest_key
    ParseMasterKey: your_master_key

TIP: Note you can add have different Parse projects (dev and release version). Add your parameters in your different parameters configuration provides an easy way to handle this issue.

class BaseController extends Controller
{
    ....

    public function setContainer(ContainerInterface $container = null)
    {
        parent::setContainer( $container );
        $app_id = $container->getParameter('ParseAppId');
        $rest_key = $container->getParameter('ParseRestKey');
        $master_key = $container->getParameter('ParseMasterKey');
        ParseClient::initialize( $app_id, $rest_key, $master_key );
    }
}
Rafa0809
  • 1,733
  • 21
  • 24