Epok
Epok

Reputation: 681

Add a default role during user registration with FOSUserBundle

Version : Symfony 2.2

I'm trying to add a default role when a user register on my website. I use FOSUserBundle and i see that when a user register the role field is empty in a database. I begin with this huge bundle and it's not very easy to understand. So i read all the documentation and i'm not sur what to do.

For now, i create an Event to add this role dynamically, but it doesn't work (i have no error but my database is still empty) I'm not even sur this is the good way to do that ?

My Event :

use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class AddDefaultRoleListener implements EventSubscriberInterface {

  private $container;

  public function __construct(Container $container)
  {
    $this->container = $container;
  }

  /**
   * {@inheritDoc}
   */
  public static function getSubscribedEvents()
  {
    return array(
        FOSUserEvents::REGISTRATION_SUCCESS => 'onAddDefaultRoleSuccess',
    );
  }

  public function onAddDefaultRoleSuccess(FormEvent $event)
  {
    $doctrine = $this->container->get('doctrine');
    $em = $doctrine->getManager();

    $user = $event->getForm()->getData();
    $user->addRole('ROLE_USER');
    //$user->setRoles(array('ROLE_USER'));

    $em->persist($user);
  }
}

As you see i create a simple event which listen on REGISTRATION_SUCCESS, but nothing seems to work. It's my first try with Events and services. So if someone has an advice, i'll take it :)

Upvotes: 26

Views: 36778

Answers (6)

Mohamed Ben HEnda
Mohamed Ben HEnda

Reputation: 2776

You can add an Event Subscriber to a Form Class and use the form event "formEvents::POST_SUBMIT"

<?php

//src/yourNS/UserBundle/Form/Type/RegistrationFormType.php

use Symfony\Component\Form\FormBuilderInterface;
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType;
use yourNS\UserBundle\Form\EventListener\AddRoleFieldSubscriber;

class RegistrationFormType extends BaseType
{        
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);

        // add your custom field
        $builder->add('firstName')
            ->add('lastName')
            ->add('address')
            //...
            //...
            ->add('phone');
        $builder->addEventSubscriber(new AddRoleFieldSubscriber());
    }

    public function getName()
    {
        return 'yourNS_user_registration';
    }
}

Now the logic for adding the role field resides in it own subscriber class

<?php
//src/yourNS/UserBundle/Form/EventListener/AddRoleFieldSubscriber.php

namespace yourNS\UserBundle\Form\EventListener;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class AddRoleFieldSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return array(FormEvents::POST_SUBMIT => 'setRole');
    }

    public function setRole(FormEvent $event)
    {
        $aRoles = array('ROLE_USER');

        /** @var $user \FOS\UserBundle\Model\UserInterface */
        $user = $event->getForm()->getData();
        $user->setRoles($aRoles);
    }
}

Upvotes: 2

jelle woord
jelle woord

Reputation: 193

public function __construct()
{
    parent::__construct();
    $this->setRoles(["ROLE_WHATEVER"]);
}

Upvotes: 0

alvaropgl
alvaropgl

Reputation: 850

What i have done is override the entity constructor:

Here a piece of my Entity/User.php

public function __construct()
{
    parent::__construct();
    // your own logic
    $this->roles = array('ROLE_USER');
}

This is the lazy way. If you want the right and better way see the @RayOnAir answer

Upvotes: 38

andrew
andrew

Reputation: 409

I think @RayOnAir solution is right way of doing this. But it will not work due to FOS default role handling

to make possible to persist default role in database one need to override User::setRoles() method (add it to your User entity):

/**
 * Overriding Fos User class due to impossible to set default role ROLE_USER 
 * @see User at line 138
 * @link https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Model/User.php#L138
 * {@inheritdoc}
 */
public function addRole($role)
{
    $role = strtoupper($role);

    if (!in_array($role, $this->roles, true)) {
        $this->roles[] = $role;
    }

    return $this;
}

Tested under:

Symfony version 2.3.6, FOSUserBundle 2.0.x-dev

Upvotes: 4

RayOnAir
RayOnAir

Reputation: 2048

The recommended way to do it as indicated by a main contributor to the FOSUserBundle (in the comment here linked) is to register an Event Listener on the REGISTRATION_SUCCESS event and use the $event->getForm()->getData() to access the user and modify it. Following those guidelines, I created the following listener (which works!):

<?php

// src/Acme/DemoBundle/EventListener/RegistrationListener.php

namespace Acme\DemoBundle\EventListener;

use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Listener responsible for adding the default user role at registration
 */
class RegistrationListener implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return array(
            FOSUserEvents::REGISTRATION_SUCCESS => 'onRegistrationSuccess',
        );
    }

    public function onRegistrationSuccess(FormEvent $event)
    {
        $rolesArr = array('ROLE_USER');

        /** @var $user \FOS\UserBundle\Model\UserInterface */
        $user = $event->getForm()->getData();
        $user->setRoles($rolesArr);
    }
}

Also, the service needs to be registered as follows:

// src/Acme/DemoBundle/Resources/config/services.yml
services:
    demo_user.registration_listener:
        class: Acme\DemoBundle\EventListener\RegistrationListener
        arguments: []
        tags:
            - { name: kernel.event_subscriber }

Notice that adding a default role in the User class __construct() may have some issues as indicated in this other answer.

Upvotes: 39

Epok
Epok

Reputation: 681

Ok now it's working with that :

 public function onAddDefaultRoleSuccess(FilterUserResponseEvent $event)
{
    $doctrine = $this->container->get('doctrine');
    $em = $doctrine->getManager();

    $user = $event->getUser();
    $user->addRole('ROLE_BLOGGER');

    $em->persist($user);
    $em->flush();
}

I change my listener and know use REGISTRATION_COMPLETED. If someone has a better idea to do that, don't hesitate :)

Upvotes: 1

Related Questions