Skip to content
Advertisement

Symfony Registering New User getUser returns null on handling request

Trying to register a new user with a form and ajax request (as it will become a modal form) and hit a snag on trying to validate the form. When the request gets handled, it states that the user is null in the password validator. And not understand how to get past this or allow this one route to allow the user to register.

I’ve tried updating the security yaml, changing the route

Controller that loads the initial page

<?php

declare(strict_types=1);

namespace AppController;

use AppEntityUser;
use AppFormRegistrationFormType;
use AppRepositoryUserRepository;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentRoutingAnnotationRoute;
use SymfonyComponentHttpFoundationResponse;

class HomeController extends AbstractController
{
    /**
     * Undocumented function
     * 
     * @Route("/", name="index")
     *
     * @return Response
     */
    public function index(UserRepository $userRepository): Response
    {
        $user = new User();
        $registerForm = $this->createForm(RegistrationFormType::class, $user);

        //dd($userRepository->getUserByUserIdentifier('samueldurw@outlook.com'));

        $pageContent = [
            'registrationForm' => $registerForm->createView(),
        ];

        return $this->render('base.html.twig', $pageContent);
    }
}

Controller that handles the request

<?php

declare(strict_types=1);

namespace AppControllerSecurity;

use AppEntityUser;
use AppFormRegistrationFormType;
use DoctrineORMEntityManagerInterface;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationRedirectResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingAnnotationRoute;

/**
 * Undocumented class
 */
class RegistrationController extends AbstractController
{
    /**
     * Registering a new user.
     * 
     * @Route("/ajax/registration", name="registration")
     *
     * @return Response
     */
    public function register(Request $request, EntityManagerInterface $entityManager): Response
    {
        $user = new User();
        $registrationForm = $this->createForm(RegistrationFormType::class, $user);
        
        $registrationForm->handleRequest($request);
        //dd("I'm here after request");
        if ($registrationForm->isSubmitted() && $registrationForm->isValid()) {
            $entityManager->persist($user);
            $entityManager->flush();
            
            return new RedirectResponse($request->headers->get('referer'));
        }

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

User Entity that will be created

<?php

declare(strict_types=1);

namespace AppEntity;

use AppEntityTraitTimestampableEntity;
use DoctrineORMMapping as ORM;
use SymfonyComponentPasswordHasherHasherUserPasswordHasherInterface;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreValidatorConstraints as SecurityAssert;
use SymfonyComponentValidatorConstraints as Assert;

/**
 *
 * @ORMTable(name="tblUser")
 * @ORMEntity(repositoryClass=UserRepository::class)
 */
class User implements UserInterface
{
    use TimestampableEntity;

    /**
     * @var int
     *
     * @ORMId()
     * @ORMGeneratedValue(strategy="IDENTITY")
     * @ORMColumn(name="intUserId", type="integer", nullable=false)
     */
    private int $id;

    /**
     * @var string
     *
     * @ORMColumn(name="strFirstName", type="string", nullable=false)
     *
     * @AssertNotBlank
     * @AssertLength(
     *        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
     *
     * @ORMColumn(name="strLastName", type="string", nullable=false)
     *
     * @AssertNotBlank
     * @AssertLength(
     *        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
     *
     * @ORMColumn(name="strUsername", type="string", nullable=false)
     *
     * @AssertUnique()
     * @AssertLength(
     *        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
     *
     * @ORMColumn(name="strPassword", type="string", nullable=false)
     *
     * @AssertNotNull()
     *
     * @SecurityAssertUserPassword(message = "Password is incorrect, please try again")
     */
    private string $password;

    /**
     * @var string
     *
     * @ORMColumn(name="strEmail", type="string", nullable=false)
     *
     * @AssertUnique()
     * @AssertEmail()
     */
    private string $email;

    /**
     * @var bool
     * 
     *  @ORMColumn(name="bolAcceptTermsConditions", type="boolean", nullable=false)
     * 
     * @AssertNotNull()
     */
    private bool $acceptTermsAndConditions;

    /**
     * @var bool
     * 
     *  @ORMColumn(name="bolAcceptPrivacyPolicy", type="boolean", nullable=false)
     * 
     * @AssertNotNull()
     */
    private bool $acceptPrivacyPolicy;

    /**
     * @var bool
     * 
     * @ORMColumn(name="bolEmailOptIn", type="boolean", nullable=false)
     * 
     * @AssertNotNull()
     */
    private bool $emailOptIn;

    /**
     * @return string
     */
    public function getFullName(): string
    {
        return $this->firstName . " " . $this->lastName;
    }

    /**
     * @return string
     */
    public function getFirstName(): string
    {
        return $this->firstName;
    }

    /**
     * @return string
     */
    public function getLastName(): string
    {
        return $this->lastName;
    }

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

    public function getRoles()
    {
        // TODO: Implement getRoles() method.
    }

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

    /**
     * Undocumented function
     *
     * @return boolean
     */
    public function getAcceptTermsAndConditions(): bool
    {
        return $this->acceptTermsAndConditions;
    }

    /**
     * Undocumented function
     *
     * @return boolean
     */
    public function getAcceptPrivacyPolicy(): bool
    {
        return $this->acceptPrivacyPolicy;
    }

    /**
     * Undocumented function
     *
     * @return boolean
     */
    public function getEmailOptIn(): bool
    {
        return $this->emailOptIn;
    }

    /**
     * @return void
     */
    public function getSalt()
    {
        // TODO: Implement getSalt() method.
    }

    public function eraseCredentials()
    {
        // TODO: Implement eraseCredentials() method.
    }

    /**
     * @return string
     */
    public function getUserIdentifier(): string
    {
        return $this->username;
    }

    /**
     * @return string
     */
    public function getUsername(): string
    {
        return $this->username;
    }

    /**
     * Undocumented function
     *
     * @param string $firstname
     * 
     * @return void
     */
    public function setFirstName(string $firstname)
    {
        $this->firstName = $firstname;
    }

    /**
     * Undocumented function
     *
     * @param string $lastName
     * @return void
     */
    public function setLastName(string $lastName)
    {
        $this->lastName = $lastName;
    }

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

    public function setUsername(string $username)
    {
        $this->username = $username;
    }

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

    public function setAcceptTermsAndConditions(bool $accepted)
    {
        $this->acceptTermsAndConditions = $accepted;
    }

    public function setAcceptPrivacyPolicy(bool $accepted)
    {
        $this->acceptPrivacyPolicy = $accepted;
    }

    public function setEmailOptIn(bool $accepted)
    {
        $this->emailOptIn = $accepted;
    }

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

Form contains all the fields and is mapped to the user entity. Struggling to identify how to get this working without a major rework of the entire registration system.

security.yaml

security:
    encoders:
        AppEntityUser:
            algorithm: auto

    enable_authenticator_manager: true

    password_hashers:
        SymfonyComponentSecurityCoreUserPasswordAuthenticatedUserInterface: 'auto'

    providers:
    #users_in_memory: { memory: null }
        app_user_provider:
            entity:
                class: AppEntityUser
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            lazy: true
            provider: app_user_provider
            custom_authenticator:
                - AppSecurityLoginFormAuthenticator
            logout:
                path: logout

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        # - { path: ^/admin, roles: ROLE_ADMIN }
        # - { path: ^/profile, roles: ROLE_USER }
        - { path: /registration, roles: PUBLIC_ACCESS}

Advertisement

Answer

Fixed and can now add a new user, some changes will be made to where they are being directed, however thats out of the scope of this question.

Registration Controller: needs fixing to return and display the errors present in the form, and a redirect to a home page after login.

<?php

declare(strict_types=1);

namespace AppControllerSecurity;

use AppEntityUser;
use AppFormRegistrationFormType;
use DoctrineORMEntityManagerInterface;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationRedirectResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentPasswordHasherHasherUserPasswordHasherInterface;
use SymfonyComponentRoutingAnnotationRoute;

/**
 * Undocumented class
 */
class RegistrationController extends AbstractController
{
    /**
     * Registraion method
     * 
     * @Route("/registration", name="registration")
     *
     * @return Response
     */
    public function register(Request $request, EntityManagerInterface $entityManager,
    UserPasswordHasherInterface $passwordHasher): Response
    {
        $user = new User();
        $registrationForm = $this->createForm(RegistrationFormType::class, $user);

        $registrationForm->handleRequest($request);

        dd($user->getUsername());
        if ($registrationForm->isSubmitted() && $registrationForm->isValid()) {
            $password = $passwordHasher->hashPassword($user, $user->getPlainPassword());
            $user->setPassword($password);

            //dd($user->getPlainPassword(), $user->getPassword());

            $entityManager->persist($user);
            $entityManager->flush();

            $pageContent = [
                'registrationForm' => $registrationForm->createView(),
            ];
            
            return $this->render('base.html.twig', $pageContent);
        }

        $pageContent = [
            'registrationForm' => $registrationForm->createView(),
            'formErrors' => $registrationForm->getErrors()
        ];
        
        return new RedirectResponse($request->headers->get('referer'));
    }
}

User entity: made some mistakes around how the asserts worked and the limitations around them, removed as unnecessary.

<?php

declare(strict_types=1);

namespace AppEntity;

use AppEntityTraitTimestampableEntity;
use CarbonCarbon;
use DoctrineORMMapping as ORM;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreValidatorConstraints as SecurityAssert;
use SymfonyComponentValidatorConstraints as Assert;

/**
 *
 * @ORMTable(name="tblUser")
 * @ORMEntity(repositoryClass=UserRepository::class)
 */
class User implements UserInterface
{
    use TimestampableEntity;

    /**
     * @var int
     *
     * @ORMId()
     * @ORMGeneratedValue(strategy="IDENTITY")
     * @ORMColumn(name="intUserId", type="integer", nullable=false)
     */
    private int $id;

    /**
     * @var string
     *
     * @ORMColumn(name="strFirstName", type="string", nullable=false)
     *
     * @AssertNotBlank
     * @AssertLength(
     *        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
     *
     * @ORMColumn(name="strLastName", type="string", nullable=false)
     *
     * @AssertNotBlank
     * @AssertLength(
     *        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
     *
     * @ORMColumn(name="strUsername", type="string", nullable=false)
     *
     * @AssertLength(
     *        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
     *
     * @ORMColumn(name="strPassword", type="string", nullable=false)
     *
     */
    private string $password;

    /**
     * Plain string password used for form registration
     *
     * @var string
     * 
     */
    private string $plainPassword;

    /**
     * @var string
     *
     * @ORMColumn(name="strEmail", type="string", nullable=false)
     *
     * @AssertNotNull()
     * @AssertEmail()
     */
    private string $email;

    /**
     * @var bool
     * 
     *  @ORMColumn(name="bolAcceptTermsConditions", type="boolean", nullable=false)
     * 
     * @AssertNotNull()
     */
    private bool $acceptTermsAndConditions;

    /**
     * @var bool
     * 
     *  @ORMColumn(name="bolAcceptPrivacyPolicy", type="boolean", nullable=false)
     * 
     * @AssertNotNull()
     */
    private bool $acceptPrivacyPolicy;

    /**
     * @var bool
     * 
     * @ORMColumn(name="bolEmailOptIn", type="boolean", nullable=false)
     * 
     * @AssertNotNull()
     */
    private bool $emailOptIn;

    public function __construct()
    {
        $this->dateAdded = Carbon::now();
    }

    /**
     * @return string
     */
    public function getFullName(): string
    {
        return $this->firstName . " " . $this->lastName;
    }

    /**
     * @return string
     */
    public function getFirstName(): string
    {
        return $this->firstName;
    }

    /**
     * @return string
     */
    public function getLastName(): string
    {
        return $this->lastName;
    }

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

    public function getRoles()
    {
        // TODO: Implement getRoles() method.
    }

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

    public function getPlainPassword(): string
    {
        return $this->plainPassword;
    }

    /**
     * Undocumented function
     *
     * @return boolean
     */
    public function getAcceptTermsAndConditions(): bool
    {
        return $this->acceptTermsAndConditions;
    }

    /**
     * Undocumented function
     *
     * @return boolean
     */
    public function getAcceptPrivacyPolicy(): bool
    {
        return $this->acceptPrivacyPolicy;
    }

    /**
     * Undocumented function
     *
     * @return boolean
     */
    public function getEmailOptIn(): bool
    {
        return $this->emailOptIn;
    }

    /**
     * @return void
     */
    public function getSalt()
    {
        // TODO: Implement getSalt() method.
    }

    public function eraseCredentials()
    {
        // TODO: Implement eraseCredentials() method.
    }

    /**
     * @return string
     */
    public function getUserIdentifier(): string
    {
        return $this->username;
    }

    /**
     * @return string
     */
    public function getUsername(): string
    {
        return $this->username;
    }

    /**
     * Undocumented function
     *
     * @param string $firstname
     * 
     * @return void
     */
    public function setFirstName(string $firstname)
    {
        $this->firstName = $firstname;
    }

    /**
     * Undocumented function
     *
     * @param string $lastName
     * @return void
     */
    public function setLastName(string $lastName)
    {
        $this->lastName = $lastName;
    }

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

    public function setUsername(string $username)
    {
        $this->username = $username;
    }

    public function setPlainPassword($password)
    {
        $this->plainPassword = $password;
    }

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

    public function setAcceptTermsAndConditions(bool $accepted)
    {
        $this->acceptTermsAndConditions = $accepted;
    }

    public function setAcceptPrivacyPolicy(bool $accepted)
    {
        $this->acceptPrivacyPolicy = $accepted;
    }

    public function setEmailOptIn(bool $accepted)
    {
        $this->emailOptIn = $accepted;
    }

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

Will be adding an automatic login after registration but not at that stage. Symfony Docs, symfony casts and Bogdan George Moza

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement