symfony5 – error 500 page instead form error in twig

I set up a register form using the form builder.

Problem is Symfony throw an InvalidArgumentException page with messageExpected argument of type "string", "null" given at property path "user_name".

Of course setUserName in User entity define user_name type hinted as string but I added constraint NotBlank in my form builder. I expected an error inside twig like ‘this field can’t be empty’.

Why errors are not showing up into my twig template ? I’ve already implements this flow in Symfony 4 and it’s working like a charm.

Here is the builder

<?php

namespace AppFormType;

use AppEntityDepartment;
use AppEntityLevel;
use DoctrineORMEntityManagerInterface;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormExtensionCoreTypeChoiceType;
use SymfonyComponentFormExtensionCoreTypeDateType;
use SymfonyComponentFormExtensionCoreTypeEmailType;
use SymfonyComponentFormExtensionCoreTypeSubmitType;
use SymfonyComponentFormExtensionCoreTypeTextareaType;
use SymfonyComponentFormExtensionCoreTypeTextType;
use SymfonyComponentFormExtensionCoreTypePasswordType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentValidatorConstraintsLength;
use SymfonyComponentValidatorConstraintsNotBlank;
use SymfonyComponentValidatorConstraintsRegex;

class InscriptionType extends AbstractType
{
    /**
     * EntityManagerInterface
     *
     * @var EntityManagerInterface
     */
    private $em;

    /**
     * Constructor
     *
     * @param EntityManagerInterface $em
     */
    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    /**
     * Build the register form
     *
     * @param FormBuilderInterface $builder
     * @param array $options
     * @return void
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('user_name', TextType::class, [
                'label' => 'Nom',
                'attr' => [
                    'placeholder' => 'Doe'
                ],
                'constraints' => [
                    new Length([
                        'min' => 3,
                        'minMessage' => 'Doit comporter 2 caractères ou plus',
                    ]),
                    new Regex([
                        'pattern' => '/^[wéèêàäâçïöôîûüù' -]+$/',
                        'message' => 'La chaîne comporte des caractères non autorisés',
                    ]),
                    new NotBlank()
                ]
            ])
            ->add('user_firstname', TextType::class, [
                'label' => 'Prénom',
                'attr' => [
                    'placeholder' => 'John'
                ],
                'constraints' => [
                    new Length([
                        'min' => 3,
                        'minMessage' => 'Doit comporter 2 caractères ou plus',
                    ]),
                    new Regex([
                        'pattern' => '/^[wéèêàäâçïöôîûüù' -]+$/',
                        'message' => 'La chaîne comporte des caractères non autorisés',
                    ]),
                    new NotBlank()
                ],
            ])
            ->add('user_birthdate', DateType::class, [
                'label' => 'Date de naissance',
                'placeholder' => [
                    'year' => 'Année',
                    'month' => 'Mois',
                    'day' => 'Jours',
                ],
                'widget' => 'single_text',
                'input' => 'array',
                'constraints' => [
                    new NotBlank()
                ],
            ])
            ->add('email', EmailType::class, [
                'label' => 'Adresse email',
                'attr' => [
                    'placeholder' => '[email protected]'
                ],
                'constraints' => [
                    new NotBlank(),
                ],
            ])
            ->add('user_department', ChoiceType::class, [
                'label' => 'Département',
                'placeholder' => 'Sélectionnez un departement',
                'choices' => $this->getDepartmentList(),
                'constraints' => [
                    new NotBlank(),
                ],
            ])
            ->add('user_level', ChoiceType::class, [
                'label' => 'Niveau',
                'placeholder' => 'Sélectionnez votre niveau',
                'choices' => $this->getLevelList(),
                'constraints' => [
                    new NotBlank(),
                ],
            ])
            ->add('user_description', TextareaType::class, [
                'label' => 'Description',
                'constraints' => [
                    new Length([
                        'min' => 3,
                        'minMessage' => 'Doit comporter 2 caractères ou plus',
                    ]),
                    new NotBlank(),
                ],
            ])
            ->add('password', PasswordType::class, [
                'label' => 'Mot de passe',
                'constraints' => [
                    new Length([
                        'min' => 3,
                        'minMessage' => 'Doit comporter 2 caractères ou plus',
                    ]),
                    new NotBlank(),
                ],
            ])
            ->add('confirm_password', PasswordType::class, [
                'mapped' => false,
                'label' => 'Confirmation',
                'constraints' => [
                    new Length([
                        'min' => 3,
                        'minMessage' => 'Doit comporter 2 caractères ou plus',
                    ]),
                    new NotBlank(),
                ],
            ])
            ->add('submit', SubmitType::class, [
                'label' => 'Valider',
            ]);

        /* TO DO IMPLEMENTER CAPTCHA */
        /*
    if ($_ENV['GOOGLE_RECAPTCHA_ACTIVE'] === 'true') {
    $builder->add('CaptchaDmd', HiddenType::class,[
    'label' => 'Captcha',
    'mapped' => false, // le captcha n'est pas une propriete existante dans l'entite demandePass, on indique que on ne doit pas la mapper
    'error_bubbling' => false,
    'constraints' => [
    new NotBlank([
    'message' => $this->translator->trans('LibBlankCaptcha')
    ])
    ]
    ]);
    }
     */
    }

    /**
     * Retrieve department list
     *
     * @return void
     */
    protected function getDepartmentList()
    {
        $repo = $this->em->getRepository(Department::class);
        $departments = [];

        $departmentList = $repo->findAll();

        foreach ($departmentList as $department) {
            # $country est une instance de AppEntityLangueInternational
            $libelle = $department->getDepartmentNom() . ' (' . $department->getDepartementCode() . ')';
            $valeur = $department->getId();

            $departments[$libelle] = $valeur;
        }

        return $departments;
    }

    /**
     * Retrieve level list
     *
     * @return void
     */
    protected function getLevelList()
    {
        $repo = $this->em->getRepository(Level::class);
        $levels = [];

        $levelList = $repo->findAll();

        foreach ($levelList as $level) {
            # $country est une instance de AppEntityLangueInternational
            $libelle = ucfirst($level->getLevelName());
            $valeur = $level->getId();

            $levels[$libelle] = $valeur;
        }

        return $levels;
    }

}

User entity

<?php

namespace AppEntity;

use AppRepositoryUserRepository;
use DoctrineORMMapping as ORM;
use SymfonyComponentSecurityCoreUserUserInterface;

/**
 * @ORMEntity(repositoryClass=UserRepository::class)
 */
class User implements UserInterface
{
    /**
     * @ORMId
     * @ORMGeneratedValue
     * @ORMColumn(type="integer")
     */
    private $id;

    /**
     * @ORMColumn(type="string", length=180, unique=true)
     */
    private $email;

    /**
     * @ORMColumn(type="json")
     */
    private $roles = [];

    /**
     * @var string The hashed password
     * @ORMColumn(type="string")
     */
    private $password;

    /**
     * @ORMColumn(type="string", length=255)
     */
    private $user_name;

    /**
     * @ORMColumn(type="string", length=255)
     */
    private $user_firstname;

    /**
     * @ORMColumn(type="date")
     */
    private $user_birthdate;

    /**
     * @ORMColumn(type="integer")
     */
    private $user_region;

    /**
     * @ORMColumn(type="integer")
     */
    private $user_department;

    /**
     * @ORMColumn(type="text")
     */
    private $user_description;

    /**
     * @ORMColumn(type="integer")
     */
    private $user_level;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;

        return $this;
    }

    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUsername(): string
    {
        return (string) $this->email;
    }

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    public function setRoles(array $roles): self
    {
        $this->roles = $roles;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getPassword(): string
    {
        return (string) $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getSalt()
    {
        // not needed when using the "bcrypt" algorithm in security.yaml
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }

    public function setUserName(string $user_name): self
    {
        $this->user_name = $user_name;

        return $this;
    }

    public function getUserFirstname(): ?string
    {
        return $this->user_firstname;
    }

    public function setUserFirstname(string $user_firstname): self
    {
        $this->user_firstname = $user_firstname;

        return $this;
    }

    public function getUserBirthdate(): ?DateTimeInterface
    {
        return $this->user_birthdate;
    }

    public function setUserBirthdate(DateTimeInterface $user_birthdate): self
    {
        $this->user_birthdate = $user_birthdate;

        return $this;
    }

    public function getUserRegion(): ?int
    {
        return $this->user_region;
    }

    public function setUserRegion(int $user_region): self
    {
        $this->user_region = $user_region;

        return $this;
    }

    public function getUserDepartment(): ?int
    {
        return $this->user_department;
    }

    public function setUserDepartment(int $user_department): self
    {
        $this->user_department = $user_department;

        return $this;
    }

    public function getUserDescription(): ?string
    {
        return $this->user_description;
    }

    public function setUserDescription(string $user_description): self
    {
        $this->user_description = $user_description;

        return $this;
    }

    public function getUserLevel(): ?int
    {
        return $this->user_level;
    }

    public function setUserLevel(int $user_level): self
    {
        $this->user_level = $user_level;

        return $this;
    }
}

Template

{{ form_start(inscriptionForm, {'attr': {'novalidate' : 'novalidate'}}) }}
      {{ form_errors(inscriptionForm) }}
      <div class="form-row">
        <div class="form-group col-md-6">
          {{ form_label(inscriptionForm.user_name) }}
          {{ form_widget(inscriptionForm.user_name) }}
          {{ form_errors(inscriptionForm.user_name) }}
        </div>
        <div class="form-group col-md-6">
          {{ form_label(inscriptionForm.user_firstname) }}
          {{ form_widget(inscriptionForm.user_firstname) }}
          {{ form_errors(inscriptionForm.user_firstname) }}
        </div>
      </div>
      <div class="form-row">
        <div class="form-group col-md-6">
          {{ form_label(inscriptionForm.email) }}
          {{ form_widget(inscriptionForm.email) }}
          {{ form_errors(inscriptionForm.email) }}
        </div>
        <div class="form-group col-md-6">
          {{ form_label(inscriptionForm.user_birthdate) }}
          {{ form_widget(inscriptionForm.user_birthdate) }}
          {{ form_errors(inscriptionForm.user_birthdate) }}
        </div>
      </div>
      <div class="form-row">
        <div class="form-group col-md-6">
          {{ form_label(inscriptionForm.password) }}
          {{ form_widget(inscriptionForm.password) }}
          {{ form_errors(inscriptionForm.password) }}
        </div>
        <div class="form-group col-md-6">
          {{ form_label(inscriptionForm.confirm_password) }}
          {{ form_widget(inscriptionForm.confirm_password) }}
          {{ form_errors(inscriptionForm.confirm_password) }}
        </div>
      </div>
      <div class="form-row">
        <div class="form-group col-md-6">
          {{ form_label(inscriptionForm.user_level) }}
          {{ form_widget(inscriptionForm.user_level) }}
          {{ form_errors(inscriptionForm.user_level) }}
        </div>
        <div class="form-group col-md-6">
          {{ form_label(inscriptionForm.user_description) }}
          {{ form_widget(inscriptionForm.user_description) }}
          {{ form_errors(inscriptionForm.user_description) }}
        </div>
      </div>
      <div class="form-row">
        <div class="form-group col-md-6">
          {{ form_label(inscriptionForm.user_department) }}
          {{ form_widget(inscriptionForm.user_department) }}
          {{ form_errors(inscriptionForm.user_department) }}
        </div>
      </div>
      <div class="form-row">
        <div class="form-group col-md-6">
          {{ form_widget(inscriptionForm.submit) }}
        </div>
      </div>
      
      {{ form_end(inscriptionForm) }}

And controller which handle form submission

<?php

namespace AppController;

use AppEntityUser;
use AppFormTypeInscriptionType;
use SymfonyComponentHttpFoundationRequest;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentRoutingAnnotationRoute;

class InscriptionController extends AbstractController
{
    /**
     * @Route("/inscription", name="inscription")
     */
    public function inscriptionAction(Request $request)
    {
        $user = new User();
        
        // Creation du formulaire d'inscription
        $inscriptionForm = $this->createForm(InscriptionType::class, $user);

        // Si requete en POST et formulaire soumit
        if ($request->isMethod('POST')) {
          error_log('Formulaire inscription soumis');

          // On indique au formulaire de prendre en charge le contenu de la requete
          // Il va mapper les different champs soumis avec le contenu de l entite $user
          $inscriptionForm->handleRequest($request);

          if ($inscriptionForm->isSubmitted() && $inscriptionForm->isValid()) {
            error_log("Formulaire inscription ok, sauvegarde de l'inscription");
          }
        }

        // Affichage
        return $this->render('inscription.html.twig', array(
          'inscriptionForm' => $inscriptionForm->createView(),
          'errors' => (isset($errors) ? $errors : ''),
      ));
    }
}

Source: Symfony Questions

Was this helpful?

0 / 0

Leave a Reply 0

Your email address will not be published. Required fields are marked *