在 Symfony 中,我正在为 Angular2 编写一个 API。我将 FOSRestBundle 与 JMSSerializerBundle 一起使用。现在,我有一个实体“用户”,它有一个带有 OneToOne 关联的实体字段“地址”。而且我无法保存用户的地址。
所以我首先对用户对象进行 GET,它返回整个对象,地址为 json。然后我用那个完全相同的对象做 PUT 请求。在我的 PUT 函数中,我使用 Symfony 表单来验证数据并返回错误:
{
"children": {
"address": {
"errors": [
"This value is not valid."
]
}
}
}
我的用户实体上有一些其他字段,当我在表单构建器中省略地址字段时,这些字段被完美保存。顺便说一句:我省略了其他字段,以免代码量过多。
我使用这些版本:
- 交响乐:3.1
- jms/序列化器:1.1
- Friendsofsymfony/rest-bundle: 2.0
我一直在寻找 2 天,但我找不到任何可以帮助我解决这个问题的东西。我使用像FOSRestBundle这样的日期转换说:http ://symfony.com/doc/current/bundles/FOSRestBundle/2-the-view-layer.html#data-transformation
我希望我的问题足够好,并提供了足够的信息。
这是我的简化代码:
用户等级:
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
/**
* @ORM\Entity
*/
class User
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\OneToOne(targetEntity="Address", cascade={"persist", "remove"}, orphanRemoval=true)
* @JMS\Type("AppBundle\Entity\Address")
*/
private $address;
地址类:
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Address
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string")
*/
private $street;
/**
* @ORM\Column(type="string")
*/
private $number;
/**
* @ORM\Column(type="string")
*/
private $postalCode;
/**
* @ORM\Column(type="string")
*/
private $city;
/**
* @ORM\Column(type="string")
*/
private $country;
用户类型类:
use FOS\RestBundle\Form\Transformer\EntityToIdObjectTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Data transformation needed for relationship entities
$addressTransformer = new EntityToIdObjectTransformer($options['em'], 'AppBundle:Address');
$builder
->add($builder->create('address', TextType::class)->addModelTransformer($addressTransformer))
;
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\User',
'csrf_protection' => false,
'allow_extra_fields' => true,
'em' => null
));
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'user';
}
}
用户控制器类:
use AppBundle\Entity\User;
use AppBundle\Form\UserType;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
/**
* Class UserController
* @package AppBundle\Controller
*/
class UserController extends Controller
{
/**
* @Rest\View
* @Route("/users/{id}")
* @Method("PUT")
*/
public function putAction(Request $request, $id)
{
$user = $this->getEntity($id);
$form = $this->createForm(UserType::class, $user, array(
'method' => 'PUT',
'em' => $this->getDoctrine()->getManager()
));
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$response = new Response();
$response->setStatusCode(204);
$response->setContent('User saved!');
return $response;
}
return View::create($form, 400);
}
/**
* @Rest\View
* @Route("/users/{id}", requirements={"id": "\d+"})
* @Method("GET")
*/
public function getAction($id)
{
$user = $this->getEntity($id);
return array('user' => $user);
}
/**
* Get the User entity object by the given ID and return it
*
* @param $id
*
* @return User
*/
private function getEntity($id)
{
$user = $this->getDoctrine()->getRepository('AppBundle:User')->find($id);
if (!$user instanceof User) {
throw new NotFoundHttpException('User not found');
}
return $user;
}
我 GET 和 PUT 的 json-object 看起来像这样:
{
"user":
{
"id":1,
"address": {
"id":1,
"street":"Teststreet",
"number":"1",
"postalCode":"9999",
"city":"Citytest",
"country":"Countrytest"
}
}
}
我的 config.yml:
fos_rest:
param_fetcher_listener: true
body_listener:
array_normalizer: fos_rest.normalizer.camel_keys
format_listener:
rules:
path: ^/
fallback_format: json
prefer_extension: false
priorities: [json, xml]
body_converter:
enabled: false
validate: false
view:
view_response_listener: force
formats:
json: true
xml: true
templating_formats:
html: true
force_redirects:
html: true
failed_validation: HTTP_BAD_REQUEST
default_engine: twig
mime_types:
json: ['application/json', 'application/json;version=1.0', 'application/json;version=1.1']
routing_loader:
default_format: json
serializer:
serialize_null: true
nelmio_api_doc: ~
jms_serializer:
metadata:
directories:
FOSUB:
namespace_prefix: "FOS\\UserBundle"
path: "%kernel.root_dir%/serializer/FOSUserBundle"