Home > OS >  Symfony Registering New User getUser returns null on handling request
Symfony Registering New User getUser returns null on handling request

Time:09-22

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 App\Controller;

use App\Entity\User;
use App\Form\RegistrationFormType;
use App\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;

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('[email protected]'));

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

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

Controller that handles the request

<?php

declare(strict_types=1);

namespace App\Controller\Security;

use App\Entity\User;
use App\Form\RegistrationFormType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * 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 App\Entity;

use App\Entity\Trait\TimestampableEntity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;

/**
 *
 * @ORM\Table(name="tblUser")
 * @ORM\Entity(repositoryClass=UserRepository::class)
 */
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()
     *
     * @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\Email()
     */
    private string $email;

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

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

    /**
     * @var bool
     * 
     * @ORM\Column(name="bolEmailOptIn", type="boolean", nullable=false)
     * 
     * @Assert\NotNull()
     */
    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:
        App\Entity\User:
            algorithm: auto

    enable_authenticator_manager: true

    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'

    providers:
    #users_in_memory: { memory: null }
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            lazy: true
            provider: app_user_provider
            custom_authenticator:
                - App\Security\LoginFormAuthenticator
            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}

CodePudding user response:

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 App\Controller\Security;

use App\Entity\User;
use App\Form\RegistrationFormType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;

/**
 * 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 App\Entity;

use App\Entity\Trait\TimestampableEntity;
use Carbon\Carbon;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;

/**
 *
 * @ORM\Table(name="tblUser")
 * @ORM\Entity(repositoryClass=UserRepository::class)
 */
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\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)
     *
     */
    private string $password;

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

    /**
     * @var string
     *
     * @ORM\Column(name="strEmail", type="string", nullable=false)
     *
     * @Assert\NotNull()
     * @Assert\Email()
     */
    private string $email;

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

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

    /**
     * @var bool
     * 
     * @ORM\Column(name="bolEmailOptIn", type="boolean", nullable=false)
     * 
     * @Assert\NotNull()
     */
    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

  • Related