Permalink
Switch branches/tags
Nothing to show
Find file Copy path
308 lines (231 sloc) 7.58 KB

PUGXMultiUserBundle Documentation

PUGXMultiUserBundle came by the need to use different types of users using only one fos_user service. In practice it is an addon, that forces FOSUserBundle 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.

Prerequisites

This version of the bundle requires Symfony (any version) and FOSUserBundle dev-master

[FOSUserBundle] (https://github.com/FriendsOfSymfony/FOSUserBundle)

Installation

  1. Download PUGXMultiUserBundle
  2. Enable the Bundle
  3. Create your Entities
  4. Configure the FOSUserBundle (PUGXMultiUserBundle params)
  5. Configure parameters for UserDiscriminator
  6. Create your controllers
  7. Using the User Manager

1. Download PUGXMultiUserBundle

Using composer

$ php composer.phar require pugx/multi-user-bundle

2. Enable the bundle

Enable the bundles in the kernel:

<?php
// app/AppKernel.php

public function registerBundles()
{
    $bundles = array(
        // ...
        new PUGX\MultiUserBundle\PUGXMultiUserBundle(),
        new FOS\UserBundle\FOSUserBundle(),
    );
}

3. Create your Entities

Create entities using Doctrine2 inheritance.

Abstract User that directly extends the model FOS\UserBundle\Model\User

<?php

namespace Acme\UserBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\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/master/Resources/doc/overriding_forms.rst)

4. Configure the FOSUserBundle (PUGXMultiUserBundle params)

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

Note:

Acme\UserBundle\Entity\User must be an abstract class, because you don't have to use it. In fact is the discriminator that has responsibility to get the user class depending on context.

5. Configure the PUGXMultiUserBundle

# app/config/config.yml

pugx_multi_user:
  users:
    user_one:
        entity: 
          class: Acme\UserBundle\Entity\UserOne
#          factory: 
        registration:
          form: 
            type: Acme\UserBundle\Form\Type\RegistrationUserOneFormType
            name: fos_user_registration_form
            validation_groups:  [Registration, Default]
          template: AcmeUserBundle:Registration:user_one.form.html.twig
        profile:
          form:
            type: Acme\UserBundle\Form\Type\ProfileUserOneFormType
            name: fos_user_profile_form
            validation_groups:  [Profile, Default] 
    user_two:
        entity: 
          class: Acme\UserBundle\Entity\UserTwo
        registration:
          form: 
            type: Acme\UserBundle\Form\Type\RegistrationUserTwoFormType
          template: AcmeUserBundle:Registration:user_two.form.html.twig
        profile:
          form: 
            type: Acme\UserBundle\Form\Type\ProfileUserTwoFormType

6. Create your controllers

Route configuration

# app/config/routing.yml

user_one_registration:
    path:  /register/user-one
    defaults: { _controller: AcmeUserBundle:RegistrationUserOne:register }

user_two_registration:
    path:  /register/user-two
    defaults: { _controller: AcmeUserBundle:RegistrationUserTwo:register }

Note:

You have to disable the default route registration coming from FOSUser or you have to manage it for prevent incorrect registration

Controllers

RegistrationUserOneController

<?php

namespace Acme\UserBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class RegistrationUserOneController extends Controller
{
    public function registerAction()
    {
        return $this->container
                    ->get('pugx_multi_user.registration_manager')
                    ->register('Acme\UserBundle\Entity\UserOne');
    }
}

RegistrationUserTwoController

<?php

namespace Acme\UserBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class RegistrationUserTwoController extends Controller
{
    public function registerAction()
    {
        return $this->container
                    ->get('pugx_multi_user.registration_manager')
                    ->register('Acme\UserBundle\Entity\UserTwo');
    }
}

Note:

Remember to create the templates for registration form with correct routes

something like this, if you are extending fosub

{% extends "FOSUserBundle::layout.html.twig" %}

{% block fos_user_content %}
    {% trans_default_domain 'FOSUserBundle' %}

    <form action="{{ path('user_one_registration') }}" {{ form_enctype(form) }} method="POST">
        {{ form_widget(form) }}
        <div>
            <input type="submit" value="{{ 'registration.submit'|trans }}" />
        </div>
    </form>
{% endblock fos_user_content %}

Note:

For now only registration and profile form factories are wrapped; if you need creat a custom FormType you have to inject the discriminator.

7. Using the User Manager

Creating a new UserOne:

$discriminator = $this->container->get('pugx_user.manager.user_discriminator');
$discriminator->setClass('Acme\UserBundle\Entity\UserOne');

$userManager = $this->container->get('pugx_user_manager');

$userOne = $userManager->createUser();

$userOne->setUsername('admin');
$userOne->setEmail('admin@mail.com');
$userOne->setPlainPassword('123456');
$userOne->setEnabled(true);

$userManager->updateUser($userOne, true);