FOSRestBundle and JMS Serializer, error getting JSON

I tested Symfony 2.2, FOSRest Bundle (using JMS Serializer) and Doctrine ODM using MongoDB.

After many hours of trying to figure out how to properly configure the FOSRest package, I still have problems: I have a very simple route that returns a list of products and prices. Whenever I request the HTML format, I get the correct answer, but if I request any other format (JSON, XML), I get the error message:

[{"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 message here

My current setup is very simple: I created one route to the controller, which returns a list of products and price (I followed in this example to create a 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 Resources / Product / get.html.twig controller:

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

Any ideas why this will work correctly for one format, but not for others? Anything else I need to set up?

UPDATE: These are the configuration values ​​that I used. At the end of app / config / config.yml, I had the following:

 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:

After doing some more research, I came across another error that led me to these questions and answered:

stack overflow

Once I got rid of Doctrine\ODM\MongoDB\LoggableCursor , adding each result to an array like this:

 $productsQ = $dm->getRepository('RestApiBundle:Product')->findAll(); foreach ($productsQ as $product) { $products[] = $product; } return $products; 

I started to get the results in the correct format. This is a kind of lame solution and still hopes to find a better answer to this question.

+4
source share
2 answers

If you want to get a RestApiBundle: Product document collision, you MUST call the "toArray" method after calling the find method from the repository or the getQuery method from the 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; } 

you can also call array_values ​​($ products) to properly serialize the exception strategy

+5
source

Most likely, the error lies somewhere in your configuration files or, perhaps, is missing? Add your configs, and if I can update my answer.

For now, I'll walk you through a simple implementation.

First, start with the configs:

Note. I will use annotations for some parameters, see SensioFrameworkExtraBundle .

 #app/config/config.yml sensio_framework_extra: view: annotations: false fos_rest: param_fetcher_listener: true body_listener: true format_listener: true view: view_response_listener: 'force' 

First we set up the optional sensio kit. default config allows annotations to set to true. I have disabled annotations for presentation (I will not use them here).

For fos_rest, we create Listeners , we save it simply, so we are going to use this example from our documents.

We will create an object:

 <?php namespace Demo\DataBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints; use JMS\Serializer\Annotation\ExclusionPolicy; //Ver 0.11+ the namespace has changed from JMS\SerializerBundle\* to JMS\Serializer\* use JMS\Serializer\Annotation\Expose; //Ver 0.11+ the namespace has changed from JMS\SerializerBundle\* to JMS\Serializer\* /** * Demo\DataBundle\Entity\Attributes * * @ORM\Table() * @ORM\Entity(repositoryClass="Demo\DataBundle\Entity\AttributesRepository") * * @ExclusionPolicy("all") */ class Attributes { /** * @var integer $id * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") * * @Expose */ private $id; /** * @var string $attributeName * * @ORM\Column(name="attribute_name", type="string", length=255) * * @Expose */ private $attributeName; /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set attributeName * * @param string $attributeName * @return Attributes */ public function setAttributeName($attributeName) { $this->attributeName = $attributeName; return $this; } /** * Get attributeName * * @return string */ public function getAttributeName() { return $this->attributeName; } } 

You will notice a couple of annotation settings. First we set @ExclusionPolicy ("all"), then manually set which object we want to use @Expose for the API. You can find out about it here and the JMS Serializer annotation list.

Now let's move on to a simple controller:

 <?php namespace Demo\DataBundle\Controller; use FOS\RestBundle\Controller\FOSRestController; use FOS\RestBundle\Controller\Annotations as Rest; //Lets use annotations for our FOSRest config use FOS\RestBundle\Routing\ClassResourceInterface; use FOS\Rest\Util\Codes; use Symfony\Component\HttpFoundation\Request; use Demo\DataBundle\Entity\Attributes; class AttributesController extends FOSRestController implements ClassResourceInterface { /** * Collection get action * @var Request $request * @return array * * @Rest\View() */ public function cgetAction(Request $request) { $em = $this->getDoctrine()->getManager(); $entities = $em->getRepository('DemoDataBundle:Attributes')->findAll(); return array( 'entities' => $entities, ); } } 

This is a simple controller that will return everything.

Hope this helps. I think your error comes from a bad setup related to Serializer. Make sure you show some data.

+2
source

All Articles