Symfony2 FOSRESTBundle序列化实体数组到JSON

Symfony2 FOSRESTBundle serialization entity array to JSON

我在尝试序列化 JSON 中的实体数组 Game 时遇到问题。 我一开始就有一个循环引用异常,我设法修复了它(但也许我的解决方案是问题的根源)。

目前我的请求 /games return 一个有效的 JSON 数组,但在浏览器中没有正确显示,应用程序无法解析它。 Chrome return 我出现以下错误:

Resource interpreted as Document but transferred with MIME type application/json

令人惊讶的是我确实将 Content-Type 发送为 application/json。 完全相同的 headers 用于另一个请求 /players 并且正确显示和解析没有错误。

我在这两个实体之间存在双向关系:游戏和玩家。

实体游戏:

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Game
 *
 * @ORM\Table(name="game")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\GameRepository")
 */
class Game
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\TournamentType", inversedBy="games")
     */
    private $refType;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="TournamentDate", type="date")
     */
    private $tournamentDate;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Ground", inversedBy="games")
     */
    private $ground;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Referee", inversedBy="games")
     */
    private $referee;

    /**
    * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Player", cascade={"persist"})
    */
    private $players;

    /**
     * @var int
     *
     * @ORM\Column(name="NbSetsPlayerOne", type="integer")
     */
    private $nbSetsPlayerOne;

    /**
     * @var int
     *
     * @ORM\Column(name="NbSetsPlayerTwo", type="integer")
     */
    private $nbSetsPlayerTwo;

    /**
    * @var boolean
    * 
    * @ORM\Column(name="IsOver", type="boolean")
    */
    private $isOver;

    public function __construct(){
        $this->players = new \Doctrine\Common\Collections\ArrayCollection();
    }

实体玩家:

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Player
 *
 * @ORM\Table(name="player")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\PlayerRepository")
 */
class Player
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="LastName", type="string", length=255)
     */
    private $lastName;

    /**
     * @var string
     *
     * @ORM\Column(name="FirstName", type="string", length=255)
     */
    private $firstName;

    /**
     * @var string
     *
     * @ORM\Column(name="Sexe", type="string", length=255)
     */
    private $sexe;

    /**
     * @var string
     *
     * @ORM\Column(name="Country", type="string", length=255)
     */
    private $country;

    /**
     * @var int
     *
     * @ORM\Column(name="Ranking", type="integer")
     */
    private $ranking;

    /**
    * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Game", cascade={"persist"})
    */
     private $games;


    public function __construct(){
        $this->games = new \Doctrine\Common\Collections\ArrayCollection();
    }

App/Config/config.yml :

# FOSRestBundle API Configuration
fos_rest:
    format_listener:
        rules:
            - { path: '^/game', priorities: 'json', fallback_format: json, prefer_extension: true }
            - { path: '^/ground', priorities: 'json', fallback_format: json, prefer_extension: true }
            - { path: '^/player', priorities: 'json', fallback_format: json, prefer_extension: true }
            - { path: '^/referee', priorities: 'json', fallback_format: json, prefer_extension: true }
            - { path: '^/tournament-type', priorities: 'json', fallback_format: json, prefer_extension: true }
            - { path: '^/user', priorities: 'json', fallback_format: json, prefer_extension: true }
            - { path: '^/', priorities: 'json', fallback_format: json, prefer_extension: true }

游戏控制器:

/**
 * getGamesAction
 *
 * @Get("/games")
 * 
 * @param Request $request
 * @return type
 */
public function getGamesAction(Request $request) {        
    $games = $this->getDoctrine()->getManager()->getRepository("AppBundle:Game")->findAll();     
    if (count($games) === 0) {
        $view = $this->view("No Game found.", 404);
        return $this->handleView();
    }

    $encoder = new JsonEncoder();
    $normalizer = new ObjectNormalizer();
    $normalizer->setIgnoredAttributes(array('games', 'players'));
    $normalizer->setCircularReferenceHandler(function ($object) {
        return $object->getId();
    });
    $serializer = new Serializer(array($normalizer), array($encoder));
    $data = $serializer->serialize($games, 'json');
    $view = $this->view($data)
                 ->setTemplateVar('games')
                 ->setTemplate($this->template);
    //             ->setHeader('Content-Type', 'application/json; charset=UTF-8');
    return $this->handleView($view);
}

这里是 headers 用来获取 /games :

Cache-Control: no-cache
Connection: close
Content-Type: application/json
Date: Tue, 12 Sep 2017 12:35:45 +0200, Tue, 12 Sep 2017 10:35:45 GMT
Host: localhost:8000
X-Debug-Token: d072dd
X-Debug-Token-Link: http://localhost:8000/app_dev.php/_profiler/d072dd
X-Powered-By: PHP/7.1.1

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Cache-Control: max-age=0
Connection: keep-alive
Cookie: cookieconsent_dismissed=yes; _ga=GA1.1.372052120.1482146348; PHPSESSID=l1fgb45492lr02a6hi10rat7ha
Host: localhost:8000
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0

那些获得 /玩家 :

Cache-Control: no-cache
Connection: close
Content-Type: application/json
Date: Tue, 12 Sep 2017 12:38:18 +0200, Tue, 12 Sep 2017 10:38:18 GMT
Host: localhost:8000
X-Debug-Token: 609af7
X-Debug-Token-Link: http://localhost:8000/app_dev.php/_profiler/609af7
X-Powered-By: PHP/7.1.1

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Connection: keep-alive
Cookie: cookieconsent_dismissed=yes; _ga=GA1.1.372052120.1482146348; PHPSESSID=l1fgb45492lr02a6hi10rat7ha
Host: localhost:8000
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0

您可以访问 /games 呈现的 json 视图示例: JSON shared URL

Application/json 内容类型不正确,所以我设法在计数器中解决手动修复 UTF-8 编码(这是 application/json 的默认编码)和返回的字符串到 JSON 对象。

编码:

$encoder = new JsonEncoder(new JsonEncode(JSON_UNESCAPED_UNICODE), new JsonDecode(false));

转换 JSON 对象中的字符串:

$this->view(json_decode($data, true))

我的控制器方法现在是:

/**
 * getGamesAction
 *
 * @Get("/games")
 * 
 * @param Request $request
 * @return type
 */
public function getGamesAction(Request $request) {        
    $games = $this->getDoctrine()->getManager()->getRepository("AppBundle:Game")->findAll();     
    if (count($games) === 0) {
        $view = $this->view("No Game found.", 404);
        return $this->handleView();
    }

    $encoder = new JsonEncoder(new JsonEncode(JSON_UNESCAPED_UNICODE), new JsonDecode(false));
    $normalizer = new ObjectNormalizer();
    $normalizer->setIgnoredAttributes(array('games', 'players'));
    $normalizer->setCircularReferenceHandler(function ($object) {
        return $object->getId();
    });
    $serializer = new Serializer(array($normalizer), array($encoder));
    $data = $serializer->serialize($games, 'json');
    $view = $this->view(json_decode($data, true))
                 ->setTemplateVar('games')
                 ->setTemplate($this->template)
                 ->setHeader('Content-Type', 'application/json; charset=UTF-8')
                 ->setFormat('json');
    return $this->handleView($view);
}