4

私は Symfony 2.2、FOSRest バンドル (JMS シリアライザーを使用)、および 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",...

ここで完全なエラーメッセージを見ることができます

現在の設定は非常に単純です。製品のリストと価格を返すコントローラーへのルートを 1 つ作成しました (この例に従って製品ドキュメントを作成しました)。

これはルートです:

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>

これが 1 つの形式では正しく機能し、他の形式では機能しない理由はありますか? セットアップすることになっている追加の何かはありますか?

更新: これは私が使用している構成値です。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;

結果を正しい形式で取得し始めました。これは一種の不十分な解決策であり、この問題に対するより良い答えを見つけることを望んでいます.

4

2 に答える 2

6

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) を呼び出すこともできます

于 2013-10-16T14:30:05.830 に答える
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 をセットアップします。デフォルトの構成では、注釈が 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") を設定してから、API に @Expose するオブジェクトを手動で設定します。詳細については、こちらJMS シリアライザー アノテーションのリストをご覧ください。

次に、単純なコントローラーに移りましょう。

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

これは、すべてを返す単純なコントローラーです。

うまくいけば、これは役に立ちました。あなたのエラーは、シリアライザーに関連する悪い設定から来ていると思います。いくつかのデータを公開していることを確認してください。

于 2013-04-26T07:14:38.887 に答える