Remarque : Vous voulez en savoir plus sur le routage ? Consultez la page "Why a framework?" pour une explication plus détaillée.
Le routage de base dans Flight se fait en associant un motif d'URL avec une fonction de rappel ou un tableau d'une classe et d'une méthode.
Flight::route('/', function(){ echo 'Bonjour le monde !'; });
Les routes sont associées dans l'ordre où elles sont définies. La première route à correspondre à une requête sera invoquée.
Le rappel peut être n'importe quel objet qui est appelable. Vous pouvez donc utiliser une fonction normale :
function hello() { echo 'Bonjour le monde !'; } Flight::route('/', 'hello');
Vous pouvez également utiliser une méthode statique d'une classe :
class Greeting { public static function hello() { echo 'Bonjour le monde !'; } } Flight::route('/', [ 'Greeting','hello' ]);
Ou en créant d'abord un objet et en appelant ensuite la méthode :
// Greeting.php class Greeting { public function __construct() { $this->name = 'John Doe'; } public function hello() { echo "Bonjour, {$this->name} !"; } } // index.php $greeting = new Greeting(); Flight::route('/', [ $greeting, 'hello' ]); // Vous pouvez également le faire sans créer d'abord l'objet // Remarque : Aucun argument ne sera injecté dans le constructeur Flight::route('/', [ 'Greeting', 'hello' ]); // De plus, vous pouvez utiliser cette syntaxe plus courte Flight::route('/', 'Greeting->hello'); // ou Flight::route('/', Greeting::class.'->hello');
Si vous souhaitez utiliser l'injection de dépendances via un conteneur (PSR-11, PHP-DI, Dice, etc.), le seul type de routes où cela est disponible est soit en créant directement l'objet vous-même et en utilisant le conteneur pour créer votre objet, soit vous pouvez utiliser des chaînes pour définir la classe et la méthode à appeler. Vous pouvez consulter la page Injection de dépendances pour plus d'informations.
Voici un exemple rapide :
use flight\database\PdoWrapper; // Greeting.php class Greeting { protected PdoWrapper $pdoWrapper; public function __construct(PdoWrapper $pdoWrapper) { $this->pdoWrapper = $pdoWrapper; } public function hello(int $id) { // faire quelque chose avec $this->pdoWrapper $name = $this->pdoWrapper->fetchField("SELECT name FROM users WHERE id = ?", [ $id ]); echo "Bonjour, le monde ! Mes prénom est {$name} !"; } } // index.php // Configurez le conteneur avec les paramètres dont vous avez besoin // Consultez la page d'injection de dépendances pour plus d'informations sur PSR-11 $dice = new \Dice\Dice(); // N'oubliez pas de réaffecter la variable avec '$dice = '!!!!! $dice = $dice->addRule('flight\database\PdoWrapper', [ 'shared' => true, 'constructParams' => [ 'mysql:host=localhost;dbname=test', 'root', 'password' ] ]); // Enregistrer le gestionnaire de conteneur Flight::registerContainerHandler(function($class, $params) use ($dice) { return $dice->create($class, $params); }); // Routes comme d'habitude Flight::route('/bonjour/@id', [ 'Greeting', 'hello' ]); // ou Flight::route('/bonjour/@id', 'Greeting->hello'); // ou Flight::route('/bonjour/@id', 'Greeting::hello'); Flight::start();
Par défaut, les motifs de route sont associés à toutes les méthodes de requête. Vous pouvez répondre à des méthodes spécifiques en plaçant un identifiant avant l'URL.
Flight::route('GET /', function () { echo 'J'ai reçu une requête GET.'; }); Flight::route('POST /', function () { echo 'J'ai reçu une requête POST.'; }); // Vous ne pouvez pas utiliser Flight::get() pour les routes car c'est une méthode // pour obtenir des variables, et non pour créer une route. // Flight::post('/', function() { /* code */ }); // Flight::patch('/', function() { /* code */ }); // Flight::put('/', function() { /* code */ }); // Flight::delete('/', function() { /* code */ });
Vous pouvez également mapper plusieurs méthodes à un seul rappel en utilisant un délimiteur | :
|
Flight::route('GET|POST /', function () { echo 'J'ai reçu soit une requête GET, soit une requête POST.'; });
De plus, vous pouvez obtenir l'objet Route qui a quelques méthodes d'aide à utiliser :
$router = Flight::router(); // associe toutes les méthodes $router->map('/', function() { echo 'Bonjour le monde !'; }); // requête GET $router->get('/utilisateurs', function() { echo 'utilisateurs'; }); // $router->post(); // $router->put(); // $router->delete(); // $router->patch();
Vous pouvez utiliser des expressions régulières dans vos routes :
Flight::route('/utilisateur/[0-9]+', function () { // Ceci correspondra à /utilisateur/1234 });
Bien que cette méthode soit disponible, il est recommandé d'utiliser des paramètres nommés, ou des paramètres nommés avec des expressions régulières, car ils sont plus lisibles et plus faciles à maintenir.
Vous pouvez spécifier des paramètres nommés dans vos routes qui seront transmis à votre fonction de rappel.
Flight::route('/@nom/@id', function (string $nom, string $id) { echo "bonjour, $nom ($id) !"; });
Vous pouvez également inclure des expressions régulières avec vos paramètres nommés en utilisant le délimiteur : :
:
Flight::route('/@nom/@id:[0-9]{3}', function (string $nom, string $id) { // Ceci correspondra à /bob/123 // Mais ne correspondra pas à /bob/12345 });
Remarque : Il n'est pas possible d'associer des groupes regex () avec des paramètres nommés. :'(
()
Vous pouvez spécifier des paramètres nommés qui sont optionnels pour la correspondance en enveloppant les segments entre parenthèses.
Flight::route( '/blog(/@annee(/@mois(/@jour)))', function(?string $annee, ?string $mois, ?string $jour) { // Cela correspondra aux URL suivantes : // /blog/2012/12/10 // /blog/2012/12 // /blog/2012 // /blog } );
Tous les paramètres optionnels qui ne sont pas associés seront transmis en tant que NULL.
NULL
La correspondance se fait uniquement sur des segments d'URL individuels. Si vous souhaitez faire correspondre plusieurs segments, vous pouvez utiliser le joker *.
*
Flight::route('/blog/*', function () { // Cela correspondra à /blog/2000/02/01 });
Pour faire correspondre toutes les requêtes à un seul rappel, vous pouvez faire :
Flight::route('*', function () { // Faire quelque chose });
Vous pouvez passer l'exécution à la route correspondante suivante en retournant true depuis votre fonction de rappel.
true
Flight::route('/utilisateur/@nom', function (string $nom) { // Vérifier certaines conditions if ($nom !== "Bob") { // Continuer à la prochaine route return true; } }); Flight::route('/utilisateur/*', function () { // Ceci sera appelé });
Vous pouvez attribuer un alias à une route, de sorte que l'URL puisse être générée dynamiquement plus tard dans votre code (comme un modèle par exemple).
Flight::route('/utilisateurs/@id', function($id) { echo 'utilisateur:'.$id; }, false, 'vue_utilisateur'); // plus tard dans le code Flight::getUrl('vue_utilisateur', [ 'id' => 5 ]); // renverra '/utilisateurs/5'
Cela est particulièrement utile si votre URL change. Dans l'exemple ci-dessus, supposons que les utilisateurs ont été déplacés vers /admin/utilisateurs/@id. Avec l'alias, vous n'avez pas à modifier partout où vous référencez l'alias car l'alias renverra maintenant /admin/utilisateurs/5 comme dans l'exemple ci-dessus.
/admin/utilisateurs/@id
/admin/utilisateurs/5
L'alias de route fonctionne également dans les groupes :
Flight::group('/utilisateurs', function() { Flight::route('/@id', function($id) { echo 'utilisateur:'.$id; }, false, 'vue_utilisateur'); }); // plus tard dans le code Flight::getUrl('vue_utilisateur', [ 'id' => 5 ]); // renverra '/utilisateurs/5'
Si vous voulez inspecter les informations de la route correspondante, vous pouvez demander que l'objet de route soit transmis à votre fonction de rappel en passant true comme troisième paramètre dans la méthode de route. L'objet de route sera toujours le dernier paramètre transmis à votre fonction de rappel.
Flight::route('/', function(\flight\net\Route $route) { // Tableau des méthodes HTTP associées $route->methods; // Tableau des paramètres nommés $route->params; // Correspondance d'expression régulière $route->regex; // Contient le contenu de tout '*' utilisé dans le motif d'URL $route->splat; // Affiche le chemin de l'URL....si vous en avez vraiment besoin $route->pattern; // Affiche quels middleware sont assignés à cela $route->middleware; // Montre l'alias assigné à cette route $route->alias; }, true);
Il peut arriver que vous vouliez regrouper des routes liées ensemble (comme /api/v1). Vous pouvez le faire en utilisant la méthode group :
/api/v1
group
Flight::group('/api/v1', function () { Flight::route('/utilisateurs', function () { // Correspond à /api/v1/utilisateurs }); Flight::route('/publications', function () { // Correspond à /api/v1/publications }); });
Vous pouvez même imbriquer des groupes de groupes :
Flight::group('/api', function () { Flight::group('/v1', function () { // Flight::get() récupère des variables, il ne définit pas une route ! Voir le contexte de l'objet ci-dessous Flight::route('GET /utilisateurs', function () { // Correspond à GET /api/v1/utilisateurs }); Flight::post('/publications', function () { // Correspond à POST /api/v1/publications }); Flight::put('/publications/1', function () { // Correspond à PUT /api/v1/publications }); }); Flight::group('/v2', function () { // Flight::get() récupère des variables, il ne définit pas une route ! Voir le contexte de l'objet ci-dessous Flight::route('GET /utilisateurs', function () { // Correspond à GET /api/v2/utilisateurs }); }); });
Vous pouvez toujours utiliser le groupage de routes avec l'objet Engine de la manière suivante :
Engine
$app = new \flight\Engine(); $app->group('/api/v1', function (Router $router) { // utilisez la variable $router $router->get('/utilisateurs', function () { // Correspond à GET /api/v1/utilisateurs }); $router->post('/publications', function () { // Correspond à POST /api/v1/publications }); });
Vous pouvez désormais diffuser des réponses au client en utilisant la méthode streamWithHeaders(). Ceci est utile pour envoyer de gros fichiers, des processus longs ou générer de grandes réponses. La diffusion d'une route est gérée un peu différemment qu'une route régulière.
streamWithHeaders()
Remarque : La diffusion de réponses n'est disponible que si vous avez défini flight.v2.output_buffering sur false.
flight.v2.output_buffering
Vous pouvez diffuser une réponse au client en utilisant la méthode stream() sur une route. Si vous faites cela, vous devez définir toutes les méthodes manuellement avant de renvoyer quoi que ce soit au client. Ceci est fait avec la fonction php header() ou la méthode Flight::response()->setRealHeader().
stream()
header()
Flight::response()->setRealHeader()
Flight::route('/@nomFichier', function($nomFichier) { // vous auriez évidemment à assainir le chemin et tout. $nomFichierSecurise = basename($nomFichier); // Si vous avez des en-têtes supplémentaires à définir ici après que la route ait été exécutée // vous devez les définir avant d'afficher quoi que ce soit. // Ils doivent tous être un appel brut à la fonction header() ou // un appel à la méthode Flight::response()->setRealHeader() header('Content-Disposition: attachment; filename="'.$nomFichierSecurise.'"'); // ou Flight::response()->setRealHeader('Content-Disposition', 'attachment; filename="'.$nomFichierSafe.'"'); $donneesFichier = file_get_contents('/chemin/vers/fichiers/'.$nomFichierSecurise); // Gestion des erreurs et autres if(empty($donneesFichier)) { Flight::halt(404, 'Fichier non trouvé'); } // définir manuellement la longueur du contenu si vous le souhaitez header('Content-Length: '.filesize($nomFichier)); // Diffuser les données vers le client echo $donneesFichier; // Voici la ligne magique ici })->stream();
Vous pouvez également utiliser la méthode streamWithHeaders() pour définir les en-têtes avant de commencer la diffusion.
Flight::route('/stream-utilisateurs', function() { // vous pouvez ajouter tous les en-têtes supplémentaires que vous souhaitez ici // vous devez simplement utiliser header() ou Flight::response()->setRealHeader() // peu importe comment vous extrayez vos données, juste à titre d'exemple... $users_stmt = Flight::db()->query("SELECT id, first_name, last_name FROM users"); echo '{'; $user_count = count($users); while($user = $users_stmt->fetch(PDO::FETCH_ASSOC)) { echo json_encode($user); if(--$user_count > 0) { echo ','; } // Cela est requis pour envoyer les données au client ob_flush(); } echo '}'; // Voici comment vous allez définir les en-têtes avant de commencer la diffusion. })->streamWithHeaders([ 'Content-Type' => 'application/json', 'Content-Disposition' => 'attachment; filename="users.json"', // code d'état facultatif, par défaut à 200 'status' => 200 ]);