How to Disable Registation in FOSUserBundle


In this video we are going to look at a few different ways to disable registration in FOSUserBundle.

The first method will be to simply remove the /register link from the active list of routes in our project. Whilst certainly effective in achieving our goal, it is never the less, quite blunt in its approach.

The subsequent two methods build on what we learned in the previous two videos. You may find these two approaches a little overkill, depending on your situation. As part of these two methods we will add in a parameter to our parameters.yml file, allowing site registration to be toggled on or off, depending on your needs.

Method 1 - Removing The Registration Route

If you've been following along with this video series, or have simply followed the installation instructions for FOSUserBundle, it is likely that you have imported the FOSUserBundle routes as instructed:

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

This is a standard Symfony approach to routing. We import a file - all.xml - which contains many more routes.

Normally we wouldn't need to concern ourselves any further at this point. The site works, all is good.

However, our approach for this method is to disable one of these routes. We don't own / control this routing collection, other than one top level import statement. We cannot simply open up this file and disable the fos_user_register section... Well, we could, but that would be terrible practice. We should never directly change anything inside a third party bundle.

Instead, it makes sense to directly import all the routes ourselves, and then selectively disable the fos_user_register section, and / or any other sections we don't want to make available.

We can't import the XML routes into our YAML file - that would result in our routes becoming unparsable / unreadable by Symfony.

Thankfully, FOSUserBundle documentation provides all the routes for us in YAML format:

# app/config/routing.yml
fos_user_security:
    resource: "@FOSUserBundle/Resources/config/routing/security.xml"

fos_user_profile:
    resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
    prefix: /profile

fos_user_register:
    resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
    prefix: /register

fos_user_resetting:
    resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
    prefix: /resetting

fos_user_change_password:
    resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
    prefix: /profile

As such, you can replace that single top level fos_user resource with the five resources above, and immediately you have gained more control over your routing without having to touch any third party code.

We can now simply comment out or delete the fos_user_register section, and this will be sufficient to disable registration, albeit in a somewhat clumsy manner.

# app/config/routing.yml

#fos_user_register:
#    resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
#    prefix: /register

There are better ways of achieving our goal, so lets continue.

Feature Toggle

It may be that you wish to enabled and disable registration selectively.

In this instance, and for the improvement of site administrator user experience, we can use a simple parameter value to allow the site registration to be toggled between and enabled and disabled state.

To achieve this, all we need to do is add in a new parameter in to parameters.yml:

# app/config/parameters.yml
parameters:
    registration_enabled: true

It is best practice to update the parameters.yml.dist file also, as this file will be used by anyone 'installing' this project for the first time. You want to ensure anyone new to the project gets all the required parameters that don't come by default with Symfony, otherwise the project very likely won't work for them:

# app/config/parameters.yml.dist
parameters:
    registration_enabled: true

Now, so long as we write code which checks for this parameter, we can toggle our site registration into an enabled or disabled state simply by updating our parameters.yml.

Let's do that now.

Method 2 - Overriding The FOSUserBundle Registation Controller

I've already covered the concept of overriding a controller, so be sure to check out that video and show notes if unsure what is happening here.

We need to make sure we are overriding the correct controller.

We can either follow the routing files, or use a Symfony console command to help us figure out which route we need to look at:

$ php app/console debug:router
[router] Current routes
 Name                              Method   Scheme Host Path                                                    
 fos_user_security_login           GET|POST ANY    ANY  /login                                                  
 fos_user_security_check           POST     ANY    ANY  /login_check                                            
 fos_user_security_logout          GET      ANY    ANY  /logout                                                 
 fos_user_profile_show             GET      ANY    ANY  /profile/                                               
 fos_user_profile_edit             GET|POST ANY    ANY  /profile/edit                                           
 fos_user_registration_register    GET|POST ANY    ANY  /register/                                              
 fos_user_registration_check_email GET      ANY    ANY  /register/check-email                                   
 fos_user_registration_confirm     GET      ANY    ANY  /register/confirm/{token}                               
 fos_user_registration_confirmed   GET      ANY    ANY  /register/confirmed                                     
 fos_user_resetting_request        GET      ANY    ANY  /resetting/request                                      
 fos_user_resetting_send_email     POST     ANY    ANY  /resetting/send-email                                   
 fos_user_resetting_check_email    GET      ANY    ANY  /resetting/check-email                                  
 fos_user_resetting_reset          GET|POST ANY    ANY  /resetting/reset/{token}                                
 fos_user_change_password          GET|POST ANY    ANY  /profile/change-password 

In our case, fos_user_registration_register seems to fit the bill quite nicely.

Given that we know the route name, we can either do a cheeky 'find' for that string inside the /vendor/friendsofsymfony directory, or simply follow the standard Symfony bundle directory convention: Resources/config/routing/

In there we will find registration.xml which contains the route we are interested in:

    <route id="fos_user_registration_register" path="/" methods="GET POST">
        <default key="_controller">FOSUserBundle:Registration:register</default>
    </route>

Immediately now we can see we need to create ourselves a RegistrationController with a registerAction.

Be sure to have set up your bundle as a child of FOSUserBundle if following this approach. Again, if unsure, please watch the video where this was covered in greater depth.

The important part of this approach is to first check if the registration_enabled parameter exists before we try to access it:

<?php

// src/ChrisUserBundle/Controller/RegistrationController.php

namespace ChrisUserBundle\Controller;

use \FOS\UserBundle\Controller\RegistrationController as BaseController;
use Symfony\Component\HttpFoundation\Request;

class RegistrationController extends BaseController
{
    public function registerAction(Request $request)
    {
        if ($this->container->hasParameter('registration_enabled')) {

            if ($this->getParameter('registration_enabled') === false) {

                return $this->render(':registration:disabled.html.twig');

            }

        }

        return parent::registerAction($request);
    }
}

If for any reason the registration_enabled parameter is not found, registration will default to enabled. If the parameter is found, and set to false, we can show a registration disabled page.

Nice.

However, I don't like overriding FOSUserBundle controllers unless I absolutely have to. And in this instance, I don't think we do.

So let's look at a better way.

Method 3 - Using an Event Listener

Again, we have already been through using an Event Listener to customise FOSUserBundle. Be sure to watch that video if any of this does not make sense.

Our Event Listener setup and logic here is going to be very similar to the previous listener we created.

If the route does not match fos_user_registration_register then return early.

If the route matches fos_user_registration_register but registration_enabled is set to true, then return early.

Only if the route matches and registration is disabled do we want to show the registration disabled page.

Also, we don't really want to have to create ourselves a new controller here just to handle the rendering of a simple twig template.

Let's create ourselves a listener:

<?php

// src/AppBundle/Event/RegistrationRouteListener.php

namespace AppBundle\Event;

use FOS\UserBundle\Model\User;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class RegistrationRouteListener
{
    /**
     * @var RouterInterface
     */
    private $routerInterface;
    private $registrationEnabled;

    public function __construct(RouterInterface $routerInterface, $registrationEnabled)
    {
        $this->routerInterface = $routerInterface;
        $this->registrationEnabled = $registrationEnabled;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        $request = $event->getRequest();

        if ($request->get('_route') !== 'fos_user_registration_register') {
            return;
        }

        if ($this->registrationEnabled === true) {
            return;
        }

        $event->setResponse(
            new RedirectResponse(
                $this->routerInterface->generate('registration_disabled_page')
            )
        );
    }
}

Note this time we didn't need to create our Listener in a bundle that is a child of FOSUserBundle.

All our logic is in place, and the only thing that's different from the previous video is we are injecting the registration_enabled parameter instead of another Symfony service.

We do still need to add in the config for our registration_disabled route.

# app/config/routing.yml

registration_disabled_page:
    path: /registration-disabled
    defaults:
        _controller: FrameworkBundle:Template:template
        template: ':registration:disabled.html.twig'

And so, without having to have created a specific controller, we can get Symfony to kindly render out our basic :registration:disabled.html.twig template.

We still have our registration_enabled feature toggle, but this time the parameter is being injected in for us.

Any of these approaches should solve the problem of disabling registration inside FOSUserBundle. It entirely depends on how thorough you wish to be.

Code For This Course

Get the code for this course.

Episodes