đŸȘ¶ Flight PHP#

Indication

Cette page à pour but de découvrir le langage PHP au travers de micro framework et le design pattern MVC.

Composer#

Note

Composer est un gestionnaire de dépendances écrit en PHP pour PHP.

Il permet Ă  ses utilisateurs de dĂ©clarer et d’installer les bibliothĂšques dont le projet principal a besoin.

Composer utilise un fichier composer.json qui contient plusieurs informations sur le projet dont la liste des librairies utilisées. Il est ensuite capable de télécharger automatiquement ces librairies (et les dépendances associées) et de générer un autoloader pour les utiliser simplement dans vos projets PHP.

Installation de composer#

L’installation de composer est trùs simple (dans les 2 cas il faut avoir la commande php disponible dans le terminal) :

  • Sous Windows, il vous suivre les instructions suivantes

  • Sous unix utiliser votre gestionnaire de package apt-get install composer , dnf install composer , 


Utilisation de composer#

Composer est un logiciel qui fonctionne en ligne de commande, ainsi il vous suffit d’invoquer composer pour accùder à la commande composer.

CrĂ©ation d’un rĂ©pertoire pour le projet#

$ mkdir test_composer
$ cd test_composer

Installation d’une librairie via composer#

$ composer require rmccue/requests

Cette commande lance la rĂ©cupĂ©ration et l’installation de la librairie requests. Si c’est la premiĂšre fois que la commande est lancĂ©e, celle-ci va créée plusieurs rĂ©pertoires et fichiers :

composer.json

pour spécifier les différentes dépendances,

composer.lock

instannée des dépendances à un instant \(t\),

vendor/

le répertoire qui contient les fichies des dépendances.

Note

L’avantage c’est que composer est capable de gĂ©rer les dĂ©pendances, donc si votre librairie Ă  besoin d’une autre librairie pour fonctionner elle sera automatiquement tĂ©lĂ©chargĂ©e.

Avertissement

Il est intéressant de versionner le fichier composer.json toutefois le composer.lock ainsi que le dossier vendor viendrait en revanche polluer notre dépÎt Git.

Utilisation de notre librairie#

C’est bien beau de tĂ©lĂ©charger des librairie mais encore faut-il ĂȘtre en mesure de les inclure.

Note

Lors d’une install ou d’un update composer va automatiquement gĂ©nĂ©rĂ© un autoloader autoload.php disponible Ă  la racine du rĂ©pertoire vendor.

Cet autoloader permet de ne pas avoir Ă  inclure les fichier des diffĂ©rentes librairies mais utilise un systĂšme d’autoloader, vous n’avez qu’à vous soucier des namespace.

<?php
require "vendor/autoload.php"; // Inclusion de l'autoloader

Découverte de requests en PHP#

Objectif

Nous allons voir dans cette partie comment dĂ©velopper une application en PHP appelant une API qui va rĂ©cupĂ©rer le rĂ©sultat de la requĂȘte en JSON (JavaScript Object Notation) pour l’afficher sur votre site web.

Les API sur Internet

Les API sont un moyen d’accĂ©der aux donnĂ©es d’un site sans avoir l’autorisation d’accĂ©der directement Ă  la base de donnĂ©es. Il y a beaucoup de portails sĂ©curisĂ©s permettant Ă  vos applications web de manipuler les donnĂ©es renvoyĂ©es par ces sites.

L’exemple parfait est Twitter. Elle permet de lire la timeline d’une personne en particulier, de rechercher des statuts Ă  partir d’un mot clĂ©, de modifier les paramĂštres de votre compte, etc.

Pourquoi le format JSON ?

Vous pouvez utiliser les API avec de nombreux langages et retourner les donnĂ©es de plusieurs façons. L’une d’elles est le JSON (JavaScript Object Notation). C’est un format de donnĂ©es lĂ©ger, facile Ă  lire et Ă  Ă©crire et compatible avec pas mal de langages de dĂ©veloppement.

Sa structure est composĂ©e d’objets et de tableaux. Sa flexibilitĂ© fait de JSON le parfait candidat pour retourner des donnĂ©es.

Requests et PHP#

Faire une requĂȘte est trĂšs simple :

<?php
$response = Requests::get('https://ingen.ugaritic.fr/api/books/');

Et si on affiche le contenu de $response :

<?php
var_dump($response->body);

Pour obtenir le statut de la réponse:

<?php
var_dump($response->status_code);

Pour obtenir un tableau à partir du corp de la réponse:

<?php
$books = json_decode($response->body);

On peut maintenant itérer sur ce tableau pour afficher chaque titre de livre:

<?php
foreach($books as $book){
    echo $book->title;
}

À faire

  • Modifiez votre fichier pour afficher sous une belle forme HTML chaque Ă©lĂ©ment retournĂ© par l’API,

  • Essayez de rĂ©cupĂ©rer l’élĂ©ment JSON Ă  l’url suivante: /api/books/a-game-of-thrones comme prĂ©cĂ©demment,

  • Comment corriger ce problĂšme ?

Indication

Vous venez de découvrir un gestionnaire de dépendances en PHP qui sera bien utile pour la suite de nos aventures ! Vous avez également découvert les API REST et le format de données JSON ! Félicitations !

PHP & la POO#

La dĂ©finition d’une classe commence par le mot-clĂ© class suivi du nom de la classe.

warrior.php#
<?php
class Warrior{
   //Attributs
   public $name = 'Conan'; //default value
   public function my_name(){
      echo $this->var;
   }
}

Pour crĂ©er l’instance d’une classe on utilise le mot-clĂ© new.

index.php#
<?php
include('warrior.php');
$warrior1 = new Warrior();
$warrior1->my_name();

Note

Les attributs sont dĂ©finies au sein d’une classe en utilisant un des mots-clĂ©s public, protected ou private suivie d’une dĂ©claration classique de variable.

Important

Les variables au sein d’une classe sont appellĂ©es attributs (membres, propriĂ©tĂ©s ou encore champs).

Au sein des mĂ©thodes de classes, les attributs peuvent ĂȘtre appelĂ©es en utilisant la syntaxe -> (opĂ©rateur de l’objet):

$this->my_attr.

La pseudo-variable $this est disponible au sein de n’importe quelle mĂ©thode quand celle-ci est appelĂ©e depuis un objet. $this est une rĂ©fĂ©rence Ă  l’objet appellant.

À faire

Dans notre classe warrior, ajouter les attributs (publiques) suivants avec une valeur par défault:

  • point de vie (hp)

  • point d’attaque (att)

  • point de dĂ©fence (def)

Note

Les attributs sont définies comme publiques, protégées ou privées.

À faire

warrior.php#
<?php
class Warrior{
   //Attributs
   public $name = 'Conan'; //default value
   private $hp = 10;
   private $att = 6;
   private $def = 3;
   public function my_name(){
      echo $this->var;
   }
}
index.php#
<?php
include('warrior.php');
$warrior1 = new Warrior();
$warrior1->my_name();
echo $warrior->name;
echo $warrior->att;
echo $warrior->def;
echo $warrior->hp;

Que se passe t’il lors de l’accùs au attributs hp, att et def ?

Astuce

Pour remĂ©dier aux soucis d’accessibilitĂ©s, nous allons mettre en oeuvre la notion de getter et de setter

À faire

warrior.php#
<?php
class Warrior{
   //Attributs
   public $name = 'Conan'; //default value
   private $hp = 10;
   private $att = 6;
   private $def = 3;
   public function get_hp(){
      return $this->hp;
   }
   public function set_hp($hp){
      $this->hp = $hp;
   }
   public function my_name(){
      echo $this->var;
   }
}

Tester ces deux nouvelles mĂ©thodes, quels est leur intĂ©rĂȘt ? Ajouter les getters et setters pour les autres attributs de notre classe.

Note

La dĂ©claration de constructeur permet d’ajouter un comportement qui sera appelĂ© Ă  chaque crĂ©ation d’une nouvelle instance de la classe.

warrior.php#
<?php
class Warrior{
    //Attributs
    public $name = 'Conan'; //default value
    private $hp = 10;
    private $att = 6;
    private $def = 3;
    function __construct($name, $hp, $att, $def){
       //TODO: complete behavior
    }
}

Ce constructeur permet d’initialiser les attributs de notre instance lors de sa crĂ©ation.

À faire

  • ComplĂ©tez le constructeur de notre classe puis instanciez plusieurs objets de type Warrior et enfin manipulez les.

  • Ajouter une mĂ©thode slap qui permet Ă  un guerrier de gifler un autre guerrier ..

  • Ajouter une mĂ©thode take_damage qui permet Ă  un guerrier de subir des dĂ©gĂąts ..

  • Simuler une « bagarre » entre deux guerriers ..

Flight PHP#

Flight est un framework performant, simple et extensible pour PHP.

Flight vous permet de créer rapidement et facilement des applications Web (RESTful).

Flight est un micro framework PHP intĂ©grant notamment la gestion du routing , les views et bien d’autres choses..

Installation de Flight PHP#

$ composer require mikecao/flight

Note

Pour rappel, composer ne fait que tĂ©lĂ©charger les sources des librairies PHP (les fichiers php donc) et crĂ©er automatiquement un autoloader que nous utiliserons dans notre projet. Il faut donc retenir que ces librairies ne sont pas installĂ©es dans le systĂšme mais uniquement tĂ©lĂ©charger dans le rĂ©pertoire vendor. Il s’agit d’ailleurs d’une bonne pratique d’avoir un dossier vendor par projet.

Pour commencer#

index.php#
<?php
require "vendor/autoload.php";

Découverte du routing#

Dans le fichier index.php rajouter le code suivant:

<?php

Flight::route('/', function(){
    echo 'hello world!';
});

Flight::start();

Rendez-vous sur votre site web local

Normalement vous devriez voir une page blanche avec les mots hello world! ,

Félicitations!

Quelques précisions:

La méthode statique: start permet de charger le framework et de mettre en place le routing.

La mĂ©thode statique route permet d’associer Ă  un pattern de route, une fonction. En l’occurrence / signifie l’index du site web et ensuite nous avons dĂ©clarĂ© une fonction directement dans le passage de variable.

Ainsi, ceci:

<?php

Flight::route('/', function(){
   echo 'hello world!';
});

est identique Ă  cela:

<?php

function hello(){
   echo 'hello world!';
}
Flight::route('/', 'hello');

Routing & paramĂštre#

<?php

Flight::route('/hello/@name', function($name){
    echo "hello, $name!";
});

À faire

Qu’elle est l’utilitĂ© de ce code ?

Indication

Nous venons de dĂ©couvrir la base de routing et le principe d’un framework, voyez vous l’utilitĂ© du routing Ă  prĂ©sent ?

Composer et autoloading#

Vous aurez remarqué que depuis le début nous utilisons le fichier autoload.php pour charger les librairies installées via composer.

Et si je souhaite charger automatiquement mes propres fichiers ?

Nous l’avons dĂ©jĂ  vue, le fichier composer.json permet de lister les dĂ©pendances dont notre projet Ă  besoin mais nous pouvons Ă©galement y ajouter nos propres fichiers.

Nous adoptons la structure de projet suivante:

-- src/
-- vendor/
-- composer.json
-- composer.lock
-- index.php

Astuce

Si nous ajoutons un fichier functions.php dans notre dossier src, il suffit de modifier le fichier composer.json comme ceci pour ajouter notre fichier de fonctions à l’autoloader:

{
   "require": {
      "mikecao/flight": "^1.3",
   },
   "autoload": {
      "files": [
            "src/functions.php",
            "src/utils.php"
      ]
   }
}

Via l’objet autoload et sa propriĂ©tĂ© files nous indiquons Ă  composer de charger les fichiers lister.

Ainsi functions.php et utils.php seront chargés automatiquement.

Attention

Il convient d’appeller la commande composer dump-autoload aprùs chaque modification du fichier composer.json.

Vous savez dĂ©sormais charger automatiquement vos fichiers via composer, ainsi seul le require de l’autoloader de composer sera requis. En clair vous n’aurez plus besoin de charger un Ă  un vos fichiers PHP !

Test unitaire & d’intĂ©gration avec PHP#

PlutĂŽt que de tout tester Ă  la main de maniĂšre rĂ©pĂ©titif et fastidieuse, nous allons apprendre Ă  automatiser les tests unitaires et d’intĂ©grations.

Pré-requis en PHP

Pour rĂ©aliser les tests unitaires et d’intĂ©grations nous aurons besoin des librairies php suivantes:

  • phpunit/phpunit

  • guzzlehttp/guzzle

  • symfony/process

Un petit composer require pour l’installation ?

Nous allons donc créer un répertoire tests à la racine de notre projet qui contiendra nos fichier de tests.

Premier test unitaire en PHP#

L’exemple le plus simple pour comprendre le principe des tests unitaires est la fonction de multiplication.

Note

Pour rappel une multiplication est l’opĂ©ration mathĂ©matique permettant d’obtenir le produit de deux facteur (nommĂ©s facteur gauche et facteur droite).

À faire

  1. Créer un fichier (vide) functions.php dans le répertoire src/

  2. Créer dans le répertoire tests/ un fichier UnitariesTest.php

  3. Pensez à modifier votre composer.json pour charger automatiquement le fichier de fonctions qui se trouve dans le répertoire src/

PHPUnit#

Note

PHPUnit est un framework open source de tests unitaires dédié au langage de programmation PHP.

Il permet l’implĂ©mentation des tests de non-rĂ©gression en vĂ©rifiant que les exĂ©cutions correspondent aux assertions prĂ©dĂ©finies.

Premier test#

Modifier le fichier UnitariesTest.php pour que son contenu soit:

 1<?php
 2
 3require_once 'vendor/autoload.php';
 4
 5use PHPUnit\Framework\TestCase;
 6
 7class UnitariesTest extends TestCase {
 8
 9    public function test_multiply(){
10        $this->assertEquals(4, multiply(2, 2));
11    }
12}

Quelques précisions

Nous venons de dĂ©finir une classe de tests qui possĂ©de un fonction permettant de tester notre fonction de multiplication (notez la prĂ©sence du require pour charger l’autoloader de composer).

La ligne 10 permet de vérifier que la fonction retourne bien le produit de 2 par 2 (à savoir 4).

Nous avons définit notre premier test, il serait donc temps de le lancer via la commmande suivante:

$ vendor/bin/phpunit tests/UnitariesTest.php

Normalement vous devriez avoir l’erreur suivante :

PHPUnit 7.5.2 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 15 ms, Memory: 4.00MB

There was 1 error:

1) MultiplyTest::test_multiply
Error: Call to undefined function multiply()

/home/sam/php/tests/UnitariesTest.php:8

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

C’est normal ! Nous respectons la philosophie TDD Ă  savoir Ă©crire nos tests d’abord puis vĂ©rifier que ceux-ci Ă©chouent !

À faire

Il convient de créer maintenant notre fonction de multiplication, copier-coller dans votre fichier functions.php le code (sans corriger erreur) suivant:

<?php

function multiply($facteur_gauche, $facteur_droite)
{
   return $facteur_gauche + $facteur_droite;
}

Relancez votre test via la commmande suivante:

$ vendor/bin/phpunit tests/UnitariesTest.php

Attention

Notre test passe ! Mais notre jeu de donnĂ©es n’est pas complet ! Il convient donc d’ajouter une assertion supplĂ©mentaire Ă  notre test.

À faire

  1. Ajoutez l’assertion que le produit de 3 par 7 est 21

  2. Relancez votre test que constatez vous ?

  3. Corrigez le code de votre fonction pour régler ce souci.

Bravo vous venez de faire votre premiĂšre suite de test unitaire.

Astuce

Le rĂ©pertoire tests ainsi que le fait de suffixer nos fichier par Test.php est une convention qui permet Ă  php unit de charger de maniĂšre automatique l’ensemble des tests du rĂ©pertoire.

Il suffit de lancer la commande suivante pour lancer l’ensemble des tests du rĂ©pertoire tests/ :

$ vendor/bin/phpunit tests/

Test d’intĂ©gration avec FlightPHP#

Tester nos fonctions c’est bien, utile et indispensable. Toutefois il est tout aussi indispensable de tester le retour de nos pages, nous allons donc voir comment mettre en place des tests d’intĂ©grations.

CrĂ©ation d’un client de test en PHP#

Pour pouvoir tester notre site en intégration il convient de créer un client de tests. Votre professeur étant fort sympatique en voici un à placer dans le fichier src/utils.php

<?php

use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\Process;
use GuzzleHttp\Client;

abstract class IntegrationTestCase extends TestCase {

    private static $process;

    public static function setUpBeforeClass(): void
    {
        self::$process = new Process(["php", "-S", "localhost:8080", "-t", "."]);
        self::$process->start();
        usleep(100000); //wait for server to get going
    }

    public static function tearDownAfterClass(): void
    {
        self::$process->stop();
    }

    public function get_client()
    {
        return new Client(['http_errors' => false]);
    }

    public function build_url($url)
    {
        return "localhost:8080" . $url;
    }

    public function make_request($method, $url)
    {
        $client =  $this->get_client();
        return $client->request($method, $this->build_url($url));
    }
}

Ce client lance en processus votre site web et permet de tester le retour de requĂȘte HTTP sur celui-ci.

Notre premier test d’intĂ©gration avec FlightPHP#

Créer un fichier IntegrationsTest.php dans le répertoire tests/ avec le contenu suivant:

<?php
require_once 'vendor/autoload.php';

class PagesIntegrationTest extends IntegrationTestCase{

    public function test_index()
    {
        $response = $this->make_request("GET", "/");
        $this->assertEquals(200, $response->getStatusCode());
        $this->assertEquals("Hello World!", $response->getBody()->getContents());
        $this->assertContains("text/html", $response->getHeader('Content-Type')[0]);
    }
}

Le test d’intĂ©gration test_index permet de:

  1. Tester si le retour de la requĂȘte sur / en mĂ©thode GET retourne le code de statut 200,

  2. Et que le contenu de la réponse est bien Hello World!.

  3. Et que le type de contenu est bien du text/html.

À faire

  1. Lancez la suite de tests,

  2. Que constatez vous ?

  3. Comment corriger le problĂšme ?

  4. Comment mettre en place un test d’intĂ©gration pour la route hello de votre site ? Pensez Ă  l’esprit TDD et comment tester cela.

  5. Et si notre route hello retourner une string sous la forme <h2>Hello $name </h2> ?

  6. Et si on utiliser l’assertion assertContains ?

Twig#

Maintenant que nous savons router nos fonctions PHP vers un pattern d’url (routing + Controller), il convient de s’intĂ©resser au V de MVC Ă  savoir les vues !

Des vues ?#

Note

Les vues (parfois nommés templates) permettent de séparer la présentation (le code HTML) de notre logique métier (le controller). Flight intégre un mécanisme de gestion des vues mais celui-ci est plutÎt limité. Nous allons donc utiliser le moteur de templates du secteur PHP à savoir Twig.

Twig, un moteur de template#

Important

Twig est un moteur de templates pour le langage de programmation PHP, utilisé par défaut par le framework Symfony. Celui-ci est une traduction de jinja, moteur de templates écrit en python.

Twig dispose des fonctionnalités suivantes:

  • ContrĂŽle de flux complexe

  • Échappement automatique

  • HĂ©ritage des templates

  • Filtres de variables

  • Internationalisation (via gettext)

  • Macros

  • Langage extensible

Syntaxe de Twig#

Afficher le contenu d’une variable#
{{ ma_variable }}
Afficher un Ă©lĂ©ment d’un tableau ou d’un objet#
{{ book.title }}
Itérer sur un tableau#
{% for book in books %}
    {{ book.title }}
{% endfor %}
Et si on mélange tout ça avec du HTML ?#
<ul>
{% for book in books %}
    <li>
        <strong>{{ book.title }}</strong>
    </li>
{% endfor %}
</ul>

Filtres dans un template Twig#

Important

Les filtres fournissent des traitements sur une expression, si on les place aprÚs elle séparés par des pipes.

capitalize

met une majuscule à la premiùre lettre d’une chaine de caractùres.

upper

met la chaine en lettres capitales.

first

affiche la premiùre ligne d’un tableau.

length

renvoie la taille de la variable.

Variables spéciales et Twig#

  • loop : contient les informations de la boucle dans laquelle elle se trouve. Par exemple loop.index donne le nombre d’itĂ©rations dĂ©jĂ  survenue.

  • _route : partie de URL situĂ©e aprĂšs le domaine

Obtenir la route d’une page#
{{ path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')) }}

Installation de twig#

Un composer require sur le package twig/twig ?

Twig et FlightPHP#

Initialisation

Pour commencer créer un répertoire views/ à la racine du projet.

Puis nous devons indiquer à Flight que nous allons utiliser Twig et le charger en extension mais tout d’abord nous devons charger Twig et le configurer.

index.php#
<?php

$loader = new \Twig\Loader\FilesystemLoader(dirname(__FILE__) . '/views');
$twigConfig = array(
   // 'cache' => './cache/twig/',
   // 'cache' => false,
   'debug' => true,
);

Une fois que nous avons charger et configurer Twig, il convient d’indiquer à Flight de l’inscrire en tant qu’extension

index.php#
<?php
Flight::register('view', '\Twig\Environment', array($loader, $twigConfig), function ($twig) {
   $twig->addExtension(new \Twig\Extension\DebugExtension()); // Add the debug extension
});

DĂ©sormais Flight sera en mesure d’utiliser Twig.

Notre premiĂšre vue#

Et maintenant nous allons utiliser Twig conjointement avec Flight pour gĂ©nĂ©rer notre page Ă  partir d’une vue.

<?php
Flight::route('/first_view/', function(){
    Flight::view()->display('first_view.twig');
});

À faire

  • Que se passe t’il en se rendant sur notre page first_view ?

  • CrĂ©er le fichier views/first_view.twig pour corriger l’erreur.

  • Un fichier vide c’est bien, et si nous ajoutions un peu de HTML ?

Afficher des choses plus utiles#

Afficher du HTML via Twig c’est bien, afficher le conteu de variables, tableaux, c’est encore mieux. Nous allons dĂ©couvrir comment passĂ© des donnĂ©es Ă  notre vue.

En reprenant notre vue:

<?php
Flight::route('/first_view/', function(){
    Flight::view()->display('first_view.twig');
});

Nous allons la modifier, pour lui passer quelques données:

<?php
Flight::route('/first_view/', function(){
    $data = [
        'contenu' => 'Hello World!',
        'name' => 'Ben Kenobi',
    ];
    Flight::view()->display('first_view.twig', $data);
});

Nous passons à notre fichier twig le tableau data qui contient deux éléments. Si nous rechargons notre page nous ne voyons pas nos données apparaßtre. Il faut donc modifier notre fichier .twig pour afficher les données:

Ajoutez le code suivant Ă  votre vue:

{{ contenu }}

{{ name }}

Twig et l’hĂ©ritage de template#

Important

La partie la plus puissante de Twig est l’hĂ©ritage des templates. L’hĂ©ritage de templates vous permet de crĂ©er un « squelette » de base contenant tous les Ă©lĂ©ments communs de votre site et dĂ©finissant les blocs que les modĂšles enfants peuvent remplacer.

Cela semble compliqué mais reste trÚs basique. Il est plus facile de comprendre cela en commençant par un exemple.

Template de base#

Ce template, que nous appellerons base.twig , dĂ©finit un simple squelette de document HTML que vous pouvez utiliser pour une page simple Ă  deux colonnes. C’est le travail des templates « enfants » de remplir les blocs vides de contenu:

<!DOCTYPE html>
<html lang="en">
<head>
    {% block head %}
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}{% endblock %} - My Webpage</title>
    {% endblock %}
</head>
<body>
    <main>{% block content %}{% endblock %}</main>
    <footer>
        {% block footer %}
        &copy; Copyright 2008 by <a href="http://domain.invalid/">you</a>.
        {% endblock %}
    </footer>
</body>
</html>

Dans cet exemple, les balises {% block %} définissent quatre blocs que les modÚles enfants peuvent remplir.

Note

La balise de bloc indique simplement au moteur de gabarit qu’un modĂšle enfant peut remplacer les espaces rĂ©servĂ©s qu’il contient.

Template enfant#

Un modĂšle enfant pourrait ressembler Ă  ceci:

{% extends "base.twig" %}
{% block title %}Index{% endblock %}
{% block head %}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
      Welcome to my awesome homepage.
    </p>
{% endblock %}

Note

La balise {% extend %} est la clĂ© ici. Il indique au moteur de modĂšle que ce modĂšle « étend » un autre modĂšle. Lorsque le systĂšme de gabarit Ă©value ce gabarit, il localise d’abord le parent. La balise extend devrait ĂȘtre la premiĂšre balise du modĂšle.

Variables global et filtre#

Parfois nous avons besoins de passer la mĂȘme valeur Ă  plusieurs voir toutes nos vues, Twig intĂ©gre un mĂ©canisme trĂšs intĂ©ressant appellĂ© global.

<?php
Flight::register('view', '\Twig\Environment', array($loader, $twigConfig), function ($twig) {
    $twig->addExtension(new \Twig\Extension\DebugExtension()); // Add the debug extension
    $twig->addGlobal('ma_valeur', "Hello There!");
});

Ainsi la variable ma_valeur sera passĂ© Ă  chaque vue, il est possible de rendre cela plus intĂ©ressant en passant des variables plus complexes, voir le rĂ©sultat d’appel de fonction.

Twig et les Filtres#

Twig intégre de nombreux filtres par défaut, il est possible de créer nos propres filtres au besoin:

<?php
Flight::register('view', 'Twig_Environment', array($loader, $twigConfig), function ($twig) {
    // Twig loading treatment
    $twig->addFilter(new \Twig\TwigFilter('trad', function($string){
        return $string;
    }));
});

Note

Il s’agit d’un filtre trĂšs intĂ©ressant qui retourne la valeur inchangĂ©e.. Le but est ici juste de vous prĂ©senter la syntaxe pour crĂ©er vos propres filtres.

Shortcut#

Faire appel à Twig pour rendre nos templates c’est chouette, toutefois faire appel à cette ligne de code :

<?php
Flight::view()->display('first_view.twig');

Reste assez complexe. Et si nous utilisions un raccourci pour faire appel Ă  cette fonction ?

Aprùs l’enregistrement de Twig ajouter le code suivant:

<?php

Flight::map('render', function($template, $data=array()){
   Flight::view()->display($template, $data);
});

Ce code permet de dire que lorsque que nous ferons appel à la méthode render de Flight, nous utiliserons Twig.

Sans shortcut

Avec shortcut

<?php
Flight::route('/first_view/', function(){
   Flight::view()->display('first_view.twig');
});
<?php
Flight::route('/first_view/', function(){
   Flight::render('first_view.twig');
});

À faire

En utilisant l’approche TDD, les Tests unitaires et d’intĂ©grations

  • CrĂ©er une fonctions permettant de rĂ©cupĂ©rer les livres lister Ă  l’adresse suivante https://ingen.ugaritic.fr/api/books/,

  • CrĂ©er une route ainsi qu’une vue (template Twig) pour afficher le nombre de livres ainsi que les diffĂ©rents livres.

Voir aussi

Il reste encore pas mal d’aspects de twig Ă  dĂ©couvrir comme Les structures de contrĂŽles , ou encore l’escaping

Formatter du Markdown en PHP#

Voir aussi

Pour en savoir un peu plus sur le 📄 Markdown.

Pour générer du HTML à partir de markdown on utilise en PHP la librairie michelf/php-markdown (composer require ?)

Dans votre fichier functions.php , ajouter la fonction suivante:

<?php
use MichelfMarkdown;

function renderHTMLFromMarkdown($string_markdown_formatted)
{
    return Markdown::defaultTransform($string_markdown_formatted);
}

Et si nous ajoutions une route (markdown_test) pour utiliser notre fonction ?

<?php
Flight::route('/markdown_test', function(){
    echo renderHTMLFromMarkdown("##HELLO WORLD!");
});

Allons un peu plus loin#

Il est plus intĂ©ressant de stocker le contenu de nos pages statiques (prĂ©sentation de l’entreprise, mentions lĂ©gales, Ă  propos, ..) dans diffĂ©rents fichiers puis de lire leurs contenu Ă  la demande.

  • CrĂ©er dans Ă  la racine de votre projets un rĂ©pertoire pages

  • CrĂ©er dans le rĂ©pertoire pages/ un fichier test.md avec le contenu suivant:

## Test

Indication

Pour rĂ©cupĂ©rer le contenu d’un fichier, PHP nous fournit la fonction file_get_contents.

Ainsi nous pouvons créer dans notre fichier tests/UnitariesTest.php la fonction de test suivante:

<?php
public function test_readFileContent(){
    $this->assertEquals("## Test", readFileContent("pages/test.md"));
}
  • On relance notre suite de tests, test_readFileContent Ă©choue .. parfait !

  • Ajoutons la fonction readFileContent

<?php
function readFileContent($filepath){
    return file_get_contents($filepath);
}
  • Remplacer dans notre controller pour /markdown_test , la string ##HELLO WORLD par le contenu du fichier pages/test.md

À faire

  1. Créer un template Twig pour afficher le contenu de votre page dans un template HTML,

  2. Le code HTML produit s’affiche correctement ? L’utilisation du filtre raw pourra vous ĂȘtre utile,

  3. CrĂ©er une fonction readPagesContent qui prend en paramĂštre uniquement le nom de votre fichier .md (sans l’extension .md ) et qui vous retourne le contenu de la pages (TDD?),

  4. Convertir le markdown en HTML n’est pas un job pour notre controller, il s’agit d’un boulot pour notre vue ! CrĂ©er un filtre Twig pour convertir du Markdown en HTML

Indication

La fonction sprintf permet de faire du formatage de chaßne de caractéres.

<?php
$name = "Ben";
$hello_string = sprintf("hello %s", $name); // Hello Ben

Jurassic Park en PHP#

Un site commandé par InGen#

IngenLogo

Note

La société InGen, spécialisée dans la création de créatures préhistoriques génétiquement modifiées; souhaite créer un site pour son dernier projet.

La majeure partie de son activitĂ© consiste Ă  faire naĂźtre des dinosaures et Ă  les prĂ©senter au sein de Jurassic Park. John Hammond, le PDG de l’entreprise InGen, travaille Ă  la crĂ©ation d’un parc d’attractions sur Isla Nublar, une Ăźle qu’il possĂšde au large du Costa Rica. Le parc comporte des animaux disparus tels que les dinosaures, comme attractions. Les crĂ©atures ont Ă©tĂ© clonĂ©s dans des installations spĂ©ciales Ă  proximitĂ© sur Isla Sorna et amenĂ©s au parc.

ÉnoncĂ© du projet Jurassic Park en PHP#

Note

Le but de cet exercice est de contrĂŽler votre acquisition de connaissances par un simple exercice. Il convient de mettre en application les notions vues.

En appliquant les notions vues sur PHP, composer, les frameworks, etc. vous rĂ©aliserez un site web basique prĂ©sentant les diffĂ©rents dinosaures du parc. Les donnĂ©es vous sont pour cela fournit via l’API REST suivante API Dinosaurs.

  • CrĂ©ation de deux pages diffĂ©rentes (accueil et dĂ©tails sur un dinosaure),

  • Mise en oeuvre du TDD (Test Driven Development),

  • Versionning sous Git (pensez Ă  versionner votre projet au fur et Ă  mesure de votre avancĂ©),

  • Les donnĂ©es sont disponibles via l’API Dinosaurs ,

  • Les fichiers css, d’images, etc. sont disponibles ici ,

  • Les templates HTML vous sont fournis dans la suite de cet Ă©noncĂ©,

  • Quelques conseils Ă©galement.

Résultat du projet PHP

  1. Page d’accueil listant l’ensemble des dinosaures

    • L’url de cette page devra ĂȘtre la racine de votre site ( / ),

    • Les donnĂ©es seront rĂ©cupĂ©rer depuis l’API Dinosaurs.

  2. Page de détails sur un dinosaure

    • L’url de cette page devra ĂȘtre sous la forme /dinosaur/<slug du dinosaure>/ (oĂč le slug correspond au slug retournĂ© par l’API Dinosaurs);

    • Les donnĂ©es d’un seul dinosaure peuvent ĂȘtre rĂ©cupĂ©rĂ©es via l’API Dinosaurs, par exemple https://ingen.ugaritic.fr/api/dinosaurs/brachiosaurus permet de rĂ©cupĂ©rer les informations du brachiosaure;

    • Les « Top Rated Dinosaurs » sont une rĂ©cupĂ©ration alĂ©atoire de trois dinosaures parmis les septs retournĂ©es par l’API Dinosaurs , l’utilisation de la fonction PHP array_rand vous est vivement conseillĂ©.

Indication

  • CrĂ©er d’abord votre projet sous Gitlab et pensez directement Ă  le cloner;

  • RĂ©cupĂ©rer les fichiers d’assets et placer les dans un rĂ©pertoire assets Ă  la racine de votre projet;

  • Penser Ă  faire un composer require de toutes les libs;

  • L’approche TDD vous aidera grandement, quelles sont les fonctions que je vais devoir dĂ©velopper et les T.U associĂ©s, les pages et les T.I associĂ©es;

  • Avancer par Ă©tape, d’abord la rĂ©cupĂ©ration de tous les dinosaures (test ?) puis la page d’accueil, puis la page de dĂ©tail et enfin les  » Top Rated Dinosaurs « ;

  • Respirer c’est important;

  • Aller c’est cadeau un petit exemple de la fonction array_rand (par contre la grande question demeure .. comment recrĂ©er un tableau Ă  partir des clĂ©s d’un autre tableau ?):

<?php
$colors = array("red","green","blue","yellow","brown");
$random_keys = array_rand($colors, 3); // On récupére trois clés aléatoires
echo $colors[$random_keys[0]];
echo $colors[$random_keys[1]];
echo $colors[$random_keys[2]];

Quelques templates ?

base.twig#
<!DOCTYPE html>
<html>
   <head>
      <title>{%block title %}{% endblock %}Jurassic Park</title>
      <meta charset="utf8" />
      <link rel="stylesheet" type="text/css" href="/assets/css/reset.css" />
      <link rel="stylesheet" type="text/css" href="/assets/css/style.css" />
      <link href="https://fonts.googleapis.com/css?family=Montserrat|Staatliches" rel="stylesheet">
   </head>
   <body>
      <header>
            <a href="/">
               Jurassic Park
            </a>
            <nav>
               <a href="/">Home</a>
            </nav>
      </header>
      <main>
            {% block main %}{% endblock %}
      </main>
      <footer>
            <img src="/assets/img/logojp.png" alt="Jurassic Park" />
      </footer>
   </body>
</html>
list.html#
<!-- Héritage de template ? Block(s) ? -->
<section>
   <h2>The world of Jurassic Park</h2>

   <!-- iterate here ? -->
      <a href="">
            <figure>
               <img src="" alt="" />
               <figcaption>Discover the Brachiosaurus</figcaption>
            </figure>
      </a>
</section>
detail.html#
<!-- Héritage de template ? Block(s) ? -->
<div class="grid">
   <article>
      <h2>Discover the Brachiosaurus</h2>

      <div class="description">
            Lorem ispum
      </div>

      <div class="card">
            <img src="" alt="" />
            <dl>
               <dt>Name</dt>
               <dd>Brachiosaurus</dd>
               <dt>Name meaning</dt>
               <dd>Brachiosaurus</dd>
               <dt>Diet</dt>
               <dd>Brachiosaurus</dd>
               <dt>Height</dt>
               <dd>Brachiosaurus m.</dd>
               <dt>Length</dt>
               <dd>Brachiosaurus m.</dd>
               <dt>Weight</dt>
               <dd>Brachiosaurus kg.</dd>
            </dl>
      </div>
   </article>

   <aside>
      <h3>Top rated dinosaurs</h3>
      <!-- iterate here ? -->
            <a href="">
               <figure>
                  <img src="" alt="" />
                  <figcaption>Discover the Brachiosaurus</figcaption>
               </figure>
            </a>
   </aside>
</div>

ORM et FlightPHP#

Note

Un ORM est une technique de programmation informatique qui crĂ©e l’illusion d’une base de donnĂ©es orientĂ©e objet Ă  partir d’une base de donnĂ©es relationnelle en dĂ©finissant des correspondances entre cette base de donnĂ©es et les objets du langage utilisĂ©. On pourrait le dĂ©signer par « correspondance entre monde objet et monde relationnel ».

Découverte de Paris#

Paris est un ORM PHP open source disponible à cette adresse , il se base sur idiorm. Il s’agit d’une introduction à l’installation et l’utilisation de Paris. Je ne peux que vous encourager à aller consulter la documentation de celui-ci.

Comme toujours un simple composer require j4mie/paris

La base de données de tweets#

AprÚs avoir installé le package j4mie/paris il suffit de configurer une connexion à notre base de données. Pour la suite nous allons utiliser la base de données SQLite tweets.sqlite3.

https://www.plantuml.com/plantuml/svg/ZP6nQiD038PtFOMuiP122rayPIgTEhLqBFATR8kSTK4d4qB8k_VIK8Y7GZK8f5_I9w5TTJ9VvWmrKcPyVjn2tOiUo6Z6dk9-jB9eYYKNGpVIsYHMlwjAFD2I_QMelz7C-Dgw8FFWw0LDnianYN5qAGe0CLEj-57Py0pOx3m8vtH1IHsAEezigxoseHrMDz5n9GnYrVzKbqPOYPTVzlkHsVy9FonzbaZNtRyIUPjszQkIlgJJFGH-RWjF0JSR30_XnkimuAU9Eolsfm0mIMASsQUIwYs8OZ4pm8urjPTy0m==

Diagramme UML de la base de données tweets#

Configuration de Paris#

Astuce

Nous allons utiliser une capacitĂ© spĂ©ciale de Flight, le filtering pour ajouter un traitement avant que le framework ne traite notre requĂȘte.

Nous allons donc ajouter la connexion automatique Ă  notre basse de donnĂ©es avant que celui-ci ne soit dĂ©marrĂ© (ce code doit ĂȘtre placĂ© juste aprĂšs l’enregistrement de l’extension Twig ):

<?php

Flight::before('start', function(&$params, &$output){
   ORM::configure('sqlite:tweets.sqlite3');
});

Notre premier Model avec Paris#

Dans le dossier src crĂ©er le fichier models.php , pensez Ă  l’ajouter au composer.json

<?php
class User extends Model {
    public static $_table = 'Users';
}

VoilĂ  ! Notre model est créé, Ă  nous de l’utiliser !

Note

Il est inutile de prĂ©ciser la nature de notre table, l’ORM se chargera pour nous de dĂ©duire la structure de nos objets Ă  partir de la base de donnĂ©es. Le mapping de nos champs se fait automatiquement Ă  partir de la structure de notre table.

Ainsi il sera possible d’accĂ©der au champ name d’un utilisateur via l’attribut name qui sera automatiquement gĂ©nĂ©rĂ© lors de l’éxĂ©cution par l’ORM.

Par convention, les champs de nos tables ne doivent contenir ni préfixe, ni suffixe, les alias ont cette utilité ! De plus la clé primaire (unique) de notre table sera toujours nomée par convention id.

RequĂȘte via paris#

Pour plus d’informations sur la maniĂšre d’écrire des requĂȘtes, je vous invite Ă  vous rendre Ă  cette page de la documentation.

Dans le fichier index.php nous allons crĂ©er une route pour afficher l’ensemble des utilisateurs au sein d’un fichier de vue users.twig.

RĂ©cupĂ©rer l’ensemble des utilisateurs prĂ©sent en base#
<?php
User::find_many();

Cette ligne permet de rĂ©cupĂ©rer tout les utilisateurs prĂ©sent en bases. A vous maintenant d’itĂ©rer sur le tableau retourner afin d’obtenir une liste des utilisateurs au sein de votre vue.

À faire

  1. Créer la classes dans le fichier models.php pour les tweets,

  2. Créer une route pour lister tous les tweets présent en base,

  3. Récupérer les tweets de chaque utilisateur, cf la documentation sur les associations.

  4. CrĂ©er une vue pour afficher uniquement les informations d’un seul utilisateur en prenant en paramĂštre @username le nom d’utilisateur cf la partie sur le requĂȘtage de la documentation.

  5. CrĂ©er une vue pour afficher un formulaire permettant d’ajouter un tweet en base.

Indication

Nous venons de voir que manipuler une base de données est extrÚmement simple avec les bons outils, je vous invite donc à lire la documentation de Paris notamment sur la partie Querying.

API REST & JSON#

Note

Une API (Application Programming Interface) est une interface pour les applications; elle permet la manipulations de donnĂ©es, mĂ©thodes, fonctions etc. C’est un mĂ©canisme Ă  la base de tout gĂ©nie logiciel complexe.

Nous allons voir dans cette partie comment dĂ©velopper une API en PHP qui retournera un rĂ©sultat sous la forme d’une rĂ©ponse au format JSON (JavaScript Object Notation).

Note

REST ( Representational State Transfer ) est un standard créé en 2000 par Roy Fielding dans sa thÚse « Architectural Styles and the Design of Network-based Software Architectures ».

Les API sur Internet

Les API sont un moyen d’accĂ©der aux donnĂ©es d’un site sans avoir l’autorisation d’accĂ©der directement Ă  la base de donnĂ©es. Il y a beaucoup de portails sĂ©curisĂ©s permettant Ă  vos applications web de manipuler les donnĂ©es renvoyĂ©es par ces sites.

L’exemple parfait est Twitter. Elle permet de lire la timeline d’une personne en particulier, de rechercher des statuts Ă  partir d’un mot clĂ©, de modifier les paramĂštres de votre compte, etc.

Ou encore l’API proposer par sur ce site à savoir ingen.ugaritic.fr

Important

Les API REST sont basĂ©es sur le Protocole HTTP ( Hypertext Transfer Protocol ) le protocole au coeur du web ! Bien sĂ»r, toutes les API ne sont pas basĂ©es sur HTTP, mais en choisissant une API REST, vous simplifiez l’intĂ©gration et l’utilisation de votre API en utilisant un protocole ouvert, standardisĂ© et simple d’utilisation.

Les API REST imitent la façon dont le web lui-mĂȘme marche dans les Ă©changes entre un client et un serveur. Une API REST est donc:

  • Sans Ă©tat (aucune idĂ©e de l’état du client entre deux requĂȘtes, donc aucune liaison entre elles),

  • Cacheable (avec cache = mĂ©moire),

  • OrientĂ© client-serveur.

Pourquoi le format JSON ?

Vous pouvez utiliser les API avec de nombreux langages et retourner les donnĂ©es de plusieurs façons. L’une d’elles est le JSON (JavaScript Object Notation). C’est un format de donnĂ©es lĂ©ger, facile Ă  lire et Ă  Ă©crire et compatible avec pas mal de langages de dĂ©veloppement.

Sa structure est composĂ©e d’objets et de tableaux. Sa flexibilitĂ© fait de JSON le parfait candidat pour retourner des donnĂ©es.

Une API avec PHP & Flight#

Pour créer une api rien de bien complexe, il suffit de:

  1. Définir une route (par exemple /api/helloworld),

  2. Retourner des données au format JSON depuis cette route.

Nous souhaitons créer une API associé à la route /api/helloworld qui nous retourne un résultat équivalent à:

{"data":"Hello World!"}

Nous allons créer une nouvelle classe de test (donc un nouveau fichier php dans le répertoire tests ) ApiTest qui servira à tester notre api !

<?php
require_once 'vendor/autoload.php';

class ApiTest extends IntegrationTest{

    public function test_api_helloworld()
    {
        $response = $this->make_request("GET", "/api/helloworld");
        $this->assertEquals(200, $response->getStatusCode());
        $this->assertContains("application/json", $response->getHeader('Content-Type')[0]);


        $body = $response->getBody()->getContents();

        $json_result = json_encode(['data' => 'Hello World!']);

        $this->assertEquals($json_result, $body);
    }
}

Quelques précisions

Le test test_api_helloworld effectue une requĂȘte sur /api/helloworld et vĂ©rifie les assertions suivantes:

  • Le code statut de la requĂȘte est Ă©gale Ă  200,

  • Le type de rĂ©ponse est bien application/json et non text/html ,

  • Le contenu de la rĂ©ponse est Ă©gale Ă  la conversion en JSON d’un tableau associatif contenant une clĂ© data avec la valeur Hello World.

<?php
Flight::route('/api/helloworld', function(){
    $data = [
        'data' => 'Hello World!',
    ];
    Flight::json($data);
});

Flight nous permet de retourner directement des données au format JSON via la méthode Flight::json.

À faire

  1. Créer une route (et les tests associés) /api/helloworld/@name qui retourne Hello $name ,

  2. CrĂ©er une route (et les tests associĂ©s) /api/users qui retourne l’ensemble des utilisateurs de la base de donnĂ©es tweets.

  3. CrĂ©er une route /api/user/@username qui retourne un utilisateur selon son nom d’utilisateur et l’ensemble de ses tweets.

Javascript#

JS

Note

JavaScript (qui est souvent abrégé en « JS ») est un langage de script léger, orienté objet, principalement connu comme le langage de script des pages web.

Mais il est aussi utilisé dans de nombreux environnements extérieurs aux navigateurs web tels que Node.js, Apache CouchDB voire Adobe Acrobat.

Le code JavaScript est interprĂ©tĂ© ou compilĂ© Ă  la volĂ©e (JIT). C’est un langage Ă  objets utilisant le concept de prototype, disposant d’un typage faible et dynamique qui permet de programmer suivant plusieurs paradigmes de programmation : fonctionnelle, impĂ©rative et orientĂ©e objet.

Une définition générale#

JavaScript est un langage de programmation qui permet d’implĂ©menter des mĂ©canismes complexes sur une page web. À chaque fois qu’une page web fait plus que simplement afficher du contenu statique — afficher du contenu mis Ă  jour Ă  des temps dĂ©terminĂ©s, des cartes interactives, des animations 2D/3D, des menus vidĂ©o dĂ©filants, etc.

JavaScript a de bonnes chances d’ĂȘtre impliquĂ©. C’est la troisiĂšme couche des technologies standards du web, les deux premiĂšres Ă©tant HTML et CSS. Les trois couches viennent s’empiler naturellement.

Premier exemple de javascript#

Attention

Je vous conseille de mettre cette exemple dans une route Ă  part de votre site par exemple /js/exemple1

Nous pouvons la baliser en HTML pour définir sa structure et son but:

<p>Player 1: Ben</p>

Nous pouvons ensuite ajouter du CSS pour rendre ça plus joli:

p {
    font-family: 'helvetica neue', helvetica, sans-serif;
    letter-spacing: 1px;
    text-transform: uppercase;
    text-align: center;
    border: 2px solid rgba(0,0,200,0.6);
    background: rgba(0,0,200,0.3);
    color: rgba(0,0,200,0.6);
    box-shadow: 1px 1px 2px rgba(0,0,200,0.4);
    border-radius: 10px;
    padding: 3px 10px;
    display: inline-block;
    cursor:pointer;
}

Et enfin utiliser JavaScript pour ajouter un comportement dynamique :

let para = document.querySelector('p');

para.addEventListener('click', updateName);

function updateName() {
  let name = prompt('Enter a new name');
  para.textContent = 'Player 1: ' + name;
}

Pensez Ă  placer le code javascript en fin de fichier HTML dans les balises:

<script type="text/javascript">

</script>

JavaScript peut faire bien plus. Voyons cela plus en détail.

Que peut-il vraiment faire ?#

Le cƓur de JavaScript est constituĂ© de fonctionnalitĂ©s communes de programmation permettant de :

  • stocker des valeurs utiles dans des variables.
    • Dans l’exemple plus haut, nous demandons un nouveau nom Ă  l’utilisateur puis le stockons dans une variable appellĂ©e name.

  • faire des opĂ©rations sur des strings.
    • Dans l’exemple plus haut, nous prenons la chaĂźne de caractĂšres « Player 1:  » et lui adjoinions la variable name pour crĂ©er l’étiquette texte complĂšte “”Player 1: Chris ».

  • exĂ©cuter du code en rĂ©ponse Ă  certains Ă©vĂšnements se produisant sur une page web.
    • Nous avons utilisĂ© un Ă©vĂšnement (« event ») click dans l’exemple plus haut pour dĂ©tecter quand l’utilisateur clique sur le bouton et alors exĂ©cuter le code qui met Ă  jour l’étiquette texte.

  • Et bien plus encore!

Ajax#

AJAX est un raccourci pour Asynchronous JavaScript + XML (JavaScript asynchrone plus XML) inventĂ© par Jesse James Garrett. Pour simplifier, il s’agit d’employer l’objet non standard XMLHttpRequest pour communiquer avec des scripts situĂ©s sur le serveur.

L’objet permet d’échanger des informations sous diffĂ©rents formats (dont XML, HTML ou texte), mais son principal attrait est sa nature « asynchrone » qui implique qu’il peut communiquer avec le serveur, Ă©changer des donnĂ©es et mettre Ă  jour sans avoir Ă  sans recharger la page.

Les deux fonctionnalités combinées vous permettent de :

  • faire des requĂȘtes vers le serveur sans avoir Ă  recharger la page ;

  • analyser et travailler avec des documents XML.

XMLHttpRequest#

Pour faire une requĂȘte HTTP vers le serveur Ă  l’aide de JavaScript, il faut disposer d’une instance d’une classe fournissant cette fonctionnalitĂ©. C’est ici que la classe XMLHttpRequest intervient. Une telle classe a d’abord Ă©tĂ© introduite dans Internet Explorer sous la forme d’un objet ActiveX appelĂ© XMLHTTP.

Par la suite, Mozilla, Safari et d’autres navigateurs ont suivi en implĂ©mentant une classe XMLHttpRequest qui fournit les mĂȘmes mĂ©thodes et propriĂ©tĂ©s que l’objet ActiveX original de Microsoft. Dans l’intervalle, Microsoft a Ă©galement implĂ©mentĂ© XMLHttpRequest.

Par conséquent, pour créer une instance (un objet) de la classe désirée fonctionnant sur plusieurs navigateurs, vous pouvez utiliser :

httpRequest = new XMLHttpRequest();

Un exemple simple#

Notre JavaScript demande un document HTML situĂ© Ă  l’URL /js/test/, qui contient le texte "Je suis un test.", et nous affichons le contenu de cette ressource dans un message alert().

Note

Remarquez que cet exemple n’utilise que JavaScript (jQuery n’est pas utilisĂ© ici).

<script type="text/javascript" language="javascript">

    function makeRequest(url) {

        var httpRequest = false;

        httpRequest = new XMLHttpRequest();

        if (!httpRequest) {
            alert('Abandon :( Impossible de créer une instance XMLHTTP');
            return false;
        }
        httpRequest.onreadystatechange = function() { alertContents(httpRequest); };
        httpRequest.open('GET', url, true);
        httpRequest.send(null);

    }

    function alertContents(httpRequest) {

        if (httpRequest.readyState == XMLHttpRequest.DONE) {
            if (httpRequest.status == 200) {
                alert(httpRequest.responseText);
            } else {
                alert('Un problĂšme est survenu avec la requĂȘte.');
            }
        }

    }
</script>
<span
    style="cursor: pointer; text-decoration: underline"
    onclick="makeRequest('/js/test')">
        Effectuer une requĂȘte
</span>

Dans cet exemple :

  • L’utilisateur clique sur le lien « Effectuer une requĂȘte » dans le navigateur ;

  • Ceci appelle la fonction makeRequest() avec un paramĂštre: l’url /js/test/;

  • la requĂȘte est faite et ensuite ( onreadystatechange ) l’exĂ©cution est passĂ©e Ă  alertContents() ;

  • alertContents() vĂ©rifie si la rĂ©ponse a Ă©tĂ© reçue et est correcte, et affiche ensuite la contenu de la ressource dans un message alert().

Un deuxiĂšme exemple#

Pour finir, envoyons quelques données au serveur et réceptionons la réponse.

Notre JavaScript demandera cette fois çi une réponse dynamique, /api/hello/ qui prendra notre contenu envoyé et revera une chaßne « calculée »

"Bonjour, [user data] !"

que nous transmettrons Ă  la fonction alert().

Nous allons dĂ©jĂ  ajouter un boĂźte de texte dans notre HTML afin que l’utilisateur puisse saisir son nom :

<label>Vore nom :
  <input type="text" id="ajaxTextbox" />
</label>
<span id="ajaxButton" style="cursor: pointer; text-decoration: underline">
  Lancer une requĂȘte
</span>

Nous allons Ă©galement ajouter une ligne Ă  notre gestionnaire d’évĂ©nement pour obtenir les donnĂ©es de l’utilisateur de la boite de texte et l’envoyer Ă  la fonction makePostRequest() ainsi que l’URL de notre script cĂŽtĂ© serveur :

document.getElementById("ajaxButton").onclick = function() {
    var userName = document.getElementById("ajaxTextbox").value;
    makePostRequest('/api/hello',userName);
};

Nous devons crĂ©er makePostRequest() afin qu’il accepte les donnĂ©es de l’utilisateur et les transmette jusqu’au serveur.

function makeRequest(url, userName) {

    var httpRequest = false;
    httpRequest = new XMLHttpRequest();

    if (!httpRequest) {
        alert('Abandon :( Impossible de créer une instance XMLHTTP');
        return false;
    }
    httpRequest.onreadystatechange = function() { alertNameContents(httpRequest); };
    httpRequest.open('POST', url);
    httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    httpRequest.send('userName=' + encodeURIComponent(userName));
}

La fonction alertNameContent() peut ĂȘtre Ă©crite de la mĂȘme maniĂšre qu’au dessus pour afficher notre chaĂźne calculĂ©e, si c’est tout ce que le serveur renvoie.

Cependant, le serveur renvoie et la phrase calculée et la donnée originale. Donc si notre utilisateur saisi « Ben », la réponse du serveur ressemblera à :

{"userData":"Ben","computedString":"Bonjour, Ben !"}

Pour utiliser cette phrase dans alertNameContent() , nous pouvons simplement afficher une alerte avec le contenu de responseText, nous devons la récupérer et afficher computedString, la propriété que nous souhaitons :

function alertNameContents() {
    if (httpRequest.readyState === XMLHttpRequest.DONE) {
        if (httpRequest.status === 200) {
            var response = JSON.parse(httpRequest.responseText);
            alert(response.computedString);
        } else {
            alert('Un problĂšme est survenu avec la requĂȘte.');
        }
    }
}

À faire

  1. CrĂ©er une nouvelle route qui contiendra le code javascript qui chargera les dinosaures depuis l’api dĂ©veloppĂ© au sein de notre projet,

  2. Et qui les ajoutera au sein de la page HTML, je vous conseille la lecture de cet article de MDN.