Remise à niveau Symfony3: slides + planning
This commit is contained in:
parent
729f2c318a
commit
cb42e8734b
|
@ -0,0 +1,705 @@
|
||||||
|
<style>pre { font-size: 0.7em !important; }</style>
|
||||||
|
|
||||||
|
# Remise à niveau Symfony3
|
||||||
|
## William Petit - S.C.O.P. Cadoles
|
||||||
|
|
||||||
|
---
|
||||||
|
<!-- page_number:true -->
|
||||||
|
|
||||||
|
# Les principales nouveautés de Symfony 3
|
||||||
|
|
||||||
|
- Simplification de l'authentification avec le système de "Guard"
|
||||||
|
- Composant LDAP pour l'authentification (compatible Active Directory)
|
||||||
|
- Amélioration des mécanismes d'injection de dépendances: "auto-wiring", services dépréciés...
|
||||||
|
- Un "MicroKernel" pour créer des applications minimalistes basées sur Symfony3
|
||||||
|
- Et beaucoup d'autres améliorations et composants mineurs...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Structure d'un projet, générateurs et "bundles"
|
||||||
|
|
||||||
|
## Amorçage d'un projet
|
||||||
|
## Notion de "bundle"
|
||||||
|
## Structuration d'un projet
|
||||||
|
## La console, les commandes et les générateurs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Amorçage d'un projet
|
||||||
|
|
||||||
|
### Récupération de l'installeur Symfony
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mkdir -p /usr/local/bin
|
||||||
|
sudo curl -LsS https://symfony.com/installer \
|
||||||
|
-o /usr/local/bin/symfony
|
||||||
|
sudo chmod a+x /usr/local/bin/symfony
|
||||||
|
```
|
||||||
|
|
||||||
|
### Création du projet (avec la dernière LTS)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
symfony new <my_project_name> 3.4
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notion de "bundle"
|
||||||
|
|
||||||
|
> Un "bundle" est un ensemble de fichiers (code, templates, etc) représentant une unité fonctionnelle dans le framework Symfony.
|
||||||
|
|
||||||
|
**Avant Symfony 3** Les "bundles" étaient le moyen utilisé pour structurer le code d'une application. Une application pouvait donc avoir plusieurs bundles "internes", i.e. ne provenant pas d'un développeur tiers.
|
||||||
|
|
||||||
|
**Après Symfony 3** Les bundles ne sont plus considérés à titre organisationnel mais uniquement comme un moyen de diffuser le code sous forme d'unité réutilisable. Une application ne devrait donc plus qu'avoir un seul bundle interne: `AppBundle`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Structuration d'un projet (1)
|
||||||
|
|
||||||
|
### Les principaux répertoires et leur rôle
|
||||||
|
|
||||||
|
|Répertoire|Rôle|
|
||||||
|
|:-:|:-:|
|
||||||
|
|`app/config/`|Configuration de l'application|
|
||||||
|
|`app/Resources/`|Depuis Symfony3, répertoire contenant les vues ainsi les "assets" de l'application|
|
||||||
|
|`src/AppBundle/`|Sources de l'application|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
## Structuration d'un projet (2)
|
||||||
|
|
||||||
|
|Répertoire|Rôle|
|
||||||
|
|:-:|:-:|
|
||||||
|
|`tests/`|Répertoire contenant les tests de l'application (unitaire comme fonctionnels)|
|
||||||
|
|`var/`|Répertoire contenant toutes les données "vivantes" de l'application|
|
||||||
|
|`vendor/`| Dépendances Composer
|
||||||
|
|`web/`| Répertoire des ressources publiques de l'application
|
||||||
|
|
||||||
|
---
|
||||||
|
## La console, les commandes et les générateurs (1)
|
||||||
|
|
||||||
|
### Quelques commandes (très) utiles
|
||||||
|
|Commande|Description|
|
||||||
|
|:-:|:-:|
|
||||||
|
|`server:run`|Exécuter l'application avec le serveur HTTP PHP|
|
||||||
|
|`security:check`|Vérifier que les dépendances du projet ne comportent pas de vulnérabilités connues|
|
||||||
|
|`debug:container`|Retrouver le mapping services <-> classe PHP|
|
||||||
|
|`router:match`|Vérifier quelle controleur/action sera utilisée pour un chemin donné|
|
||||||
|
---
|
||||||
|
|
||||||
|
## La console, les commandes et les générateurs (2)
|
||||||
|
|
||||||
|
### Les générateurs par défaut
|
||||||
|
|Commande|Description|
|
||||||
|
|:-:|:-:|
|
||||||
|
|`generate:bundle`|Créer un nouveau bundle|
|
||||||
|
|`generate:controller`|Créer un nouveau contrôleur|
|
||||||
|
|`generate:command`|Créer une nouvelle commande|
|
||||||
|
|`doctrine:generate:entity`|Créer une nouvelle entité Doctrine|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Le routage et les contrôleurs
|
||||||
|
|
||||||
|
## Création d'un nouveau contrôleur
|
||||||
|
## Déclaration des contrôleurs
|
||||||
|
## Actions, routes et verbes HTTP avec les annotations
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Création d'un nouveau contrôleur
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bin/console generate:controller
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Déclaration des contrôleurs
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Actions, routes et verbes HTTP avec les annotations (1)
|
||||||
|
|
||||||
|
### Action annotée basique
|
||||||
|
```php
|
||||||
|
class DemoController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/demo")
|
||||||
|
*/
|
||||||
|
public function demoAction()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Actions, routes et verbes HTTP avec les annotations (2)
|
||||||
|
|
||||||
|
### Action avec méthodes HTTP contraintes
|
||||||
|
|
||||||
|
```php
|
||||||
|
class DemoController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route(
|
||||||
|
* "/demo",
|
||||||
|
* methods = { "POST", "PUT" }
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function demoAction()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Actions, routes et verbes HTTP avec les annotations (3)
|
||||||
|
|
||||||
|
### Action nommée
|
||||||
|
|
||||||
|
```php
|
||||||
|
class DemoController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/demo-named", name="my_demo_action")
|
||||||
|
*/
|
||||||
|
public function demoAction()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Actions, routes et verbes HTTP avec les annotations (4)
|
||||||
|
|
||||||
|
### Action avec paramètres
|
||||||
|
|
||||||
|
```php
|
||||||
|
class DemoController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/demo/{myParam}")
|
||||||
|
*/
|
||||||
|
public function demoAction($myParam)
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/demo/{paramWithDefaultVal}")
|
||||||
|
*/
|
||||||
|
public function demoAction($paramWithDefaultVal = 1)
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Actions, routes et verbes HTTP avec les annotations (5)
|
||||||
|
|
||||||
|
### Action avec paramètres contraints
|
||||||
|
|
||||||
|
```php
|
||||||
|
class DemoController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route(
|
||||||
|
* "/demo/{myParam}",
|
||||||
|
* requirements = { "myParam"="^\d+$" }
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function demoAction($myParam)
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Actions, routes et verbes HTTP avec les annotations (6)
|
||||||
|
|
||||||
|
### Action avec paramètres contraints
|
||||||
|
|
||||||
|
```php
|
||||||
|
class DemoController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route(
|
||||||
|
* "/demo/{myParam}",
|
||||||
|
* requirements = { "myParam"="^\d+$" }
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function demoAction($myParam)
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Actions, routes et verbes HTTP avec les annotations (7)
|
||||||
|
|
||||||
|
### Paramètres spéciaux
|
||||||
|
|
||||||
|
|Paramètre|Description|
|
||||||
|
|:-:|:-:|
|
||||||
|
|`_locale`| La "locale" utilisé par l'application pour la requête en cours |
|
||||||
|
|`_format`| Le "format" utilisé par l'application pour la requête en cours |
|
||||||
|
|`_controller`| L'identifiant du contrôleur et son action utilisés pour traiter la requête en cours|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Actions, routes et verbes HTTP avec les annotations (8)
|
||||||
|
|
||||||
|
### Générer une URL pour une route nommée
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
|
||||||
|
$this->generateUrl(
|
||||||
|
'demo', // Nom de la route
|
||||||
|
['myParam' => 'my-value'], // Paramètres à injecter
|
||||||
|
// L'URL générée doit elle être absolue ou non ?
|
||||||
|
UrlGeneratorInterface::ABSOLUTE_URL
|
||||||
|
);
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
# Services
|
||||||
|
|
||||||
|
## Utilisation des services
|
||||||
|
## Création de nouveaux services
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Utilisation des services (1)
|
||||||
|
|
||||||
|
### Lister les services existants
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bin/console debug:container
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Utilisation des services (2)
|
||||||
|
|
||||||
|
### Utiliser un service (méthode classique)
|
||||||
|
|
||||||
|
```php
|
||||||
|
class DemoController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/demo")
|
||||||
|
*/
|
||||||
|
public function demoAction()
|
||||||
|
{
|
||||||
|
$logger = $this->get('logger');
|
||||||
|
$logger->info('Hello world !');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Utilisation des services (3)
|
||||||
|
|
||||||
|
### Utiliser un service (Via le "type hint")
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class DemoController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/demo")
|
||||||
|
*/
|
||||||
|
public function demoAction(LoggerInterface $logger)
|
||||||
|
{
|
||||||
|
$logger->info('Hello world !');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tip** Pour identifier les différentes interfaces disponibles, utilisez la commande `bin/console debug:autowiring`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Création d'un service (1)
|
||||||
|
|
||||||
|
### Création de la classe PHP
|
||||||
|
|
||||||
|
```php
|
||||||
|
namespace AppBundle\Service;
|
||||||
|
|
||||||
|
class MyService {
|
||||||
|
public function doNothing() {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tip** On peut vérifier que le service est bien détecté par l'application avec la commande `bin/console debug:autowiring`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Création d'un service (2)
|
||||||
|
|
||||||
|
### Utilisation du service dans un contrôleur
|
||||||
|
|
||||||
|
```php
|
||||||
|
use AppBundle\Service\MyService;
|
||||||
|
|
||||||
|
class DemoController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/demo")
|
||||||
|
*/
|
||||||
|
public function demoAction(MyService $my)
|
||||||
|
{
|
||||||
|
$my->doNothing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Création d'un service (3)
|
||||||
|
|
||||||
|
### Déclaration de dépendances inter-services
|
||||||
|
|
||||||
|
```php
|
||||||
|
namespace AppBundle\Service;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class MyService {
|
||||||
|
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
public function __construct(LoggerInterface $logger) {
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function log($message) {
|
||||||
|
$this->logger->info($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Création d'un service (4)
|
||||||
|
|
||||||
|
### Déclaration de dépendances vers des valeurs de configuration
|
||||||
|
|
||||||
|
```php
|
||||||
|
namespace AppBundle\Service;
|
||||||
|
|
||||||
|
class MyService {
|
||||||
|
|
||||||
|
private $myCustomParameter;
|
||||||
|
|
||||||
|
public function __construct($myCustomParameter) {
|
||||||
|
$this->myCustomParameter = $myCustomParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Création d'un service (5)
|
||||||
|
|
||||||
|
### Déclaration explicite de la dépendance
|
||||||
|
|
||||||
|
Dans `app/config/services.yml`, déclarer la dépendance explicitement:
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
AppBundle\Service\MyService:
|
||||||
|
arguments:
|
||||||
|
$myCustomParameter: 'test'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Authentification et autorisation
|
||||||
|
|
||||||
|
## Le fichier `app/config/security.yml`
|
||||||
|
## Firewalls, providers et encoders
|
||||||
|
## Gestion des rôles et contrôle des accès
|
||||||
|
## Méthode d'authentification personnalisée
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Le fichier `app/config/security.yml`
|
||||||
|
|
||||||
|
### Authentifications et autorisations
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Firewalls (1)
|
||||||
|
|
||||||
|
### Déclarer une nouvelle méthode d'authentification dans un firewall
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
firewalls:
|
||||||
|
main:
|
||||||
|
anonymous: ~
|
||||||
|
http_basic: ~
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Firewalls (2)
|
||||||
|
|
||||||
|
### Multiple firewalls
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
|
||||||
|
firewalls:
|
||||||
|
|
||||||
|
authenticated_area:
|
||||||
|
pattern: ^/secured
|
||||||
|
http_basic: ~
|
||||||
|
|
||||||
|
public_area:
|
||||||
|
anonymous: ~
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Providers (1)
|
||||||
|
|
||||||
|
### Utilisation du provider `memory`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
|
||||||
|
providers:
|
||||||
|
in_memory:
|
||||||
|
memory:
|
||||||
|
users:
|
||||||
|
bob:
|
||||||
|
password: bob
|
||||||
|
roles: 'ROLE_USER'
|
||||||
|
admin:
|
||||||
|
password: 123456
|
||||||
|
roles: 'ROLE_ADMIN'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Providers (2)
|
||||||
|
|
||||||
|
### Déclaration de l'`encoder` pour la gestion des mots de passe
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
encoders:
|
||||||
|
Symfony\Component\Security\Core\User\User: plaintext
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Providers (3)
|
||||||
|
|
||||||
|
### Utilisation d'un `encoder` apportant un meilleur niveau de sécurité
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
encoders:
|
||||||
|
Symfony\Component\Security\Core\User\User:
|
||||||
|
algorithm: bcrypt
|
||||||
|
cost: 12
|
||||||
|
```
|
||||||
|
#### Calcul de l'empreinte d'un mot de passe
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bin/console security:encode-password
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gestion des rôles et contrôle des accès (1)
|
||||||
|
|
||||||
|
## Définition de rôles
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
access_control:
|
||||||
|
- { path: ^/admin, roles: ROLE_ADMIN }
|
||||||
|
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gestion des rôles et contrôle des accès (2)
|
||||||
|
|
||||||
|
## Restriction d'accès par adresse IP
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
access_control:
|
||||||
|
- path: ^/local-api
|
||||||
|
roles: ROLE_API_USER
|
||||||
|
ips: [127.0.0.1]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## Gestion des rôles et contrôle des accès (3)
|
||||||
|
|
||||||
|
## Définition de règles d'accès pour les actions
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
|
||||||
|
|
||||||
|
class DemoController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/demo")
|
||||||
|
* @Security("has_role('ROLE_ADMIN')")
|
||||||
|
*/
|
||||||
|
public function demoAction()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Méthode d'authentification personnalisée
|
||||||
|
|
||||||
|
### Exercice
|
||||||
|
|
||||||
|
Implémenter une classe `Guard` pour créer un firewall pour un serveur d'authentification "passwordless" basé sur JWT.
|
||||||
|
|
||||||
|
**Ressources**
|
||||||
|
- Tutoriel Symfony3 sur l'utilisation de la classe Guard https://symfony.com/doc/3.4/security/guard_authentication.html
|
||||||
|
- Instance de démonstration du serveur d'authentification: https://forge.cadoles.com/wpetit/ciku
|
||||||
|
- Sources du serveur d'authentification: https://forge.cadoles.com/wpetit/ciku
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Les vues et le moteur de templating Twig
|
||||||
|
|
||||||
|
## Organisation des vues
|
||||||
|
## Syntaxe Twig
|
||||||
|
## Héritage et composition
|
||||||
|
## Étendre Twig
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Organisation des vues dans le projet
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Syntaxe Twig
|
||||||
|
|
||||||
|
```twig
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<p>{{ myVar }}</p>
|
||||||
|
<ul>
|
||||||
|
{% for i in items %}
|
||||||
|
<li>{{ i.text }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Héritage et composition (1)
|
||||||
|
|
||||||
|
### Héritage
|
||||||
|
|
||||||
|
```twig
|
||||||
|
// parent.html.twig
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
{% block body %}
|
||||||
|
<div>
|
||||||
|
Default content
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
```twig
|
||||||
|
// child.html.twig
|
||||||
|
{% extends 'parent.html.twig' %}
|
||||||
|
{% block body %}
|
||||||
|
<div>
|
||||||
|
Child content
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Héritage et composition (21)
|
||||||
|
|
||||||
|
### Composition
|
||||||
|
|
||||||
|
```twig
|
||||||
|
// layout.html.twig
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
{% for i in items %}
|
||||||
|
{{ include('_partial.html.twig', { 'item': i }) }}
|
||||||
|
{% endfor %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
```twig
|
||||||
|
// _partial.html.twig
|
||||||
|
<div>
|
||||||
|
Item #{{ item.id }}
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étendre Twig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Les formulaires
|
||||||
|
|
||||||
|
## Création et traitement de formulaires
|
||||||
|
## Validation des données
|
||||||
|
## Les évènements
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# L'ORM Doctrine et le modèle de données
|
||||||
|
|
||||||
|
## Concept d'ORM
|
||||||
|
## Entité et Dépôt
|
||||||
|
## Les évènements
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Mise en production
|
||||||
|
|
||||||
|
## Gestion des environnements
|
||||||
|
## Cache applicatif
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Licence
|
||||||
|
|
||||||
|
## CC BY-NC-SA 3.0 FR
|
||||||
|
|
||||||
|
[Creative Commons - Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 3.0 France](https://creativecommons.org/licenses/by-nc-sa/3.0/fr/)
|
Binary file not shown.
Loading…
Reference in New Issue