1 - Création de l'application Symfony
1.1 - Installation de Symfony 3.4
Télécharger le gestionnaire de paquets composer.phar. Ce dernier va nous permettre de télécharger Symfony.
cd /var/www
curl -s https://getcomposer.org/installer | php
Télécharger Symfony 3.4 standard :
php composer.phar create-project symfony/framework-standard-edition candidate-back "3.4.*"
À la fin de l'installation de Symfony, le script d'installation va nous demander de renseigner la configuration de notre application.
On va renseigner l'accès à la base de données et laisser les autres champs vides (ils prendront la valeur par défaut afficher entre parenthèse) :
database_host (127.0.0.1):
database_port (null): 5432
database_name (symfony): db-name
database_user (root): db-user
database_password (null): db-pwd
mailer_transport (smtp):
mailer_host (127.0.0.1):
mailer_user (null):
mailer_password (null):
secret (ThisTokenIsNotSoSecretChangeIt):
1.2 - Création de l'application
symfony new FosSf3
Remarque : Sur Symfony 3.4, il faudra remplacer la ligne suivante dans le fichier composer.json :
"autoload": {
"psr-4": {
"": "src/"
},
//... },
Puis exécuter la commande :
php composer.phar dump-autoload
1.3 - Création des Bundles
On va organiser notre application en quatre bundles :
- MainBundle : contiendra les entités et les services commun au FrontOfficeBundle et au BackOfficeBundle
- BackOfficeBundle : concerne le back-office administrateur
- FrontOfficeBundle : concerne le front-office utilisateur
- CmsBundle : concerne l'accès public au site
php bin/console generate:bundle
Remplir le formulaire de création de bundle :
- partage avec d'autres applications : no
- espace de nom : FosSf3/NomBundle [Ex : FosSf3/MainBundle]
- dossier cible : src/
- configuration format : annotation
On supprime le Bundle App crée par défaut à l'installation de Symfony :
- Suppression de l'entrée dans le fichier le fichier app/AppKernel.php
- Suppression des routes du bundle dans le fichier app/config/routing.yml
- Suppression des services du bundle dans le fichier app/config/services.yml
- Suppression du Bundle src/AppBundle
1.4 - Installation de FOSUserBundle
curl -s https://getcomposer.org/installer | php
php composer.phar require friendsofsymfony/user-bundle
Activation du Bundle :
nano app/AppKernel.php
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new FOS\UserBundle\FOSUserBundle(),
// ...
);
}
1.5 - Ajout de la configuration de FOSUserBundle
nano app/config/config.yml
# FOS User Bundle
fos_user:
db_driver: orm
firewall_name: main
user_class: Sf3App\MainBundle\Entity\User
service:
mailer: fos_user.mailer.twig_swift
registration:
form:
type: FOS\UserBundle\Form\Type\RegistrationFormType
name: fos_user_registration_form
validation_groups: [Registration, Default]
confirmation:
enabled: true
template: '@FOSUser/Registration/email.txt.twig'
profile:
form:
type: FOS\UserBundle\Form\Type\ProfileFormType
#validation_groups: [Profile, Default]
resetting:
email:
template: '@FOSUser/Resetting/email.txt.twig'
group:
group_class: FosSf3\MainBundle\Entity\Group
from_email:
address: mail@domain.tld
sender_name: user
Activer les traduction en décommentant la ligne "configuration translator" dans config.yml :
// ..
framework:
// ..
translator: { fallbacks: ["%locale%"] }
1.6 - Création de l'entité User
nano src/FosSf3/MainBundle/Entity/User.php
<?php
namespace FosSf3\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
/**
* Class User
* @package FosSf3\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\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();
}
/**
* @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;
}
}
Création et mise à jour du schéma de la base de données :
php bin/console doctrine:database:create
php bin/console doctrine:schema:update --force
1.7 - Ajout des routes de FOSUser
nano app/config/routing.yml
Ajouter en haut du fichier l'appel de routes de FOSUser :
# app/config/routing.yml
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
1.8 - Configuration du fichier security.yml
nano app/config/security.yml
# app/config/security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
1.9 - Héritage de FOSUserBundle pour le MainBundle
nano src/FosSf3/MainBundle/FosSf3MainBundle.php
<?php
namespace FosSf3\MainBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class FosSf3MainBundle extends Bundle
{
public function getParent()
{
return 'FOSUserBundle';
}
}
2 - Implémentation du login back-office
2.1 - Création du fichier de traduction
nano app/Resources/FOSUserBundle/translations/FOSUserBundle.fr.yml
# Profile
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
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>
2.2 - Création du template de vue 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{% endblock %}</title>
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
</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>
</body>
</html>
2.3 - Création de la vue login
nano app/Resources/FOSUserBundle/views/Security/login.html.twig
{% extends 'back-office.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">Admin</h1>
<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 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 %}
3 - Création d'un utilisateur en base de données
Création d'un utilisateur avec les droits super-admin :
- login : admin
- password : admin
- email : mail@domain.tld
php bin/console fos:user:create admin mail@domain.tld admin --super-admin
4 - Test du login
On se connecte l'url du back-office : http://fos-sf3.local/admin
On test le login, on constate avec le profiler qu'on est connecté en tant qu'admin.