Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FOSRestBundle and JMS Serializer, error when geting JSON

I have been trying out Symfony 2.2, the FOSRest Bundle (using JMS Serializer), and Doctrine ODM using MongoDB.

After many hours of trying to figure out how to correctly setup the FOSRest Bundle I'm still having some trouble: I have a very simple route that returns a list of products and prices. Whenever I request for the HTML format I get the correct response, but if I request any other format (JSON, XML) I get an error:

[{"message": "Resources are not supported in serialized data. Path: Monolog\\Handler\\StreamHandler -> Symfony\\Bridge\\Monolog\\Logger -> Doctrine\\Bundle\\MongoDBBundle\\Logger\\Logger -> Doctrine\\Bundle\\MongoDBBundle\\Logger\\AggregateLogger -> Doctrine\\ODM\\MongoDB\\Configuration -> Doctrine\\MongoDB\\Connection -> Doctrine\\ODM\\MongoDB\\LoggableCursor",
    "class": "JMS\\Serializer\\Exception\\RuntimeException",...

you can see the full error message here

My current setup is very simple: I have created a single route to a controller that returns a list of products and the price (I followed this example to create the product document).

This is the route:

rest_product:
    type: rest
    resource: Onema\RestApiBundle\Controller\ProductController

This is the controller:

<?php
namespace Onema\RestApiBundle\Controller;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Routing\ClassResourceInterface;
use FOS\Rest\Util\Codes;
use JMS\Serializer\SerializationContext;
use Onema\RestApiBundle\Document\Product;

class ProductController extends FOSRestController implements ClassResourceInterface
{
    public function getAction()
    {
        $dm = $this->get('doctrine_mongodb')->getManager();
        $products = $dm->getRepository('RestApiBundle:Product')->findAll();

        if(!$products)
        {
            throw $this->createNotFoundException('No product found.');
        }

        $data = array('documents' => $products);         
        $view = $this->view($data, 200);
        $view->setTemplate("RestApiBundle:Product:get.html.twig");
        return $this->handleView($view);
    }
}

This is the view called from the controller Resources/Product/get.html.twig:

<ul>
{% for document in documents %}
<li>
    {{ document.name }}<br />
    {{ document.price }}
</li>
{% endfor %}
</ul>

Any ideas why this would work correctly for one format but not the others? Anything additional I'm supposed to setup?

UPDATE: This is the config values I have been using. At the end of app/config/config.yml I had this:

sensio_framework_extra:
    view:    { annotations: false }
    router:  { annotations: true }

fos_rest:
    param_fetcher_listener: true
    body_listener: true
    format_listener: true
    view:
        formats:
            json: true
        failed_validation: HTTP_BAD_REQUEST
        default_engine: twig
        view_response_listener: 'force'

WORKAROUND:

Doing a bit more research I ran into another error which lead me to this questions and answer:

https://stackoverflow.com/a/14030646/155248

Once I got rid of the Doctrine\ODM\MongoDB\LoggableCursor by adding every result to an array like this:

$productsQ = $dm->getRepository('RestApiBundle:Product')->findAll();

foreach ($productsQ as $product) {
    $products[] = $product;
}

return $products;

I started getting the results in the correct format. This is kind of a lame solution and still hope to find a better answer to this issue.

like image 463
Onema Avatar asked Feb 17 '23 17:02

Onema


1 Answers

If you want to get a colection of RestApiBundle:Product documents, you MUST call the method "toArray" after calling find method from repository or getQuery method from query builder

/**
 * @Route("/products.{_format}", defaults={"_format" = "json"})
 * @REST\View()
 */
public function getProductsAction($_format){
    $products = $this->get('doctrine_mongodb')->getManager()
        ->getRepository('RestApiBundle:Product')
        ->findAll()->toArray();

    return $products;
}

also you can call array_values($products) for correct serialization of exclude strategy

like image 85
BattleBit Avatar answered Feb 22 '23 02:02

BattleBit