Symfony ExpressionLanguage : Comment utiliser ce composant ?
Le composant Symfony ExpressionLanguage : qu'est-ce que c'est ? Quand et comment l'utiliser ? Comment créer des expressions lors de cas plus complexes ?
Sommaire
Dans la continuité de l'article de notre très cher confrère Romain Pierlot sur Api Platfrom, nous allons essayer de faire le tour des nouvelles fonctionnalités de ce framework, et par la même occasion, mettre en place une application web, comportant une api REST Hydra
/ Graphql
avec un backend et un client full Javascript.
Pour les présentations, API Platform se veut être un framework complet permettant de créer des projets web se basant sur des APIs orientées ressource, ce qui est un peu le standard d'architecture des besoins contemporains de notre domaine.
Commençons par installer ce framework en local.
Clonons donc ce projet dans notre workspace préféré :
git clone git@github.com:api-platform/api-platform.git cd api-platform
et ensuite mettons-nous sur la dernière version taguée. Au moment où j'écris cet article, la dernière version est la v2.2.5
git checkout tags/v2.2.5
Ce fichier docker-compose.yml à la racine du projet, ne nous laisse pas indifférent, allons donc poper ces conteneurs docker de ce pas. (mes versions : docker :17.05.0-ce docker-compose : 1.18.0)
docker-compose up -d
Passons rapidement en vue les images créées :
docker-compose ps
Il y a donc 6 conteneurs docker :
Autant vous dire qu'au niveau des technos, ils ont dépensé sans compter...
Ouvrons notre navigateur pour aller à l'url https://localhost
Vous allez devoir accepter d'ajouter une exception de sécurité dans votre navigateur par rapport au certificat TLS qui a été généré au moment de l'installation.
Si vous voyez cette belle page d'accueil, c'est que tout s'est bien passé !
Pour pouvoir créer notre api, il va falloir décrire nos ressources en codant de simples objets PHP avec leurs propriétés. Créons pour l'exemple une simple liste de courses, parce que niveau mémoire c'est plus trop ça. Pour des questions de simplicité on va juste créer une classe shoppingItem et utiliser la vue List que propose le client API Platform que nous verrons plus tard (mais sachez que toutes les relations entre entités sont très bien gérées).
<?php
// api/src/Entity/ShoppingItem.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* An item of a shopping list.
*
* @ORM\Entity
*/
class ShoppingItem
{
/**
* @var int The id of this item.
*
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @var string the name of the item.
*
* @ORM\Column
* @Assert\NotBlank
*/
public $name;
/**
* @var boolean if the item has been purchased.
*
* @ORM\Column(type="boolean")
*/
public $isCheck = false;
public function getId(): ?int
{
return $this->id;
}
public function getIsCheck(): ?string
{
return $this->isCheck ? "yes" : "no";
}
}
On va en profiter pour supprimer la classe php de démo api/src/Entity/Greeting.php :
rm ./api/src/Entity/Greeting.php
et exécuter la commande doctrine pour synchroniser la base de données avec notre nouveau model :
docker-compose exec php bin/console doctrine:schema:update --force --complete
Le --complete
effacera la table gretting
de la base de données, ce que la commande ne fait pas par défaut.
Maintenant, ajoutons l'annotation magique d'API Platform à notre entité pour que le framework puisse détecter les propriétés à exposer par l'api et autoriser les opérations CRUD liées à l'objet.
<?php
// api/src/Entity/ShoppingItem.php
// ...
use ApiPlatform\Core\Annotation\ApiResource;
/**
* ...
*
* @ApiResource
*/
class ShoppingItem
{
// ...
}
Et voilà, notre API est ready !
Allons à cette adresse https://localhost:8443
Vous devriez voir cette page, qui décrit toutes les actions possibles sur cette ressource :
Oh joie! Api Platform intègre une version personnalisée de Swagger UI, qui permet de documenter vos ressources et par la même occasion de les tester, mais propose également une alternative avec NelmioApiDoc Bundle. Le format par défaut de l'api est le JSON-LD avec l'extension Hydra, qui est une version plus évoluée que le JSON standard donnant plus d'informations sur la ressource ainsi que les opérations possibles sur cette dernière. L'api supporte également les formats courants tels que le JSON, XML, HAL, JSONAPI et très récemment le graphQL ...que nous allons bien évidemment nous empresser d'activer !
Pour cela, il va falloir installer la librairie graphql-php :
docker-compose exec php composer req webonyx/graphql-php
Et voilà ! L'interface graphique GraphiQL est disponible ici https://localhost:8443/graphql
Rien de mieux pour commencer à se faire les dents sur ce super langage.
API Platform intègre un backend utilisant la librairie Admin On Rest, un client en React avec material design qui se bind directement sur une api, et construit ses vues en fonction des ressources disponibles et des opérations permises : https://localhost:444
En sachant que ce backend est entièrement paramétrable.
Le dernier point que j'aborderai et qui n'est pas des moindres, c'est la génération d'une Progressive Web App avec React/Redux, mais il est également possible de générer une application en Vue.js ou une application en React Native
Créons notre application JavaScript :
docker-compose exec client generate-api-platform-client
Ajoutons maintenant les routes et les reducers générés dans index.js comme ceci :
//client/src/index.js
import React from 'react';
import ReactDom from 'react-dom';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { reducer as form } from 'redux-form';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import createBrowserHistory from 'history/createBrowserHistory';
import { syncHistoryWithStore, routerReducer as routing } from 'react-router-redux';
import 'bootstrap/dist/css/bootstrap.css';
import 'font-awesome/css/font-awesome.css';
import registerServiceWorker from './registerServiceWorker';
import Welcome from './Welcome';
import shoppingitem from './reducers/shoppingitem/';
import shoppingitemRoutes from './routes/shoppingitem';
const store = createStore(
combineReducers({routing, form, shoppingitem}),
applyMiddleware(thunk),
);
const history = syncHistoryWithStore(createBrowserHistory(), store);
ReactDom.render(
<Provider store={store}>
<Router history={history}>
<Switch>
<Route path="/" component={Welcome} strict={true} exact={true}/>
{shoppingitemRoutes}
<Route render={() => <h1>Not Found</h1>}/>
</Switch>
</Router>
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
Concernant le choix des librairies, nous remarquerons que React Router est utilisé pour la navigation, Redux Form pour gérer les formulaires et Redux Thunk pour gérer les requêtes ou autres traitements asynchrones (désolé pour les utilisateurs de redux-saga), avec une gestion des Services Workers.
Nous pouvons maintenant aller à l'url de la vue list
de notre ressource shoppingItem
: https://localhost/shopping_items/
Parfait, vous avez votre liste de courses en react/redux qui va bien :
Ce framework est vraiment des plus complets. Ce que l'on vient d'aborder ne couvre même pas le quart de ce que propose API Platform dans sa globalité, et toutes ces possibilités se basent sur de bonnes pratiques.
Le seul point négatif que l'on peut lui trouver c'est son architecture qui est orientée événement, se basant sur le système des events kernel de Symfony. L'avantage est que cela donne une grande liberté pour développer de nouvelles fonctionnalités.
Cela devient un inconvénient sur de gros projet où l'historique du code produit par moult développeurs, sûrement très bien attentionnés, devient un peu trop conséquent. Cela peut très vite partir dans tout les sens, et au final être un enfer à débugger.
J'aurais aimé vous parler de l'intégration de FOSuser bundle avec l'autentification JWT, des tests en Behat, PHPUnit, déployer son projet API Platform sur un cluster Kubernetes en quelques lignes de commande mais le temps me manque, je vous réserve donc cela pour la prochaine fois.
Auteur(s)
Victor Delpeyroux
j'aime le back, j'aime le front, et la clarinette
Vous souhaitez en savoir plus sur le sujet ?
Organisons un échange !
Notre équipe d'experts répond à toutes vos questions.
Nous contacterDécouvrez nos autres contenus dans le même thème
Le composant Symfony ExpressionLanguage : qu'est-ce que c'est ? Quand et comment l'utiliser ? Comment créer des expressions lors de cas plus complexes ?
Découvrez comment réaliser du typage générique en PHP : introduction et définition du concept, conseils et explications pas-à-pas de cas pratique.
Découvrez un cas d'usage d'intégration d'un CRM avec une application e-commerce, en asynchrone, avec Hubspot et RabbitMQ