Symfony2: two fields comparison with custom validation constraints

I’ve already written a post on how to create a custom validation constraint here (https://creativcoders.wordpress.com/2014/07/15/symfony2-tutorial-create-custom-constraint-validation-and-use-it-with-fosuserbundle/), but what if you need to validate two fields or more in your entity?

Well, I have an entity called “Card” that stores credit cards informations and i need to check the card validity by checking the expiration month and expiration year.
The proper way to do this is to create a custom validation constraint that we will append in our “card” entity.
This is how the entity looks:

<?php

namespace EdouardKombo\StripePaymentBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Card
 *
 * @ORM\Table(name="headoo_stripe_credit_card")
 * @ORM\Entity
 */
class Card
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var integer
     *
     * @ORM\Column(name="number", type="integer")
     * @Assert\NotBlank(message="card.number.blank")
     * @Assert\Length(min="16", max="16", minMessage="card.number.length", maxMessage="card.number.length", exactMessage="card.number.length")
     * @Assert\Range(min="1000000000000000", max="9999999999999999", minMessage="card.number.range", maxMessage="card.number.range")
     * @Assert\Regex(pattern="^(([0-9]*)|(([0-9]*).([0-9]*)))$^", match=true, message="card.number.invalid")
     */
    private $number;

    /**
     * @var integer
     *
     * @ORM\Column(name="expirationMonth", type="integer")
     * @Assert\NotBlank(message="card.expiration.month.blank")
     * @Assert\Length(min="2", max="2", minMessage="card.expiration.month.length", maxMessage="card.expiration.month.length", exactMessage="card.expiration.month.length")
     * @Assert\Range(min="1", max="12", minMessage="card.expiration.month.range", maxMessage="card.expiration.month.range")
     * @Assert\Regex(pattern="^(([0-9]*)|(([0-9]*).([0-9]*)))$^", match=true, message="card.expiration.month.invalid")
     */
    private $expirationMonth;

    /**
     * @var integer
     *
     * @ORM\Column(name="expirationYear", type="integer")
     * @Assert\NotBlank(message="card.expiration.year.blank")
     * @Assert\Length(min="2", max="2", minMessage="card.expiration.year.length", maxMessage="card.expiration.year.length", exactMessage="card.expiration.year.length")
     * @Assert\Range(min="0", max="99", minMessage="card.expiration.year.range", maxMessage="card.expiration.month.range")
     * @Assert\Regex(pattern="^(([0-9]*)|(([0-9]*).([0-9]*)))$^", match=true, message="card.expiration.year.invalid")
     */
    private $expirationYear;

    /**
     * @var integer
     *
     * @ORM\Column(name="cvc", type="integer")
     * @Assert\NotBlank(message="card.cvc.blank")
     * @Assert\Length(min="3", max="4", minMessage="card.cvc.short", maxMessage="card.cvc.long", exactMessage="card.cvc.long")
     * @Assert\Range(min="1", max="9999", minMessage="card.cvc.range", maxMessage="card.cvc.range")
     * @Assert\Regex(pattern="^(([0-9]*)|(([0-9]*).([0-9]*)))$^", match=true, message="card.cvc.invalid") 
     */
    private $cvc;  


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set number
     *
     * @param integer $number
     * @return Card
     */
    public function setNumber($number)
    {
        $this->number = $number;

        return $this;
    }

    /**
     * Get number
     *
     * @return integer 
     */
    public function getNumber()
    {
        return $this->number;
    }   

    /**
     * Set expirationMonth
     *
     * @param integer $expirationMonth
     * @return Card
     */
    public function setExpirationMonth($expirationMonth)
    {
        $this->expirationMonth = $expirationMonth;

        return $this;
    }

    /**
     * Get expirationMonth
     *
     * @return integer 
     */
    public function getExpirationMonth()
    {
        return $this->expirationMonth;
    }

    /**
     * Set expirationYear
     *
     * @param integer $expirationYear
     * @return Card
     */
    public function setExpirationYear($expirationYear)
    {
        $this->expirationYear = $expirationYear;

        return $this;
    }

    /**
     * Get expirationYear
     *
     * @return integer 
     */
    public function getExpirationYear()
    {
        return $this->expirationYear;
    }

    /**
     * Set cvc
     *
     * @param integer $cvc
     * @return Card
     */
    public function setCvc($cvc)
    {
        $this->cvc = $cvc;

        return $this;
    }

    /**
     * Get cvc
     *
     * @return integer 
     */
    public function getCvc()
    {
        return $this->cvc;
    }   
}

Ok so to validate the expirationMonth and expirationYear properties with custom validation constraints, we will create one constraint, called “CardHasExpired”.

  • Create these files in your bundle main directory: “Validator/Constraints/CardHasExpired.php” and “Validator/Constraints/CardHasExpiredValidator.php”

This is how will look the CardHasExpired.php field:

<?php

namespace EdouardKombo\StripePaymentBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class CardHasExpired extends Constraint
{
    /**
     *
     * @var string
     */
    public $message = 'Your card has expired.';
    
    /**
     * 
     * @return string
     */
    public function validatedBy()
    {
        return 'card_has_expired';
    }

    /**
     * Get class constraints and properties
     * 
     * @return array
     */
    public function getTargets()
    {
        return array(self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT);
    }    
}

Now, we can open the CardHasExpiredValidator.php file and we can call the properties we want from our card entity.
This way we can validate multiple properties.

Here, i just need to check that the expiration month and year are not outdated.
This how our CardHasExpiredValidator.php file will look like.

<?php

namespace EdouardKombo\StripePaymentBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class CardHasExpiredValidator extends ConstraintValidator
{

    /**
     * Method to validate
     * 
     * @param string                                  $value      Property value    
     * @param \Symfony\Component\Validator\Constraint $constraint All properties
     * 
     * @return boolean
     */
    public function validate($value, Constraint $constraint)
    {
        $date               = getdate();
        $year               = (string) $date['year'];
        $month              = (string) $date['mon'];
        
        $yearLastDigits     = substr($year, 2);
        $monthLastDigits    = $month;
        $otherFieldValue    = $this->context->getRoot()->get('expirationMonth')->getData();
        
        if (!empty($otherFieldValue) && ($value <= $yearLastDigits) && 
                ($otherFieldValue <= $monthLastDigits)) {
            $this->context->addViolation(
                $constraint->message,
                array('%string%' => $value)
            );            
            return false;            
        }
        
        return true;
    }
}

Now, we have to create a service that will load our constraints.

<?php
    edouard_kombo_stripe_payment.card.validator.card_has_expired:
        class: EdouardKombo\StripePaymentBundle\Validator\Constraints\CardHasExpiredValidator
        tags:
            - { name: validator.constraint_validator, alias: card_has_expired } 

And finally, we can use our constraint directly in our card entity, and assign it to $expirationYear property.

<?php

namespace EdouardKombo\StripePaymentBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use EdouardKombo\StripePaymentBundle\Validator\Constraints\CardHasExpired;


/**
 * Card
 *
 * @ORM\Table(name="headoo_stripe_credit_card")
 * @ORM\Entity
 */
class Card
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var integer
     *
     * @ORM\Column(name="number", type="integer")
     * @Assert\NotBlank(message="card.number.blank")
     * @Assert\Length(min="16", max="16", minMessage="card.number.length", maxMessage="card.number.length", exactMessage="card.number.length")
     * @Assert\Range(min="1000000000000000", max="9999999999999999", minMessage="card.number.range", maxMessage="card.number.range")
     * @Assert\Regex(pattern="^(([0-9]*)|(([0-9]*).([0-9]*)))$^", match=true, message="card.number.invalid")
     */
    private $number;

    /**
     * @var integer
     *
     * @ORM\Column(name="expirationMonth", type="integer")
     * @Assert\NotBlank(message="card.expiration.month.blank")
     * @Assert\Length(min="2", max="2", minMessage="card.expiration.month.length", maxMessage="card.expiration.month.length", exactMessage="card.expiration.month.length")
     * @Assert\Range(min="1", max="12", minMessage="card.expiration.month.range", maxMessage="card.expiration.month.range")
     * @Assert\Regex(pattern="^(([0-9]*)|(([0-9]*).([0-9]*)))$^", match=true, message="card.expiration.month.invalid")
     */
    private $expirationMonth;

    /**
     * @var integer
     *
     * @ORM\Column(name="expirationYear", type="integer")
     * @Assert\NotBlank(message="card.expiration.year.blank")
     * @Assert\Length(min="2", max="2", minMessage="card.expiration.year.length", maxMessage="card.expiration.year.length", exactMessage="card.expiration.year.length")
     * @Assert\Range(min="0", max="99", minMessage="card.expiration.year.range", maxMessage="card.expiration.month.range")
     * @Assert\Regex(pattern="^(([0-9]*)|(([0-9]*).([0-9]*)))$^", match=true, message="card.expiration.year.invalid")
     * @CardHasExpired(message="card.expiration.expired")
     */
    private $expirationYear;

    /**
     * @var integer
     *
     * @ORM\Column(name="cvc", type="integer")
     * @Assert\NotBlank(message="card.cvc.blank")
     * @Assert\Length(min="3", max="4", minMessage="card.cvc.short", maxMessage="card.cvc.long", exactMessage="card.cvc.long")
     * @Assert\Range(min="1", max="9999", minMessage="card.cvc.range", maxMessage="card.cvc.range")
     * @Assert\Regex(pattern="^(([0-9]*)|(([0-9]*).([0-9]*)))$^", match=true, message="card.cvc.invalid") 
     */
    private $cvc;  


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set number
     *
     * @param integer $number
     * @return Card
     */
    public function setNumber($number)
    {
        $this->number = $number;

        return $this;
    }

    /**
     * Get number
     *
     * @return integer 
     */
    public function getNumber()
    {
        return $this->number;
    }   

    /**
     * Set expirationMonth
     *
     * @param integer $expirationMonth
     * @return Card
     */
    public function setExpirationMonth($expirationMonth)
    {
        $this->expirationMonth = $expirationMonth;

        return $this;
    }

    /**
     * Get expirationMonth
     *
     * @return integer 
     */
    public function getExpirationMonth()
    {
        return $this->expirationMonth;
    }

    /**
     * Set expirationYear
     *
     * @param integer $expirationYear
     * @return Card
     */
    public function setExpirationYear($expirationYear)
    {
        $this->expirationYear = $expirationYear;

        return $this;
    }

    /**
     * Get expirationYear
     *
     * @return integer 
     */
    public function getExpirationYear()
    {
        return $this->expirationYear;
    }

    /**
     * Set cvc
     *
     * @param integer $cvc
     * @return Card
     */
    public function setCvc($cvc)
    {
        $this->cvc = $cvc;

        return $this;
    }

    /**
     * Get cvc
     *
     * @return integer 
     */
    public function getCvc()
    {
        return $this->cvc;
    }   
}

Congratulations, you’ve done it, you’re a champion.

Symfony2: two fields comparison with custom validation constraints

Symfony2 tutorial: Create custom constraint validation and use it with FOSUserBundle

Today, we will learn how to create a custom validation constraint with Symfony2 and how to use it with FOSUserBundle.
Let’s start.

We have a user registration form in which we want the username to be automatically validated.
Create your formType and your controller classically, we will focus on constraints.

Let’s name our new constraint: “ContainsUser”.
Create a “ContainsUser.php” file in Validator/Contraints directory at your bundle root.

This file should look like this:

<?php

namespace VendorName\UserBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class ContainsUser extends Constraint
{
    public $message = 'The user "%string%" already exists.';
    
    
    public function validatedBy()
    {
        return 'contains_user';
    }

    public function getTargets()
    {
        return array(self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT);
    }    
}
  • ContainsUser will be our constraint.
  • ValidatedBy() function returns an alias that will help defines a service.
  • In getTargets() function, we specify the targets linked to our constraint (properties and/or classes).

Ok, now we have defined our constraint, we need to create the constraintValidator, it is the file containing the validation logic we want.
Create a “ContainsUserValidator.php” file, always in Validator/Constraints directory.

The file should like this:

<?php

namespace VendorName\UserBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class ContainsUserValidator extends ConstraintValidator
{
    protected $em;
    
    public function __construct(\Doctrine\ORM\EntityManager $em)
    {
        $this->em = $em;
    }
    
    public function validate($value, Constraint $constraint)
    {
        $repository     = $this->em->getRepository('HeadooUserBundle:User');
        $user           = $repository->findOneByUsername($value);
        
        if ($user) {
            $this->context->addViolation(
                $constraint->message,
                array('%string%' => $value)
            );
        }
    }
}

We only loaded a Doctrine Orm dependency and, in the “validate” method, simply checked if the user already exists and generate a context violation.

In order to make it work, we must create a service that injects specified dependencies, just like that:

    vendorname.user.validator.contains_user:
        class: VendorName\UserBundle\Validator\Constraints\ContainsUserValidator
        arguments:
            - @doctrine.orm.entity_manager        
        tags:
            - { name: validator.constraint_validator, alias: contains_user }  

Note that the alias must match the validateBy function return value in our constraint class.

Ok, we have now a constraint with a working validator.
The last thing to do is to call the constraint in FOSUserBundle validation file.
You must override the FOSUserBundle “validation.xml” file in your “Resources/config” directory.

We just need to add our constraint for the username property, so we only keep in this file, the username property constraints.

This is how our constraint must looks like:

<constraint name="VendorName\UserBundle\Validator\Constraints\ContainsUser">
    <option name="message">fos_user.username.already_used</option>
    <option name="groups">
        <value>Registration</value>
        <value>Profile</value>
    </option>                
</constraint>

if you want to keep the message specified in the constraint class, just delete the name=’message’ option.

The complete file must look like this.

<?xml version="1.0" ?>
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
        http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">  
    
    <class name="FOS\UserBundle\Model\User">

        <property name="username">
            <constraint name="NotBlank">
                <option name="message">fos_user.username.blank</option>
                <option name="groups">
                    <value>Registration</value>
                    <value>Profile</value>
                </option>
            </constraint>
            <constraint name="Headoo\UserBundle\Validator\Constraints\ContainsUser">
                <option name="message">fos_user.username.already_used</option>
                <option name="groups">
                    <value>Registration</value>
                    <value>Profile</value>
                </option>                
            </constraint>                      
            <constraint name="Length">
                <option name="min">2</option>
                <option name="minMessage">fos_user.username.short</option>
                <option name="max">255</option>
                <option name="maxMessage">fos_user.username.long</option>
                <option name="groups">
                    <value>Registration</value>
                    <value>Profile</value>
                </option>
            </constraint>
        </property>
    </class>

</constraint-mapping>

And that’s it, you have a fully functional customed constraint validation.

Have fun !

Symfony2 tutorial: Create custom constraint validation and use it with FOSUserBundle

Symfony2 tutorial: Log a user manually by creating your own listener

I had to develop a user registration form with specific roles. The problem was that the form was too big and needed to be simplified.
I then decided to create my own bundle for multi-step registrations, and I needed to log a user manually after form registration, and I want to share what I’ve learned with you.

This is how you can perform it.
First of all, you have to know some symfony base principles:
– Current user informations are stored in the security context token, and, can be retrieved from here.
– The security context token listens to security interactiveLogin event that requires user object and token.

So, to log manually a user, we have to:
– create a user object and generate a token (we will use UsernamePasswordToken for that).
– Listen to interactiveLogin event and sends him the token with the current request
– Dispatch InteractiveLogin event to the security context.

Right, now let’s go!

Instead of creating a controller, we’ll create a listener “LoginListener” in a Listener directory.
This is how our code will looks like.

<?php

/**
 * Main docblock
 *
 * PHP version 5
 *
 * @category  Listener
 * @package   MultiStepFormsBundle
 * @author    Edouard Kombo <edouard.kombo@gmail.com>
 * @license   http://www.opensource.org/licenses/mit-license.php MIT License
 * @version   GIT: 1.0.0
 * @link      https://creativcoders.wordpress.com
 * @since     0.0.0
 */
namespace VendorName\UserBundle\Listener;

use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\SecurityContext;

/**
 * Listen to interactive login event and log in a user manually
 *
 * @category Listener
 * @package  MultiStepFormsBundle
 * @author   Edouard Kombo <edouard.kombo@gmail.com>
 * @license  http://www.opensource.org/licenses/mit-license.php MIT License
 * @link     https://creativcoders.wordpress.com
 */
class LoginListener
{
    /** 
     * @var \Symfony\Component\Security\Core\SecurityContext 
     */
    protected $securityContext;
        
    /**
     *
     * @var string $username
     */
    protected $username;
    
    /**
     *
     * @var object $em
     */
    protected $em;
    
    /**
     *
     * @var string $firewall
     */
    protected $firewall; 
    
    /**
     *
     * @var string $userEntity
     */
    protected $userEntity;     
    
    /**
     *
     * @var object $container
     */
    protected $container;    
    
    /**
     * Constructor
     * 
     * @param \Doctrine\ORM\EntityManager $em              Doctrine orm
     * @param object                      $container       Container Object
     * @param SecurityContext             $securityContext Security Management
     * 
     * @return \EdouardKombo\MultiStepFormsBundle\Listener\LoginListener
     */
    public function __construct(\Doctrine\ORM\EntityManager $em, $container, 
            SecurityContext $securityContext)
    {
        $this->em               = (object) $em; 
        $this->container        = (object) $container;
        $this->securityContext  = (object) $securityContext;
        
        return $this;
    }
    
    /**
     * Set the username
     * 
     * @param string $username Username of the current user
     * 
     * @return \EdouardKombo\MultiStepFormsBundle\Listener\LoginListener
     */
    public function setUsername($username)
    {
        $this->username = (string) $username;
        return $this;
    }
    
    /**
     * Set the firewall
     * 
     * @param string $firewall Actual security firewall
     * 
     * @return \EdouardKombo\MultiStepFormsBundle\Listener\LoginListener
     */
    public function setFirewall($firewall)
    {
        $this->firewall = (string) $firewall;
        return $this;
    }
    
    /**
     * Define the user entity
     * 
     * @param string $userEntity Project User entity
     * 
     * @return \EdouardKombo\MultiStepFormsBundle\Listener\LoginListener
     */
    public function setUserEntity($userEntity)
    {
        $this->userEntity = (string) $userEntity;
        return $this;
    }    
    
    /**
     * Login a user and dispatch the event.
     * 
     * @return object
     * @throws UsernameNotFoundException
     */
    public function secureInteractiveLogin()
    {
        if (!$this->securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
            
            $repository  = $this->em->getRepository($this->userEntity);       
            $user        = $repository->findOneByUsername($this->username);

            $request     = $this->container->get('request');
                
            if (!$user) {
                throw new UsernameNotFoundException("User not found");

            } else {
                //We need the name of the firewall
                $token = new UsernamePasswordToken($user, null, $this->firewall, 
                    $user->getRoles());

                $this->securityContext->setToken($token);

                //Now, login the user
                $event = new InteractiveLoginEvent($request, $token);
                return $this->container->get("event_dispatcher")->dispatch(
                    "security.interactive_login", 
                    $event
                );
            }            
        } else {
            $user = $event->getAuthenticationToken()->getUser();
        }
        
        return $user;
    }    
}

Last step is to create a service to inject dependencies on object construct.

//Change depending on your needs
services:
    multistep_forms.login_listener:
        class: %multistep_forms.login_listener.class%
        arguments:
            - @doctrine.orm.entity_manager
            - @service_container
            - @security.context
Symfony2 tutorial: Log a user manually by creating your own listener

Symfony2 differences between doctrine:schema:update and doctrine:migrations

When you have to create or update your database schema from entities, you are used to type these commands:

php app/console doctrine:schema:update --dump-sql
php app/console doctrine:schema:update --force

Doctrine offers another extension called Migrations that helps you:
– Save your different database schemas during the life of your project
– Move tables and databases with their content, what a simple doctrine:schema:update can’t do.
– Generate accessible migrations queries from the difference between your entities and your database schema.
– Include your own migration queries.

To use doctrine migrations, you will often use these commands:

php app/console doctrine:migrations:diff #Generate migrations queries
php app/console doctrine:migrations:migrate #Refresh your database schema from migrations queries

Finally, for rapid schema updates, use doctrine:schema:update, but, for complex modifications in your database, prefer doctrine:migrations.

Symfony2 differences between doctrine:schema:update and doctrine:migrations

How to install and configure FOSUserBundle with Symfony 2.5.*

When it comes to start multiple projects, configuring all the necessary vendors become an automatism.
Here is a guideline to help you configure new symfony projects with FOSUserBundle.

 
First, target FOSUserBundle dependency in your composer.json

"require": {
    "friendsofsymfony/user-bundle": "2.0.*@dev"
}

 
Install all your dependencies

php composer.phar update

 
Then, generate a new bundle we will name userBundle

php bin/console generate:bundle

 
In the userBundle.php generated file, extend FOSUserBundle like this

class UserBundle extends Bundle
 {
    public function getParent()
    {
      return 'FOSUserBundle';
    }
 }

 
We can now configure FOSUserBundle in our security.yml in “app/config”.
We will change default encoder

encoders:
  FOS\UserBundle\Model\UserInterface: sha512

 
We change the default provider

providers:       
    fos_userbundle:
        id: fos_user.user_provider.username

 
We then the new firewall of our application

main:
  pattern: ^/
     form_login:
         provider: fos_userbundle
         csrf_provider: form.csrf_provider
     logout:       true
     anonymous:    true

 
Once the firewall is configured, we have to secure our application urls

- { path: ^/(_(profiler|wdt)|css|images|js)/, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, role: ROLE_ADMIN }

  
Ok, right, we have configured the basic security options and created a userBundle that extends FOSUserBundle.
But Symfony doesn’t actually know who is FOSUserBundle, and, our firewall doesn’t know where to find the user entity.

 
We have to call FOSUserBundle in the appKernel.

$bundles = array(
         new FOS\UserBundle\FOSUserBundle(),
 );

 
Generate an empty User entity.

php bin/console doctrine:generate:entity --entity=VendorUserBundle:User

 
in the User entity, extend FOSUserBundle and turn id attribute from private to protected.

<?php

namespace Vendor\UserBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Entity\User as BaseUser;

/**
 * User
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class User extends BaseUser
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }
}

 
Ok, now we must specify FOSUserBundle where to find the user entity in app/config/config.yml, and activate framework locale by uncommenting it.

fos_user:
  db_driver: orm
  firewall_name: main
  user_class: Vendor\UserBundle\Entity\User

framework:
    translator:      { fallback: "%locale%" }

 
To finish, just add FOSUserBundle routes in our app/config/routing.yml file…

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

 
And finally, upgrade your database schema

php bin/console doctrine:schema:update --dump-sql
php bin/console doctrine:schema:update --force

You have a ready to use FOSUserBundle installation.

How to install and configure FOSUserBundle with Symfony 2.5.*