Symfony 和 Wildurand/Hateoas Bundle - JSON 响应中没有链接
Symfony and Wildurand/Hateoas Bundle - no links on JSON reposnse
我正在使用 FOSRest 和 Willdurand/Hateoas 捆绑包。
我遵循以下示例
https://github.com/willdurand/Hateoas#configuring-links
但是 JSON 响应中没有 "links" 字段。
/**
* Users
*
* @ORM\Table(name="users")
* @ORM\Entity
* @Serializer\ExclusionPolicy("ALL")
* @Hateoas\Relation("self", href="expr('/users' ~ object.getId())")
*/
class User
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
* @Serializer\Groups({"Default", "Deserialize"})
* @Serializer\Expose()
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=30)
* @Assert\NotBlank()
* @Assert\Length(max="30", min="5")
* @Serializer\Groups({"Default", "Deserialize"})
* @Serializer\Expose()
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="email", type="string", length=30)
* @Assert\NotBlank()
* @Assert\Email()
* @Assert\Length(max="30")
* @Serializer\Groups({"Default", "Deserialize"})
* @Serializer\Expose()
*/
private $email;
/**
* @var string
*
* @ORM\Column(name="username", type="string", length=15)
* @Assert\NotBlank()
* @Assert\Length(max="15", min="3")
* @Serializer\Groups({"Default", "Deserialize"})
* @Serializer\Expose()
*/
private $username;
/**
* @var string
*
* @ORM\Column(name="password", type="string", length=32)
* @Assert\NotBlank()
*/
private $password;
/**
* @var string
*
* @ORM\Column(name="active", type="boolean", length=32)
* @Serializer\Groups({"Default", "Deserialize"})
* @Serializer\Expose()
*/
private $active = true;
/**
* @var ArrayCollection
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Role", inversedBy="user")
* @Serializer\Expose()
*/
private $roles;
public function __construct()
{
$this->roles = new ArrayCollection();
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* @param string $email
*/
public function setEmail($email)
{
$this->email = $email;
}
/**
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* @param string $username
*/
public function setUsername($username)
{
$this->username = $username;
}
/**
* @return string
*/
public function getPassword()
{
return $this->password;
}
/**
* @param string $password
*/
public function setPassword($password)
{
$this->password = $password;
}
/**
* @return string
*/
public function getActive()
{
return $this->active;
}
/**
* @param string $active
*/
public function setActive($active)
{
$this->active = $active;
}
/**
* @return Collection
*/
public function getRoles()
{
return $this->roles;
}
/**
* @param ArrayCollection $roles
*/
public function setRoles($roles)
{
$this->roles = $roles;
}
}
主要是我想向 Roles 实体显示一个 link,但也许更容易找出导致 SELF link 问题的原因,然后继续进一步。
这里是配置
fos_rest:
routing_loader:
default_format: json
include_format: false
view:
view_response_listener: 'force'
body_converter:
enabled: true
validate: true
validation_errors_argument: validationErrors
param_fetcher_listener: true
exception:
enabled: true
exception_controller: 'AppBundle\Controller\ExceptionController::showAction'
serializer:
groups: ['Default']
sensio_framework_extra:
view:
annotations: true
request:
converters: true
这个配置很好,意味着所有端点都可以正常工作,除了没有 link。
此时,我在 GET 请求
上收到此响应
[
{
"id": 1,
"name": "Test name",
"email": "test@email.com",
"username": "toskadv",
"active": true
},
{
"id": 2,
"name": "Test name",
"email": "test@email.com",
"username": "toskadv",
"active": true
},
{
"id": 3,
"name": "Test name",
"email": "test@email.com",
"username": "toskadv",
"active": true,
"roles": {
"id": 1,
"name": "ROLE_USER"
}
}
]
还有控制器数据。
/**
* Class UsersController
* @package AppBundle\Controller
*/
class UsersController extends AbstractController
{
use ControllerTrait;
/**
* @Rest\View()
*/
public function getUsersAction()
{
$users = $this->getDoctrine()->getRepository('AppBundle:User')->findAll();
return $users;
}
/**
* @param User $user
* @param ConstraintViolationListInterface $validationErrors
*
* @Rest\View(statusCode=201)
* @ParamConverter("user", converter="fos_rest.request_body")
* @Rest\NoRoute()
*
* @return User $user
*/
public function postUsersAction(User $user, ConstraintViolationListInterface $validationErrors)
{
if (count($validationErrors) > 0) {
throw new ValidationException($validationErrors);
}
$em = $this->getDoctrine()->getManager();
$role = $em->getRepository('AppBundle:Role')->find(1);
$user->setRoles($role);
$em->persist($user);
$em->flush();
return $user;
}
/**
* @param User|null $user
*
* @Rest\View()
*/
public function deleteUserAction(User $user = null) {
if (null === $user) {
return $this->view(null, 404);
}
$em = $this->getDoctrine()->getManager();
$em->remove($user);
$em->flush();
}
/**
* @param User $user
* @return User|\FOS\RestBundle\View\View|null
*
* @Rest\View()
*/
public function getUserAction(User $user)
{
if (null === $user) {
return $this->view(null, 404);
}
return $user;
}
/**
* @param Role $role
* @return Role|\FOS\RestBundle\View\View
*
* @Rest\View()
*/
public function getRoleAction(Role $role)
{
if (null === $role) {
return $this->view(null, 404);
}
return $role;
}
/**
* @param User $user
* @return \Doctrine\Common\Collections\Collection
*
* @Rest\View()
*/
public function getUserRolesAction(User $user)
{
return $user->getRoles();
}
/**
* @param User $user
* @param Role $role
* @param ConstraintViolationListInterface $validationErrors
*
* @Rest\View(statusCode=201)
* @ParamConverter("role", converter="fos_rest.request_body", options={"deserializationContext"={"groups"={"Deserialize"}}})
* @Rest\NoRoute()
*
* @return Role
*/
public function postUserRolesAction(User $user, Role $role, ConstraintViolationListInterface $validationErrors)
{
if (count($validationErrors) > 0) {
throw new ValidationException($validationErrors);
}
$role->setUser($user);
$em = $this->getDoctrine()->getManager();
$user->getRoles()->add($role);
$em->persist($user);
$em->flush();
return $role;
}
}
问题是您 return 实体,您需要从序列化程序传递以获得 hateoas 链接。
像这样:
我用jsm_serializer
$serializer = $this->get('jms_serializer');
return new Response(
$serializer->serialize(
$users,
'json',
SerializationContext::create()->enableMaxDepthChecks()
),
201
);
而不是这个:
return $users;
真丢脸:/
问题出在第一步,
我只是没有在 AppKernel.php
中包含捆绑包
new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(),
这是一个缺失的行。没有借口。
我正在使用 FOSRest 和 Willdurand/Hateoas 捆绑包。 我遵循以下示例 https://github.com/willdurand/Hateoas#configuring-links
但是 JSON 响应中没有 "links" 字段。
/**
* Users
*
* @ORM\Table(name="users")
* @ORM\Entity
* @Serializer\ExclusionPolicy("ALL")
* @Hateoas\Relation("self", href="expr('/users' ~ object.getId())")
*/
class User
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
* @Serializer\Groups({"Default", "Deserialize"})
* @Serializer\Expose()
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=30)
* @Assert\NotBlank()
* @Assert\Length(max="30", min="5")
* @Serializer\Groups({"Default", "Deserialize"})
* @Serializer\Expose()
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="email", type="string", length=30)
* @Assert\NotBlank()
* @Assert\Email()
* @Assert\Length(max="30")
* @Serializer\Groups({"Default", "Deserialize"})
* @Serializer\Expose()
*/
private $email;
/**
* @var string
*
* @ORM\Column(name="username", type="string", length=15)
* @Assert\NotBlank()
* @Assert\Length(max="15", min="3")
* @Serializer\Groups({"Default", "Deserialize"})
* @Serializer\Expose()
*/
private $username;
/**
* @var string
*
* @ORM\Column(name="password", type="string", length=32)
* @Assert\NotBlank()
*/
private $password;
/**
* @var string
*
* @ORM\Column(name="active", type="boolean", length=32)
* @Serializer\Groups({"Default", "Deserialize"})
* @Serializer\Expose()
*/
private $active = true;
/**
* @var ArrayCollection
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Role", inversedBy="user")
* @Serializer\Expose()
*/
private $roles;
public function __construct()
{
$this->roles = new ArrayCollection();
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* @param string $email
*/
public function setEmail($email)
{
$this->email = $email;
}
/**
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* @param string $username
*/
public function setUsername($username)
{
$this->username = $username;
}
/**
* @return string
*/
public function getPassword()
{
return $this->password;
}
/**
* @param string $password
*/
public function setPassword($password)
{
$this->password = $password;
}
/**
* @return string
*/
public function getActive()
{
return $this->active;
}
/**
* @param string $active
*/
public function setActive($active)
{
$this->active = $active;
}
/**
* @return Collection
*/
public function getRoles()
{
return $this->roles;
}
/**
* @param ArrayCollection $roles
*/
public function setRoles($roles)
{
$this->roles = $roles;
}
}
主要是我想向 Roles 实体显示一个 link,但也许更容易找出导致 SELF link 问题的原因,然后继续进一步。
这里是配置
fos_rest:
routing_loader:
default_format: json
include_format: false
view:
view_response_listener: 'force'
body_converter:
enabled: true
validate: true
validation_errors_argument: validationErrors
param_fetcher_listener: true
exception:
enabled: true
exception_controller: 'AppBundle\Controller\ExceptionController::showAction'
serializer:
groups: ['Default']
sensio_framework_extra:
view:
annotations: true
request:
converters: true
这个配置很好,意味着所有端点都可以正常工作,除了没有 link。
此时,我在 GET 请求
上收到此响应[
{
"id": 1,
"name": "Test name",
"email": "test@email.com",
"username": "toskadv",
"active": true
},
{
"id": 2,
"name": "Test name",
"email": "test@email.com",
"username": "toskadv",
"active": true
},
{
"id": 3,
"name": "Test name",
"email": "test@email.com",
"username": "toskadv",
"active": true,
"roles": {
"id": 1,
"name": "ROLE_USER"
}
}
]
还有控制器数据。
/**
* Class UsersController
* @package AppBundle\Controller
*/
class UsersController extends AbstractController
{
use ControllerTrait;
/**
* @Rest\View()
*/
public function getUsersAction()
{
$users = $this->getDoctrine()->getRepository('AppBundle:User')->findAll();
return $users;
}
/**
* @param User $user
* @param ConstraintViolationListInterface $validationErrors
*
* @Rest\View(statusCode=201)
* @ParamConverter("user", converter="fos_rest.request_body")
* @Rest\NoRoute()
*
* @return User $user
*/
public function postUsersAction(User $user, ConstraintViolationListInterface $validationErrors)
{
if (count($validationErrors) > 0) {
throw new ValidationException($validationErrors);
}
$em = $this->getDoctrine()->getManager();
$role = $em->getRepository('AppBundle:Role')->find(1);
$user->setRoles($role);
$em->persist($user);
$em->flush();
return $user;
}
/**
* @param User|null $user
*
* @Rest\View()
*/
public function deleteUserAction(User $user = null) {
if (null === $user) {
return $this->view(null, 404);
}
$em = $this->getDoctrine()->getManager();
$em->remove($user);
$em->flush();
}
/**
* @param User $user
* @return User|\FOS\RestBundle\View\View|null
*
* @Rest\View()
*/
public function getUserAction(User $user)
{
if (null === $user) {
return $this->view(null, 404);
}
return $user;
}
/**
* @param Role $role
* @return Role|\FOS\RestBundle\View\View
*
* @Rest\View()
*/
public function getRoleAction(Role $role)
{
if (null === $role) {
return $this->view(null, 404);
}
return $role;
}
/**
* @param User $user
* @return \Doctrine\Common\Collections\Collection
*
* @Rest\View()
*/
public function getUserRolesAction(User $user)
{
return $user->getRoles();
}
/**
* @param User $user
* @param Role $role
* @param ConstraintViolationListInterface $validationErrors
*
* @Rest\View(statusCode=201)
* @ParamConverter("role", converter="fos_rest.request_body", options={"deserializationContext"={"groups"={"Deserialize"}}})
* @Rest\NoRoute()
*
* @return Role
*/
public function postUserRolesAction(User $user, Role $role, ConstraintViolationListInterface $validationErrors)
{
if (count($validationErrors) > 0) {
throw new ValidationException($validationErrors);
}
$role->setUser($user);
$em = $this->getDoctrine()->getManager();
$user->getRoles()->add($role);
$em->persist($user);
$em->flush();
return $role;
}
}
问题是您 return 实体,您需要从序列化程序传递以获得 hateoas 链接。
像这样:
我用jsm_serializer
$serializer = $this->get('jms_serializer');
return new Response(
$serializer->serialize(
$users,
'json',
SerializationContext::create()->enableMaxDepthChecks()
),
201
);
而不是这个:
return $users;
真丢脸:/
问题出在第一步, 我只是没有在 AppKernel.php
中包含捆绑包new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(),
这是一个缺失的行。没有借口。