Closed astrowild99 closed 3 years ago
Can you create a small example application that allows to reproduce your issue?
sure: here is the problem i have:
I try to create a controller to answer to this request:
{ "username": "uname", "password": "pwd", "email": "uname@mail.me", "role": { "id": 1 } }
and i have two entities:
* @ORM\Entity
* @ORM\Table(name="role")
*/
class Role
{
const LEVEL_ADMIN = 0;
/* voluntarily left empty for some new level */
const LEVEL_DOCTOR = 2;
const LEVEL_USER = 3;
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=20, nullable=false)
*/
private $name;
/**
* @ORM\Column(type="integer", nullable=false)
*/
private $level;
/**
* @ORM\OneToMany(targetEntity="App\Entity\User", mappedBy="role")
*/
private $users;
public function __construct()
{
$this->users = new ArrayCollection();
}
* @ORM\Entity
* @ORM\Table(name="fos_user")
* @UniqueEntity("username")
* @UniqueEntity("email")
*/
class User extends BaseUser
{
/**
* I am forced to use the normal id to let the oauth work
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @Serializer\Groups({"Default"})
*/
protected $id;
/**
* @Serializer\Groups({"Default"})
* @Assert\NotBlank
*/
protected $username;
/**
* @Serializer\Groups({""})
*/
protected $usernameCanonical;
/**
* @Serializer\Groups({"Default"})
* @Assert\NotBlank
* @Assert\Email
*/
protected $email;
// [...]
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Role", inversedBy="users")
* @ORM\JoinColumn(name="id_role", referencedColumnName="id")
* @Serializer\Groups({"Default"})
*/
private $role;
now i try to register a new user via the form:
{
/**
* @var EntityManagerInterface
*/
private $em;
/**
* UserCredentialsType constructor.
* @param EntityManagerInterface $em
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
/**
* When i edit the user i wanna set the new Password only if required
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$roleTransformer = new EntityToIdObjectTransformer($this->em, Role::class);
$builder
->add('username', TextType::class, array(
'required' => true,
'mapped' => true,
'documentation' => array(
'type' => 'string',
'description' => 'new user\'s username'
)
))
->add('password', TextType::class, array(
'required' => true,
'mapped' => false,
'documentation' => array(
'type' => 'string',
'description' => 'the user\'s password, in plain text'
)
))
->add('email', EmailType::class, array(
'required' => true,
'mapped' => true,
'documentation' => array(
'type' => 'string',
'description' => 'the user\'s email'
)
))
->add($builder->create('role', TextType::class)->addModelTransformer($roleTransformer))
->add('submit', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class,
'csrf_protection' => false,
'allow_extra_fields' => true
));
}
}
and call via the following controller
class RegistrationController extends AbstractFOSRestController
{
/**
* Register as a new user, this call does NOT need authentication
* @Rest\Post("/register")
* @SWG\Response(
* response="201",
* description="Returns the newly created user",
* @SWG\Schema(type="object", ref=@Model(type=User::class, groups={"Default"})))
* @SWG\Response(
* response="400",
* description="bad request",
* @SWG\Schema(type="object", ref=@Model(type=FormError::class, groups={"Default"})))
* @SWG\Parameter(
* name="form",
* in="body",
* @Model(type=UserCredentialsType::class))
*
* @param Request $request
* @param AuthenticationHelper $authenticationHelper
* @return View
*/
public function postRegistrationAction(Request $request, AuthenticationHelper $authenticationHelper)
{
$user = new User();
$form = $this->get('form.factory')->createNamed('', UserCredentialsType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$user = $authenticationHelper->createNewUserCredentials($user, $form['password']->getData());
$em->persist($user);
$em->flush();
return View::create($user, Response::HTTP_CREATED);
}
return View::create($form->getErrors(), Response::HTTP_BAD_REQUEST);
}
}
I tried to follow the documentation in every step but the controller returns code 400 and debugging the form creation, as i wrote before, the field 'role' is empty and so the Transformer is not called either, Thank you For your help
Sorry for this request, i found out the issue: for whoever having my same issue check the decoders in
fos_rest:
body_listener:
decoders:
json: fos_rest.decoder.jsontoform
Hope this is helpful for others.
Following the official documentation page on "Step 2: The view layer" when trying to create the transformer quoted in the docs under "Data Transformation" It doesn't work. After some simple debugging it looks like the problem is on new validations of the TextType form type that prevents the data to be passed to the EntityToIdObjectTransformer::reverseTransform is not called at all. Thank you for your constant work in improving Symfony. Hope this could help.