2013-04-23 36 views
4

我一直在試用Symfony 2.2,FOSRest Bundle(使用JMS串行器)和Doctrine ODM使用MongoDB。FOSRestBundle和JMS串行器,在創建JSON時出錯

經過很多小時的試圖弄清楚如何正確設置FOSRest軟件包,我仍然遇到了一些麻煩:我有一個非常簡單的路線,返回產品和價格列表。 每當我要求爲HTML格式,我得到了正確的反應,但如果我請求任何其他格式(JSON,XML)我得到一個錯誤:

[{"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",... 

,你可以看到完整的錯誤信息here

我目前的設置非常簡單:我創建了一條返回控制器的路線,返回產品列表和價格(我遵循this example來創建產品文檔)。

這是路線:

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

這是控制器:

<?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); 
    } 
} 

這是從控制器資源/產品/ get.html.twig稱爲視圖:

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

任何想法,爲什麼這將工作正確的一種格式,但不是其他人?還有什麼額外的我應該設置?

更新: 這是我一直在使用的配置值。 在應用程序/配置/ config.yml結束時,我有這樣的:

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' 

解決方法:

做更多的研究,我遇到了另一個錯誤,導致我這個問題和答案:

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

一旦我被每個結果加入一個這樣的數組擺脫Doctrine\ODM\MongoDB\LoggableCursor的:

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

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

return $products; 

我開始以正確的格式獲得結果。這是一種蹩腳的解決方案,但仍希望能找到更好的解決方案。

+2

無需循環。 Doctrine ODM'find *'方法返回一個'Cursor'。你可以在'Cursor'上調用'toArray'。 – Entea 2013-06-27 05:29:25

回答

2

最有可能的錯誤在於你的配置文件或可能缺乏?添加你的配置,如果我可以,我會更新我的答案。

現在,我會引導你通過一個簡單的實現。

首先讓我們開始與CONFIGS:

注:我將使用註解的某些設置看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' 

首先我們設置sensio extra bundle。 default config使註釋設置爲true。我禁用了視圖的註釋(我不會在這裏使用它們)。

對於fos_rest,我們正在設置Listeners,我們保持簡單,因此我們將使用他們的文檔中的示例。

我們將創建實體:

<?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; 
    } 
} 

你會發現一對夫婦的註釋設置。首先我們設置@ExclusionPolicy(「all」),然後我們手動設置我們想要@Expose到API的對象。你可以找到更多關於這個hereJMS Serializer annotations

列表現在讓我們討論一個簡單的控制器:

<?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, 
     ); 
    } 
} 

這是一個簡單的控制器,將返回的一切。

希望這有助於。我認爲你的錯誤來自與串行器相關的糟糕設置。確保你公開一些數據。

+0

比你對於你的詳細答案如此之多,我的設置與你在這裏描述的設置非常相似。儘管你和我的區別在於我在MongoDB中使用Doctrine ODM。我試圖用一個Doctrine ORM實體做同樣的事情,它馬上就可以工作。這可能是序列化程序中的一個錯誤嗎?我發現你的設置和ODM的一個有趣的事情是格式HTML停止工作,我得到'無法找到模板'「。 'WTH?對於json和xml,我仍然會得到和以前一樣的錯誤消息。 – Onema 2013-04-28 16:05:57

+0

實際上,我採取HTML格式的評論不工作......我錯過了控制器中的@Rest \ View()註釋:P其他所有內容保持不變。 – Onema 2013-04-28 16:31:42

5

如果你想獲得RestApiBundle的保藏:產品文檔,則必須從倉庫或getQuery方法調用find方法從查詢生成器

/** 
* @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; 
} 

也可以撥打array_values後調用方法「指定者」( $產品)正確的序列化排除策略