I'm having a strange issue and I think I'm missing something.
I'm using Symfony 2.7 and I'm working on a user password update function.
I have a user entity (Extends FosUserBundle user entity) with multiple properties. One of them is the plainPassword (ofcourse not persisted to DB).
User.php
...
/**
* @ORM\Table(name="prefix_users")
* @ORM\Entity(repositoryClass="UserRepository")
*
* @UniqueEntity(fields={"email"}, message="unique", groups={"registration"})
* @UniqueEntity("username", message="unique", groups={"registration"})
*
* @ExclusionPolicy("all")
*/
class User extends BaseUser
{
...
/* @var string
*
* @Assert\NotBlank(message="blank",groups={"accountUpdate", "passwordUpdate"})
* @Assert\Length(min=8, minMessage="short", max=4096, maxMessage="long")
*/
protected $plainPassword;
As you can see I'm using annotations for the validation of my properties. I'm also using validation groups to be sure only the correct properties will be validated.
I have created a form
UserUpdatePasswordType.php
class UserUpdatePasswordType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('plainPassword', 'repeated', array(
'type' => 'password',
'invalid_message' => 'password_mismatch',
));
}
/**
* @param OptionsResolverInterface $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'My\Bundle\UserBundle\Entity\User',
'csrf_protection' => false,
'intention' => 'resetting',
/**
* Need to add method to prevent this form from bein marked as invalid.
* @see http://sroze.io/2013/10/30/symfony2-form-patch-requests-and-handlerequest-form-never-valid/
*/
'method' => 'PATCH'
));
}
I'm building a restful API with FOSRestBundle and I'd like to provide a nice and clean output if form validation fails.
As far as I know I can validate a form in two ways:
Now the strange part comes, the two methods above give different validation errors.
Request parameters
user_update_password[plainPassword][first]:sffsdfdsfds
user_update_password[plainPassword][second]:fdsfdsfsd
Response from $formErrors = $this->get('validator')->validate($user, null, ['passwordUpdate']); The response is not correct, because the plainPassword is not blank.
{
"property_path": "plainPassword",
"message": "blank"
}
Response form $form->isValid() which seems to look better
"form": {
"children": {
"plainPassword": {
"children": {
"first": {
"errors": [
"password_mismatch"
]
},
"second": {}
}
}
}
},
"errors": []
The only difference I can see is the difference that I'm not providing a validation group name in the $form->isValid().
Why am I getting different results and what should I do to fix? Can I provide a validation group name to the $form->isValid() or should I fix a problem with the $validator->validate code?
I would love to see how this is managed in other Symfony2 based APIs...
There're three reasons of difference.
request
to model
when validating by service. Use $form->submit($request)
as a safe proxy data settersetDefaults
) BTW. Your @Assert\Length
won't be used until you add groups to this annotation or add validation group Default
to service/form
validators arrayrepeated
type in form, which have additional Constraints
in comparison to your model Constraints
. Form validator checks for both model and form constraints belonging to passed validation groups (by default 'Default' group is used)Actually, there is another difference (besides using of validation group). When you are using Form (rather than just a Validator), there is a 'repeated' type involved.
Validation
One of the key features of the repeated field is internal validation (you don't need to do anything to set this up) that forces the two fields to have a matching value. If the two fields don't match, an error will be shown to the user.
So actually in one case you're using an additional constraint, and at another you are not. No surprise validations give different results.
So in your case I would probably make own implementation of "repeat" for a password in the User object and would use a validator service.
Another option that I see is to use a Form object to validate User, but it's not a clean and clear way to make API.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With