Ce tutorial vise à réaliser un site avec un back-office pour l'administration et un espace mon compte pour les utilisateurs. Les utilisateurs pourront s'inscrire au site et recevrons un mail de confirmation pour finaliser leur inscription. Pour ce faire nous allons Utiliser le Bundle FOSUserBundle. Ce dernier va nous fournir deux entités Utilisateur et Groupe avec un ensemble de méthodes permettant le login, enregistrement et reset du mot de passe utilisateur pour ne citer que celles que nous utiliserons.
Description : Création d'un back-office et d'un espace mon compte sur Symfony 2 avec FOSUserBundle. Keywords : développement, web, PHP, Symfony 2, FOS, FOSUserBundle
Partie 1 - Création de l'admin
1 - Installation de Symfony 2.8
sudo php composer.phar create-project symfony/framework-standard-edition /Users/gerard/Documents/htdocs/sf_web_app/ 2.8
Installation de composer.phar : curl -s https://getcomposer.org/installer | php
2 - Création des Bundles
On va créer 4 bundles : MainBundle, BackOfficeBundle, FrontOfficeBundle et CmsBundle.
MainBundle va contenir nos Entités, BackOfficeBundle sera dédié au BackOffice, FrontOfficeBundle sera dédié à l'espace mon compte pour les utilisateurs inscrits au site (front-office) et enfin CmsBundle sera dédié à la gestion de la partie publique du site.
Lors de la création des bundles, on choisira le yml pour le format des fichiers de configuration.
sudo php app/console generate:bundle --namespace=SfWebApp/MainBundle
sudo php app/console generate:bundle --namespace=SfWebApp/BackOfficeBundle
sudo php app/console generate:bundle --namespace=SfWebApp/FrontOfficeBundle
sudo php app/console generate:bundle --namespace=SfWebApp/CmsBundle
Vérifier que les Bundles soient bien enregistrés dans le kernel :
nano AppKernel.php
$bundles = array(
// ...
// app bundle
new SfWebApp\MainBundle\SfWebAppMainBundle(),
new SfWebApp\BackOfficeBundle\SfWebAppBackOfficeBundle(),
new SfWebApp\FrontOfficeBundle\SfWebAppFrontOfficeBundle(),
new SfWebApp\CmsBundle\SfWebAppCmsBundle(),
// ...
);
3 - Installation du vendor FOSUserBundle
On va ajouter à la section "require" de notre fichier /composer.json le bundle FOSUserBundle dans la section "require" :
"friendsofsymfony/user-bundle": "v1.3.6"
On lance un composer update :
sudo php composer.phar update
Ensuite on enregistre les bundles dans le fichier AppKernel en ajoutant dans le tableau $bundles, l'entrée suivante:
// user
new FOS\UserBundle\FOSUserBundle(),
Mettre à jour les droits sur les dossiers :
sudo chown -R "user" sf_sf_web_app sudo chmod -R 755 sf_sf_web_app sudo chmod -R 777 sf_sf_web_app/app/cache sf_sf_web_app/app/logs
4 - Configuration de du fichier de config de l'app :
On va configurer les directives du fichier config.yml de notre app en modifiant la section concernée comme suit :
nano app/config/config.yml
# FOS User Bundle
fos_user:
db_driver: orm
firewall_name: main
user_class: SfWebApp\MainBundle\Entity\User
service:
mailer: fos_user.mailer.twig_swift
registration:
form:
type: sf_web_app_fos_user_register
validation_groups: [Register, Default, Registration]
confirmation:
enabled: true
template: SfWebAppFrontOfficeBundle:Registration:email.html.twig
profile:
form:
type: sf_web_app_fos_user_profile
#validation_groups: [Profile, Default]
resetting:
email:
template: SfWebAppFrontOfficeBundle:Resetting:email.html.twig
group:
group_class: SfWebApp\MainBundle\Entity\Group
from_email:
address: mail@domain.tld
sender_name: name
Toujours dans le même fichier, on va activer le traducteur :
framework:
translator: ~
Créer un dossier session vide avec un fichier gitkeep à la racine de app afin de pouvoir commiter un dossier de session vide sur le serveur. Ne pas oublier d'exclure le contenu du dossier dans le fichier ".gitignore".
mkdir app/sessions chmod -R 777 app/sessions
5 - Créations des entité User et Group
On va créer deux entités User et Group qui vont étendre les entités du bundle FOSUserBundle.
Créations de l'entité User :
nano src/SfWebApp/MainBundle/Entity/User.php
<?php
namespace SfWebApp\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use FOS\UserBundle\Entity\User as BaseUser;
/**
* Class User
* @package SfWebApp\MainBundle\Entity
* @ORM\Table(name="fos_user")
* @ORM\Entity
*/
class User extends BaseUser
{
const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
const ROLE_ADMIN = 'ROLE_ADMIN';
const ROLE_USER = 'ROLE_USER';
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var
*
* @ORM\ManyToMany(targetEntity="Group", inversedBy="users")
* @ORM\JoinTable(name="users_groups",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
/**
* @var
*
* @ORM\Column(name="gender", type="string", length=255, nullable=true)
*/
protected $gender;
/**
* @var
*
* @ORM\Column(name="firstname", type="string", length=255, nullable=true)
*/
protected $firstname;
/**
* @var
*
* @ORM\Column(name="lastname", type="string", length=255, nullable=true)
*/
protected $lastname;
/**
* @var
*
* @ORM\Column(name="address", type="text", nullable=true, nullable=true)
*/
protected $address;
/**
* @var
*
* @ORM\Column(name="zip_code", type="string", length=255, nullable=true)
*/
protected $zipCode;
/**
* @var
*
* @ORM\Column(name="city", type="string", length=255, nullable=true)
*/
protected $city;
/**
* @var
*
* @ORM\Column(name="country", type="string", length=255, nullable=true)
*/
protected $country;
/**
* @var
*
* @ORM\Column(name="phone", type="string", length=255, nullable=true)
*/
protected $phone;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->groups = new ArrayCollection();
}
/**
* @param mixed $gender
*/
public function setGender($gender)
{
$this->gender = $gender;
}
/**
* @return mixed
*/
public function getGender()
{
return $this->gender;
}
/**
* @param mixed $firstname
*/
public function setFirstname($firstname)
{
$this->firstname = $firstname;
}
/**
* @return mixed
*/
public function getFirstname()
{
return $this->firstname;
}
/**
* @param mixed $lastname
*/
public function setLastname($lastname)
{
$this->lastname = $lastname;
}
/**
* @return mixed
*/
public function getLastname()
{
return $this->lastname;
}
/**
* @param mixed $address
*/
public function setAddress($address)
{
$this->address = $address;
}
/**
* @return mixed
*/
public function getAddress()
{
return $this->address;
}
/**
* @param mixed $city
*/
public function setCity($city)
{
$this->city = $city;
}
/**
* @return mixed
*/
public function getCity()
{
return $this->city;
}
/**
* @param mixed $country
*/
public function setCountry($country)
{
$this->country = $country;
}
/**
* @return mixed
*/
public function getCountry()
{
return $this->country;
}
/**
* @param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @param mixed $zipCode
*/
public function setZipCode($zipCode)
{
$this->zipCode = $zipCode;
}
/**
* @return mixed
*/
public function getZipCode()
{
return $this->zipCode;
}
/**
* @param mixed $phone
*/
public function setPhone($phone)
{
$this->phone = $phone;
}
/**
* @return mixed
*/
public function getPhone()
{
return $this->phone;
}
/**
* @param $group
* @return $this
*/
public function addGoup($group)
{
$this->groups[] = $group;
$group->setUser($this);
return $this;
}
/**
* @param $groups
*/
public function setGroups($groups)
{
$this->groups->clear();
foreach ($groups as $group) {
$this->addGroup($group);
}
}
/**
* @return ArrayCollection
*/
public function getGroups()
{
return $this->groups;
}
}
Création de l'entité Group :
nano src/SfWebApp/MainBundle/Entity/Group.php
<?php
namespace SfWebApp\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use FOS\UserBundle\Entity\Group as BaseGroup;
/**
* Group
*
* @ORM\Table(name="fos_group")
* @ORM\Entity
*/
class Group extends BaseGroup
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var
*
* @ORM\ManyToMany(targetEntity="User", mappedBy="groups")
*/
protected $users;
/**
* Constructor
*/
public function __construct($name, $roles)
{
parent::__construct($name, $roles);
$this->users = new ArrayCollection();
}
/**
* @param $user
* @return $this
*/
public function addUser($user)
{
$this->users[] = $user;
$user->setGroup($this);
return $this;
}
/**
* @param $users
*/
public function setUsers($users)
{
$this->users->clear();
foreach ($users as $user) {
$this->addUser($user);
}
}
/**
* @return mixed
*/
public function getUsers()
{
return $this->users;
}
}
6 - Configuration de security.yml
On configure le fichier security.yml de façon à ce que le login soit pris en charge par FOSUserBundle. On va donc modifier les directives de notre fichier security.yml comme suit :
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_USER: [ROLE_USER]
ROLE_ADMIN: [ROLE_ADMIN]
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
# login area for backoffice users
backoffice:
context: primary_auth
pattern: ^/admin
form_login:
provider: fos_userbundle
login_path: sf_web_app_back_office_security_login
use_forward: true
use_referer: true
check_path: sf_web_app_back_office_security_check
failure_path: sf_web_app_back_office_bundle_admin_index
default_target_path: sf_web_app_back_office_bundle_admin_index
logout:
path: sf_web_app_back_office_security_logout
target: sf_web_app_cms_bundle_homepage
anonymous: true
# defaut login area for standard users
main:
context: primary_auth
pattern: ^/
form_login:
provider: fos_userbundle
login_path: fos_user_security_login
use_forward: true
use_referer: true
check_path: fos_user_security_check
#failure_path: null
default_target_path: fos_user_profile_show
logout:
path: fos_user_security_logout
target: sf_web_app_cms_bundle_homepage
anonymous: true
access_control:
# back-office
- { path: ^/admin/connexion, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/private-space, roles: ROLE_USER }
# front-office
- { path: ^/, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/connexion, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/inscription, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/mot-de-passe-oublie, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/profile, role: IS_AUTHENTICATED_FULLY }
- { path: ^/deconnexion$, role: IS_AUTHENTICATED_FULLY }
7 - Création de la base de données et mise à jour du schéma
Lancer les commandes suivantes :
php app/console doctrine:database:create php app/console doctrine:schema:update --force
8 - Nettoyage du bundle CmsBundle
Mise en place d'une route, action de controller et vue pour la home de notre site.
Dans le fichier routing.yml du bundle, ajouter la route suivante :
nano src/SfWebApp/CmsBundle/Ressources/config/routing.yml
sf_web_app_cms_homepage:
path: /
defaults: { _controller: SfWebAppCmsBundle:Default:index }
Dans le DefaultController :
nano src/SfWebApp/CmsBundle/Controller/DefaultController.php
<?php
namespace SfWebApp\CmsBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
public function indexAction()
{
return $this->render('SfWebAppCmsBundle:Default:index.html.twig');
}
}
Dans la vue index :
nano src/SfWebApp/CmsBundle/Resources/views/Default/index.html.twig
Hello !
A partir de ce moment, on va pouvoir charger la home de notre site dans l'environnement de dev : http://sf-web-app.local/app_dev.php
9 - Ajouts des routes
On ajoute les routes pour nos bundles dans le fichier de routing de l'app :
nano app/config/routing.yml
# FOS USER BUNDLE ROUTES
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: /change-password
# REGISTRATION
fos_user_registration_register:
pattern: /inscription
defaults: { _controller: FOSUserBundle:Registration:register }
requirements:
_method: GET|POST
fos_user_registration_check_email:
pattern: /inscription/e-mail
defaults: { _controller: FOSUserBundle:Registration:checkEmail }
requirements:
_method: GET
fos_user_registration_confirm:
pattern: /inscription/confirmation/{token}
defaults: { _controller: FOSUserBundle:Registration:confirm }
requirements:
_method: GET
fos_user_registration_confirmed:
pattern: /inscription/confirmation
defaults: { _controller: FOSUserBundle:Registration:confirmed }
requirements:
_method: GET
# RESETTING PASSWORD
fos_user_resetting_request:
pattern: /mot-de-passe-oublie/reinitialisation
defaults: { _controller: FOSUserBundle:Resetting:request }
requirements:
_method: GET
fos_user_resetting_send_email:
pattern: /mot-de-passe-oublie/e-mail
defaults: { _controller: FOSUserBundle:Resetting:sendEmail }
requirements:
_method: GET|POST
fos_user_resetting_check_email:
pattern: /mot-de-passe-oublie/verification
defaults: { _controller: FOSUserBundle:Resetting:checkEmail }
requirements:
_method: GET
fos_user_resetting_reset:
pattern: /mot-de-passe-oublie/{token}
defaults: { _controller: FOSUserBundle:Resetting:reset }
requirements:
_method: GET|POST
# APP BUNDLES
sf_web_app_cms:
resource: « @SfWebAppCmsBundle/Resources/config/routing.yml"
prefix: /
sf_web_app_back_office:
resource: « @SfWebAppBackOfficeBundle/Resources/config/routing.yml"
prefix: /admin
sf_web_app_front_office:
resource: « @SfWebAppFrontOfficeBundle/Resources/config/routing.yml"
prefix: /private-space
On va pouvoir ajouter ensuite les routes des Bundles.
9.1 - Ajouts des routes du BackOfficeBundle
Création du fichier de routes rassemblant les includes :
nano app/src/SfWebApp/BackOfficeBundle/Resources/config/routing.yml
# SECURITY
sf_web_app_back_office_security:
resource: "@SfWebAppBackOfficeBundle/Resources/config/routing/security.yml"
# BACKOFFICE
sf_web_app_back_office_bo:
resource: "@SfWebAppBackOfficeBundle/Resources/config/routing/backoffice.yml"
Création du fichier de routes pour l'authentification :
nano app/src/SfWebApp/BackOfficeBundle/Resources/config/routing/security.yml
sf_web_app_back_office_security_login:
path: /login
defaults: { _controller: SfWebAppBackOfficeBundle:Security:login }
sf_web_app_back_office_security_check:
path: /login-check
defaults: { _controller: SfWebAppBackOfficeBundle:Security:check }
requirements:
_method: POST
sf_web_app_back_office_security_logout:
path: /logout
defaults: { _controller: SfWebAppBackOfficeBundle:Security:logout }
Création du fichier de routes pour le back-office :
nano app/src/SfWebApp/BackOfficeBundle/Resources/config/routing/backoffice.yml
sf_web_app_backofficebundle_home:
pattern: /
defaults: { _controller: "SfWebAppBackOfficeBundle:Default:index" }
requirements:
_method: GET
9.2 - Ajouts des routes du FrontOfficeBundle
Création du fichier de routes pour le front-office :
nano app/src/SfWebApp/FrontOfficeBundle/Resources/config/routing.yml
sf_web_app_front_office_homepage:
path: /
defaults: { _controller: SfWebAppFrontOfficeBundle:Default:index }
# SECURITY
sf_web_app_front_office_security:
resource: « @SfWebAppFrontOfficeBundle/Resources/config/routing/security.yml"
9.3 - Ajouts des routes du Front
Création du fichier de routes pour le front :
nano app/src/SfWebApp/CmsBundle/Resources/config/routing.yml
sf_web_app_cms_homepage:
path: /
defaults: { _controller: SfWebAppCmsBundle:Default:index }
9.3.1 - Surcharge routes Profile
mkdir src/SfWebApp/FrontOfficeBundle/Resources/config/routing
nano src/SfWebApp/FrontOfficeBundle/Resources/config/routing/security.yml
# PROFILE
fos_user_profile_show:
pattern: /profile
defaults: { _controller: FOSUserBundle:Profile:show }
requirements:
_method: GET
fos_user_profile_edit:
pattern: /profile/editer
defaults: { _controller: FoulquierInfoFrontOfficeBundle:Profile:edit }
requirements:
_method: GET|POST
10 - Création d'un utilisateur admin
Création d'un utilisateur admin avec le mot de passe admin.
php app/console fos:user:create admin admin@example.com admin --super-admin
11 - Création du controller Security et de la vue login
Dans le BackOfficeBundle, on va créer le controller chargé de l'authentification :
nano src/SfWebApp/BackOfficeBundle/Controller/SecurityController.php
<?php
namespace SfWebApp\BackOfficeBundle\Controller;
use FOS\UserBundle\Controller\SecurityController as BaseSecurityController;
class SecurityController extends BaseSecurityController
{
/**
* Renders the login template with the given parameters. Overwrite this function in
* an extended controller to provide additional data for the login template.
*
* @param array $data
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function renderLogin(array $data)
{
return $this->container->get('templating')->renderResponse('SfWebAppBackOfficeBundle:Security:login.html.twig', $data);
}
}
Création du template de base pour le back-office :
nano app/Resources/views/back-office.html.twig
{# add navigation current nav mark #}
{% set route = app.request.get('_route') %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>{% block title %}Back-Office Blog Test{% endblock %}</title>
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
{% block stylesheets %}
{% stylesheets filter='cssrewrite'
'@SfWebAppBackOfficeBundle/Resources/public/css/libs/bootstrap.min.css'
'@SfWebAppBackOfficeBundle/Resources/public/css/libs/bootstrap-theme.min.css'
'@SfWebAppBackOfficeBundle/Resources/public/css/libs/jquery-ui.min.css'
'@SfWebAppBackOfficeBundle/Resources/public/css/libs/jquery-ui.structure.min.css'
'@SfWebAppBackOfficeBundle/Resources/public/css/libs/backoffice.css' %}
<link rel="stylesheet" href="{{ asset_url }}" type="text/css" />
{% endstylesheets %}
{% endblock %}
</head>
<body>
<div class="container">
{% block header %}{% endblock %}
{% block flash %}
{% for flashMessage in app.session.flashbag.get('notice') %}
<div>
{{ flashMessage }}
</div>
{% endfor %}
{% for flashMessage in app.session.flashbag.get('error') %}
<div>
{{ flashMessage }}
</div>
{% endfor %}
{% endblock %}
<!-- container content - BEGIN -->
<div class="container container-content">
<div id="layout-view" class="view view-villa-all">
{% block content %}{% endblock %}
</div>
</div>
<!-- container content - END -->
{% block footer %}{% endblock footer %}
</div>
{% block javascripts %}
{% javascripts
'@SfWebAppBackOfficeBundle/Resources/public/js/libs/jquery-1.10.1.min.js'
'@SfWebAppBackOfficeBundle/Resources/public/js/libs/jquery-ui.min.js'
'@SfWebAppBackOfficeBundle/Resources/public/js/libs/bootstrap.min.js' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
<script>
// get locale
locale = "{{ app.request.locale }}";
// get route
route = "{{ route }}";
</script>
{% endblock %}
</body>
</html>
On prendra soin d'ajouter TwitterBootstrap et jQuery aux templates (FrontOffice, BackOffice et Cms). Pour cela on va créer dans chacun des dossiers css et js dans src/SfWebApp/BackOfficeBundle/Resources/public/, un dossier libs auquel on va ajouter les fichiers JS et CSS de TwitterBootstrap et jQuery.
Création du template pour le login :
nano src/SfWebApp/BackOfficeBundle/Resources/views/layout-login.htm.twig
{% extends '::back-office.html.twig' %}
{% block header %}
{% endblock %}
{% block content %}
{% endblock %}
{% block footer %}
{% endblock %}
Création de la vue login :
nano src/SfWebApp/BackOfficeBundle/Resources/views/Security/login.htm.twig
{% extends 'SfWebAppBackOfficeBundle::layout-login.html.twig' %}
{% block content %}
<div id="layout-view" class="view view-login">
{% if error %}
<div class="bg-danger">{{ error|trans({}, 'FOSUserBundle') }}</div>
{% endif %}
<div id="login-form" class="col-md-4 col-md-offset-4">
<h1 class="text-center">Blog Test</h1>
<form action="{{ path("sf_web_app_back_office_security_check") }}" method="post" class="center-block">
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
<div class="form-group">
<input class="form-control" type="text" id="username" name="_username" value="{{ last_username }}" required="required" placeholder="{{ 'email_address'|trans }}"/>
</div>
<div class="form-group">
<input class="form-control" type="password" id="password" name="_password" required="required" placeholder="{{ 'password'|trans }}"/>
</div>
<div class="form-group">
<input type="checkbox" id="remember_me" name="_remember_me" value="on" />
<label for="remember_me">{{ 'security.login.remember_me'|trans({}, 'FOSUserBundle') }}</label>
</div>
<input class="btn btn-primary btn-block" type="submit" id="_submit" name="_submit" value="{{ 'security.login.submit'|trans({}, 'FOSUserBundle') }}" />
</form>
</div>
</div>
{% endblock %}
On génère les assets :
rm -rf app/cache/* php app/console assets:install --symlink php app/console assetic:dump
12 - Ajout des traductions
On va ajouter les traductions pour le login :
mkdir app/Resources/translations
nano app/Resources/translations/FOSUserBundle.fr.yml
profile:
fields:
gender: Civilité
firstname: Prénom
lastname: Nom
address: Adresse
zip_code: Code postal
phone: Tél.
email: E-mail
password_first: Mot de passe
password_second: Mot de passe (validation)
register:
fields:
firstname: Nom
# Resetting account
resetting:
email:
subject: |
Réinitialisation de votre mot de passe
message: |
<p>Pour réinitialiser votre mot de passe, merci de cliquer sur le lien suivant :</p>
<p><a href="%confirmationUrl%">%confirmationUrl%</a></p>
# Registration
registration:
confirmed: Votre compte est maintenant activé.
email:
subject: |
Confirmation de l'inscription
message: |
<p>Pour valider votre compte utilisateur, merci de vous rendre sur :</p>
<p><a href="%confirmationUrl%">%confirmationUrl%</a></p>
13 - Accès à l'admin
On peut dès maintenant accès à notre admin par l'url suivante > http://sf-web-app.local/app_dev.php/backoffice/
Partie 2 - Création de l'espace utilisateur
1 - Création du controller DefaultController
nano src/SfWebApp/FrontOfficeBundle/Controller/DefaultController.php
<?php
namespace SfWebApp\FrontOfficeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
public function indexAction()
{
return $this->render('SfWebAppFrontOfficeBundle:Default:index.html.twig');
}
}
2 - Création de la vue index
nano src/SfWebApp/FrontOfficeBundle/Resources/Default/index.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout.html.twig' %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-info">
<div class="panel-heading">
<h2 class="panel-title">{{ 'dashboard'|trans }}</h2>
</div>
<div class="panel-body">
</div>
</div>
</div>
</div>
{% endblock %}
Partie 3 - Création du login et inscription espace utilisateur
1 - SfWebAppFrontOfficeBundle hérite de FOSUserBundle
nano src/SfWebApp/FrontOfficeBundle/SfWebAppFrontOfficeBundle.php
<?php
namespace SfWebApp\FrontOfficeBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class SfWebAppFrontOfficeBundle extends Bundle
{
public function getParent()
{
return 'FOSUserBundle';
}
}
2 - Création des formulaires d'inscription et de modifications des informations utilisateurs
2.1 - Formulaire information utilisateur
nano src/SfWebApp/FrontOfficeBundle/Form/Type/ProfileType.php
<?php
namespace SfWebApp\FrontOfficeBundle\Form\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use FOS\UserBundle\Form\Type\ProfileFormType;
class ProfileType extends ProfileFormType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('gender', 'choice', array(
'label' => 'profile.fields.gender',
'translation_domain' => 'forms',
'choices' => array(
'm' => 'M.',
'f' => 'Mme'
),
'required' => false
))
->add('firstname', 'text', array(
'label' => 'profile.fields.firstname',
'translation_domain' => 'forms',
'required' => false
))
->add('lastname', 'text', array(
'label' => 'profile.fields.lastname',
'translation_domain' => 'forms',
'required' => false
))
->add('address', 'textarea', array(
'label' => 'profile.fields.address',
'translation_domain' => 'forms',
'required' => false
))
->add('zip_code', 'text', array(
'label' => 'profile.fields.zip_code',
'translation_domain' => 'forms',
'required' => false
))
->add('city', 'text', array(
'label' => 'profile.fields.city',
'translation_domain' => 'forms',
'required' => false
))
->add('country', 'text', array(
'label' => 'profile.fields.country',
'translation_domain' => 'forms',
'required' => false
))
->add('phone', 'text', array(
'label' => 'profile.fields.phone',
'translation_domain' => 'forms',
'required' => false
))
->add('email', 'email', array(
'label' => 'profile.fields.email',
'translation_domain' => 'forms',
'required' => false
))
->add('plainPassword', 'repeated', array(
'first_options' => array(
'label' => 'profile.fields.password_first',
'required' => false
),
'second_options' => array(
'label' => 'profile.fields.password_second'
),
'required' => false,
'translation_domain' => 'forms',
'required' => false
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => array('Default', 'Account'),
'data_class' => 'SfWebApp\MainBundle\Entity\User'
));
}
public function getName()
{
return ‘sf_web_app_fos_user_profile';
}
}
3.2 - Formulaire inscription utilisateur
nano src/SfWebApp/FrontOfficeBundle/Form/Type/RegisterType.php
<?php
namespace SfWebApp\FrontOfficeBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use FOS\UserBundle\Form\Type\RegistrationFormType;
class RegisterType extends RegistrationFormType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder
->add('gender', 'text', array(
'label' => 'profile.fields.gender',
'translation_domain' => 'forms'
))
->add('firstname', 'text', array(
'label' => 'profile.fields.firstname',
'translation_domain' => 'forms'
))
->add('lastname', 'text', array(
'label' => 'profile.fields.lastname',
'translation_domain' => 'forms'
))
->add('address', 'text', array(
'label' => 'profile.fields.address',
'translation_domain' => 'forms'
))
->add('zip_code', 'text', array(
'label' => 'profile.fields.zip_code',
'translation_domain' => 'forms'
))
->add('city', 'text', array(
'label' => 'profile.fields.city',
'translation_domain' => 'forms'
))
->add('country', 'text', array(
'label' => 'profile.fields.country',
'translation_domain' => 'forms'
))
->add('phone', 'text', array(
'label' => 'profile.fields.phone',
'translation_domain' => 'forms'
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => ’SfWebApp\MainBundle\Entity\User'
));
}
public function getName()
{
return ‘sf_web_app_fos_user_register';
}
}
3.3 - Enregistrement des formulaires en tant que services
nano src/SfWebApp/FrontOfficeBundle/Resources/config/services.yml
services:
user.form.profile.type:
class: SfWebApp\FrontOfficeBundle\Form\Type\ProfileType
parent: fos_user.profile.form.type
tags:
- { name: form.type, alias: sf_web_app_fos_user_profile }
user.form.register.type:
class: SfWebApp\FrontOfficeBundle\Form\Type\RegisterType
parent: fos_user.registration.form.type
tags:
- { name: form.type, alias: sf_web_app_fos_user_register }
3.4 - Création des vues profile
- Création de la vue profile show :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Profile/show.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout.html.twig' %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-info">
<div class="panel-heading">
<h2 class="panel-title">{{ 'profile'|trans }}</h2>
</div>
<div class="panel-body">
<p>Nom d'utilisateur : {{ app.user.username }}</p>
<p>Prénom : {{ app.user.firstname }}</p>
<p>Nom : {{ app.user.lastname }}</p>
<p>CP : {{ app.user.zipCode }}</p>
<p>Ville : {{ app.user.city }}</p>
<p>Pays : {{ app.user.country }}</p>
<p>Tel. : {{ app.user.phone }}</p>
<p>Adresse e-mail : {{ app.user.email }}</p>
<a href="{{ path('fos_user_profile_edit') }}" class="btn btn-primary">{{ 'edit' }}</a>
</div>
</div>
</div>
</div>
{% endblock %}
- Création de la vue profile edit :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Profile/edit.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout.html.twig' %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-info">
<div class="panel-heading">
<h2 class="panel-title">{{ 'user_infos'|trans }}</h2>
</div>
<div class="panel-body">
{% form_theme form 'bootstrap_3_layout.html.twig' %}
{{ form_start(form) }}
{{ form_row(form.gender) }}
{{ form_row(form.firstname) }}
{{ form_row(form.lastname) }}
{{ form_row(form.email) }}
{{ form_row(form.phone) }}
{{ form_row(form.address) }}
{{ form_row(form.zip_code) }}
{{ form_row(form.city) }}
{{ form_row(form.country) }}
{{ form_row(form.plainPassword.first) }}
{{ form_row(form.plainPassword.second) }}
<button type="submit" value="Mettre à jour" class="btn btn-success"/>{{ 'save'|trans }}</button>
{{ form_end(form) }}
</div>
</div>
</div>
</div>
{% endblock %}
3.5 - Création des vues registration
- Création de la vue register :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Registration/register.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout.html.twig' %}
{% block title %}Register{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-info">
<div class="panel-heading">
<h2 class="panel-title">{{ 'title_user_register'|trans }}</h2>
</div>
<div class="panel-body">
{% form_theme form 'bootstrap_3_layout.html.twig' %}
{{ form_start(form) }}
{{ form_row(form.gender) }}
{{ form_row(form.username) }}
{{ form_row(form.firstname) }}
{{ form_row(form.lastname) }}
{{ form_row(form.email) }}
{{ form_row(form.phone) }}
{{ form_row(form.address) }}
{{ form_row(form.zip_code) }}
{{ form_row(form.city) }}
{{ form_row(form.country) }}
{{ form_row(form.plainPassword.first) }}
{{ form_row(form.plainPassword.second) }}
<button type="submit" value="{{ 'registration.submit'|trans({}, 'FOSUserBundle') }}" class="btn btn-success"/>{{ 'register'|trans }}</button>
{{ form_end(form) }}
</div>
</div>
</div>
</div>
{% endblock %}
- Création de la vue email :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Registration/email.html.twig
{% block subject %}
{% autoescape false %}
{{ 'registration.email.subject'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}, 'FOSUserBundle') }}
{% endautoescape %}
{% endblock %}
{% block body_text %}
{% autoescape false %}
{{ 'registration.email.message'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}, 'FOSUserBundle') }}
{% endautoescape %}
{% endblock %}
{% block body_html %}
{% include 'SfWebAppFrontOfficeBundle:Registration:inc/email.html.twig' %}
{% endblock %}
- Création de la vue confirmed :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Registration/confirmed.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout.html.twig' %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-info">
<div class="panel-heading">
<h2 class="panel-title">{{ 'title_user_register'|trans }}</h2>
</div>
<div class="panel-body">
<p>{{ 'registration.confirmed'|trans({'%username%': user.username}, 'FOSUserBundle') }}</p>
{% if app.session is not empty %}
{% set targetUrl = app.session.get('_security.' ~ app.security.token.providerKey ~ '.target_path') %}
{% if targetUrl is not empty %}<p><a href="{{ targetUrl }}">{{ 'registration.back'|trans({}, 'FOSUserBundle') }}</a></p>{% endif %}
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
- Création de la vue checkEmail :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Registration/checkEmail.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout.html.twig' %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-info">
<div class="panel-heading">
<h2 class="panel-title">{{ 'check_email'|trans }}</h2>
</div>
<div class="panel-body">
<p>{{ 'registration.check_email'|trans({'%email%': user.email}, 'FOSUserBundle') }}</p>
</div>
</div>
</div>
</div>
{% endblock %}
- Création de l'include email :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Registration/inc/email.html.twig
<html>
<head>
<style type="text/CSS">
/* for Yahoo Beta, AOL */
body, #body_style {background: #ffffff; min-height: 200px; color: #fff; font-family: Arial, Helvetica, sans-serif; font-size: 12px;}
/* for Hotmail */
.ExternalClass {width: 100%;}
/* for Yahoo Classic and New */
.yshortcuts {color: #F00;}
/* some css reset for Gmail, Hotmail */
p {margin: 0; padding: 0; margin-bottom: 0;}
a, a:link, a:visited {color: #2A5DB0;}
</style>
</head>
{# for Gmail, Lotus Notes 6.5 and 7, AOL #}
<body style="background: #ffffff; min-height: 500px; color: #000; font-family: Arial, Helvetica, sans-serif; font-size: 13px" alink="#FF0000" link="#FF0000" bgcolor="#f5f5f5" text="#000000">
{# for AOL #}
<span id="body_style" style="display: block">
<table bgcolor="#ffffff" width="600" align="center">
<tr>
<td>
<table width="600" border="0" align="center" cellpadding="0" cellspacing="0" bgcolor="#ffffff">
<tr>
<td></td>
</tr>
<tr style="height: 20px;"></tr>
</table>
<!-- CONTENT - BEGIN -->
<table width="600" border="0" align="center" cellpadding="0" cellspacing="0" bgcolor="#ffffff">
<tr>
<td style="color: #000000; font-family: Tahoma, Arial, sans-serif; font-size: 10pt; width: 600px; padding: 0px;">
<div style="margin-left: 10px; margin-right: 10px;">
<p>Confirmation inscription</p>
<p style="text-align: left;">{{ 'registration.email.message'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}, 'FOSUserBundle')|raw }}</p>
</div>
</td>
</tr>
<tr style="height: 40px;"></tr>
</table>
<!-- CONTENT - END -->
</td>
</tr>
</table>
</span>
</body>
</html>
3.6 - Création des vues resetting
- Création de la vue reset :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Resetting/reset.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout.html.twig' %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-info">
<div class="panel-heading">
<h2 class="panel-title">{{ 'reset_password'|trans }}</h2>
</div>
<div class="panel-body">
{% form_theme form 'bootstrap_3_layout.html.twig' %}
{{ form_start(form) }}
{{ form_row(form.new.first) }}
{{ form_row(form.new.second) }}
<button type="submit" class="btn btn-primary" value="{{ 'resetting.reset.submit'|trans({}, 'FOSUserBundle') }}" />{{ 'reset_password'|trans }}</button>
{{ form_end(form) }}
</div>
</div>
</div>
</div>
{% endblock %}
- Création de la vue request :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Resetting/request.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout.html.twig' %}
{% block content %}
<div class="row" >
<div class="col-md-12">
<div class="panel panel-info">
<div class="panel-heading">
<h2 class="panel-title">{{ 'reset_password'|trans }}</h2>
</div>
<div class="panel-body">
{% if invalid_username is defined %}
<p>{{ 'resetting.request.invalid_username'|trans({'%username%': invalid_username}, 'FOSUserBundle') }}</p>
{% endif %}
<form action="{{ path('fos_user_resetting_send_email') }}" method="POST" class="fos_user_resetting_request">
<div class="form-group">
<label for="username">{{ 'resetting.request.username'|trans({}, 'FOSUserBundle') }}</label>
<input type="text" id="username" class="form-control" name="username" required="required" />
</div>
<button type="submit" class="btn btn-primary" value="{{ 'resetting.request.submit'|trans({}, 'FOSUserBundle') }}" />{{ 'reset_password'|trans }}</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
- Création de la vue passwordAlreadyRequested :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Resetting/passwordAlreadyRequested.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout.html.twig' %}
{% block content %}
<div class="row"></div>
<p>{{ 'resetting.password_already_requested'|trans({}, 'FOSUserBundle') }}</p>
{% endblock %}
- Création de la vue email :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Resetting/email.html.twig
{% block subject %}
{% autoescape false %}
{{ 'resetting.email.subject'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}, 'FOSUserBundle') }}
{% endautoescape %}
{% endblock %}
{% block body_text %}
{% autoescape false %}
{{ 'resetting.email.message'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}, 'FOSUserBundle') }}
{% endautoescape %}
{% endblock %}
{% block body_html %}
{% include 'SfWebAppFrontOfficeBundle:Resetting:inc/email.html.twig' %}
{% endblock %}
- Création de la vue checkEmail :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Resetting/checkEmail.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout.html.twig' %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-info">
<div class="panel-heading">
<h2 class="panel-title">{{ 'reset_password'|trans }}</h2>
</div>
<div class="panel-body">
<p>{{ 'resetting.check_email'|trans({'%email%': email}, 'FOSUserBundle') }}</p>
</div>
</div>
</div>
</div>
{% endblock %}
- Création de l'include email :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Resetting/inc/email.html.twig
<html>
<head>
<style type="text/CSS">
/* for Yahoo Beta, AOL */
body, #body_style {background: #ffffff; min-height: 200px; color: #fff; font-family: Arial, Helvetica, sans-serif; font-size: 12px;}
/* for Hotmail */
.ExternalClass {width: 100%;}
/* for Yahoo Classic and New */
.yshortcuts {color: #F00;}
/* some css reset for Gmail, Hotmail */
p {margin: 0; padding: 0; margin-bottom: 0;}
a, a:link, a:visited {color: #2A5DB0;}
</style>
</head>
{# for Gmail, Lotus Notes 6.5 and 7, AOL #}
<body style="background: #ffffff; min-height: 500px; color: #000; font-family: Arial, Helvetica, sans-serif; font-size: 13px" alink="#FF0000" link="#FF0000" bgcolor="#f5f5f5" text="#000000">
{# for AOL #}
<span id="body_style" style="display: block">
<table bgcolor="#ffffff" width="600" align="center">
<!-- DI - BEGIN -->
<tr>
<td>
<table width="600" border="0" align="center" cellpadding="0" cellspacing="0" bgcolor="#ffffff">
<tr>
<td></td>
</tr>
<tr style="height: 20px;"></tr>
</table>
<!-- CONTENT - BEGIN -->
<table width="600" border="0" align="center" cellpadding="0" cellspacing="0" bgcolor="#ffffff">
<tr>
<td style="color: #000000; font-family: Tahoma, Arial, sans-serif; font-size: 10pt; width: 600px; padding: 0px;">
<div align="left">
<p>{{ 'resetting.email.message'|trans({'%username%': user.username, '%confirmationUrl%': confirmationUrl}, 'FOSUserBundle')|raw }}</p>
</div>
</td>
</tr>
<tr style="height: 40px;"></tr>
</table>
<!-- CONTENT - END -->
</td>
</tr>
<!-- DI - END -->
</table>
</span>
</body>
</html>
3.7 - Création la vue login et des templates du bundle
- Création de la vue login :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/Security/login.html.twig
{% extends 'SfWebAppFrontOfficeBundle::layout-login.html.twig' %}
{% block content %}
<div id="layout-view" class="view view-login">
{% if error %}
<div class="bg-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<div id="login-form" class="col-md-4 col-md-offset-4">
<div class="columns clearfix">
<div class="column-01">
</div>
<div class="column-02">
<h1></h1>
<p>Espace client</p>
</div>
</div>
<form action="{{ path("fos_user_security_check") }}" method="post" class="center-block">
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
<div class="form-group">
<input type="text" class="form-control" id="username" name="_username" value="{{ last_username }}" required="required"/>
</div>
<div class="form-group">
<input type="password" class="form-control" id="password" name="_password" required="required"/>
</div>
<div class="form-group">
<input type="checkbox" id="remember_me" name="_remember_me" value="on" />
<label for="remember_me">{{ 'security.login.remember_me'|trans({}, 'FOSUserBundle') }}</label>
</div>
<div class="form-group">
<a href="{{ path('fos_user_resetting_request') }}">
<strong>{{ 'reset_password'|trans }}</strong>
</a>
</div>
<input class="btn btn-primary btn-block" type="submit" id="_submit" name="_submit" value="{{ 'security.login.submit'|trans({}, 'FOSUserBundle') }}" />
</form>
</div>
</div>
{% endblock %}
- Création du layout login :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/layout-login.html.twig
{% extends '::front-office.html.twig' %}
{% block header %}
{% endblock %}
{% block content %}
{% endblock %}
{% block footer %}
{% endblock %}
- Création du layout de FrontOfficeBunble :
nano src/SfWebApp/FrontOfficeBundle/Resources/views/layout.html.twig
{% extends '::front-office.html.twig' %}
{% block header %}
<nav class="navbar navbar-default main-nav">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
<ul class="nav navbar-nav">
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a class="dropdown-toggle" href="" data-toggle="dropdown">{{ app.user.firstname }} {{ app.user.lastname }} <b class="caret"></b></a>
<ul class="dropdown-menu">
<li>
<a href="{{ path('fos_user_profile_show') }}">{{ 'my_account'|trans }}</a>
</li>
<li>
<a href="{{ path('fos_user_security_logout') }}">{{ 'logout'|trans }}</a>
</li>
</ul>
</li>
</ul>
{% else %}
<ul class="nav navbar-nav">
<li>
<a href="">{{ 'sf_web_app'|trans }}</a>
</li>
</ul>
{% endif %}
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
{% endblock %}
{% block content %}{% endblock %}
{% block footer %}{% endblock %}
- Création du template front-office :
nano app/Resources/views/front-office.html.twig
{# add navigation current nav mark #}
{% set route = app.request.get('_route') %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>{% block title %}Front-Office D&i{% endblock %}</title>
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
{% block stylesheets %}
{% stylesheets filter='cssrewrite'
'@SfWebAppFrontOfficeBundle/Resources/public/css/libs/bootstrap.min.css'
'@SfWebAppFrontOfficeBundle/Resources/public/css/libs/bootstrap-theme.min.css'
'@SfWebAppFrontOfficeBundle/Resources/public/css/libs/jquery-ui.min.css'
'@SfWebAppFrontOfficeBundle/Resources/public/css/libs/jquery-ui.structure.min.css'
'@SfWebAppFrontOfficeBundle/Resources/public/css/libs/jquery.dataTables.min.css'
'@SfWebAppFrontOfficeBundle/Resources/public/css/front-office.css' %}
<link rel="stylesheet" href="{{ asset_url }}" type="text/css" />
{% endstylesheets %}
{% endblock %}
</head>
<body>
<div class="container">
{% block header %}{% endblock %}
{% block flash %}
{% for flashMessage in app.session.flashbag.get('notice') %}
<div>
{{ flashMessage }}
</div>
{% endfor %}
{% for flashMessage in app.session.flashbag.get('error') %}
<div>
{{ flashMessage }}
</div>
{% endfor %}
{% endblock %}
{% block content %}{% endblock %}
{% block footer %}{% endblock footer %}
</div>
{% block javascripts %}
{% javascripts
'@SfWebAppFrontOfficeBundle/Resources/public/js/libs/jquery-1.10.1.min.js'
'@SfWebAppFrontOfficeBundle/Resources/public/js/libs/jquery-ui.min.js'
'@SfWebAppFrontOfficeBundle/Resources/public/js/libs/bootstrap.min.js'
'@SfWebAppFrontOfficeBundle/Resources/public/js/libs/jquery.dataTables.min.js'
'@SfWebAppFrontOfficeBundle/Resources/public/js/datatables-fo.js' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
<script>
// get locale
locale = "{{ app.request.locale }}";
// get route
route = "{{ route }}";
</script>
{% endblock %}
</body>
</html>
3.8 - Ajout des traductions
Formulaires FOSUserBundle :
nano app/Resources/translations/forms.fr.yml
profile:
fields:
gender: Civilité
firstname: Prénom
lastname: Nom
address: Adresse
city: Ville
country: Pays
zip_code: Code postal
phone: Téléphone
email: E-mail
password_first: Mot de passe
password_second: Mot de passe (validation)
register:
fields:
firstname: Nom
FOSUserBundle :
nano app/Resources/translations/FOSUserBundle.fr.yml
profile:
fields:
gender: Civilité
firstname: Prénom
lastname: Nom
address: Adresse
zip_code: Code postal
phone: Tél.
email: E-mail
password_first: Mot de passe
password_second: Mot de passe (validation)
register:
fields:
firstname: Nom
# Resetting account
resetting:
email:
subject: |
Réinitialisation de votre mot de passe
message: |
<p>Pour réinitialiser votre mot de passe, merci de cliquer sur le lien suivant :</p>
<p><a href="%confirmationUrl%">%confirmationUrl%</a></p>
# Registration
registration:
confirmed: Votre compte est maintenant activé.
email:
subject: |
Confirmation de l'inscription
message: |
<p>Pour valider votre compte utilisateur, merci de vous rendre sur :</p>
<p><a href="%confirmationUrl%">%confirmationUrl%</a></p>
Validators :
nano app/Resources/translations/validators.fr.yml
valid_phone_number: Cette valeur n'est pas un numéro de téléphone valide.
"'{{ value }}' is not a valid email.": "'{{ value }}' n'est pas une adresse e-mail valide."
not_empty_field: Le champs ne peut être vide.
4 - Configuration de l'envoi d'email
nano app/config/parameters.yml
Modifier les champs suivantes :
mailer_transport: smtp
mailer_host: ssl0.ovh.net
mailer_user: "mail@ovh.com"
mailer_password: "pwd"
5 - Surcharge du ProflieController de FOSUserBundle
Suite à un problème de validation sur editProfile(), j’ai surchargé le controller de FOSUserBundle :
MAJ : Le problème de validation à été corrigé avec la version 1.3.6 de FOSUserBundle, la surcharge des contrôleurs de FOSUserBundle n'est pas nécessaire.
nano src/SfWebApp/FrontOfficeBundle/Controller/ProfileController.php
<?php
namespace SfWebApp\FrontOfficeBundle\Controller;
use FOS\UserBundle\Controller\ProfileController as BaseController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use FOS\UserBundle\Model\UserInterface;
class ProfileController extends BaseController
{
protected $container;
/**
* @return ContainerInterface
*/
public function getContainer()
{
return $this->container;
}
/**
* Show the user
*/
public function showAction()
{
$user = $this->container->get('security.context')->getToken()->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
return $this->container->get('templating')->renderResponse('FOSUserBundle:Profile:show.html.'.$this->container->getParameter('fos_user.template.engine'), array('user' => $user));
}
/**
* Edit the user
*/
public function editAction()
{
$user = $this->container->get('security.context')->getToken()->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
$request = $this->container->get('request');
$form = $this->container->get('fos_user.profile.form');
$data = $request->request->get('fos_user_profile_form');
$userId = $user->getId();
if ($request->getMethod() == 'POST') {
$em = $this->getContainer()->get('doctrine.orm.entity_manager');
$user = $em->getRepository(‘SfWebAppMainBundle:User')->find($userId);
$user->setGender($data['gender']);
$user->setFirstname($data['firstname']);
$user->setLastname($data['lastname']);
$user->setEmail($data['email']);
$user->setEmailCanonical($data['email']);
$user->setPhone($data['phone']);
$user->setAddress($data['address']);
$user->setZipCode($data['zip_code']);
$user->setCity($data['city']);
$user->setCountry($data['country']);
$user->setPlainPassword($data['plainPassword']['first']);
$em->persist($user);
$em->flush();
$this->setFlash('fos_user_success', 'profile.flash.updated');
return new RedirectResponse($this->getRedirectionUrl($user));
}
return $this->container->get('templating')->renderResponse(
'FOSUserBundle:Profile:edit.html.'.$this->container->getParameter('fos_user.template.engine'),
array('form' => $form->createView())
);
}
/**
* Generate the redirection url when editing is completed.
*
* @param \FOS\UserBundle\Model\UserInterface $user
*
* @return string
*/
protected function getRedirectionUrl(UserInterface $user)
{
return $this->container->get('router')->generate('fos_user_profile_show');
}
/**
* @param string $action
* @param string $value
*/
protected function setFlash($action, $value)
{
$this->container->get('session')->getFlashBag()->set($action, $value);
}
}