Makina Blog
Comment démarrer un projet Symfony 5 en 5 minutes ?
Depuis quelques versions, le framework Symfony fournit de nombreux outils pour bâtir très rapidement une application fonctionnelle. Voyons ce qu'on peut faire en 5 minutes.
À l'occasion de la sortie du passage en LTS de la version 5 du plus connu des frameworks PHP, nous vous montrons comment Symfony peut vous aider à bâtir très rapidement une mini application web.
L'idée principale est d'utiliser au maximum Composer (le principal gestionnaire de dépendances de la communauté PHP) pour gérer l'application, notamment au lancement.
Flex, le squelette et les recettes
Dans le monde PHP, l'installation de nouveaux modules passe par l'usage de composer. La version 4 de Symfony a introduit Symfony Flex qui est une surcouche à Composer permettant d'exécuter des tâches sur certaines commandes Composer (require, update et remove). L'idée est de ne plus se limiter à l'installation des modules PHP ou bundles Symfony, mais également de fournir des fichiers exemples ou des morceaux de configuration avec des valeurs classiques, qui permettent de rendre le module immédiatement opérationnel et d'améliorer la "developer experience".
Ces tâches supplémentaires sont appelées des recettes (Recipes), elles sont listées sur le site Symfony Recipes et sont disponibles sur le dépôt Symfony pour les recettes officielles ou ce dépôt de recettes additionnelles fournies par la communauté.
Pour tout savoir sur Flex, vous pouvez consulter la présentation donnée par Fabien Potencier (créateur de Symfony) lors de la SymfonyCon, mais si vous êtes pressés (j'ai dit 5 minutes après tout), il vous suffit de continuer l'article.
Pour créer notre projet projet Symfony, nous pouvons donc utiliser Composer et l'un des 2 squelettes par défaut :
- symfony/skeleton : pour avoir une base vraiment minimaliste avec peu de modules, utile pour bâtir un petit service REST par exemple
- symfony/website-skeleton : pour avoir une liste plus complète de modules permettant d'afficher des écrans HTML ou encore de stocker les données dans une base de données
Pour éviter de devoir rapidement installer de nombreux modules supplémentaires, partons sur :
$ composer create-project symfony/website-skeleton demo
$ cd demo
Nos premiers bundles
Flex contient notamment, pour certaines fonctionnalités, LA bonne solution (du moins la solution recommandée par la communauté) pour implémenter cette fonctionnalité. Du coup, plutôt que comparer les différents bundles qui existent pour implémenter une fonctionnalité, l'idée est désormais de suivre les recettes de la communauté.
Par exemple, dans notre application, nous savons que nous aurons besoin d'une gestion de la base de données, d'une interface d'administration de ces données, et d'une API (quelle application web moderne n'a pas d'API ?).
En utilisant Flex, et sachant que nous avons déjà l'ORM Doctrine installé dans le squelette "website", l'installation de ces composants se fait en une ligne :
$ composer req admin api
Nous allons également installer un outil de génération de code ("Maker bundle") que l'on va utiliser ensuite, mais qui ne servira qu'en environnement de développement :
$ composer req maker --dev
Notre première entité
Puisque nous utilisons un framework tel que Symfony, c'est a priori pour réaliser une application métier. Nous devons donc commencer la modélisation de nos données, en prenant pour exemple une entité Product.
Pour aller plus vite, nous allons générer une grosse partie du code en utilisant le générateur de code que nous venons d'installer :
$ ./bin/console make:entity Product
Il est possible de renseigner tous les champs de notre entité, par exemple utiliser :
- name (string, 255)
- price (integer)
A ce stade, une classe PHP a été générée, avec des annotations Doctrine qui indiquent comment stocker les données dans une base de données.
La base de données
Comme cela était indiqué dans le terminal lors de l'installation du squelette de base qui contenait la recette "orm", il nous reste à configurer l'accès à la base de données. La recette nous a fourni un fichier de configuration avec différentes propositions d'URL de connexion à utiliser selon la BD choisie. Partons sur SQLite qui nous évite d'installer un service additionnel (ou de lancer un conteneur), mais libre à vous d'ajuster si vous êtes plus à l'aise avec d'autres solutions. Il faut par contre s'assurer d'avoir l'extension PHP associée à la BD retenue. Par exemple, pour SQLite, il vous faudra un paquet dont le nom est proche de php-sqlite3 (à adapter selon la distribution Linux utilisée).
$ vim .env
###> doctrine/doctrine-bundle ###
DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
# DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7"
# DATABASE_URL="postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=13&charset=utf8"
###< doctrine/doctrine-bundle ###
Passer par les commandes Symfony Console pour créer la BD et mettre à jour le schéma à partir des annotations des différentes entités :
$ ./bin/console doctrine:database:create
$ ./bin/console doctrine:schema:update --force
Cette dernière commande peut être jouée à chaque modification ou ajout d'entités. Pour aller plus loin, il est possible de versionner les changements de structure de ce schéma via les migrations Doctrine.
Une interface de saisie
A ce stade, il serait possible d'utiliser des commandes comme composer make:crud pour rapidement produire :
- le controller qui gère les requêtes de création, modification, consultation et suppression de notre entité produit
- un formulaire basé sur le composant Symfony Form
- des templates d'affichage basiques avec Twig
Pour produire un résultat plus rapide et avoir des interfaces plus propres, nous allons utiliser le module EasyAdmin installé précédemment.
Attention : habituellement, ce module permet de bâtir rapidement des interfaces d'administration pour le backoffice, que l'on protège donc par une authentification, dans le cas présent on s'en sert pour rapidement remplir la BD, ca n'est pas une fonction qu'il faudrait laisser en accès anonyme.
Contrairement aux versions précédentes qui nécessitaient des fichiers de configuration YAML, la configuration de la version 3 d'EasyAdmin passe par des classes PHP. Là encore, utilisons le générateur de code pour produire une classe de configuration générale de l'administration puis une autre classe spécifiquement pour administrer les produits :
$ ./bin/console make:admin:dashboard
$ ./bin/console make:admin:crud # choisir l'entité Product
Editer ensuite le dashboard afin d'exposer l'administration des produits :
<?php
// src/Controller/Admin/DashboardController.php
namespace App\Controller\Admin;
// instructions use ignorées
class DashboardController extends AbstractDashboardController
{
/**
* @Route("/admin", name="admin")
*/
public function index(): Response
{
// Default route to product management
$routeBuilder = $this->get(AdminUrlGenerator::class);
return $this->redirect($routeBuilder->setController(ProductCrudController::class)->generateUrl());
}
public function configureDashboard(): Dashboard
{
return Dashboard::new()
->setTitle('Easy Admin');
}
public function configureMenuItems(): iterable
{
yield MenuItem::linktoDashboard('Dashboard', 'fa fa-home');
yield MenuItem::linkToCrud('Product', 'fa fa-gift', Product::class);
}
}
Lancer le serveur web PHP :
$ php -S localhost:8000 -t public/
[Tue Oct 19 18:15:37 2021] PHP 7.4.16 Development Server (http://localhost:8000) started
Il est maintenant possible d'accéder à l'interface d'administration sur http://localhost:8000/admin
Nous obtenons un back-office responsive dans lequel nous pouvons saisir quelques produits :
Exposition par API
Un autre besoin classique est l'exposition des données par l'intermédiaire d'API. Le module API Platform est un outil particulièrement riche et complet que nous n'allons que survoler ici. Nativement, il expose les différentes API disponibles via une interface OpenAPI (ex Swagger, voir la documentation associée) disponible sur http://localhost:8000/api
Par défaut, aucune API n'est disponible, mais il suffit d'ajouter cette annotation fournie par API Platform sur l'entité produit :
<?php
// src/Controller/Entity/Product.php
namespace App\Entity;
// annotation ajoutée au niveau de la classe
use ApiPlatform\Core\Annotation\ApiResource;
/**
* @ApiResource
* @ORM\Entity(repositoryClass=ProductRepository::class)
*/
class Product
{
// reste de la classe
}
Recharger l'interface d'administration et on obtient une API autogénérée avec les valeurs par défaut :
Il est possible de vérifier son bon fonctionnement avec cURL :
$ curl -s -H "Accept: application/json" http://localhost:8000/api/products | jq
[
{
"id": 1,
"name": "Produit #1",
"price": 25
},
{
"id": 2,
"name": "Produit #2",
"price": 115
}
]
Noter que par défaut, API Platform retourne des réponses au format "application/ld+json" mais cela est personnalisable.
Résolution de problèmes
Pour utiliser les recettes qui ne sont pas mises en avant par la core team Symfony, il faut modifier un paramètre de votre application (mais vous avez pu constater que ce n'était pas nécessaire pour cet article, nous n'avons utilisé que des recettes officielles) :
$ composer config extra.symfony.allow-contrib true
Pour aller plus loin
Il est possible d'avoir plus d'information sur les nouveautés des dernières versions de Symfony 5 en suivant le blog "living on the edge".
Symfony 5 fait l'objet d'un livre de grande qualité (et gratuit dans sa version électronique) qui balaye l'intégralité des principaux composants.
Enfin, cela ne tient pas en 5 minutes, mais il est possible de sécuriser son application avec le Security bundle (qui s'est amélioré dans les versions 5 de Symfony). La documentation actuelle est d'une grande aide pour mettre en place un formulaire de connexion.
À vous de jouer !
5 minutes, comme promis. À vos développements, maintenant !
Ou venez suivre notre formation Symfony.
Formations associées
Actualités en lien
DbToolsBundle : sortie de la version 1.2
Découvrez les nouveautés de cette nouvelle version ainsi que les fonctionnalités à venir de la prochaine version majeure.
Symfony : utiliser une contrainte de type Callback dans un formulaire pour de la validation spécifique
Vous devez développer une contrainte pour un formulaire métier ? La déclarer à l'aide du composant Validation de Symfony est peut-être excessif : il est aussi possible de le faire en passant par une assertion de type Callback.
Le framework Symfony, un choix réfléchi
Alliant souplesse, performance et efficacité, Symfony devient un incontournable dans nos technologies.