Créer son application Web en PHP (et Composer) : Partie 2

Notre projet dispose maintenant des fonctionnalités premières d'un site. Maintenant, le problème est de savoir comment simplifier et automatiser au maximum l'exécution de notre code lors d'une requête utilisateur.

Publié le lun. 25 mar (20:31). Actualisé le ven. 30 aoû (21:01)

Signaler cette publication  
Miniature de la publication : Créer son application Web en PHP (et Composer) : Partie 2

Nous voilà arrivés à la deuxième partie de ce tutoriel sur la réalisation d'une application Web en PHP. Lors de la partie précédente, nous avons vu comment configurer la base de notre projet et y apporter les fonctionnalités premières, telles que le routage et la gestion des requêtes des utilisateurs.

Maintenant, passons à une partie plus complexe, mais qui nous simplifiera la suite pour coder notre application : la gestion des dépendances !

Lors de la première partie, nous avons vu comment utiliser des librairies au sein de notre projet, qui étaient déjà toutes intégrées grâce à PSR-4 (l'autoload).

Toutefois dans cette partie, nous allons voir comment tirer profit de ces dépendances pour optimiser au maximum l'expérience orientée objet de notre application. Souvenez-vous, lorsqu'un chemin correspondait à une entrée dans le fichier Routes.php, notre fichier Bootstrap.php traitait l'action comme ceci :

<?php
// ./src/Bootstrap.php
// ...
switch ($routeInfo[0])
{
	case \FastRoute\Dispatcher::FOUND:
		$className = $routeInfo[1][0];
		$method = $routeInfo[1][1];
		$vars = $routeInfo[2];
		
		$class = new $className;
		$response->setBody($class->$method($vars));
		break;
}

Focalisons-nous sur la ligne $response->setBody($class->$method($vars));. Ici, notre application va appeler la méthode de la classe correspondante, en lui passant des paramètres, le cas échéant. Toutefois, cette méthode dispose d'un risque majeur : tous les objets instanciés de cette manière auront les mêmes objets injectés, ce qui n'est pas souhaitable.

C'est là que va intervenir Auryn, un injecteur de dépendances ! Cela va se révéler très utile, car grâce à Auryn, vous pourrez définir des alias de vos classes, et même de partager des instances de vos classes. Ce dernier est un des atout les plus remarquables d'un injecteur de dépendances, et vous allez le voir en pratique.

Commençons d'abord par intégrer Auryn au sein de notre projet :

composer require rdlowrey/auryn

Une fois Auryn installé, retournez dans votre éditeur, vérifier que le fichier composer.json a bien été modifié en conséquence et préparez-vous pour la suite.

Ici, nous allons partager les instances des classes Request et Response, afin que notre Controller puisse définir le contenu de la page à afficher lui-même. Pas de panique, cela peut sembler abstrait, mais d'ici la fin de cette partie, cela sera certainement plus clair pour vous.

Tout d'abord, commencez par créer un nouveau fichier nommé Dependencies.php au sein de votre dossier src, avec le contenu suivant :

<?php
// src/Dependencies.php

$injector = new \Auryn\Injector;

$injector->alias('Sabre\HTTP\Request', 'Sabre\HTTP\Sapi');
$injector->share('Sabre\HTTP\Sapi');
$injector->define('Sabre\HTTP\Sapi', [
	':get' => $_GET,
	':post' => $_POST,
	':cookies' => $_COOKIE,
	':files' => $_FILES,
	':server' => $_SERVER
]);

$injector->share('Sabre\HTTP\Response'); return $injector;

Vous aurez donc remarqué la ligne $injector->share('Sabre\HTTP\Sapi');, laquelle est, vous l'avez compris, très importante dans le cadre de cette partie. Brièvement, la méthode alias() permet de définir un équivalent (un alias, pour éviter une redite) à la classe de départ. Elle se révèle pratique dans notre exemple, étant donné que le nom Sabre\Http\Request est plus évocateur que Http\Sabre\Sapi. Enfin, selon la documentation d'Auryn sur Github, la méthode define() sert à déterminer les arguments du constructeur à définir de la classe (ou alias) passé en premier argument de la méthode.

Maintenant, occupons nous de notre Bootstrap.php, afin de rendre opérationnelle notre injection de dépendances :

<?php
// src/Bootstrap.php

namespace Project;
require __DIR__ . './../vendor/autoload.php';

$injector = include('Dependencies.php');
$request = $injector->make('Sabre\HTTP\Request')->getRequest();
$response = $injector->make('Sabre\HTTP\Response');

Ici, afin de pallier le fait que nous ne pouvons injecter que des classes (logique…), j'ai appelé la méthode getRequest() de la classe Sapi (caché par l'alias Request). De cette manière, notre variable $request agira comme une véritable classe Request, et comprendra toute la partie “Requêtes”. Il nous reste encore une dernière partie avant que notre fichier Bootstrap.php puisse injecter correctement les bonnes dépendances de manière autonome, il faut modifier la partie routage !

Vous avez certainement dû remarquer la méthode make() ; nous allons la réutiliser pour injecter les dépendances Request et Response dans nos propres classes !

<?php
// src/Bootstrap.php

$routeInfo = $dispatcher->dispatch($request->getMethod(), $request->getPath());
switch ($routeInfo[0])
{
	case \FastRoute\Dispatcher::FOUND:
	$className = $routeInfo[1][0];
	$method = $routeInfo[1][1];
	$vars = $routeInfo[2];
	
	$class = $injector->make($className);
	$class->$method($vars); break;
}

Bien, maintenant, allons dans le concret, et créons notre premier contrôleur ! Pour ce projet, nous ferons une application très simple, je ne rentrerai pas dans les détails d'un gros projet. Nous ne nous bornerons qu'au développement des bases d'une application de e-commerce, intégrant la liste des articles et la page de vue détaillée d'un article, pour que vous compreniez le fonctionnement d'une véritable application PHP.

Commençons déjà par définir le chemin de cette page au sein du fichier Routes.php :

<?php
// src/Routes.php
return [ ['GET', 'index', ['Project\Controllers\Index', 'show']] ];

Ensuite, au sein de votre dossier Controllers/, créez le fichier Index.php, lequel contiendra la liste des articles disponibles, et remplissez le contenu de votre classe Index.

<?php
// src/Controllers/Index.php

namespace Project\Controllers;

use Sabre\HTTP\Request;
use Sabre\HTTP\Response;
class Index
{
	private $_response;
	private $_request;
	
	public function __construct(
		Request $request,
		Response $response
	) {
		$this->_request = $request;
		$this->_response = $response;
	}
	
	public function show()
	{
		// ... Récupérer les articles déjà présents via une requête en DB, ou sur un fichier, peu importe au final.
		// Remarque : si vous utilisez une autre classe pour aller chercher vos données :
		// Pensez à toujours spécifier un namespace, pour que vous alliez chercher la bonne classe lors de l'intégration.
	
		$items = $db->fetchData('items_for_sale');
		$this->_response->setBody($items);
	}
}

Concernant le namespace de vos classes annexes, il doit être intégré de la manière suivante dans votre fichier Index.php :

<?php
use Project\Domain\MyClass;

Pensez à remplacer les noms par ceux de votre projet. En tout état de cause, vous devez utiliser la commande use en la faisant suivre du namespace de votre classe, plus le nom de celle-ci. Ensuite, instanciez votre classe normalement au sein de votre méthode.

Maintenant, dirigez vous sur la page définie (en l'occurrence /index). Rien ne s'affichera. Il faut donc que vous fassiez un var_dump de votre objet Response : ajoutez à la fin de votre fichier Bootstrap.php la ligne suivante :

<?php
// src/Bootstrap.php
// Haut du fichier

var_dump($response->getBody());

Rechargez la page de votre navigateur, et celui-ci devrait afficher le résultat attendu (un tableau ou une chaîne JSON, selon vos besoins). Si toutefois cela ne fonctionne pas pensez à vérifier vos chemins au niveau de votre Routeur. Dans votre fichier Bootstrap.php, avant que vous n'appeliez la méthode du contrôleur, insérez la ligne suivante : 

<?php
// src/Bootstrap.php
// ...

die(var_dump($request->getPath()));

Veillez ensuite à remplacer le chemin affiché par votre navigateur à l'endroit adéquat dans votre fichier Routes.php.

C'en est fini de cette deuxième partie sur la création d'une application Web en PHP sans framework ! En cas de questions ou de suggestions, n'hésitez pas à envoyer un message via le formulaire de Contact présent sur ce lien ! En attendant, portez-vous bien, et on se retrouve d'ici une semaine pour la troisième partie de ce tuto. Je ne veux rien vous spoiler, mais on va attaquer la partie graphique avec les Templates ;)

Ces publications pourraient vous intéresser...

Miniature de la publication : Créer son application Web en PHP (et Composer) : Partie 3.

Créer son application Web en PHP (et Composer) : Partie 3

Vous avez maintenant une architecture métier prête à l'emploi. Maintenant, la question est de savoir comment s'en servir pour afficher du contenu à vos utilisateurs. C'est précisément le sujet de cette 3e partie !

  lun. 01 avr (21:17)

  5

Miniature de la publication : Créer son application Web en PHP (et Composer) : Partie 1.

Créer son application Web en PHP (et Composer) : Partie 1

Vous avez un projet de grande envergure mais ne voulez pas vous embêter avec ces frameworks PHP pré-conçus ? Vous êtes au bon endroit !

  mar. 19 mar (17:53)

  7

Commentaires

Vous pouvez publier un commentaire pour donner votre avis sur la publication, ou poser vos questions le cas échéant. Veillez à rester courtois et respectueux vis-à-vis des autres membres. En cas de détection d'un commentaire allant à l'encontre des règles du site, le commentaire sera supprimé.

Vous devez être connecté pour publier un commentaire. Connectez-vous.