【问题标题】:FOSRestBundle and JMS Serializer, error when geting JSONFOSRestBundle 和 JMS 序列化器,获取 JSON 时出错
【发布时间】:2013-04-23 15:31:40
【问题描述】:

我一直在尝试 Symfony 2.2、FOSRest Bundle(使用 JMS Serializer)和使用 MongoDB 的 Doctrine ODM。

经过数小时试图弄清楚如何正确设置 FOSRest Bundle 后,我仍然遇到了一些麻烦:我有一个非常简单的路线,可以返回产品和价格列表。 每当我请求 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);
    }
}

这是从控制器 Resources/Product/get.html.twig 调用的视图:

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

任何想法为什么这对一种格式可以正常工作而其他格式不能正常工作?我应该设置什么额外的东西吗?

更新: 这是我一直在使用的配置值。 在 app/config/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;

我开始以正确的格式获取结果。这是一种蹩脚的解决方案,仍然希望找到更好的解决方案。

【问题讨论】:

  • 不需要循环。 Doctrine ODM find* 方法返回 Cursor。您可以在Cursor 上致电toArray

标签: php mongodb symfony doctrine-odm fosrestbundle


【解决方案1】:

如果您想获取 RestApiBundle:Product 文档的集合,您必须在从存储库调用 find 方法或从查询构建器调用 getQuery 方法后调用方法“toArray”

/**
 * @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($products) 来正确序列化排除策略

【讨论】:

    【解决方案2】:

    错误很可能出在您的配置文件中,或者可能没有?添加您的配置,如果可以,我将更新我的答案。

    现在我将引导您完成一个简单的实现。

    首先让我们从配置开始:

    注意:我将为某些设置使用注释,请参阅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,
            );
        }
    }
    

    这是一个简单的控制器,它将返回所有内容。

    希望这会有所帮助。我认为您的错误来自与序列化程序相关的错误设置。确保您公开一些数据。

    【讨论】:

    • 非常感谢您的详细回答,我的设置与您在此处描述的设置非常相似。尽管你和我之间的一个区别是我将 Doctrine ODM 与 MongoDB 一起使用。我尝试对 Doctrine ORM 实体做同样的事情,它立即工作。这可能是序列化程序中的错误吗?我在您的设置和 ODM 中发现的一件有趣的事情是 HTML 格式停止工作,我得到“无法找到模板”。 '什么???对于 json 和 xml,我仍然收到与以前相同的错误消息。
    • 其实我认为 HTML 格式不起作用的注释...我错过了控制器中的注释 @Rest\View() :P 其他一切都保持不变。
    猜你喜欢
    • 2016-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    • 2021-09-02
    • 2017-05-10
    • 1970-01-01
    相关资源
    最近更新 更多