Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/symfony/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带有FOSRestBundle的Symfony API:已检测到循环引用_Api_Symfony_Serialization_Entity_Fosrestbundle - Fatal编程技术网

带有FOSRestBundle的Symfony API:已检测到循环引用

带有FOSRestBundle的Symfony API:已检测到循环引用,api,symfony,serialization,entity,fosrestbundle,Api,Symfony,Serialization,Entity,Fosrestbundle,我正在进行一个symfony项目,以构建一个rest API,我有4个彼此相关的实体,如下所示: 我安装FOSRestBundle只是为了构建一个GET web服务,当我想要获取资源时,例如: 我得到了这个错误: 消息:“检测到循环引用(已配置 限制:1)。” 这是我的控制器: <?php namespace API\APIBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use

我正在进行一个symfony项目,以构建一个rest API,我有4个彼此相关的实体,如下所示:

我安装FOSRestBundle只是为了构建一个GET web服务,当我想要获取资源时,例如:

我得到了这个错误:

消息:“检测到循环引用(已配置 限制:1)。”

这是我的控制器:

<?php

namespace API\APIBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use FOS\RestBundle\Controller\Annotations as Rest;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Serializer;

class CartographyController extends Controller
{
    /**
     * @Rest\View()
     * @Rest\Get("/posts")
     * @param Request $request
     * @return Response
     */
    public function getPostsAction(Request $request)
    {
        $encoder = new JsonEncoder();
        $normalizer = new GetSetMethodNormalizer();

        $serializer = new Serializer(array($normalizer), array($encoder));
        $posts = $this->get('doctrine.orm.entity_manager')
            ->getRepository('EvalBundle:Post')
            ->findAll();

        return new Response($serializer->serialize($posts, 'json'));

    }

    /**
     * @Rest\View()
     * @Rest\Get("/employments")
     * @param Request $request
     * @return Response
     */
    public function geEmploymentAction(Request $request)
    {
        $encoder = new JsonEncoder();
        $normalizer = new GetSetMethodNormalizer();

        $serializer = new Serializer(array($normalizer), array($encoder));
        $employments = $this->get('doctrine.orm.entity_manager')
            ->getRepository('EvalBundle:Employment')
            ->findAll();
        return new Response($serializer->serialize($employments, 'json'));

    }

    /**
     * @Rest\View()
     * @Rest\Get("/professions")
     * @param Request $request
     * @return Response
     */
    public function geProfessionsAction(Request $request)
    {
        $encoder = new JsonEncoder();
        $normalizer = new GetSetMethodNormalizer();

        $serializer = new Serializer(array($normalizer), array($encoder));
        $professions = $this->get('doctrine.orm.entity_manager')
            ->getRepository('EvalBundle:Profession')
            ->findAll();

        return new Response($serializer->serialize($professions, 'json'));    }

    /**
     * @Rest\View()
     * @Rest\Get("/families")
     * @param Request $request
     * @return Response
     */
    public function geFamiliesAction(Request $request)
    {
        $encoder = new JsonEncoder();
        $normalizer = new GetSetMethodNormalizer();

        $serializer = new Serializer(array($normalizer), array($encoder));
        $families = $this->get('doctrine.orm.entity_manager')
            ->getRepository('EvalBundle:Family')
            ->findAll();

        return new Response($serializer->serialize($families, 'json'));
    }
}
<?php

namespace EvalBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;

/**
 * Family
 *
 * @ORM\Table(name="family")
 * @ORM\Entity(repositoryClass="EvalBundle\Repository\FamilyRepository")
   */
class Family
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

    /**
     * One Family has Many Professions.
     * @ORM\OneToMany(targetEntity="Profession", mappedBy="family",orphanRemoval=true,cascade={"persist", "remove"},fetch="EAGER")
     */
    protected  $professions;



    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Family
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return mixed
     */
    public function getProfessions()
    {
        return $this->professions;
    }

    /**
     * @param mixed $professions
     */
    public function setProfessions($professions)
    {
        $this->professions = $professions;
    }
    public function __toString() {
        return $this->name;
    }
}
<?php

namespace EvalBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Profession
 *
 * @ORM\Table(name="profession")
 * @ORM\Entity(repositoryClass="EvalBundle\Repository\ProfessionRepository")
 */
class Profession
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

    /**
     * Many professions have One Family.
     * @ORM\ManyToOne(targetEntity="Family", inversedBy="professions",cascade={"persist", "remove"})
     */
    public $family;

    /**
     * One Profession has Many Employment.
     * @ORM\OneToMany(targetEntity="Employment", mappedBy="profession",cascade={"persist", "remove"}, orphanRemoval=true,fetch="EAGER")
     */
    private $employments;

    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Profession
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return mixed
     */
    public function getEmployments()
    {
        return $this->employments;
    }

    /**
     * @param mixed $employments
     */
    public function setEmployments($employments)
    {
        $this->employments = $employments;
    }

    /**
     * @return mixed
     */
    public function getFamily()
    {
        return $this->family;
    }

    /**
     * @param mixed $family
     */
    public function setFamily($family)
    {
        $this->family = $family;
    }

    public function __toString() {
        return $this->name;
    }
}
<?php

namespace EvalBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Post
 *
 * @ORM\Table(name="post")
 * @ORM\Entity(repositoryClass="EvalBundle\Repository\PostRepository")
 */
class Post
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

    /**
     * Many Posts have One Employment.
     * @ORM\ManyToOne(targetEntity="Employment", inversedBy="posts", fetch="EAGER")
     * @ORM\JoinColumn(name="employment_id", referencedColumnName="id",nullable=false)
     */
    public $employment;

    /**
     * One Post has Many LevelRequired.
     * @ORM\OneToMany(targetEntity="RequiredLevel", mappedBy="post")
     */
    private $requiredLevels;

    /**
     * One Post has Many PostEvaluation.
     * @ORM\OneToMany(targetEntity="PostEvaluation", mappedBy="post")
     */
    private $postEvaluations;


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Post
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return mixed
     */
    public function getEmployment()
    {
        return $this->employment;
    }


    public function getProfession(){
        return $this->employment->profession;
    }

    public function getFamily(){
        return $this->employment->profession->family;
    }


    /**
     * @param mixed $employment
     */
    public function setEmployment($employment)
    {
        $this->employment = $employment;
    }

    public function __toString() {
        return $this->name;
    }
}
<?php

namespace EvalBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Employment
 *
 * @ORM\Table(name="employment")
 * @ORM\Entity(repositoryClass="EvalBundle\Repository\EmploymentRepository")
 */
class Employment
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

    /**
     * Many Employments have One Profession.
     * @ORM\ManyToOne(targetEntity="Profession", inversedBy="employments",fetch="EAGER")
     */
    public $profession;

    /**
     * One Employment has Many post.
     * @ORM\OneToMany(targetEntity="Post", mappedBy="employment",cascade={"persist", "remove"}, orphanRemoval=true,cascade={"persist", "remove"})
     */
    private $posts;

    /**
     * One Employment has One Grid.
     * @ORM\OneToOne(targetEntity="Grid", mappedBy="employment")
     */
    private $grid;


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Employment
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return mixed
     */
    public function getProfession()
    {
        return $this->profession;
    }

    /**
     * @param mixed $profession
     */
    public function setProfession($profession)
    {
        $this->profession = $profession;
    }

    /**
     * @return mixed
     */
    public function getPosts()
    {
        return $this->posts;
    }

    /**
     * @param mixed $posts
     */
    public function setPosts($posts)
    {
        $this->posts = $posts;
    }

    /**
     * @return mixed
     */
    public function getGrid()
    {
        return $this->grid;
    }

    /**
     * @param mixed $grid
     */
    public function setGrid($grid)
    {
        $this->grid = $grid;
    }
    public function __toString() {
        return $this->name;
    }
}

例如,您可以避免这样的循环引用

$normalizer = new ObjectNormalizer();
$normalizer->setCircularReferenceLimit(1);

$normalizer->setCircularReferenceHandler(function ($object) {
    return $object->getName();
});

$serializer = new Serializer(array($normalizer), array(new JsonEncoder()));
var_dump($serializer->serialize($org, 'json'));
但在您的示例中,您没有对控制器中的视图使用FOSRestBundle。FOSRestController为您提供一个handleView()和一个view()方法。像这样

class CartographyController extends FOSRestController 
{
    public function getPostsAction(Request $request)
    {
        $posts = $this->get('doctrine.orm.entity_manager')
            ->getRepository('EvalBundle:Post')
            ->findAll();
        $view = $this->view($posts, 200);

        return $this->handleView($view);
    }
在这种情况下,serialiser是一个服务,该服务在config.yml中激活:

在你的app/config/config.yml中

framework:
    serializer: { enabled: true }
为了避免循环引用,可以这样做。 在你的app/config/services.yml中

circular_reference_handler:
    public: false
    class: callback
    factory: [AppBundle\Serializer\CircularHandlerFactory, getId]
serializer.normalizer.object:
    class: Symfony\Component\Serializer\Normalizer\ObjectNormalizer
    arguments: ["@serializer.mapping.class_metadata_factory", null, "@serializer.property_accessor"]
    public: false
    tags: [serializer.normalizer]
    calls:
        - method: setCircularReferenceLimit
          arguments: [1]
        - method: setCircularReferenceHandler
          arguments: ["@circular_reference_handler"]
工厂可以是这样的:

namespace AppBundle\Serializer;

class CircularHandlerFactory
{
    /**
     * @return \Closure
     */
    public static function getId()
    {
        return function ($object) {
            return $object->getId();
        };
    }
}
另一个想法是为序列化程序使用组。FosRestBundle给出了一个注释: @Rest\View(serializerGroups={“用户”})

更多信息请点击此处:
例如,您可以避免这样的循环引用

$normalizer = new ObjectNormalizer();
$normalizer->setCircularReferenceLimit(1);

$normalizer->setCircularReferenceHandler(function ($object) {
    return $object->getName();
});

$serializer = new Serializer(array($normalizer), array(new JsonEncoder()));
var_dump($serializer->serialize($org, 'json'));
但在您的示例中,您没有对控制器中的视图使用FOSRestBundle。FOSRestController为您提供一个handleView()和一个view()方法。像这样

class CartographyController extends FOSRestController 
{
    public function getPostsAction(Request $request)
    {
        $posts = $this->get('doctrine.orm.entity_manager')
            ->getRepository('EvalBundle:Post')
            ->findAll();
        $view = $this->view($posts, 200);

        return $this->handleView($view);
    }
在这种情况下,serialiser是一个服务,该服务在config.yml中激活:

在你的app/config/config.yml中

framework:
    serializer: { enabled: true }
为了避免循环引用,可以这样做。 在你的app/config/services.yml中

circular_reference_handler:
    public: false
    class: callback
    factory: [AppBundle\Serializer\CircularHandlerFactory, getId]
serializer.normalizer.object:
    class: Symfony\Component\Serializer\Normalizer\ObjectNormalizer
    arguments: ["@serializer.mapping.class_metadata_factory", null, "@serializer.property_accessor"]
    public: false
    tags: [serializer.normalizer]
    calls:
        - method: setCircularReferenceLimit
          arguments: [1]
        - method: setCircularReferenceHandler
          arguments: ["@circular_reference_handler"]
工厂可以是这样的:

namespace AppBundle\Serializer;

class CircularHandlerFactory
{
    /**
     * @return \Closure
     */
    public static function getId()
    {
        return function ($object) {
            return $object->getId();
        };
    }
}
另一个想法是为序列化程序使用组。FosRestBundle给出了一个注释: @Rest\View(serializerGroups={“用户”})

更多信息请点击此处:

处理实体关系时,循环引用很常见。请参阅:,我认为您必须使用JMSSerializerBundle…在处理实体关系时,循环引用很常见。请看:,我认为您必须使用JMSSerializerBundle…遗憾的是,他们没有关于此类内容的任何文档。这就像“看,我们新的功能齐全的开源工具太棒了,但我们不会告诉任何人如何使用它。”遗憾的是,他们没有类似的文档。这就像“看,我们新的全功能开源工具太棒了,但我们不会告诉任何人如何使用它。”