Recently I have been learning to use Symfony for a project of mine as a less opinionated and more modular alternative to Laravel. So far it has been a very nice experience, and I believe it is a great framework for large scale developments.

Symfony uses Bundles, which are redistributable and standalone packages that provide certain features to your website. One of the most popular ones obviously is a User Bundle to handle Registration, Login, Forgot Password etc.

For this, the Friends of Symfony User Bundle is a great solution which acts as a User provider for the core Security Bundle.

However, there is one major problem I have with it. It uses a Username field instead of just an email field, which while great for things such as community websites, it is quite terrible for Service based websites. Asking someone to call themselves johnsmith22 is embaressing sometimes.

Thankfully, Symfony is designed to be very modular and changeable, so in this post I am going to show you how to setup Email only login and registration with the FOS User Bundle.

You can find the instructions to set up the FOS User Bundle in their documentation, and then follow this on from there

Instructions

First, we have to enable login with either Email or Username which is something that the FOS User Bundle offers as an option.

# app/config/security.yml
security:
    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email

Next we create an Event Listener, which subscribes to the Registration form submission event and triggers a function to modify the data before it is saved to the database.

<?php
//src/AppBundle/EventListener/UserRegistrationListener.php

namespace AppBundle\EventListener;

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

class UserRegistrationListener implements EventSubscriberInterface{

    /**
     * subscribe to the registration event
     * @return array Registration Event as key, method as value
     */
    public static function getSubscribedEvents(){
        return array(
            FOSUserEvents::REGISTRATION_INITIALIZE => 'onRegistrationInit'
        );
    }

    /**
     * set the username to a unique id at registration
     * @param \FOS\UserBundle\Event\UserEvent $userevent
     */
    public function onRegistrationInit(UserEvent $userevent){
        $user = $userevent->getUser();
        $user->setUsername(uniqid());
    }
}
?>

In order to hide the Username component of the default form, we have to override it with a new RegistrationFormType

<?php
// src/AppBundle/Form/Type/RegistrationFormType.php

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class RegistrationFormType extends AbstractType{

    public function buildForm(FormBuilderInterface $builder, array $options){
        $builder->remove('username');
    }

    public function getParent(){
        return 'fos_user_registration';
    }

    public function getName(){
        return 'app_user_registration';
    }
}
?>

Then we have to let the FOS User Bundle know what form to use

# app/config/config.yml
fos_user:
    # ...
    registration:
        form:
            type: app_user_registration

Finally, we need to register the Event Listener and Form Type as Services so that Symfony can use them

# app/config/services.yml
services:
    # ...
    app_user_registration_listener:
        class: AppBundle\EventListener\UserRegistrationListener
        tags:
            - { name: kernel.event_subscriber }

    app_user.registration.form.type:
        class: AppBundle\Form\Type\RegistrationFormType
        tags:
            - { name: form.type, alias: app_user_registration }

Update 18/09/2016

Symfony 3 has made some slight changes so you need to change the following:

  • The fos_user registration form type in config.yml should now be AppBundle\Form\Type\RegistrationFormType
  • getParent in RegistrationFormType.php should now return 'FOS\UserBundle\Form\Type\RegistrationFormType'
  • Add getBlockPrefix() function to RegistrationFormType.php:
     public function getBlockPrefix()
     {
         return 'app_user_registration';
     }
    
  • getName in RegistrationFormType.php should now return $this->getBlockPrefix()

After those changes it will work perfectly in Symfony 3

Conclusion

All done, now Users can register using only their email instead of creating a username.

I’ll most likely be doing some more writing on Symfony in the near future, its quite nice and has plenty of features I could write about.

Much of the code for this was sourced from Issue #555, this is a collation of their efforts