PUGXMultiUserBundle came by the need to use different types of users using only one fos_user service. In practice it is an hack that forces FOSUser bundle through custom UserManager, controllers, and forms handlers.
It's just a lazy way to use for free most of the functionality of FOSUserBundle.
This bundle has been realized as a part of a real application that uses doctrine orm, so for now it only supports the ORM db driver.
This version of the bundle requires Symfony 2.1
[FOSUserBundle] (https://github.com/FriendsOfSymfony/FOSUserBundle)
- Download PUGXMultiUserBundle
- Enable the Bundle
- Create your UserBundle
- Create your Entities
- Configure the FOSUserBundle (PUGXMultiUserBundle params)
- Configure parameters for UserDiscriminator
- Create your controllers
Using composer
Add the following lines in your composer.json:
{
"require": {
"pugx/multi-user-bundle": "1.3.x-dev"
}
}
Now, run the composer to download the bundle:
$ php composer.phar update pugx/multi-user-bundleEnable the bundle in the kernel:
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new PUGX\MultiUserBundle\PUGXMultiUserBundle(),
);
}Create a bundle that extends PUGXMultiUserBundle ([How to use Bundle Inheritance to Override parts of a Bundle] (http://symfony.com/doc/current/cookbook/bundles/inheritance.html))
<?php
namespace Acme\UserBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AcmeUserBundle extends Bundle
{
public function getParent()
{
return 'PUGXMultiUserBundle';
}
}
### 4. Create your Entities
Create entities using Doctrine2 inheritance.
Abstract User that directly extends from FOS\UserBundle\Entity\User
``` php
<?php
namespace Acme\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Entity\User as BaseUser;
/**
* @ORM\Entity
* @ORM\Table(name="user")
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="type", type="string")
* @ORM\DiscriminatorMap({"user_one" = "UserOne", "user_two" = "UserTwo"})
*
*/
abstract class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
}UserOne
<?php
namespace Acme\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use PUGX\MultiUserBundle\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity
* @ORM\Table(name="user_one")
* @UniqueEntity(fields = "username", targetClass = "Acme\UserBundle\Entity\User", message="fos_user.username.already_used")
* @UniqueEntity(fields = "email", targetClass = "Acme\UserBundle\Entity\User", message="fos_user.email.already_used")
*/
class UserOne extends User
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
}UserTwo
<?php
namespace Acme\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use PUGX\MultiUserBundle\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity
* @ORM\Table(name="user_two")
* @UniqueEntity(fields = "username", targetClass = "Acme\UserBundle\Entity\User", message="fos_user.username.already_used")
* @UniqueEntity(fields = "email", targetClass = "Acme\UserBundle\Entity\User", message="fos_user.email.already_used")
*/
class UserTwo extends User
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
}You must also create forms for your entities: see [Overriding Default FOSUserBundle Forms] (https://github.com/FriendsOfSymfony/FOSUserBundle/blob/1.1.0/Resources/doc/overriding_forms.md)
Keep in mind that PUGXMultiUserBundle overwrites user_class via UserDiscriminator but it does it only in controllers and forms handlers; in the other cases (command, sonata integration, etc) it still uses the user_class configured in the config.
# Acme/UserBundle/Resources/config/config.yml
fos_user:
db_driver: orm
firewall_name: main
user_class: Acme\UserBundle\Entity\User
service:
user_manager: pugx_user_manager
registration:
form:
handler: pugx_user_registration_form_handler
profile:
form:
handler: pugx_user_profile_form_handler# Acme/UserBundle/Resources/config/config.yml
parameters:
pugx_user_discriminator_parameters:
classes:
user_one:
entity: Acme\UserBundle\Entity\UserOne
registration: Acme\UserBundle\Form\Type\RegistrationUserOneFormType
profile: Acme\UserBundle\Form\Type\ProfileUserOneFormType
factory:
user_two:
entity: Acme\UserBundle\Entity\UserTwo
registration: Acme\UserBundle\Form\Type\RegistrationUserTwoFormType
profile: Acme\UserBundle\Form\Type\ProfileUserTwoFormType
factory:If you need to pass custom options to the form (like a validation groups)
# Acme/UserBundle/Resources/config/config.yml
parameters:
pugx_user_discriminator_parameters:
classes:
user_one:
entity: Acme\UserBundle\Entity\UserOne
registration: Acme\UserBundle\Form\Type\RegistrationUserOneFormType
registration_options:
validation_groups: [Registration, Default]
profile: Acme\UserBundle\Form\Type\ProfileUserOneFormType
profile_options:
validation_groups: [Profile, Default]
factory:
user_two:
entity: Acme\UserBundle\Entity\UserTwo
registration: Acme\UserBundle\Form\Type\RegistrationUserTwoFormType
profile: Acme\UserBundle\Form\Type\ProfileUserTwoFormType
factory:PUGX\MultiUserBundle\Controller\RegistrationController can handle registration flow only for the first user passed to discriminator, in this case user_one. To handle flow of user_two you must configure a route and add a controller in your bundle.
Route configuration
# Acme/UserBundle/Resources/config/routing.yml
user_two_registration:
pattern: /register/user-two
defaults: { _controller: AcmeUserBundle:RegistrationUserTwo:register }<?php
namespace Acme\UserBundle\Controller;
use PUGX\MultiUserBundle\Controller\RegistrationController as BaseController;
class RegistrationUserTwoController extends BaseController
{
public function registerAction()
{
$discriminator = $this->container->get('nmn_user_discriminator');
$discriminator->setClass('Acme\UserBundle\Entity\UserTwo');
return parent::registerAction();
}
}Custom view
<?php
namespace Acme\UserBundle\Controller;
use PUGX\MultiUserBundle\Controller\RegistrationController as BaseController;
use Symfony\Component\HttpFoundation\RedirectResponse;
class RegistrationUserTwoController extends BaseController
{
public function registerAction()
{
$discriminator = $this->container->get('pugx_user_discriminator');
$discriminator->setClass('Acme\UserBundle\Entity\UserTwo');
$form = $discriminator->getRegistrationForm();
$return = parent::registerAction();
if ($return instanceof RedirectResponse) {
return $return;
}
return $this->container->get('templating')->renderResponse('AcmeUserBundle:Registration:user_two.form.html.'.$this->getEngine(), array(
'form' => $form->createView(),
));
}
}Customize all registrations
You can also define a custom route for UserOne but in this case remember to override the RegistrationController and create the route and the controller for UserOne
<?php
namespace Acme\UserBundle\Controller;
use NmnPUGX\MultiUserBundle\Controller\RegistrationController as BaseController;
use Symfony\Component\HttpFoundation\RedirectResponse;
class RegistrationController extends BaseController
{
public function registerAction()
{
$url = $this->container->get('router')->generate('home');
return new RedirectResponse($url);
}
}