Dans Symfony, j'écris une API pour Angular2. J'utilise le FOSRestBundle avec le JMSSerializerBundle. Maintenant, j'ai une entité "Utilisateur" qui a un champ d'entité "adresse" avec une association OneToOne. Et j'ai du mal à enregistrer l'adresse de l'utilisateur.Symfony REST api - Champ d'association d'entité -> valeur non valide
Donc, je fais d'abord un GET de l'objet utilisateur et il renvoie l'objet entier avec l'adresse en json. Ensuite, je fais PUT demande avec ce même objet même. Dans ma fonction PUT-je utiliser un formulaire Symfony pour valider les données et là, il renvoie une erreur:
{
"children": {
"address": {
"errors": [
"This value is not valid."
]
}
}
}
J'ai d'autres domaines sur mon entité utilisateur et ceux sont enregistrés parfaitement quand je quitte le champ d'adresse dans mon constructeur de formulaire. BTW: J'ai omis ces autres champs pour ne pas surcharger la quantité de code.
-je utiliser ces versions:
- symfony: 3.1
- jms/sérialiseur: 1.1
- friendsofsymfony/repos paquet: 2,0
J'ai cherché pendant 2 jours maintenant et je ne peux pas trouver quelque chose qui m'aide avec cette question. J'utilise les transformations de date comme FOSRestBundle dit: http://symfony.com/doc/current/bundles/FOSRestBundle/2-the-view-layer.html#data-transformation
J'espère avoir formulé ma question assez bon et donné assez d'informations.
Voici mon code simplifié:
classe User:
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;
Adresse Classe:
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;
classe UserType:
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';
}
}
classe UserController:
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("https://stackoverflow.com/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("https://stackoverflow.com/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;
}
Et le JSON-objet que je GET et PUT ressemble à ceci:
{
"user":
{
"id":1,
"address": {
"id":1,
"street":"Teststreet",
"number":"1",
"postalCode":"9999",
"city":"Citytest",
"country":"Countrytest"
}
}
}
mon 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"