0

I'm using Symfony 5.3.7, and using the @Assert annotations, attempting to validate a new user upon registering. Trying to understand the docs however not getting anywhere. Ideally I'd like to be able to understand how to validate an entity using these annotations. I've tried using a separate class, and got nowhere with understanding, although I do want to go down this route in case i reuse the component elsewhere. (I'd rather not validate in the form, but if i have to I can) Entity


class User implements UserInterface
{
    use TimestampableEntity;

    /**
     * @var int
     *
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @ORM\Column(name="intUserId", type="integer", nullable=false)
     */
    private int $id;

    /**
     * @var string
     *
     * @ORM\Column(name="strFirstName", type="string", nullable=false)
     *
     * @Assert\NotBlank
     * @Assert\Length(
     *        min = 2,
     *        max = 50,
     *        minMessage = "Your first name must be at least {{ limit}} characters long",
     *        maxMessage = "Your first name cannot be longer than {{ limit }} characters"
     * )
     */
    private string $firstName;

    /**
     * @var string
     *
     * @ORM\Column(name="strLastName", type="string", nullable=false)
     *
     * @Assert\NotBlank
     * @Assert\Length(
     *        min = 2,
     *        max = 50,
     *        minMessage = "Your first name must be at least {{ limit}} characters long",
     *        maxMessage = "Your first name cannot be longer than {{ limit }} characters"
     * )
     */
    private string $lastName;

    /**
     * @var string
     *
     * @ORM\Column(name="strUsername", type="string", nullable=false)
     *
     * @Assert\Unique()
     * @Assert\Length(
     *        min = 2,
     *        max = 15,
     *        minMessage = "Your first name must be at least {{ limit}} characters long",
     *        maxMessage = "Your first name cannot be longer than {{ limit }} characters"
     * )
     */
    private string $username;

    /**
     * @var string
     *
     * @ORM\Column(name="strPassword", type="string", nullable=false)
     *
     * @Assert\NotNull()
     * @Assert\Regex(pattern = "^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$")
     *
     * @SecurityAssert\UserPassword(message = "Password is incorrect, please try again")
     */
    private string $password;

    /**
     * @var string
     *
     * @ORM\Column(name="strEmail", type="string", nullable=false)
     *
     * @Assert\Unique()
     * @Assert\Regex(pattern = "\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b")
     */
    private string $email;

    /**
     * @var boolean
     * 
     *  @ORM\Column(name="bolAcceptTermsConditions", type="bool", nullable=false)
     * 
     * @Assert\NotNull()
     */
    private bool $acceptTermsAndConditions;

    /**
     * @var boolean
     * 
     *  @ORM\Column(name="bolAcceptPrivacyPolicy", type="bool", nullable=false)
     * 
     * @Assert\NotNull()
     */
    private bool $acceptPrivacyPolicy;

    /**
     * @var boolean
     * 
     * @ORM\Column(name="bolEmailOptIn", type="bool", nullable=false)
     * 
     * @Assert\NotNull()
     */
    private bool $emailOptIn;

    /**
     * User constructor.
     *
     * @param string $firstName
     * @param string $lastName
     * @param string $username
     * @param string $email
     * @param string $password
     */
    public function __construct(
        string $firstName,
        string $lastName,
        string $username,
        string $email,
        string $password,
        bool $acceptTermsAndConditions = false,
        bool $acceptPrivacyPolicy = false,
        bool $emailOptIn = false
    ) {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
        $this->username = $username;
        $this->email = $email;
        $this->password = $password;
        $this->acceptTermsAndConditions = $acceptTermsAndConditions;
        $this->acceptPrivacyPolicy = $acceptPrivacyPolicy;
        $this->emailOptIn = $emailOptIn;

        $this->dtmAdded = Carbon::now();
    }

Ideally I'd pass in the new entity or the array, either create the entity in the validator or similar Controller

public function register(Request $request): Response
    {
        $registrationForm = $this->createForm(RegistrationFormType::class);

        $registrationForm->handleRequest($request);
        if ($registrationForm->isSubmitted() && $registrationForm->isValid()) {
            
            
            $newUserData = $registrationForm->getData();
            $user = new User(
                $newUserData['firstName'],
                $newUserData['lastName'],
                $newUserData['email'],
                $newUserData['username'],
                $newUserData['password'],
                $newUserData['termsConditions'],
                $newUserData['privacyPolicy'],
                $newUserData['emailFrequency']
            );        

            return new RedirectResponse($request->headers->get('referer'));
        }

        return new RedirectResponse($request->headers->get('referer'));
    }

Form

<?php

declare(strict_types=1);

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class RegistrationFormType extends AbstractType
{
    public const FORM_NAME = 'registrationForm';

    /**
     * Form Builder for Registration Form
     *
     * @param FormBuilderInterface $builder
     * @param array $options
     *
     * @return void
     */
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add('firstName', TextType::class, [
            'label' => 'Firstname:',
            'required' => true,
            'attr' => [
                'class' => 'form-input input-type-text',
                'placeholder' => 'John',
            ],

        ]);

        $builder->add('lastName', TextType::class, [
            'label' => 'Lastname:',
            'required' => true,
            'attr' => [
                'class' => 'form-input input-type-text',
                'placeholder' => 'Doe'
            ],

        ]);

        $builder->add('email', EmailType::class, [
            'label' => 'Email:',
            'required' => true,
            'attr' => [
                'class' => 'form-input input-type-email',
                'placeholder' => '[email protected]'
            ]
        ]);

        $builder->add('username', TextType::class, [
            'label' => 'Username:',
            'required' => true,
            'attr' => [
                'class' => 'form-input input-type-text',
            ]
        ]);

        $builder->add('password', PasswordType::class, [
            'label' => 'Password:',
            'required' => true,
            'attr' => [
                'class' => 'form-input input-type-email',
            ]
        ]);

        $builder->add('termsConditions', CheckboxType::class, [
            'label' => 'I accept the terms & conditions',
            'required' => true,
        ]);

        $builder->add('privacyPolicy', CheckboxType::class, [
            'label' => 'I have read and understood the privacy policy',
            'required' => true,
        ]);

        $builder->add('emailFrequency', ChoiceType::class, [
            'label' => 'Opt in to emails:',
            'multiple' => false,
            'expanded' => true,
            'choices' => [
                'Yes' => true,
                'No' => false,
            ],
        ]);
    }

    /**
     * @param OptionsResolver $resolver
     *
     * @return void
     */
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([]);
    }

    /**
     * @return string
     */
    public function getBlockPrefix(): string
    {
        return self::FORM_NAME;
    }
}

1 Answer 1

3

so the issue is that you are not passing the new User object to the form, so the validation will not happen in this case.

What you can do to fix this is, declare the data_class for the form to be User in this case

public function configureOptions(OptionsResolver $resolver): void
{
    $resolver->setDefaults([
        'data_class' => User::class,
    ]);
}

And when you create the form in the action you need to pass a new User object to it like:

$user = new User();
$registrationForm = $this->createForm(RegistrationFormType::class, $user);

And you can remove the part where you instantiate and send data to the user entity

$user = new User(
            $newUserData['firstName'],
            $newUserData['lastName'],
            $newUserData['email'],
            $newUserData['username'],
            $newUserData['password'],
            $newUserData['termsConditions'],
            $newUserData['privacyPolicy'],
            $newUserData['emailFrequency']
        );

instead of that, you should just use the entity manager to save the new user , for that, you need to inject the entity manager, like so:

public function register(Request $request, EntityManagerInterface $entityManager): Response

and just use it to save the user object into the database

if ($registrationForm->isSubmitted() && $registrationForm->isValid()) {
    $entityManager->persist($user);
    $entityManager->flush();
}
Sign up to request clarification or add additional context in comments.

3 Comments

Got most of it working, however on submission, says there's a call to getUser() returning null, as if its trying to log the user in, when $registrationForm->handleRequest($request) is hit, not sure if this should be desired behaviour or how to fix this, otherwise, thank you very much and i understand how to go about it!
Great that you got it working, unfortunately, I don't know why that happens, I would maybe need more information to figure it out, maybe start another post with the issue where you include even the security.yaml file.
I'll Ad it after work today, looking into it with the docs

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.