Search code examples
phpsymfonyfosuserbundle

Issues with Symfony 4.3.1 and FosUserBundle 2.1.2


For a new project, I use Symfony 4.3 and FosUserBundle 2.1. I installed with success this bundle but when I try to use it, I've got somes issues.

When I try to access on login page (http://127.0.0.1:8000/login), it works well. But, on register page I've got some errors:

Property "superAdmin" does not exist in class "App\Entity\User"

I try to add the properties superAdmin and group in my User entity (I don't know if it's a good idea). The page is displayed correctly. Now, when I try to submit register form, 4 errors appear (all fields are filled):

  • This value should not be null. => "data.password"
  • This value should not be null. => "data.superAdmin"
  • This value should not be null. => "data.groups"
  • This value should not be null. => "data.group"

Is FosUserBundle compatible with Symfony 4.3? How to solve these problems? Are there alternatives?


Solution

  • here is the solution : ==> you must add $group and $superAdmin in your entity User, so you can just set $group to nullable=true, and $superAdmin is boolean you can set it to true or false. NB: you must rename the column group because this group is reserved word in mysql , I set these in constructor so you can set these in custom form to like :

    <?php
    // src/AppBundle/Entity/User.php
    
    namespace App\Entity;
    
    use FOS\UserBundle\Model\User as BaseUser;
    use Doctrine\ORM\Mapping as ORM;
    use Doctrine\Common\Collections\ArrayCollection;
    
    /**
     * @ORM\Entity
     * @ORM\Table(name="fos_user")
     */
    class User extends BaseUser
    {
        /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;
    
        /**
         * @ORM\Column(type="string", nullable=true)
         */
        protected $prenom;
        /**
         * @ORM\Column(type="boolean")
         */
        protected $superAdmin;
        /**
         * @ORM\Column(name="giroupy", type="string", nullable=true)
         */
        protected $group;
    
        public function __construct()
        {
            parent::__construct();
            $this->superAdmin = false;
            $this->groups = new ArrayCollection();
            // your own logic
            if (empty($this->registerDate)) {
                $this->registerDate = new \DateTime();
            }
        }
    
        public function getId(): ?int
        {
            return $this->id;
        }
    
        public function getPrenom(): ?string
        {
            return $this->prenom;
        }
    
        public function setPrenom(string $prenom): self
        {
            $this->prenom = $prenom;
    
            return $this;
        }
    
        public function getGroup(): ?string
        {
            return $this->group;
        }
    
        public function setGroup(?string $group): self
        {
            $this->group = $group;
    
            return $this;
        }
    
        public function getSuperAdmin(): ?bool
        {
            return $this->superAdmin;
        }
    
    
        public function setSuperAdmin($superAdmin): self
        {
            $this->superAdmin = $superAdmin;
    
            return $this;
        }
    }

    so after to set password you must hook formEvent for event SUBMIT to get the entity User like :

    <?php
    // src/AppBundle/Form/RegistrationType.php
    
    namespace App\Form;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\Form\Extension\Core\Type\EmailType;
    use Symfony\Component\Form\FormEvent;
    use Symfony\Component\Form\FormEvents;
    use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
    
    class RegistrationType extends AbstractType
    {
        private $userPassWordInterface;
        public function __construct(
            UserPasswordEncoderInterface $userPassWordInterface
        )
        {
            $this->userPassWordInterface = $userPassWordInterface;
        }
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('prenom')
            ->addEventListener(
                    FormEvents::SUBMIT,
                    [$this, 'onSubmit']
                )
            ;
        }
    
        public function onSubmit(FormEvent $event)
        {
            $user = $event->getData();
            $form = $event->getForm();
    
            if (!$user) {
                return;
            }
            $passWord = $this->userPassWordInterface->encodePassword($user, $user->getPlainPassword());
            $user->setPassWord($passWord);
    
            // checks whether the user has chosen to display their email or not.
            // If the data was submitted previously, the additional value that
            // is included in the request variables needs to be removed.
    
        }
    
        public function getParent()
        {
            return 'FOS\UserBundle\Form\Type\RegistrationFormType';
        }
    
        public function getBlockPrefix()
        {
            return 'app_user_registration';
        }
    
        // For Symfony 2.x
        public function getName()
        {
            return $this->getBlockPrefix();
        }
    }

    and in security like :

    security:
        # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    
        encoders:
            App\Entity\User: bcrypt
    
        role_hierarchy:
            ROLE_SUPER_ADMIN: ROLE_ADMIN
            ROLE_ADMIN:       ROLE_USER
    
        providers:
            fos_userbundle:
                id: fos_user.user_provider.username
        firewalls:
            dev:
                pattern: ^/(_(profiler|wdt)|css|images|js)/
                security: false
            main:
                pattern: ^/
                form_login:
                    provider: fos_userbundle
                    csrf_token_generator: security.csrf.token_manager
    
                logout:       true
                anonymous:    true
    
        # 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: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
            - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
            - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
            - { path: ^/admin/, role: ROLE_ADMIN }

    so after set the form login in your package : config/packages/fos_user.yaml

    fos_user:
        db_driver: orm # other valid values are 'mongodb' and 'couchdb'
        firewall_name: main
        user_class: App\Entity\User
        registration:
            form:
                type: App\Form\RegistrationType
        from_email:
            address: "%mailer_user%"
            sender_name: "%mailer_user%"

    and don't forget to load routes in : config/routes/fos_user.yaml

    fos_user:
        resource: "@FOSUserBundle/Resources/config/routing/all.xml"