Configure el registro FOSUserBundle con la API REST FOSRestBundle

Problema solucionado, verifica mi respuesta.

Estoy construyendo un punto final de registro en mi API de descanso Symfony2.7. Estoy usando FosRestBundle y FosUserBundle

Aquí está el modelo de usuario:

<?php namespace AppBundle\Entity; use FOS\UserBundle\Model\User as BaseUser; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="fos_user") */ class User extends BaseUser { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; public function __construct() { parent::__construct(); // your own logic } } 

\ Aquí está el formulario UserType: \

 class UserType extends AbstractType { /** * @param FormBuilderInterface $builder * @param array $options */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('email', 'email') ->add('username', null) ->add('plainPassword', 'repeated', array( 'type' => 'password', 'first_options' => array('label' => 'password'), 'second_options' => array('label' => 'password_confirmation'), )) ; } /** * @param OptionsResolverInterface $resolver */ public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'AppBundle\Entity\User', 'csrf_protection' => false, )); } /** * @return string */ public function getName() { return 'user'; } } 

Y este es el controlador de usuario posterior:

 public function postUserAction(\Symfony\Component\HttpFoundation\Request $request) { $user = new \AppBundle\Entity\User(); $form = $this->createForm(new \AppBundle\Form\UserType(), $user); $form->handleRequest($request); if ($form->isValid()) { $em = $this->getDoctrine()->getManager(); $em->persist($user); $em->flush(); $view = $this->view(array('token'=>$this->get("lexik_jwt_authentication.jwt_manager")->create($user)), Codes::HTTP_CREATED); return $this->handleView($view); } return array( 'form' => $form, ); } 

El problema es que cuando envío información incorrecta, o información vacía, el servidor devuelve un error 500 con formato incorrecto con doctrine / mysql detalles del valor nulo para una fila no nula en el estado de una respuesta json con la lista de entradas con formato incorrecto.

¿Alguna idea sobre cómo solucionar este comportamiento? ¿Cómo es que la validación pasa y

Bien, después de pasar mucho tiempo leyendo el código de FOSUserBundle, y particularmente el controlador de registro y la fábrica de formularios, se me ocurrió una solución totalmente funcional.

Antes de hacer algo, no olvide deshabilitar CSRF en su configuración de symfony2.

Aquí está el controlador que uso para registrar:

  public function postUserAction(\Symfony\Component\HttpFoundation\Request $request) { /** @var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */ $formFactory = $this->get('fos_user.registration.form.factory'); /** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */ $userManager = $this->get('fos_user.user_manager'); /** @var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */ $dispatcher = $this->get('event_dispatcher'); $user = $userManager->createUser(); $user->setEnabled(true); $event = new \FOS\UserBundle\Event\GetResponseUserEvent($user, $request); $dispatcher->dispatch(\FOS\UserBundle\FOSUserEvents::REGISTRATION_INITIALIZE, $event); if (null !== $event->getResponse()) { return $event->getResponse(); } $form = $formFactory->createForm(); $form->setData($user); $form->handleRequest($request); if ($form->isValid()) { $event = new \FOS\UserBundle\Event\FormEvent($form, $request); $dispatcher->dispatch(\FOS\UserBundle\FOSUserEvents::REGISTRATION_SUCCESS, $event); $userManager->updateUser($user); if (null === $response = $event->getResponse()) { $url = $this->generateUrl('fos_user_registration_confirmed'); $response = new \Symfony\Component\HttpFoundation\RedirectResponse($url); } $dispatcher->dispatch(\FOS\UserBundle\FOSUserEvents::REGISTRATION_COMPLETED, new \FOS\UserBundle\Event\FilterUserResponseEvent($user, $request, $response)); $view = $this->view(array('token' => $this->get("lexik_jwt_authentication.jwt_manager")->create($user)), Codes::HTTP_CREATED); return $this->handleView($view); } $view = $this->view($form, Codes::HTTP_BAD_REQUEST); return $this->handleView($view); } 

Ahora la parte más complicada fue enviar el formulario usando REST. El problema fue que cuando envié i JSON como este:

 { "email":"[email protected]", "username":"xxx", "plainPassword":{ "first":"xxx", "second":"xxx" } } 

La API respondía como si no se hubiera enviado nada.

¡La solución es que Symfony2 está esperando que encapsules tus datos de formulario en el nombre del formulario!

La pregunta era “No creé esta forma, así que no sé cómo se llama …”. Así que volví a entrar en el código del paquete y descubrí que el tipo de formulario era fos_user_registration y la función getName devolvía fos_user_registration_form.

Como resultado, traté de enviar mi JSON de esta manera:

 {"fos_user_registration_form":{ "email":"[email protected]", "username":"xxxxxx", "plainPassword":{ "first":"xxxxx", "second":"xxxxx" } }} 

¡Y voilá! funcionó. Si está luchando por configurar su paquete fosuser con fósrestbundle y LexikJWTAuthenticationBundle, solo pregúnteme, estaré encantado de ayudarlo.

Otra forma es este registro sin los formularios de FOSUserBundle. Haga una solicitud POST con params: correo electrónico, usuario, contraseña.

 public function postUserAction(Request $request) { $userManager = $this->get('fos_user.user_manager'); $email = $request->request->get('email'); $username = $request->request->get('user'); $password = $request->request->get('password'); $email_exist = $userManager->findUserByEmail($email); $username_exist = $userManager->findUserByUsername($username); if($email_exist || $username_exist){ $response = new JsonResponse(); $response->setData("Username/Email ".$username."/".$email." existiert bereits"); return $response; } $user = $userManager->createUser(); $user->setUsername($username); $user->setEmail($email); $user->setLocked(false); $user->setEnabled(true); $user->setPlainPassword($password); $userManager->updateUser($user, true); $response = new JsonResponse(); $response->setData("User: ".$user->getUsername()." wurde erstellt"); return $response; } 

@Adel ‘Sean’ Helal a su manera no funciona, al menos con las últimas versiones de FOSRestBundle, FOSUserBundle y Symfony con Flex. Casi me pego un tiro en la cabeza tratando de hacerlo funcionar. Al final encontré la solución y es bastante simple. Solo se analiza la solicitud.

Fragmento de mi código de controlador

 ... $form->setData($user); // THIS LINE DO THE MAGIC $data = json_decode($request->getContent(), true); if ($data === null) { throw new BadRequestHttpException(); } $form->submit($data); if ( ! $form->isValid()) { $event = new FormEvent($form, $request); $dispatcher->dispatch(FOSUserEvents::REGISTRATION_FAILURE, $event); if (null !== $response = $event->getResponse()) { return $response; } return new JsonResponse($this->getFormErrors($form), Response::HTTP_BAD_REQUEST); } ... 

Las dependencias de composer.json :

 ... "symfony/lts": "^3", "symfony/flex": "^1.0", "friendsofsymfony/rest-bundle": "^2.3", "friendsofsymfony/user-bundle": "^2.0", "lexik/jwt-authentication-bundle": "^2.4", ... 

Mi código de prueba funcional:

 namespace App\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\DependencyInjection\Container; class ApiUserControllerTest extends WebTestCase { /** * @var Container */ private $container; public function setUp() { self::bootKernel(); $this->container = self::$kernel->getContainer(); } public function testRegistration() { $userData = [ 'username' => 'test', 'email' => '[email protected]', 'plainPassword' => [ 'first' => 'test123', 'second' => 'test123' ] ]; $client = $this->container->get('eight_points_guzzle.client.rest'); $response = $client->post( 'api/registration', ['json' => $userData] ); $bodyResponse = \GuzzleHttp\json_decode($response->getBody(), true); $this->assertEquals(201, $response->getStatusCode()); $this->assertArrayHasKey('token', $bodyResponse); $this->assertNotEmpty($bodyResponse['token']); } }