0

I'm building an Address form in Symfony 5.1.

It is created in an AddressType Class that has some required fields.

$builder
        ->add('name', TextType::class, [
            'required' => false,
            'label'  => 'address.name',
            'help' => 'address.name_help',
            'attr' => [
                'placeholder' => 'address.name_ph',
            ]
        ])
        ->add('company', TextType::class, [
            'required' => false,
            'label'  => 'address.company',
            'attr' => [
                'placeholder' => 'address.company_ph',
            ]
        ])
        ->add('first_line', TextType::class, [
            'label'  => 'address.first_line',
            'attr' => [
                'placeholder' => 'address.first_line_ph',
            ]
        ])
        ->add('second_line', TextType::class, [
            'required' => false,
            'label'  => 'address.second_line',
            'attr' => [
                'placeholder' => 'address.second_line_ph',
            ]
        ])
        ->add('add_info', TextType::class, [
            'required' => false,
            'label'  => 'address.add_info',
            'help' => 'address.add_info_help',
            'attr' => [
                'placeholder' => 'address.add_info_ph',
            ]
        ])
        ->add('postcode', TextType::class, [
            'label'  => 'address.postcode',
            'attr' => [
                'placeholder' => 'address.postcode_ph',
            ]
        ])
        ->add('city', TextType::class, [
            'label'  => 'address.city',
            'attr' => [
                'placeholder' => 'address.city_ph',
            ]
        ])
        ->add('state', TextType::class, [
            'required' => false,
            'label'  => 'address.state',
            'attr' => [
                'placeholder' => 'address.state_ph',
            ]
        ])
        ->add('country', CountryType::class, [
            'label'  => 'address.country',
            'preferred_choices' => ['FR'],
            'attr' => [
                'data-toggle' => 'select',
                'placeholder' => 'address.country_ph',
            ]
        ])
        ->add('save',
                SubmitType::class,
                [
                    'label'  => $options['submit_btn_label'],
                ]
            );

If I submit this form with the submit button, everything works as expected, my form is being processed for validation and if It detects some errors, they are shown on each field.

Here is the function that handle the form :

public function new(Request $request)
{
    $user = $this->getUser();
    $address = new Address();
    $address->setCreatedBy($user);
    $form = $this->createForm(AddressType::class, $address);
    //handle form
    $form->handleRequest($request);
    if ($form->isSubmitted()){
        //if submit, add hidden fields
        $address = $form->getData();
        //if valid, process
        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($address);
            $em->flush();   

            $this->addFlash(
                'success',
                'Your address was created.'
            );
            return $this->redirectToRoute('address_index');
        }
    } 
    return $this->render('address/new.html.twig', [
        'form' => $form->createView(),
        'mode' => 'new',
    ]);          
}

Now, If I submit this form through an AJAX request :

$(document).on('click', '.create-address', function() {
    console.log('submitting new address form...');
    var $form = $(this).closest('form')
    var data = $form.serializeArray();
    $.ajax({
        url : $form.attr('action'),
        type: $form.attr('method'),
        data : data
    });
});

In this case, my form is processed for validation and It passes ($form->isValid() returns true) even if I don't provide some of the required fields.
This causes the process of persisting the object to occur and so I get a PDOException.

My question is:
Why is my form not handled the same way (especially at the validation step) according how I post the data ?
And how different are those two methods from the point of view of the function that handle the request ?

1 Answer 1

2

The required option only adds the required attribute to the markup. This forces the browser to provide a value, but doesn't add any validation server side. You can trigger validation before your ajax call and submit only if the form status is valid.

But it is recommended to add server side validation explicitly by using the constraints option in the form or annotating the target entity. Refer to the documentation for more details.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for you answer @msg. I understand the difference between a required attribute and a constraints. The entity Address is defined with some constraints, like not nullable.
OK, I misunderstood the difference between Constraints and ORM Rules in fact. (I had ORM rule for not nullable fields which is not sufficient/equivalent for validation I suppose). Thanks
@Corentoulf I was going to ask just that. However, since 4.3 they should be automatically generated.
Hum.. So this is a strange behaviour right ? Adding a Constraint "forced" the validation anyway.
@Corentoulf I find it better to be explicit, so I'd normally add them anyways and not rely on that feature, so I can't tell you for sure, could be a regression. Can you check if you have the required dependency of symfony/property-info installed? (I think you should, it's just curiosity at this point).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.