User Tools

Site Tools


backend:symfonytuto

Symfony : Tutoriels

logo

J'utilise principalement 2 chaînes Youtube pour apprendre Symfony :

  • Lior CHAMLA qui vulgarise de manière didactique et efficace les notions abordées (il y a une super playlist POO en pratique pour le PHP orienté objet).
  • LES TEACHERS DU NET qui aborde de manière simple mais extrêmement approfondi les tutoriels.

voici les notes que j'ai pris :

Lior CHAMLA

Bases de Symfony

Notions abordées

Haut de page 🔺
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
1'15 Pré-requis : composer
2'35 Présentation de Symfony
4'03 Installation
composer create-project symfony/website-skeleton nom_projet
symfony console list
symfony console config:dump-reference
symfony console about
6'30 Utilisation du serveur local
8'00“ Controllers
10'00 créer un contrôleur:
symfony console make:controller
13'30 Controleur function home() et route racine
14'50 Fichier twig
15'48 Langage twig
{{ variable }}, {% command %}
18'42 Paramètre depuis le controleur vers la vue twig
19'35 Créer des pages, Bootstrap & Bootswatch
20'15 Récupération du lien template Bootswatch vers base.html.twig
21'50 navbar Bootswatch
25'20 Exemple d'utilisatiton d'Emmet
(article>h2{Titre de l'article}+div.metadata{Ecrit le 10/05/18}+div.content>img+(p>lorem15)*2+a.btn.btn-primary{Lire la suite})*3
<article>
  <h2>Titre de l'article</h2>
  <div class="metadata">Ecrit le 10/05/18</div>
  <div class="content">
    <img src="" alt="">
    <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Omnis quo ratione quisquam expedita fugiat architecto!</p>
    <p>Doloremque nobis nulla ipsum illo non iure voluptatem ratione, facere aliquid vero excepturi corporis molestias?</p>
    <a href="" class="btn btn-primary">Lire la suite</a>
  </div>
</article>
<article>
  <h2>Titre de l'article</h2>
  <div class="metadata">Ecrit le 10/05/18</div>
  <div class="content">
    <img src="" alt="">
    <p>Velit, sint sed, corrupti ex reprehenderit excepturi consectetur ullam, commodi asperiores consequatur vel dolorem quia!</p>
    <p>Cumque maxime nam laboriosam ab placeat in ullam accusantium reiciendis, nihil atque ex, tempora minus!</p>
    <a href="" class="btn btn-primary">Lire la suite</a>
  </div>
</article>
<article>
  <h2>Titre de l'article</h2>
  <div class="metadata">Ecrit le 10/05/18</div>
  <div class="content">
    <img src="" alt="">
    <p>Numquam atque dolores, nemo ea asperiores incidunt sequi consequatur aperiam doloribus illo, cum nesciunt fugit.</p>
    <p>In libero fuga eum quis officiis aliquam, reprehenderit ad, unde doloremque aperiam quia corporis sequi.</p>
    <a href="" class="btn btn-primary">Lire la suite</a>
  </div>
</article>
25'30 Création articles (pages blog)
26'50 placehold.it (images vides pour test)place-hold.it
30'00 show (path) pour les lire la suite
31'10 Doctrine (ORM)
33'59” Migration
34'51“ Fixtures (bases de test)
composer require orm-fixtures --dev
36'25 Doctrine .env accès MySql, création bdd
symfony console doctrine:database:create
38'00 Entity… création table
symfony console make:entity
42'50 màj des tables, script de migration
symfony console make:migration
44'36 lancement migration
symfony console doctrine:migrations:migrate
45'40 fixture (jeu fausses données)
symfony console make:fixtures
49'34 fixture flush
symfony console doctrine:fixture:load
50'30 utiliser doctrine dans l'appli
51'30 Repository
56'30 formatage date
58'54 identifiant article
1'02'00 path avec id
1'03'00 Injection de dépendances repository
1'06'00 param converter

Formulaires

Notions abordées
  • Confusion de routes
  • Fonction Twig path()
  • Fonctions Twig pour les formulaires
  • Thème Bootstrap pour les formulaires
  • Récupération des données du formulaire
  • Routes multiples
  • Composant Form
  • Validation des données grâce aux contraintes
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
2'00Création de la fonction pour créer un article
2'45Confusion de routes
3'55Création du fichier Twig
5'00Fonction Twig path()
{{ path('blog/create') }}
6'40Création d'un formulaire : approche classique (à ne pas faire)
10'50Objet ParameterBag
12'50Objet ObjectManager
14'25Fonction redirectToRoute()
return $this->redirectToRoute('blog_show', ['id'=>$article->getId()]);
15'30Création d'un formulaire : composant Form
$form = $this->createFormBuilder($article)
  ->add('title'
22'35Options des champs du formulaire dans le formulaire
$form = $this->createFormBuilder($article)
  ->add('title', TextType::class, [
      'attr' => [
          'placeholder' => "Titre de l'article",
          'class' => 'form-control'
      ]
  ])
 
24'50Fonctions Twig pour les formulaires
{{ form_start(formArticle) }}
{{ form_widget(formArticle) }}
{{ form_end(formArticle) }}
27'35Moteur de rendus Twig pour utiliser Bootstrap
28'45Thème Bootstrap pour les formulaires
# config/packages/twig.yaml
twig:
    form_themes: ['bootstrap_4_layout.html.twig']
{% form_theme form 'bootstrap_4_layout.html.twig' %}
30'50Ajout du bouton de validation du formulaire dans le controller
31'40Ajout du bouton de validation du formulaire le template Twig
33'20Options des champs du formulaire dans le template Twig : form_row()
{{ form_row(formArticle.title,
    {'attr': {'placeholder': "Titre de l'article"}}
)}}
36'40Récupération des données du formulaire
$form->handleRequest($request);
39'15Vérification que le formulaire a été soumis et est valide
if ($form->isSubmitted() && $form->isValid()) {
}
41'00Enregistrement des données dans la base de données
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
  $manager->persist($article);
  $manager->flush();
}
43'00Utilisation de la même fonction pour créer et modifier un article
43'40Routes multiples
* @Route("/blog/new", name="blog_create")
* @Route("/blog/{id}/edit", name="blog_edit")
48'30Changement dynamique du nom du bouton dans Twig
{% if editMode %}
    Enregistrer les modifications
{% else %}
    Ajouter un article
{% endif %}
50'10Création du formulaire automatiquement
symfony console make:form
51'35Création du formulaire dans le controller
$form = $this->createForm(ArticleType::class, $article);
53'25Validation des données du formulaire dans l'entité grâce aux contraintes : constraints
use Symfony\Component\Validator\Constraints as Assert;
* @Assert\Length(min=10, max=255)
59'25Modification du message d'erreur
* @Assert\Length(min=10, max=255, minMessage="Titre trop court, il doit faire au moins 10 caractères")

Entités et Relations

Notions abordées
  • Les relations avec Doctrine
  • ArrayCollection
  • Présentation des fixtures
  • Bibliothèque Faker
  • Affichage des données des catégories liées entre elles dans Twig
  • Filtres Twig |date et |raw
  • Boucle for entre les entités
  • Les relations dans les formulaires
  • Champ EntityType dans un formulaire
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
3'30Créations de l'entité Category
symfony console make:entity
4'45Création d'une propriété de type Relation
10'50Présentation de ArrayCollection
11'50Création de la migration
symfony console make:migration
13'45Problème des champs qui ne doivent pas être null
14'50Application de la migration
doctrine:migrations:migrate
16'00Création de l'entité Comment
symfony console make:entity
20'50Création de la migration
symfony console make:migration
21'30Application de la migration
doctrine:migrations:migrate
22'15Fixtures
23'20Installation de la librairie Faker
composer require fzaninotto/faker --dev
25'30Utilisation de Faker
$faker = Faker\Factory::create('fr_FR');
$category->setTitle($faker->sentence())
42'20Affichage des données des catégories liées entre elles dans Twig
{{ article.category.title }}
44'45Filtre Twig |date
45'00Filtre Twig |raw
45'05Boucle for entre les entités
{%for comment in article.comments %}
46'05Manipulation des relations dans les formulaires
47'40Champ EntityType dans un formulaire
$builder
  ->add('title')
  ->add('category', EntityType::class, [
    'class' => Category::class,
    'choice-label' => 'title'
  ])

Authentification

Notions abordées
  • Comment protéger une application
  • Firewall
  • Providers
  • Encoders
  • Entité User
  • Contrainte EqualTo
  • Hachage des mots de passe
  • Unicité d'uine propriété
  • Variable globale Twig app
  • Redirection après la connexion
Liens et informations
Liens bonus

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
1'30Comment protéger une application
3'00Présentation du composant Security : les Firewall
3'45Présentation du composant Security : les Providers
4'10Présentation du composant Security : les Encoders
4'35Configuration de Security dans le fichier security.yaml
security:
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        users_in_memory: { memory: null }
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            lazy: true
            provider: users_in_memory
6'20L'entité User
6'40Création de l'entité User
symfony console make:entity User
8'10Création de la migration
symfony console make:migration
8'40Application de la migration
doctrine:migrations:migrate
9'35Création du formulaire d'inscription
symfony console make:form RegistrationType
11'00Ajout d'une propriété $confirm_password
11'35Création d'un controler pour afficher le formulaire
symfony console make:controler
13'00Instanciation du formulaire
16'00Affichage du formulaire
17'00Ajout d'attribut au formulaire dans Twig
{{ form_row(form.username, {
  'label': "Nom d'utilisateur",
  'attr': {
    'placeholder': "Nom d'utilisateur"
}})}}
19'50Champ PasswordType dans un formulaire
21'20Codage du bouton d'inscription, utilisation de la requête et du manager
public function registration(Request $request, ObjectManager $manager)
22'50Analyse de la requête et du formulaire
24'20Ajout de contraintes de validation
use Symfony\Component\Validator\Constraints as Assert;
26'10Contrainte EqualTo
 * @Assert\EqualTo(propertyPath="password", message = "Le mot de passe et sa confirmation ne sont pas identiques")
 */
public $confirm_password;
29'00Hachage des mots de passe, configuration dans le fichier security.yaml
security:
    encoders:
        App\Entity\User:
          algorithm: bcrypt
30'40Encodage du mot de passe dans le controller
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
public function registration(Request $request, ObjectManager $manager, UserPasswordEncoderInterface $encoder)
{
  $user = new User();
 
  $form = $this->createForm(RegistrationType::class, $user);
 
  $form->handleRequest($request);
 
  if ($form->isSubmitted() && $form->isValid()) {
    $hash = $encoder->encodePassword($user, $user->getPassword());
 
    $user->setPassword($hash);
 
    $manager->persist($user);
    $manager->flush();
 
    return $this->redirectToRoute('security_login');
  }
 
  return $this->render('security/registration.html.twig', [
    'form' => $form->createView()
  ]);
}
33'15Implémentation de UserInterface dans l'entité User
class User implements UserInterface
36'20Unicité des mails
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
 * @UniqueEntity(
 *  fields = {"email"},
 *    message = "L'email {{ value }} est déjà inscrit"
 * )
 */
39'10Création de la fonction login() dans le controler et du template correspondant
41'30Création du formulaire de connexion
41'50Configuration des providers dans le fichier security.yaml
security:
    encoders:
        App\Entity\User:
          algorithm: bcrypt
 
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        users_in_memory: { memory: null }
        in_database: 
          entity:
            class: App\Entity\User
            property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            lazy: true

            provider: in_database

            form_login:
              login_path: security_login
              check_path: security_login

            logout:
              path: security_logout
              target: software
46'05Création du formulaire de connexion dans Twig
<form action="{{ path('security_login') }}" method="Post">
<h2>Connexion
    <button type="submit" class="btn btn-success float-right">Connexion</button>
</h2>
  <div class="form-group">
    <label for="">Identifiant</label>
    <input placeholder="Email" type="text" name="_username" class="form-control" required>
  </div>
  <div class="form-group">
    <label for="">Mot de passe</label>
    <input placeholder="Mot de passe" type="password" name="_password" class="form-control" required>
  </div>
</form>
48'00Utilisation de la méthode POST pour le formulaire et explication de la route utilisée
49'30Création du logout
51'10Création de boutons de connexion et de déconnexion dynamiques
52'15Variable globale dans Twig : app
{% if not app.user %}
  ...
{% else %}
  ...
{% endif %}
53'40Création du formulaire de commentaires
56'25Filtre Twig |length
57'00Ajout du formulaire à la fin des commentaires dans Twig
58'30Gestion de la réponse du formulaire dans le controller
1'01'10Variable globale dans Twig : app
1'02'50Lien vers la documentation Symfony 5.1 pour la redirection après la connexion Using the form_login Authentication Provider

❌AJAX

Notions abordées
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'0

❌Filtres Twig

Notions abordées
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'0

❌Autowiring & Container

Notions abordées
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'0

❌Session

Notions abordées
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'0

❌Cache

Notions abordées
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'0

❌API : Serializer

Notions abordées
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'0

❌API : ApiPlatform

Notions abordées
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'0

❌Framework Maison : HTTP Foundation

Notions abordées
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'0

❌Framework Maison : Le Front Controller

Notions abordées
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'0

❌Framework Maison : Le Routing

Notions abordées
Liens et informations

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'0

LES TEACHERS DU NET

Tutoriels Symfony 5

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼
Voici les vidéos de la playlist Tutoriel Symfony 5.

Concepts importantsTutoriel
01 - Présentation du Projet (Un clone de Pinterest)
02 - Qu'est-ce que Symfony?
03 - Prérequis
04 - Installer le Client Symfony sous Windows
05 - Installer le Client Symfony sous macOS
06 - Structure d'un projet Symfony
Architecture MVC07 - L'architecture MVC
Controller08 - Le contrôleur PinsController
Route09 - Configurer une route en YAML
ORM10 - À quoi sert un ORM (Object-relational Mapper)
Symfony Flex11 - Qu'est-ce qu'un pack avec Symfony Flex?
Entité 12 - Créer une entité Doctrine
Variables d'environnement 13 - À quoi servent les variables d'environnement?
Configuration MySQL 14 - Configurer l'accès à une base de données MySQL
Configuration SQLite 15 - Configurer l'accès à une base de données SQLite
16 - Paramètres de configuration
17 - Accéder aux variables d'environnement dans les fichiers de configuration
18 - Processeurs de variables d'environnements
Migration 19 - Les migrations avec Symfony
20 - Petit récapitulatif
.env.local 21 - Utilité du fichier .env.local
Packs Debug et Profiler 22 - Les packs Debug et Profiler
Création avec Doctrine 23 - Création de Pin avec Doctrine
Injection de dépendances 24 - Injection de dépendances
Repository 25 - Le repository PinRepository
26 - Un code plus concis
Formulaires 27 - Formulaire de création de pins
Noms des routes 28 - Utilité des noms de route
Formulaires avec Symfony 29 - Création de formulaires avec Symfony
30 - Options et données de formulaires
31 - Inférence de types et bonnes pratiques
doctrine:query:sql 32 - La commande doctrine:query:sql
Twig 33 - Twig: Tags, Filtres, Fonctions, Tests, Opérateurs
Routes 34 - Paramètres et priorités de routes
router:match 35 - La commande router:match
Réponse 404 36 - Générer une réponse 404
ParamConverter 37 - Un code beaucoup plus concis grâce au ParamConverter
38 - Ajout de liens de navigation
fonction Twig url 39 - La fonction Twig url
Exemple Hello City Créer et déployer une application Symfony 5

Voic les vidéos de la playlist Youtube Apprendre Symfony 5 par la pratique.

01 - Bases

Notions abordées
  • Projet
  • Controller
  • Base de données
  • Entité
  • Migration
  • Bundle Psysh
  • Repository
  • Création d'une fonction Twig
  • Dates de création et de modification
  • Trait

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Sujet traité Commandes éventuelles
Création du projet
 composer create-project symfony/website-skeleton my_project_name
symfony new my_project_name --full
Création du controller
symfony console make:controller
Configuration de l'accès à la base de données
Création de la base de données
doctrine:database:create
Structure de la table
Création de l'entité
symfony console make:entity
Création de la migration
symfony console make:migration
Voir le statut des migrations
doctrine:migrations:status
Application la migration
doctrine:migrations:migrate
Installation le bundle Psysh
composer require --dev theofidry/psysh-bundle
Création des données pour la DB avec Psysh
Injection du Repository dans le Controller
Récupération des données grâce au Repository
Passage des données à la vue
compact()
Affichage des données dans la vue (filtre length)
|length
Création d'une fonction Twig
symfony console make:twig-extension
Ajout des dates de création et de modification
Configuration du cycle de vie d'une entité
* @ORM\HasLifeCycleCallbacks
use Timestampable;
* @ORM\PrePersist
* @ORM\PreUpdate
Création d'un fichier php.ini pour la Time Zone
Ajout d'une valeur par défaut pour les dates dans l'entité, pour les données déjà présentes en DB
Choix de l'ordre d'affichage des données
Création d'un trait pour que la gestion des dates soit accessible par toutes les entités

02 - Formulaires

Notions abordées
  • Formulaire
  • Méthodes HTTP PUT et DELETE
  • Confirmation de suppression en Javascript
  • Protection CSRF

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Sujet traité Commandes éventuelles
Création d'un formulaire
FormBuilder
Traitement du formulaire
Association du formulaire à l'entité
Création d'un type de formulaire
symfony console make:form
Utilisation de la méthode HTTP PUT
Utilisation de la méthode HTTP DELETE
Confirmation de la suppression en Javascript
Ajout d'une Protection CSRF pour le formulaire de suppression

03 - Problèmes et erreurs

Notions abordées
  • Problèmes après un composer update
  • Symfony Flex
  • Recipes
  • Pack de bundles
  • Partial template
  • Filtres Twig
  • Routes
  • Page d'erreurs
  • Bundle KnpTimeBundle

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
1'30Problème avec composer update
3'25Explication du problème : Nouvelle version pour les migrations de doctrine
12'50Symfony Flex
13'15Recipes
33'25Suppression de le DB et réapplication des migrations
34'45Problème avec doctrine
37'00Explication des packs de bundle
38'40Visualisation des recettes
composer recipes
40'20Utilisation d'un partial : _form.html.twig
{{ include('...') }}
42'20Passage d'une variable au partial
44'00Utilisation du filtre | default
|default
45'20Utilisation de la même route pour show et delete, seule la méthode change : GET et DELETE
48'00Importance de l'ordre des routes
52'00Priorités des routes
54'00Page 404
55'00Customisation des pages d'erreurs
58'00Tronquage de la description avec le filtre |u
|u
1'00'55Utilisation du filtre |date
|date
1'01'20Utilisation du bundle KnpTimeBundle et du filtre |ago
|ago
1'02'55Utilité de seter 'data_class' dans le form type

04 - Webpack - SASS - Bootstrap

Notions abordées
  • Messages Flashy
  • Partial template
  • Asserts
  • Thèmes de formulaires
  • Bundle flashy-bundle
  • Exemples Bootstrap
  • Utilisation des routes pour avoir des classes dynamiques dans Twig
  • Google Fonts
  • Webpack et Webpack Encore
  • npm et yarn
  • Node.js
  • Dépendances pour Webpack
  • Compilations
  • SASS et SCSS
  • Bootstrap dans Webpack
  • Compilation compressée

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'10Ajout de messages flash
addFlash()
6'30Création d'un partial : _flash_message.html.twig
{{ include('...') }}
9'25Validation des données du formulaire
use Symfony\Component\Validator\Constraints as Assert;
   * @Assert\Length(
   *    min = 3,
   *    minMessage = "Titre trop court, il doit faire au moins 3 caractères")
14'40Utilisation de Bootstrap de manière basique
15'50Thèmes de formulaires
# config/packages/twig.yaml
twig:
    form_themes: ['bootstrap_4_horizontal_layout.html.twig']
17'30Bouton sur toute la largeur avec Bootstrap
class="btn-block"
18'10Erreur lorsqu'on affiche un formulaire avec un champs vide
public function setTitle(?string $title): self
20'20TDN a créé un bundle flashy-bundle pour les messages flashTutoriel Flashy Bundle
20'40Récupération d'exemples de menu Bootstrap Documentation officielle
21'40Utilisation d'un partial : _nav.html.twig
{{ include('...') }}
24'15Lien vers une vidéo expliquant l'utilisation des routes pour avoir des classes dynamiques dans Twig Astuces Twig
26'10Utilisation d'un partial : _footer.html.twig
{{ include('...') }}
29'55Centrage horizontal avec Bootstrap
class="mx-auto"
31'15Changement de la police avec Google Fonts
33'15Création d'un fichier CSS
35'20Introduction à SASS et SCSS
36'45Présentation de Webpack et Webpack EncoreWebpack et Webpack Encore
37'35Installation de Webpack Encore
composer require symfony/webpack-encore-bundle
39'20Présentation de npm et yarn npm et yarn
39'35Installation de Node.js pour avoir npm Node.js
43'30Utilisation de SASS grâce à Webpack Encore
44'05Installation de dépendances pour Webpack
npm install
45'00Explications sur le fichier webpack.config.js
47'25Les compilations
npm run dev
51'10Importation de plusieurs fichiers SCSS, SASS ou CSS avec app.js
import '../scss/app.scss';
53'55Chargement des fichiers créés par Webpack dans les templates
55'50Fonctions permettant un chargement automatique
{% block stylesheets %}
  {{ encore_entry_link_tags('app') }}
{% endblock %}
{% block javascripts %}
    {{ encore_entry_script_tags('app') }}
{% endblock %}
57'00Chargement de la police dans le fichier SCSS, SASS ou CSS
@import url('...')
58'00Activation de SASS dans le fichier webpack.config.js
.enableSassLoader()
58'05Installation de sass-loader et node-sass
npm install sass-loader@^8.0.0 node-sass --save-dev
1'00'25SASS : Explication de &
1'01'10SASS : Création de variables
$primary_font: 'Montserrat';
{font-family: $primary_font}
1'02'00SASS : Création d'un fichier de variables
@import 'shared/_variables.scss';
1'03'15Installation de Bootstrap dans Webpack
npm install bootstrap --save-dev

ou

npm install bootstrap -D
1'05'40Chargement de Bootstrap dans le fichier SCSS, SASS ou CSS
@import "~bootstrap/scss/bootstrap";
1'07'00Activation du Javascript en installation jQuery et Popper
npm install jquery popper.js --save-dev

ou

npm install jquery popper.js -D
1'07'50Importation de jQuerry et Bootstrap dans le fichier app.js
import $ from 'jquery';
import 'bootstrap';
1'08'35Autre commande pour charger Bootstrap dans le fichier SCSS, SASS ou CSS
@import "~bootstrap";
1'11'45Compilation compressée
npm run build

05 - VichUploader - LiipImagine

Notions abordées
  • Modification d'entité
  • Astuce : Comment choisir un bundle
  • Bundle VichUploaderBundle
  • Bundle LiipImagineBundle
  • gd, gmagick et imagick
  • Symfony Messenger
  • Affichage du nom de l'image en Javascript

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
1'30Modification d'une entité
symfony console make:entity
3'00Migration
4'50Présentation du bundle VichUploaderBundle
5'00⭐Astuce : Comment choisir un bundle
6'00Installation de VichUploaderBundle et Recipe non officielle
composer require vich/uploader-bundle
7'50Configuration de VichUploaderBundle dans vich_uploader.yaml : Driver
  db_driver: orm 
8'20Configuration de VichUploaderBundle dans vich_uploader.yaml : Mapping
  mappings:
    pin_image:
      uri_prefix: /uploads/pins
      upload_destination: '%kernel.project_dir%/public/uploads/pins'
      namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
10'55Liaison du mapping avec l'entité : Définir les classe
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
11'20Liaison du mapping avec l'entité : Annoter l'entité
* @Vich\Uploadable
11'28Liaison du mapping avec l'entité : Annoter la propriété
* @Vich\UploadableField(mapping="pin_image", fileNameProperty="imageName")
13'10Liaison du mapping avec l'entité : Ajouter un geter
public function getImageFile(): ?File
{
  return $this->imageFile;
  }
13'55Liaison du mapping avec l'entité : Ajouter un seter
 * @param File|\Symfony\Component\HttpFoundation\File\UploadedFile|null $imageFile
 */
public function setImageFile(?File $imageFile = null): void
{
  $this->imageFile = $imageFile;
  if (null !== $imageFile) {
    // It is required that at least one field changes if you are using doctrine
    // otherwise the event listeners won't be called and the file is lost
    $this->setUpdatedAt(new \DateTimeImmutable);
  }
}
16'50Configuration des évenements de cycle de vie
            inject_on_load: false
            delete_on_update: true
            delete_on_remove: true
19'15Ajout d'un champs pour l'image dans le formulaire : Définir les classe et modifier le builder
use Vich\UploaderBundle\Form\Type\VichImageType;
 
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    $builder
      ->add('imageFile', VichImageType::class, [
        'label' => 'Image (JPG or PNG file)',
        'required' => false,
        'allow_delete' => true,
        'download_uri' => false,
      ])
30'00Faire un git commit -m en ignorant les images grace au fichier .gitignore
###> custom env vars ###
/public/uploads
###< custom env vars ###
32'40Validation de la taille des images
   * @Assert\Image(maxSize="8M", maxSizeMessage="Le fichier est trop volumineux ({{ size }} {{ suffix }}), La taille maximale autorisée est de {{ limit }} {{ suffix }}.")
   */
  private $imageFile;
36'00Validation du type de fichier Constraints - File
36'45Différence entre NotBlank et NotNull
37'28Ajout des contraintes dynamiquement dans le formulaire
    $builder
      ->add('imageFile', VichImageType::class, [
        'label' => 'Image (JPG or PNG file)',
        'required' => false,
        'allow_delete' => true,
        'download_uri' => false,
        'constraints' => [
          new Image([
            'maxSize' => '8M',
            'maxSizeMessage' => 'Le fichier est trop volumineux ({{ size }} {{ suffix }}), La taille maximale autorisée est de {{ limit }} {{ suffix }}.'
          ])
        ]
      ])
43'00Installation du bundle LiipImagineBundle
composer require liip/imagine-bundle
44'15 gd, gmagick et imagick
45'00Activer le bundle dans le fichier liip_imagine.yaml
liip_imagine:
  # valid drivers options include "gd" or "gmagick" or "imagick"
  driver: "gd"
45'25Configuration des filtres dans le fichier liip_imagine.yaml
  filter_sets:
    squared_thumbnail_medium:
      filters:
        thumbnail:
          size: [300, 300]
          mode: outbound
          allow_upscale: true
48'35Utilisation dans le formulaire avec 'imagine_pattern'
$builder
  ->add('imageFile', VichImageType::class, [
    'label' => 'Image (JPG or PNG file)',
    'required' => false,
    'allow_delete' => true,
    'download_uri' => false,
    'imagine_pattern' => 'squared_thumbnail_small'
  ])
50'00Problème avec gd car l'image est trop grande, modification de php.ini
memory_limit = -1
52'25Utilisation de imagic
53'00Evocation de Symfony Messenger Tutoriel Symfony Messenger
55'30Ajout de Javascript pour mettre le nom de l'image
1'00'10Mise en page avec Webpack et Bootstrap
1'01'20Utilisation de Bootstrap dans le SCSS
img {
  @extend .mb-2;
  @extend .rounded;
  @extend .shadow;
  @extend .img-thumbnail;
}
1'07'50Affichage de images avec VichUploaderBundle Generating URLs
1'08'20Génération d'une URL dans untTemplate Twig
<img src="{{ vich_uploader_asset(pin) }}" alt="{{ pin.title }}" />
1'09'00Utilisation d'un filtre LiipImagineBundle sur l'image
<img src="{{ vich_uploader_asset(pin) | imagine_filter('squared_thumbnail_medium') }}" alt="{{ pin.title }}" />
1'10'10Utilisation d'une image par défaut s'il n'y a pas d'image
<img src="{{ (pin.imageName ? vich_uploader_asset(pin) : asset('build/images/404.jpg')) | imagine_filter('squared_thumbnail_medium') }}" alt="{{ pin.title }}"/>
1'11'55Possibilité de créer une extension Twig Astuces Twig
1'12'20Lignes et colonnes avec Bootstrap
    <div class="row">
      <div class="col-md-3">
      </div>
      <div class="col-md-9">
      </div>
    </div>
1'13'10Groupage avec le filtre |batch()
    {% for row in pins|batch(4) %}
    <div class="row mb-5">
      {% for pin in row %}
        <div class="col-md-3">
1'14'50Mise en page avec Bootstrap
1'16'50Animation en SCSS
.pin img {
  &:hover {
    transform: scale(1.075);
  }
}
1'18'20Masquage de l'image qui dépasse avec bootstrap
class="mw-100 overflow-hidden"
1'18'55Ajout d'une transition
.pin img {
  transition: transform 0.3s ease-out;
 
  &:hover {
    transform: scale(1.075);
  }
}
1'22'20Transfert des images dans assets\images pour être gérées par Webpack en configurant webpack.config.js
.copyFiles({
  from: 'assets/images',
  to: '[path][name].[hash:8].[ext]',
  context: './assets'
})
1'27'20Utilisation de la balise HTML <time> et du filtre Twig |date
<time datetime="{{ pin.createdAt|date('Y-m-d H:i:s') }}">
  {{ pin.createdAt|ago }} 
</time>

06 - User

Notions abordées
  • Entité User
  • Dates de création et de modification
  • Contrainte d'unicité d'une propriété
  • Bundle Psysh
  • Hachage de mots de passe
  • Sel cryptographique
  • Modification du nom du dernier commit Git
  • Les relations avec Doctrine
  • ArrayCollection
  • Suppression et recréation de la base de données
  • Présentation des fixtures
  • Création d'une propriété dans une entité

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
9'20Présentation de la partie utilisateurs
11'00Création de l'entité User
symfony console make:user
18'30Supression des fichiers .gitignore inutiles dans src
19'32Présenatation de l'entité User
22'20Méthode getUsername()
public function getUsername(): string
25'00Récapitulatif
26'45Modification de l'entité User
symfony console make:user
30'20Modificaiton du nom de la table de l'entité en Users
* @ORM\Table(name="users")
30'50Ajout des dates de création et de modification
31'00Configuration du cycle de vie d'une entité
* @ORM\HasLifeCycleCallbacks
use Timestampable;
* @ORM\PrePersist
* @ORM\PreUpdate
31'40Création de la migration
symfony console make:migration
32'30Information sur la contrainte d'unicité de la propriété email
* @ORM\Column(type="string", length=255, unique=true)
33'55Modification de la migration
public function getDescription(): string
{
  return 'Create users table and make it timestampable';
}
34'05Application de la migration
doctrine:migrations:migrate
35'50Création d'utilisateurs avec psysh
>>> use App\Entity\User;
>>> $user1=new User
>>> $user1->setFirstName('john')
>>> $user1->setLastName('Doe')
>>> $user1->setEmail('john.doe@example.com')
>>> $user1->setPassword('$argon2id$v=19$m=65536,t=4')
>>> $em = $container->get('doctrine')->getManager();
>>> $em->persist($user1)
>>> $em->flush()
38'50Hachage du mot de passe
security:encode-password
43'15Explication du Hachage
57'50Sel cryptographique : Salt
1:01'30Configuration de l'algorithme dans security.yaml
security:
    encoders:
        App\Entity\User:
            algorithm: auto
1'06'00Ajout du coût : Cost
security:
    encoders:
        App\Entity\User:
            algorithm: auto
            cost: 13
1'10'20Symfony gère le salt automatiquement, ce n'est pas la peine de gérer la fonction getSalt() dans l'entité User
public function getSalt()
{
  // not needed when using the "bcrypt" algorithm in security.yaml
}
1'12'00Modification du nom du dernier commit
git commit -m "..." --amend
1'12'18Implémentation obligatoire de la méthode getPassword()
1'15'00Explication du repository UserRepository
1'16'00Implémentation obligatoire de la méthode upgradePassword()
1'23'50Présentation des relations entre les entités avec des clés étrangères dans la base de données
1'27'50Gestion des relations avec Doctrine en modifiant l'entité Pin avec une propriété de type relation
symfony console make:entity Pin
 
 Your entity already exists! So let's add some new fields!
 New property name (press <return> to stop adding fields):
 > user
 Field type (enter ? to see all types) [string]:
 > ManyToOne
 What class should this entity be related to?:
 > User
 Is the Pin.user property allowed to be null (nullable)? (yes/no) [yes]:
 > no
 Do you want to add a new property to User so that you can access/update Pin objects from it - e.g. $user->getPins()? (yes/no) [yes]:
 > yes
 A new property will also be added to the User class so that you can access the related Pin objects from it.
 New field name inside User [pins]:
 > pins
 Do you want to activate orphanRemoval on your relationship?
 A Pin is "orphaned" when it is removed from its related User.
 e.g. $user->removePin($pin)
 NOTE: If a Pin may *change* from one User to another, answer "no".
 Do you want to automatically delete orphaned App\Entity\Pin objects (orphanRemoval)? (yes/no) [no]:
 > yes

 updated: src/Entity/Pin.php
 updated: src/Entity/User.php
1'36'30Présentation de ArrayCollection
1'39'20Génération de la migration
symfony console make:migration
1'41'55Pour pouvoir faire la migration à cause des champs qui ne doivent pas être null :

Suppression de la base de données
Recréation de la base de données
Applications des migrations
symfony console doctrine:database:drop --force
symfony console doctrine:database:create
symfony console doctrine:migrations:migrate
1'44'00Présentation des fixtures
1'45'00Uilisation de psysh pour créer, supprimer et modifier des utilisateurs et de pins
2'03'40Ajout du prénom et du nom du créateur des pins
Submitted by {{ pin.user.firstName }} {{ pin.user.lastName }}
2'05'30Création d'un propriété fullName
  public function getFullName(): ?string
  {
    return $this->firstName . ' ' . $this->lastName;
  }
{{ pin.user.fullName }}
2'08'20Ajout d'un user à la création d'un pin (temporaire !)

07 - Security

Notions abordées
  • Qu'est ce que la sécurité
  • Security bundle et component
  • Variable globale Twig app
  • LoginController
  • Firewall
  • LoginFormAuthenticator
  • SecurityController
  • Vérification du token csrf
  • Générer une url en se basant sur un route
  • Erreurs d'authentication
  • fonctionnalité “Remember Me”
  • Bootstrap ; flexbox et checkbox

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
1'30Utilisation de la classe text-break de Bootstrap
5'00Sécurité = Authentication (qui sommes nous ?) et Autorisation (quels sont nos droits ?)
8'20Security bundle et composant Security
9'20Ajout des liens d'inscription et de connexion
10'30Variable globale dans Twig : app
{% if app.user %}
12'20Présentation du LoginController
13'50Nouveauté Symfony 5.1 : nouveau système d'authentication expérimental Authentification et Autorisation avec Symfony 5
15'10Création automatique du LoginController
symfony console make:auth

retourne :

created: src/Security/LoginFormAuthenticator.php
updated: config/packages/security.yaml
created: src/Controller/SecurityController.php
created: templates/security/login.html.twig
18'20Authentification : Firewalls dans le fichier security.yaml
26'10Class LoginFormAuthenticator LoginFormAuthenticator.php
32'45Controller SecurityController SecurityController.php
34'00Template login.html.twig login.html.twig
36'45HTML, champs caché pour le token csrf
38'25Méthode supports() de LoginFormAuthenticator.php
public function supports(Request $request)
{
    return self::LOGIN_ROUTE === $request->attributes->get('_route')
        && $request->isMethod('POST');
}
41'30Méthode getCredentials() de LoginFormAuthenticator.php
public function getCredentials(Request $request)
{
    $credentials = [
        'email' => $request->request->get('email'),
        'password' => $request->request->get('password'),
        'csrf_token' => $request->request->get('_csrf_token'),
    ];
    $request->getSession()->set(
        Security::LAST_USERNAME,
        $credentials['email']
    );
 
    return $credentials;
}
43'20Récupération des données de la requête POST
$credentials = [
  'email' => $request->request->get('email'),
  'password' => $request->request->get('password'),
  'csrf_token' => $request->request->get('_csrf_token'),
];
48'00Méthode login() de SecurityController.php
public function login(AuthenticationUtils $authenticationUtils): Response
{
  // if ($this->getUser()) {
  //     return $this->redirectToRoute('target_path');
  // }
 
  // get the login error if there is one
  $error = $authenticationUtils->getLastAuthenticationError();
  // last username entered by the user
  $lastUsername = $authenticationUtils->getLastUsername();
 
  return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}
52'40Méthode getUser() de LoginFormAuthenticator.php
public function getUser($credentials, UserProviderInterface $userProvider)
{
  $token = new CsrfToken('authenticate', $credentials['csrf_token']);
  if (!$this->csrfTokenManager->isTokenValid($token)) {
    throw new InvalidCsrfTokenException();
  }
 
  $user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);
 
  if (!$user) {
    // fail authentication with a custom error
    throw new CustomUserMessageAuthenticationException('Email could not be found.');
  }
 
  return $user;
}
53'45Vérification du token csrf
1'01'50Exceptions pouvant être lévées
1'06'15Injection de l'EntityManagerInterface
1'11'45atouts de l'objet UserInterface
1'12'15Récapitulatif sur les méthodes supports(), getCredentials et getUser
1'14'00⭐Astuce : rester vague sur les messages d'erreurs
1'17'40Méthode checkCredentials() de LoginFormAuthenticator.php
public function checkCredentials($credentials, UserInterface $user)
{
  return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
1'23'10Interface UserPasswordEncoderInterface
1'27'15Méthode isPasswordValid() de UserPasswordEncoder.php
1'34'30Présentation de la méthode onAuthenticationFailure()
1'36'55Méthode supportsRememberMe() de AbstractFormLoginAuthenticator.php
public function supportsRememberMe()
{
    return true;
}
1'37'30Méthode onAuthenticationFailure() de AbstractFormLoginAuthenticator.php et Méthode getLoginUrl() de AbstractFormLoginAuthenticator.php
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
    if ($request->hasSession()) {
        $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);
    }
 
    $url = $this->getLoginUrl();
 
    return new RedirectResponse($url);
}
protected function getLoginUrl()
{
  return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
1'41'15⭐Astuce : générer une url en se basant sur un route
$this->urlGenerator->generate(self::LOGIN_ROUTE);
1'43'05$error dans la méthode login() de SecurityController.php
/$error = $authenticationUtils->getLastAuthenticationError();
1'44'00Passage de l'erreur d'authentication au template login.html.twig
1'46'20Récupération du message d'erreur
{{ error.messageKey }}
1'48'25Personnaliser les messages d'erreurs
1'50'00Utilisation du filtre Twig |trans et du fichier translations\security.en.yaml
{{ error.messageKey|trans(error.messageData, 'security') }}
'Invalid credentials': 'Indentifiants invalides'
1'52'20Modification du message d'erreur avec Bootstrap
1'55'15Achage avec un nouvel algorithme : PasswordAuthenticatedInterface et méthode getPassword()
public function getPassword($credentials): ?string
{
  return $credentials['password'];
}
2'00'45Méthode onAuthenticationSuccess() de AbstractFormLoginAuthenticator.php
2'06'25Méthode createAuthenticatedToken() de AuthenticatorInterface.php
2'09'05Méthode start() de AbstractFormLoginAuthenticator.php
2'11'40Affichage d'un message une fois l'utilisateur connecté
$request->getSession()->getFlashBag()->add('success', 'Logged in successfully');
2'15'55Empecher les utilisateurs connectés d'accéder au pages login et register
2'17'50⭐Astuce : accéder à l'utilisateur dans Twig et dans un controller
app.user
$this->getUser()
2'19'25Gestion du lien de déconnexion
2'23'10Gestion de la fonctionnalité “Remember me” How to Add "Remember Me" Login Functionality
2'27'10Ajout de la case à cocher “Remember me” dans Twig
<div class="checkbox mb-3">
    <label>
        <input type="checkbox" name="_remember_me"> Remember me
    </label>
</div>
2'29'25Stylisation du formulaire de connexion
2'31'55⭐Astuce : HTML - Accessibilité sur le message d'erreur
role="alert"
2'33'35⭐Astuce : Bootstrap - class Flexbox
class="d-flex justify-content-between"
2'34'10⭐Astuce : Bootstrap - Les checkboxs

❌Symfony 5 : Nouveau système d'authentication expérimental

❌08 - Episode 8

Notions abordées

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'00
0'00
0'00

❌09 - Episode 9

Notions abordées

Haut de page 🔺
Vidéos précédente ▲
Vidéos suivante ▼

Temps Sujet traité Commandes éventuelles
0'00
0'00
0'00

❌10 - Episode 10

Notions abordées

Haut de page 🔺
Vidéos précédente ▲

Temps Sujet traité Commandes éventuelles
0'00
0'00
0'00
backend/symfonytuto.txt · Last modified: 2020/09/16 10:35 (external edit)