Fosuserbundle: Can I use FOSUserBundle for 3 different roles and custom registration flow?

Created on 29 Jan 2015  路  11Comments  路  Source: FriendsOfSymfony/FOSUserBundle

I need some advice for a new project. I need 3 types/roles of users: normal user, power user and administrator. For the normal user the registration process of FOSUB it's what I need. The administrator(s) I'll have them in memory to keep things simple. For the power user though, I need a different flow: they sign up but an administrator must moderate the registration. If accepted, only then the power user can sign in. Is this possible using FOSUB? It's simpler to build it from scratch or can I achieve this customizing the bundle?

Any answer appreciated. Thanks

All 11 comments

Just use the $roles property on the user to grant different access levels. ROLE_SUPER_ADMIN, ROLE_POWER_USER and ROLE_USER (the default role FOSUB assigns).

Your registration process must be customised to somehow indicate the user wants to become a power user and alert admins, but otherwise FOSUB can handle it fine.

Can I save the roles into a table in the database? It's possible then to have two different registration forms? I forgot to mention: USER and POWER_USER will have different fields for the profile. Can this feature be implemented easily?

I'm asking because normally using a bundle it's better. But in certain cases, sometimes, instead of helping one needs to fight with to bundle to customize/change things a lot.

How different are the fields? You can only use one User entity with this bundle - the registration forms are easy enough to have different fields based on signups but the properties would all live on the same entity.

I use FOSUB but I implemented my own custom registration controller and flow rather than importing the routes from the bundle and using the provided one. There are events in the bundle's controller that might let you do what you need without overriding it too.

Roles are stored in the database, yes. https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Model/User.php#L113 & https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/config/doctrine/model/User.orm.xml#L35

Thanks for the information Tim. ROLE_POWER_USER will have some extra fields. I understand that I'll use only one entity. This means that inside the database table ROLE_USER will have the extra fields as blank. Inside the profile page for example, I'll need to check for the role and show/hide the fields, right? Do you have an example code how to implement a custom registration controller and flow?

You pretty much just need to swap out the RegistrationType used by the form component on registration depending on conditions you want to use to work out if it should be a power user signup or not.

Take a look at RegistrationController - all you might need to do is replace the formFactory service definition with your own service that implements FormFactoryInterface (https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Form/Factory/FactoryInterface.php)

What about custom redirection on login for different roles; does FOSUB provide an event for this?

@sergiu-popa the login is handled by SecurityBundle, not by FOSUserBundle

Ok, I need some help to finish this.

This is my custom controller:

class TeacherController extends Controller
{
public function registerAction()
    {
        //$form = $this->get('fos_user.registration.form');
        $form = $this->createForm(
            new RegistrationFormType('FOS\UserBundle\Entity\User'),
            null,
            array('attr' => array('teacher' => 'true')));
        $formHandler = $this->container->get('fos_user.registration.form.handler');
        $confirmationEnabled = $this->container->getParameter('fos_user.registration.confirmation.enabled');
        $process = $formHandler->process($confirmationEnabled);
        if ($process) {
            $user = $form->getData();
            $user->setEnabled(false);
            $user->setRoles(array('ROLE_USER', 'ROLE_TEACHER'));
            $authUser = false;
            if ($confirmationEnabled) {
                $this->container->get('session')->set('fos_user_send_confirmation_email/email', $user->getEmail());
                $route = 'fos_user_registration_check_email';
            } else {
                $authUser = true;
                $route = 'fos_user_registration_confirmed';
            }
            $this->setFlash('fos_user_success', 'registration.flash.user_created');
            $url = $this->container->get('router')->generate($route);
            $response = new RedirectResponse($url);
            if ($authUser) {
                $this->authenticateUser($user, $response);
            }
            return $response;
        }
        return $this->container->get('templating')->renderResponse('FOSUserBundle:Registration:register.html.'.$this->getEngine(), array(
            'form' => $form->createView(),
            'teacher' => true
        ));
    }
}

Although in register_content.html.twig I'm outputing the CSRF token ({{ form_rest(form) }}), I'm getting this error - CSRF Token invalidad and the form keeps reloading.

This is my RegistrationFormType:

add()... // comun fields for both profiles
        if(!isset($options['attr']['teacher'])) {
            // Seteaza campurile pentru student
            $builder
                // add user fields
                ->add()...
        } else {
            // add teacher fields
            $builder
                ->add()...
        }
    }
    public function getName()
    {
        return 'mt_user_registration';
    }
}

Thank you

@stof I'm in similar situation, didn't know that the login is handled by SecurityBundle, not by FOSUserBundle. If possible can next FOSUserBundle update add comment in FOS\UserBundle\FOSUserEvents indicating as such?

If you want custom registrations flows, the easiest way is to implement them yourselves (without bothering with overriding the FOSUserBundle controllers). You have the full power of Symfony available.
So I'm closing this issue.

@rparsi I don't see why we would have such a comment in FOSUserEvents as it is not about login either.

@stof Having such a comment would help newbs like myself (and others) that make false assumptions regarding FOSUserEvents (in that we assume/expect an event for user login). Maybe the comment should be somewhere in the symfony docs instead. Point is that the fact that FOSUserEvents is not about user login needs to be expressed somewhere, so people don't make pointless tickets (github issues) over it.

If you're wondering where/why this assumption comes from...the class is named FOSUserEvents, so it's not a leap of logic to then think "well a user login is an event, this class is for user events, so why isn't it there?"

Was this page helpful?
0 / 5 - 0 ratings