Learn

Apprenez à connaître Flight

Flight est un framework rapide, simple et extensible pour PHP. Il est assez polyvalent et peut être utilisé pour construire tout type d'application web. Il est conçu en gardant à l'esprit la simplicité et est écrit de manière à être facile à comprendre et à utiliser.

Concepts Importants du Framework

Pourquoi un Framework?

Voici un court article sur pourquoi vous devriez utiliser un framework. Il est bon de comprendre les avantages d'utiliser un framework avant de commencer à en utiliser un.

De plus, un excellent tutoriel a été créé par @lubiana. Bien qu'il n'aborde pas en détail Flight en particulier, ce guide vous aidera à comprendre certains des principaux concepts entourant un framework et pourquoi ils sont bénéfiques à utiliser. Vous pouvez trouver le tutoriel ici.

Flight Comparé à d'Autres Frameworks

Si vous migrez depuis un autre framework tel que Laravel, Slim, Fat-Free, ou Symfony vers Flight, cette page vous aidera à comprendre les différences entre les deux.

Thèmes Principaux

Chargement Automatique

Apprenez à charger automatiquement vos propres classes dans votre application.

Itinéraire

Apprenez à gérer les itinéraires de votre application web. Cela inclut également le regroupement d'itinéraires, les paramètres d'itinéraire et les middleware.

Middleware

Apprenez à utiliser les middleware pour filtrer les requêtes et les réponses dans votre application.

Requêtes

Apprenez comment gérer les requêtes et les réponses dans votre application.

Réponses

Apprenez à envoyer des réponses à vos utilisateurs.

Templates HTML

Apprenez à utiliser le moteur de vue intégré pour rendre vos modèles HTML.

Sécurité

Apprenez comment sécuriser votre application contre les menaces de sécurité courantes.

Configuration

Apprenez comment configurer le framework pour votre application.

Extension de Flight

Apprenez comment étendre le framework en ajoutant vos propres méthodes et classes.

Événements et Filtrage

Apprenez à utiliser le système d'événements pour ajouter des hooks à vos méthodes et aux méthodes internes du framework.

Conteneur d'Injection de Dépendances

Apprenez à utiliser des conteneurs d'injection de dépendances (DIC) pour gérer les dépendances de votre application.

API du Framework

Apprenez sur les méthodes de base du framework.

Migration vers la v3

La compatibilité ascendante a été en grande partie maintenue, mais il y a quelques changements dont vous devez être conscient lorsque vous migrez de v2 à v3.

Dépannage

Il existe quelques problèmes courants auxquels vous pourriez être confrontés lors de l'utilisation de Flight. Cette page vous aidera à résoudre ces problèmes.

Learn/stopping

Arrêt

Vous pouvez arrêter le cadre à tout moment en appelant la méthode halt:

Flight::halt();

Vous pouvez également spécifier un code d'état HTTP et un message facultatif:

Flight::halt(200, 'Je reviens bientôt...');

Appeler halt permettra de supprimer tout contenu de réponse jusqu'à ce point. Si vous souhaitez arrêter le cadre et afficher la réponse actuelle, utilisez la méthode stop:

Flight::stop();

Learn/errorhandling

Gestion des erreurs

Erreurs et exceptions

Toutes les erreurs et exceptions sont capturées par Flight et transmises à la méthode error. Le comportement par défaut est d'envoyer une réponse générique d'erreur de serveur interne HTTP 500 avec des informations sur l'erreur.

Vous pouvez remplacer ce comportement pour vos propres besoins:

Flight::map('error', function (Throwable $error) {
  // Gérer l'erreur
  echo $error->getTraceAsString();
});

Par défaut, les erreurs ne sont pas enregistrées sur le serveur web. Vous pouvez activer cela en modifiant la configuration:

Flight::set('flight.log_errors', true);

Non trouvé

Lorsqu'une URL ne peut être trouvée, Flight appelle la méthode notFound. Le comportement par défaut est d'envoyer une réponse HTTP 404 Non trouvé avec un message simple.

Vous pouvez remplacer ce comportement pour vos propres besoins:

Flight::map('notFound', function () {
  // Gérer non trouvé
});

Learn/flight_vs_laravel

Flight vs Laravel

Qu'est-ce que Laravel?

Laravel est un framework complet qui possède toutes les fonctionnalités et une incroyable écosystème axé sur les développeurs, mais au détriment des performances et de la complexité. Le but de Laravel est de procurer au développeur le plus haut niveau de productivité et de simplifier les tâches courantes. Laravel est un excellent choix pour les développeurs qui souhaitent construire une application web d'entreprise complète. Cela comporte certains compromis, notamment en termes de performances et de complexité. Apprendre les bases de Laravel peut être facile, mais acquérir une maîtrise du framework peut prendre du temps.

Il existe tellement de modules Laravel que les développeurs ont souvent l'impression que la seule façon de résoudre les problèmes est d'utiliser ces modules, alors qu'en fait vous pourriez simplement utiliser une autre bibliothèque ou écrire votre propre code.

Avantages par rapport à Flight

Inconvénients par rapport à Flight

Learn/migrating_to_v3

Migration vers v3

La compatibilité ascendante a été en grande partie maintenue, mais il y a des changements dont vous devez être conscient lorsque vous migrez de la v2 à la v3.

Comportement de l'Empaquetage de Sortie (3.5.0)

Empaquetage de sortie est le processus par lequel la sortie générée par un script PHP est stockée dans un tampon (interne à PHP) avant d'être envoyée au client. Cela vous permet de modifier la sortie avant qu'elle ne soit envoyée au client.

Dans une application MVC, le contrôleur est le "manager" et il gère ce que fait la vue. Avoir une sortie générée en dehors du contrôleur (ou dans le cas de Flight parfois une fonction anonyme) rompt avec le modèle MVC. Ce changement vise à être plus en conformité avec le modèle MVC et à rendre le framework plus prévisible et plus facile à utiliser.

Dans la v2, l'empaquetage de sortie était géré d'une manière où il ne fermait pas systématiquement son propre tampon de sortie, ce qui rendait les tests unitaires et le streaming plus difficiles. Pour la majorité des utilisateurs, ce changement ne devrait pas vraiment vous affecter. Cependant, si vous émettez du contenu en dehors des appels de fonction et des contrôleurs (par exemple dans un hook), vous risquez probablement de rencontrer des problèmes. Émettre du contenu dans les hooks, et avant que le framework ne s'exécute réellement, a pu fonctionner par le passé, mais cela ne fonctionnera pas à l'avenir.

Où vous pourriez rencontrer des problèmes

// index.php
require 'vendor/autoload.php';

// juste un exemple
define('START_TIME', microtime(true));

function hello() {
    echo 'Bonjour le monde';
}

Flight::map('hello', 'hello');
Flight::after('hello', function(){
    // cela ira en réalité
    echo '<p>Cette phrase Bonjour le monde vous est offerte par la lettre "B"</p>';
});

Flight::before('start', function(){
    // des choses comme cela vont causer une erreur
    echo '<html><head><title>Ma Page</title></head><body>';
});

Flight::route('/', function(){
    // c'est en réalité tout à fait bien
    echo 'Bonjour le monde';

    // Cela devrait également fonctionner
    Flight::hello();
});

Flight::after('start', function(){
    // cela va causer une erreur
    echo '<div>Votre page s'est chargée en '.(microtime(true) - START_TIME).' secondes</div></body></html>';
});

Activation du Comportement de Rendu v2

Pouvez-vous conserver votre vieux code tel quel sans le réécrire pour le faire fonctionner avec la v3? Oui, vous le pouvez! Vous pouvez activer le comportement de rendu v2 en paramétrant l'option de configuration flight.v2.output_buffering sur true. Cela vous permettra de continuer à utiliser l'ancien comportement de rendu, mais il est recommandé de le corriger pour l'avenir. Dans la v4 du framework, cela sera supprimé.

// index.php
require 'vendor/autoload.php';

Flight::set('flight.v2.output_buffering', true);

Flight::before('start', function(){
    // Maintenant cela fonctionnera parfaitement
    echo '<html><head><title>Ma page</title></head><body>';
});

// plus de code 

Changements du Dispatcher (3.7.0)

Si vous appelez directement des méthodes statiques pour Dispatcher telles que Dispatcher::invokeMethod(), Dispatcher::execute(), etc., vous devrez mettre à jour votre code pour ne pas appeler directement ces méthodes. Dispatcher a été converti pour être plus orienté objet afin que les conteneurs d'injection de dépendances puissent être utilisés plus facilement. Si vous avez besoin d'appeler une méthode de manière similaire à la manière dont le Dispatcher le faisait, vous pouvez utiliser manuellement quelque chose comme $result = $class->$method(...$params); ou call_user_func_array() à la place.

Changements de halt() stop() redirect() et error() (3.10.0)

Avant la version 3.10.0, le comportement par défaut était d'effacer à la fois les en-têtes et le corps de la réponse. Cela a été modifié pour effacer uniquement le corps de la réponse. Si vous devez également effacer les en-têtes, vous pouvez utiliser Flight::response()->clear().

Learn/configuration

Configuration

Vous pouvez personnaliser certains comportements de Flight en définissant des valeurs de configuration à travers la méthode set.

Flight::set('flight.log_errors', true);

Paramètres de configuration disponibles

La liste suivante présente tous les paramètres de configuration disponibles :

Configuration du Chargeur

Il y a également un autre paramètre de configuration pour le chargeur. Cela vous permettra de charger automatiquement les classes avec _ dans le nom de la classe.

// Activer le chargement de classe avec des tirets bas
// Par défaut à true
Loader::$v2ClassLoading = false;

Variables

Flight vous permet de sauvegarder des variables afin qu'elles puissent être utilisées n'importe où dans votre application.

// Sauvegardez votre variable
Flight::set('id', 123);

// Ailleurs dans votre application
$id = Flight::get('id');

Pour vérifier si une variable a été définie, vous pouvez faire :

if (Flight::has('id')) {
  // Faire quelque chose
}

Vous pouvez effacer une variable en faisant :

// Efface la variable id
Flight::clear('id');

// Effacer toutes les variables
Flight::clear();

Flight utilise également des variables à des fins de configuration.

Flight::set('flight.log_errors', true);

Gestion des Erreurs

Erreurs et Exceptions

Toutes les erreurs et exceptions sont capturées par Flight et transmises à la méthode error. Le comportement par défaut est d'envoyer une réponse générique HTTP 500 Erreur Interne du Serveur avec des informations sur l'erreur.

Vous pouvez remplacer ce comportement selon vos besoins :

Flight::map('error', function (Throwable $error) {
  // Gérer l'erreur
  echo $error->getTraceAsString();
});

Par défaut, les erreurs ne sont pas enregistrées dans le serveur web. Vous pouvez activer cela en modifiant la configuration :

Flight::set('flight.log_errors', true);

Introuvable

Lorsqu'une URL est introuvable, Flight appelle la méthode notFound. Le comportement par défaut est d'envoyer une réponse HTTP 404 Non Trouvé avec un message simple.

Vous pouvez remplacer ce comportement selon vos besoins :

Flight::map('notFound', function () {
  // Gérer l'introuvable
});

Learn/security

Sécurité

La sécurité est primordiale lorsqu'il s'agit d'applications web. Vous voulez vous assurer que votre application est sécurisée et que les données de vos utilisateurs sont en sécurité. Flight fournit plusieurs fonctionnalités pour vous aider à sécuriser vos applications web.

En-têtes

Les en-têtes HTTP sont l'un des moyens les plus simples de sécuriser vos applications web. Vous pouvez utiliser des en-têtes pour prévenir le clickjacking, les XSS et autres attaques. Il existe plusieurs façons d'ajouter ces en-têtes à votre application.

Deux excellents sites pour vérifier la sécurité de vos en-têtes sont securityheaders.com et observatory.mozilla.org.

Ajouter Manuellement

Vous pouvez ajouter manuellement ces en-têtes en utilisant la méthode header sur l'objet Flight\Response.

// Définir l'en-tête X-Frame-Options pour prévenir le clickjacking
Flight::response()->header('X-Frame-Options', 'SAMEORIGIN');

// Définir l'en-tête Content-Security-Policy pour prévenir les XSS
// Remarque : cet en-tête peut être très complexe, vous voudrez
// consulter des exemples sur internet pour votre application
Flight::response()->header("Content-Security-Policy", "default-src 'self'");

// Définir l'en-tête X-XSS-Protection pour prévenir les XSS
Flight::response()->header('X-XSS-Protection', '1; mode=block');

// Définir l'en-tête X-Content-Type-Options pour éviter le MIME sniffing
Flight::response()->header('X-Content-Type-Options', 'nosniff');

// Définir l'en-tête Referrer-Policy pour contrôler la quantité d'informations de référence envoyée
Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade');

// Définir l'en-tête Strict-Transport-Security pour forcer HTTPS
Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');

// Définir l'en-tête Permissions-Policy pour contrôler les fonctionnalités et APIs pouvant être utilisées
Flight::response()->header('Permissions-Policy', 'geolocation=()');

Ces en-têtes peuvent être ajoutés en haut de vos fichiers bootstrap.php ou index.php.

Ajouter en tant que Filtre

Vous pouvez également les ajouter dans un filtre/hook comme suit :

// Ajouter les en-têtes dans un filtre
Flight::before('start', function() {
    Flight::response()->header('X-Frame-Options', 'SAMEORIGIN');
    Flight::response()->header("Content-Security-Policy", "default-src 'self'");
    Flight::response()->header('X-XSS-Protection', '1; mode=block');
    Flight::response()->header('X-Content-Type-Options', 'nosniff');
    Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade');
    Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
    Flight::response()->header('Permissions-Policy', 'geolocation=()');
});

Ajouter en tant que Middleware

Vous pouvez également les ajouter en tant que classe middleware. C'est une bonne façon de garder votre code propre et organisé.

// app/middleware/SecurityHeadersMiddleware.php

namespace app\middleware;

class SecurityHeadersMiddleware
{
    public function before(array $params): void
    {
        Flight::response()->header('X-Frame-Options', 'SAMEORIGIN');
        Flight::response()->header("Content-Security-Policy", "default-src 'self'");
        Flight::response()->header('X-XSS-Protection', '1; mode=block');
        Flight::response()->header('X-Content-Type-Options', 'nosniff');
        Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade');
        Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
        Flight::response()->header('Permissions-Policy', 'geolocation=()');
    }
}

// index.php ou où vous avez vos routes
// FYI, ce groupe de chaîne vide agit comme un middleware global pour
// toutes les routes. Bien sûr, vous pourriez faire la même chose et ajouter
// ceci uniquement à des routes spécifiques.
Flight::group('', function(Router $router) {
    $router->get('/users', [ 'UserController', 'getUsers' ]);
    // plus de routes
}, [ new SecurityHeadersMiddleware() ]);

Forgery de Requête de Site Croisé (CSRF)

La Forgery de Requête de Site Croisé (CSRF) est un type d'attaque où un site web malveillant peut envoyer une requête au site web d'un utilisateur à son insu. Cela peut être utilisé pour effectuer des actions sur votre site sans que l'utilisateur le sache. Flight ne fournit pas de mécanisme de protection CSRF intégré, mais vous pouvez facilement implémenter le vôtre en utilisant un middleware.

Configuration

Tout d'abord, vous devez générer un jeton CSRF et le stocker dans la session de l'utilisateur. Vous pouvez ensuite utiliser ce jeton dans vos formulaires et le vérifier lors de la soumission du formulaire.

// Générer un jeton CSRF et le stocker dans la session de l'utilisateur
// (en supposant que vous avez créé un objet de session et l'avez attaché à Flight)
// consultez la documentation sur les sessions pour plus d'informations
Flight::register('session', \Ghostff\Session\Session::class);

// Vous n'avez besoin de générer qu'un seul jeton par session (pour qu'il fonctionne
// sur plusieurs onglets et requêtes pour le même utilisateur)
if(Flight::session()->get('csrf_token') === null) {
    Flight::session()->set('csrf_token', bin2hex(random_bytes(32)) );
}
<!-- Utilisez le jeton CSRF dans votre formulaire -->
<form method="post">
    <input type="hidden" name="csrf_token" value="<?= Flight::session()->get('csrf_token') ?>">
    <!-- autres champs de formulaire -->
</form>

Utilisation de Latte

Vous pouvez également définir une fonction personnalisée pour afficher le jeton CSRF dans vos modèles Latte.

// Définir une fonction personnalisée pour afficher le jeton CSRF
// Remarque : View a été configuré avec Latte comme moteur de vue
Flight::view()->addFunction('csrf', function() {
    $csrfToken = Flight::session()->get('csrf_token');
    return new \Latte\Runtime\Html('<input type="hidden" name="csrf_token" value="' . $csrfToken . '">');
});

Et maintenant, dans vos modèles Latte, vous pouvez utiliser la fonction csrf() pour afficher le jeton CSRF.

<form method="post">
    {csrf()}
    <!-- autres champs de formulaire -->
</form>

Court et simple, n'est-ce pas?

Vérifier le Jeton CSRF

Vous pouvez vérifier le jeton CSRF en utilisant des filtres d'événements :

// Ce middleware vérifie si la requête est une requête POST et si c'est le cas, il vérifie si le jeton CSRF est valide
Flight::before('start', function() {
    if(Flight::request()->method == 'POST') {

        // capturer le jeton csrf des valeurs du formulaire
        $token = Flight::request()->data->csrf_token;
        if($token !== Flight::session()->get('csrf_token')) {
            Flight::halt(403, 'Jeton CSRF invalide');
            // ou pour une réponse JSON
            Flight::jsonHalt(['error' => 'Jeton CSRF invalide'], 403);
        }
    }
});

Ou vous pouvez utiliser une classe middleware :

// app/middleware/CsrfMiddleware.php

namespace app\middleware;

class CsrfMiddleware
{
    public function before(array $params): void
    {
        if(Flight::request()->method == 'POST') {
            $token = Flight::request()->data->csrf_token;
            if($token !== Flight::session()->get('csrf_token')) {
                Flight::halt(403, 'Jeton CSRF invalide');
            }
        }
    }
}

// index.php ou où vous avez vos routes
Flight::group('', function(Router $router) {
    $router->get('/users', [ 'UserController', 'getUsers' ]);
    // plus de routes
}, [ new CsrfMiddleware() ]);

Scripting de Site Croisé (XSS)

Le Scripting de Site Croisé (XSS) est un type d'attaque où un site web malveillant peut injecter du code dans votre site web. La plupart de ces opportunités viennent des valeurs de formulaire que vos utilisateurs finaux rempliront. Vous ne devez jamais faire confiance à la sortie de vos utilisateurs ! Supposez toujours qu'ils sont les meilleurs hackers du monde. Ils peuvent injecter du JavaScript ou du HTML malveillant dans votre page. Ce code peut être utilisé pour voler des informations à vos utilisateurs ou effectuer des actions sur votre site web. En utilisant la classe de vue de Flight, vous pouvez facilement échapper la sortie pour prévenir les attaques XSS.

// Supposons que l'utilisateur soit malin et essaie d'utiliser ceci comme nom
$name = '<script>alert("XSS")</script>';

// Cela échappera la sortie
Flight::view()->set('name', $name);
// Cela produira : &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

// Si vous utilisez quelque chose comme Latte enregistré en tant que classe de vue, cela échappera également automatiquement ceci.
Flight::view()->render('template', ['name' => $name]);

Injection SQL

L'injection SQL est un type d'attaque où un utilisateur malveillant peut injecter du code SQL dans votre base de données. Cela peut être utilisé pour voler des informations de votre base de données ou effectuer des actions sur votre base de données. Encore une fois, vous ne devez jamais faire confiance à l'entrée de vos utilisateurs ! Supposez toujours qu'ils sont là pour vous nuire. Vous pouvez utiliser des instructions préparées dans vos objets PDO pour prévenir les injections SQL.

// En supposant que vous avez Flight::db() enregistré en tant qu'objet PDO
$statement = Flight::db()->prepare('SELECT * FROM users WHERE username = :username');
$statement->execute([':username' => $username]);
$users = $statement->fetchAll();

// Si vous utilisez la classe PdoWrapper, cela peut être facilement fait en une ligne
$users = Flight::db()->fetchAll('SELECT * FROM users WHERE username = :username', [ 'username' => $username ]);

// Vous pouvez faire la même chose avec un objet PDO avec des espaces réservés ?
$statement = Flight::db()->fetchAll('SELECT * FROM users WHERE username = ?', [ $username ]);

// Promettez simplement de ne JAMAIS faire quelque chose comme ceci...
$users = Flight::db()->fetchAll("SELECT * FROM users WHERE username = '{$username}' LIMIT 5");
// car que se passerait-il si $username = "' OR 1=1; -- "; 
// Après la construction de la requête, elle ressemble à ceci
// SELECT * FROM users WHERE username = '' OR 1=1; -- LIMIT 5
// Cela semble étrange, mais c'est une requête valide qui fonctionnera. En fait,
// il s'agit d'une attaque d'injection SQL très commune qui renverra tous les utilisateurs.

CORS

Le Partage des Ressources en Origine Croisée (CORS) est un mécanisme qui permet à de nombreuses ressources (p. ex., polices, JavaScript, etc.) sur une page web d'être demandées depuis un autre domaine en dehors du domaine d'origine de la ressource. Flight n'a pas de fonctionnalité intégrée pour cela, mais cela peut être facilement géré avec un hook à exécuter avant l'appel à Flight::start().

// app/utils/CorsUtil.php

namespace app\utils;

class CorsUtil
{
    public function set(array $params): void
    {
        $request = Flight::request();
        $response = Flight::response();
        if ($request->getVar('HTTP_ORIGIN') !== '') {
            $this->allowOrigins();
            $response->header('Access-Control-Allow-Credentials', 'true');
            $response->header('Access-Control-Max-Age', '86400');
        }

        if ($request->method === 'OPTIONS') {
            if ($request->getVar('HTTP_ACCESS_CONTROL_REQUEST_METHOD') !== '') {
                $response->header(
                    'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD'
                );
            }
            if ($request->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') !== '') {
                $response->header(
                    "Access-Control-Allow-Headers",
                    $request->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')
                );
            }

            $response->status(200);
            $response->send();
            exit;
        }
    }

    private function allowOrigins(): void
    {
        // personnalisez vos hôtes autorisés ici.
        $allowed = [
            'capacitor://localhost',
            'ionic://localhost',
            'http://localhost',
            'http://localhost:4200',
            'http://localhost:8080',
            'http://localhost:8100',
        ];

        $request = Flight::request();

        if (in_array($request->getVar('HTTP_ORIGIN'), $allowed, true) === true) {
            $response = Flight::response();
            $response->header("Access-Control-Allow-Origin", $request->getVar('HTTP_ORIGIN'));
        }
    }
}

// index.php ou où vous avez vos routes
$CorsUtil = new CorsUtil();

// Cela doit être exécuté avant le démarrage.
Flight::before('start', [ $CorsUtil, 'setupCors' ]);

Conclusion

La sécurité est primordiale et il est important de veiller à ce que vos applications web soient sécurisées. Flight fournit plusieurs fonctionnalités pour vous aider à sécuriser vos applications web, mais il est important d'être toujours vigilant et de s'assurer que vous faites tout ce que vous pouvez pour garder les données de vos utilisateurs en sécurité. Supposez toujours le pire et ne faites jamais confiance à l'entrée de vos utilisateurs. Échappez toujours la sortie et utilisez des instructions préparées pour prévenir les injections SQL. Utilisez toujours des middleware pour protéger vos routes des attaques CSRF et CORS. Si vous faites toutes ces choses, vous serez bien parti pour construire des applications web sécurisées.

Learn/overriding

Substitution

Flight vous permet de substituer sa fonctionnalité par défaut pour répondre à vos propres besoins, sans avoir à modifier aucun code.

Par exemple, lorsque Flight ne peut pas faire correspondre une URL à une route, il invoque la méthode notFound qui envoie une réponse générique HTTP 404. Vous pouvez substituer ce comportement en utilisant la méthode map :

Flight::map('notFound', function() {
  // Afficher une page d'erreur 404 personnalisée
  include 'errors/404.html';
});

Flight vous permet également de remplacer les composants principaux du framework. Par exemple, vous pouvez remplacer la classe Router par défaut par votre propre classe personnalisée :

// Enregistrer votre classe personnalisée
Flight::register('router', MaClasseRouter::class);

// Lorsque Flight charge l'instance du routeur, il chargera votre classe
$monrouteur = Flight::router();

Cependant, les méthodes du framework telles que map et register ne peuvent pas être substituées. Vous obtiendrez une erreur si vous essayez de le faire.

Learn/routing

Routage

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.

Rappels/Fonctions

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');

Classes

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');

Injection de dépendances via le DIC (conteneur d'injection de dépendances)

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();

Routage par Méthode

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();

Expressions Régulières

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.

Paramètres Nom-més

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. :'(

Paramètres Optionnels

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.

Jokers

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
});

Passage

Vous pouvez passer l'exécution à la route correspondante suivante en retournant true depuis votre fonction de rappel.

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é
});

Aliasing des Routes

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.

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'

Infos sur la Route

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);

Groupage de Routes

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 :

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
    });
  });
});

Groupage avec Contexte d'Objet

Vous pouvez toujours utiliser le groupage de routes avec l'objet Engine de la manière suivante :

$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
  });
});

Streaming

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.

Remarque : La diffusion de réponses n'est disponible que si vous avez défini flight.v2.output_buffering sur false.

Diffusion avec En-têtes Manuels

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().

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();

Diffusion avec En-têtes

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
]);

Learn/flight_vs_symfony

Vol Flight vs Symfony

Qu'est-ce que Symfony?

Symfony est un ensemble de composants PHP réutilisables et un framework PHP pour les projets web.

La base standard sur laquelle les meilleures applications PHP sont construites. Choisissez l'un des 50 composants autonomes disponibles pour vos propres applications.

Accélérez la création et la maintenance de vos applications web PHP. Mettez fin aux tâches de codage répétitives et profitez du pouvoir de contrôler votre code.

Avantages par rapport à Flight

Inconvénients par rapport à Flight

Learn/flight_vs_another_framework

Comparaison de Flight à un autre Framework

Si vous migrez d'un autre framework tel que Laravel, Slim, Fat-Free, ou Symfony vers Flight, cette page vous aidera à comprendre les différences entre les deux.

Laravel

Laravel est un framework complet qui possède toutes les fonctionnalités et une incroyable écosystème axé sur les développeurs, mais cela a un coût en termes de performances et de complexité.

Voir la comparaison entre Laravel et Flight.

Slim

Slim est un micro-framework similaire à Flight. Il est conçu pour être léger et facile à utiliser, mais peut être un peu plus complexe que Flight.

Voir la comparaison entre Slim et Flight.

Fat-Free

Fat-Free est un framework full-stack dans un package beaucoup plus petit. Bien qu'il possède tous les outils nécessaires, il a une architecture des données qui peut rendre certains projets plus complexes qu'ils ne le devraient.

Voir la comparaison entre Fat-Free et Flight.

Symfony

Symfony est un framework modulaire de niveau entreprise conçu pour être flexible et scalable. Pour les petits projets ou les nouveaux développeurs, Symfony peut être un peu intimidant.

Voir la comparaison entre Symfony et Flight.

Learn/variables

Variables

Flight permet de sauvegarder des variables afin qu'elles puissent être utilisées n'importe où dans votre application.

// Sauvegardez votre variable
Flight::set('id', 123);

// Ailleurs dans votre application
$id = Flight::get('id');

Pour vérifier si une variable a été définie, vous pouvez faire :

if (Flight::has('id')) {
  // Faire quelque chose
}

Vous pouvez effacer une variable en faisant :

// Efface la variable id
Flight::clear('id');

// Efface toutes les variables
Flight::clear();

Flight utilise également des variables à des fins de configuration.

Flight::set('flight.log_errors', true);

Learn/dependency_injection_container

Conteneur d'injection de dépendances

Introduction

Le Conteneur d'injection de dépendances (DIC) est un outil puissant qui vous permet de gérer les dépendances de votre application. C'est un concept clé dans les frameworks PHP modernes et est utilisé pour gérer l'instanciation et la configuration des objets. Quelques exemples de bibliothèques DIC sont : Dice, Pimple, PHP-DI et league/container.

Un DIC est un moyen sophistiqué de dire qu'il vous permet de créer et de gérer vos classes dans un emplacement centralisé. C'est utile lorsque vous avez besoin de passer le même objet à plusieurs classes (comme vos contrôleurs). Un exemple simple pourrait aider à mieux comprendre cela.

Exemple de base

L'ancienne manière de faire ressemblait à ceci :


require 'vendor/autoload.php';

// classe pour gérer les utilisateurs de la base de données
class UserController {

    protected PDO $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }

    public function view(int $id) {
        $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id');
        $stmt->execute(['id' => $id]);

        print_r($stmt->fetch());
    }
}

$User = new UserController(new PDO('mysql:host=localhost;dbname=test', 'user', 'pass'));
Flight::route('/user/@id', [ $UserController, 'view' ]);

Flight::start();

Vous pouvez voir dans le code ci-dessus que nous créons un nouvel objet PDO et le passons à notre classe UserController. C'est bien pour une petite application, mais à mesure que votre application grandit, vous constaterez que vous créez le même objet PDO à plusieurs endroits. C'est là qu'un DIC s'avère utile.

Voici le même exemple utilisant un DIC (en utilisant Dice) :


require 'vendor/autoload.php';

// même classe que ci-dessus. Rien n'a changé
class UserController {

    protected PDO $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }

    public function view(int $id) {
        $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id');
        $stmt->execute(['id' => $id]);

        print_r($stmt->fetch());
    }
}

// créer un nouveau conteneur
$container = new \Dice\Dice;
// n'oubliez pas de le réassigner comme ci-dessous !
$container = $container->addRule('PDO', [
    // shared signifie que le même objet sera retourné à chaque fois
    'shared' => true,
    'constructParams' => ['mysql:host=localhost;dbname=test', 'user', 'pass' ]
]);

// Cela enregistre le gestionnaire de conteneur pour que Flight sache l'utiliser.
Flight::registerContainerHandler(function($class, $params) use ($container) {
    return $container->create($class, $params);
});

// maintenant nous pouvons utiliser le conteneur pour créer notre UserController
Flight::route('/user/@id', [ 'UserController', 'view' ]);
// ou alternativement vous pouvez définir la route comme ceci
Flight::route('/user/@id', 'UserController->view');
// ou
Flight::route('/user/@id', 'UserController::view');

Flight::start();

Je parie que vous pouvez penser qu'il y a beaucoup de code supplémentaire ajouté à l'exemple. La magie opère lorsque vous avez un autre contrôleur qui a besoin de l'objet PDO.


// Si tous vos contrôleurs ont un constructeur qui a besoin d'un objet PDO
// chacune des routes ci-dessous l'injectera automatiquement !!!
Flight::route('/company/@id', 'CompanyController->view');
Flight::route('/organization/@id', 'OrganizationController->view');
Flight::route('/category/@id', 'CategoryController->view');
Flight::route('/settings', 'SettingsController->view');

Le bonus supplémentaire d'utiliser un DIC est que les tests unitaires deviennent beaucoup plus faciles. Vous pouvez créer un objet simulé et le passer à votre classe. C'est un énorme avantage lorsque vous rédigez des tests pour votre application!

PSR-11

Flight peut également utiliser n'importe quel conteneur compatible avec PSR-11. Cela signifie que vous pouvez utiliser n'importe un conteneur qui implémente l'interface PSR-11. Voici un exemple utilisant le conteneur PSR-11 de League :


require 'vendor/autoload.php';

// même classe UserController que ci-dessus

$container = new \League\Container\Container();
$container->add(UserController::class)->addArgument(PdoWrapper::class);
$container->add(PdoWrapper::class)
    ->addArgument('mysql:host=localhost;dbname=test')
    ->addArgument('user')
    ->addArgument('pass');
Flight::registerContainerHandler($container);

Flight::route('/user', [ 'UserController', 'view' ]);

Flight::start();

Bien que cela puisse être un peu plus verbeux que l'exemple Dice précédent, cela fonctionne tout de même avec les mêmes avantages!

Gestionnaire DIC personnalisé

Vous pouvez également créer votre propre gestionnaire DIC. C'est utile si vous avez un conteneur personnalisé que vous voulez utiliser qui n'est pas PSR-11 (Dice). Consultez l' exemple de base pour savoir comment faire cela.

De plus, il y a quelques valeurs par défaut utiles qui faciliteront votre vie lors de l'utilisation de Flight.

Instance du moteur

Si vous utilisez l'instance Engine dans vos contrôleurs/middleware, voici comment vous la configureriez :


// Quelque part dans votre fichier d'amorçage
$engine = Flight::app();

$container = new \Dice\Dice;
$container = $container->addRule('*', [
    'substitutions' => [
        // C'est ici que vous passez l'instance
        Engine::class => $engine
    ]
]);

$engine->registerContainerHandler(function($class, $params) use ($container) {
    return $container->create($class, $params);
});

// Maintenant vous pouvez utiliser l'instance Engine dans vos contrôleurs/middleware

class MyController {
    public function __construct(Engine $app) {
        $this->app = $app;
    }

    public function index() {
        $this->app->render('index');
    }
}

Ajout d'autres classes

Si vous avez d'autres classes que vous voulez ajouter au conteneur, avec Dice c'est facile car elles seront automatiquement résolues par le conteneur. Voici un exemple :


$container = new \Dice\Dice;
// Si vous n'avez pas besoin d'injecter quoi que ce soit dans votre classe
// vous n'avez pas besoin de définir quoi que ce soit !
Flight::registerContainerHandler(function($class, $params) use ($container) {
    return $container->create($class, $params);
});

class MyCustomClass {
    public function parseThing() {
        return 'thing';
    }
}

class UserController {

    protected MyCustomClass $MyCustomClass;

    public function __construct(MyCustomClass $MyCustomClass) {
        $this->MyCustomClass = $MyCustomClass;
    }

    public function index() {
        echo $this->MyCustomClass->parseThing();
    }
}

Flight::route('/user', 'UserController->index');

Learn/middleware

Middleware de Route

Flight prend en charge les middleware de route et de groupe de route. Un middleware est une fonction qui est exécutée avant (ou après) le rappel de la route. C'est un excellent moyen d'ajouter des vérifications d'authentification API dans votre code, ou de valider que l'utilisateur a la permission d'accéder à la route.

Middleware de Base

Voici un exemple de base :

// Si vous ne fournissez qu'une fonction anonyme, elle sera exécutée avant le rappel de la route. Il n'y a pas de fonctions middleware "après" à l'exception des classes (voir ci-dessous)
Flight::route('/chemin', function() { echo 'Me voici !'; })->addMiddleware(function() {
    echo 'Middleware en premier !';
});

Flight::start();

// Cela affichera "Middleware en premier ! Me voici !"

Il est important de noter quelques points essentiels concernant les middleware avant de les utiliser :

Classes Middleware

Les middleware peuvent également être enregistrés sous forme de classe. Si vous avez besoin de la fonctionnalité "after", vous devez utiliser une classe.

class MyMiddleware {
    public function before($params) {
        echo 'Middleware en premier !';
    }

    public function after($params) {
        echo 'Middleware en dernier !';
    }
}

$MyMiddleware = new MyMiddleware();
Flight::route('/chemin', function() { echo 'Me voici ! '; })->addMiddleware($MyMiddleware); // également ->addMiddleware([ $MyMiddleware, $MyMiddleware2 ]);

Flight::start();

// Cela affichera "Middleware en premier ! Me voici ! Middleware en dernier !"

Gestion des Erreurs de Middleware

Disons que vous avez un middleware d'authentification et que vous souhaitez rediriger l'utilisateur vers une page de connexion s'il n'est pas authentifié. Vous avez quelques options à votre disposition :

  1. Vous pouvez renvoyer false depuis la fonction middleware et Flight renverra automatiquement une erreur 403 Forbidden, mais sans personnalisation.
  2. Vous pouvez rediriger l'utilisateur vers une page de connexion en utilisant Flight::redirect().
  3. Vous pouvez créer une erreur personnalisée à l'intérieur du middleware et arrêter l'exécution de la route.

Exemple de Base

Voici un exemple simple avec return false; :

class MyMiddleware {
    public function before($params) {
        if (isset($_SESSION['user']) === false) {
            return false;
        }

        // comme c'est vrai, tout continue simplement
    }
}

Exemple de Redirection

Voici un exemple de redirection de l'utilisateur vers une page de connexion :

class MyMiddleware {
    public function before($params) {
        if (isset($_SESSION['user']) === false) {
            Flight::redirect('/login');
            exit;
        }
    }
}

Exemple d'Erreur Personnalisée

Disons que vous devez déclencher une erreur JSON car vous construisez une API. Vous pouvez le faire de cette manière :

class MyMiddleware {
    public function before($params) {
        $authorization = Flight::request()->headers['Authorization'];
        if(empty($authorization)) {
            Flight::jsonHalt(['error' => 'Vous devez être connecté pour accéder à cette page.'], 403);
            // ou
            Flight::json(['error' => 'Vous devez être connecté pour accéder à cette page.'], 403);
            exit;
            // ou
            Flight::halt(403, json_encode(['error' => 'Vous devez être connecté pour accéder à cette page.']);
        }
    }
}

Regroupement de Middleware

Vous pouvez ajouter un groupe de route, puis chaque route de ce groupe aura également le même middleware. C'est utile si vous devez regrouper un ensemble de routes par exemple avec un middleware d'Auth pour vérifier la clé API dans l'en-tête.


// ajouté à la fin de la méthode group
Flight::group('/api', function() {

    // Cette route en apparence "vide" correspondra en fait à /api
    Flight::route('', function() { echo 'api'; }, false, 'api');
    // Cela correspondra à /api/utilisateurs
    Flight::route('/utilisateurs', function() { echo 'utilisateurs'; }, false, 'utilisateurs');
    // Cela correspondra à /api/utilisateurs/1234
    Flight::route('/utilisateurs/@id', function($id) { echo 'utilisateur :'.$id; }, false, 'vue_utilisateur');
}, [ new ApiAuthMiddleware() ]);

Si vous souhaitez appliquer un middleware global à toutes vos routes, vous pouvez ajouter un groupe "vide" :


// ajouté à la fin de la méthode group
Flight::group('', function() {

    // C'est toujours /utilisateurs
    Flight::route('/utilisateurs', function() { echo 'utilisateurs'; }, false, 'utilisateurs');
    // Et c'est toujours /utilisateurs/1234
    Flight::route('/utilisateurs/@id', function($id) { echo 'utilisateur :'.$id; }, false, 'vue_utilisateur');
}, [ new ApiAuthMiddleware() ]);

Learn/filtering

Filtrage

Flight vous permet de filtrer les méthodes avant et après leur appel. Il n'y a pas de crochets prédéfinis que vous devez mémoriser. Vous pouvez filtrer n'importe quelle des méthodes par défaut du framework ainsi que n'importe quelle méthode personnalisée que vous avez mappée.

Une fonction de filtre ressemble à ceci :

function (array &$params, string &$output): bool {
  // Code de filtre
}

En utilisant les variables passées en paramètre, vous pouvez manipuler les paramètres d'entrée et/ou la sortie.

Vous pouvez faire exécuter un filtre avant une méthode en faisant :

Flight::before('start', function (array &$params, string &$output): bool {
  // Faire quelque chose
});

Vous pouvez faire exécuter un filtre après une méthode en faisant :

Flight::after('start', function (array &$params, string &$output): bool {
  // Faire quelque chose
});

Vous pouvez ajouter autant de filtres que vous le souhaitez à n'importe quelle méthode. Ils seront appelés dans l'ordre où ils sont déclarés.

Voici un exemple du processus de filtrage :

// Mapper une méthode personnalisée
Flight::map('hello', function (string $name) {
  return "Bonjour, $name!";
});

// Ajouter un filtre avant
Flight::before('hello', function (array &$params, string &$output): bool {
  // Manipuler le paramètre
  $params[0] = 'Fred';
  return true;
});

// Ajouter un filtre après
Flight::after('hello', function (array &$params, string &$output): bool {
  // Manipuler la sortie
  $output .= " Passez une bonne journée !";
  return true;
});

// Appeler la méthode personnalisée
echo Flight::hello('Bob');

Cela devrait afficher :

Bonjour Fred ! Passez une bonne journée !

Si vous avez défini plusieurs filtres, vous pouvez interrompre la chaîne en renvoyant false dans l'une de vos fonctions de filtre :

Flight::before('start', function (array &$params, string &$output): bool {
  echo 'un';
  return true;
});

Flight::before('start', function (array &$params, string &$output): bool {
  echo 'deux';

  // Cela mettra fin à la chaîne
  return false;
});

// Cela ne sera pas appelé
Flight::before('start', function (array &$params, string &$output): bool {
  echo 'trois';
  return true;
});

Notez que les méthodes de base telles que map et register ne peuvent pas être filtrées car elles sont appelées directement et n'exécutent pas de manière dynamique.

Learn/requests

Requêtes

Flight encapsule la requête HTTP dans un seul objet, qui peut être accédé en faisant :

$request = Flight::request();

Cas d'utilisation typiques

Lorsque vous travaillez avec une requête dans une application web, vous voudrez généralement extraire un en-tête, ou un paramètre $_GET ou $_POST, ou peut-être même le corps brut de la requête. Flight fournit une interface simple pour faire toutes ces choses.

Voici un exemple d'obtention d'un paramètre de chaîne de requête :

Flight::route('/search', function(){
    $keyword = Flight::request()->query['keyword'];
    echo "Vous recherchez : $keyword";
    // interroger une base de données ou autre chose avec le $keyword
});

Voici un exemple d'un formulaire avec une méthode POST :

Flight::route('POST /submit', function(){
    $name = Flight::request()->data['name'];
    $email = Flight::request()->data['email'];
    echo "Vous avez soumis : $name, $email";
    // enregistrer dans une base de données ou autre chose avec le $name et $email
});

Propriétés de l'objet de requête

L'objet de requête fournit les propriétés suivantes :

Vous pouvez accéder aux propriétés query, data, cookies et files comme des tableaux ou des objets.

Donc, pour obtenir un paramètre de chaîne de requête, vous pouvez faire :

$id = Flight::request()->query['id'];

Ou vous pouvez faire :

$id = Flight::request()->query->id;

CORPS DE LA REQUÊTE BRUTE

Pour obtenir le corps brut de la requête HTTP, par exemple lors du traitement des requêtes PUT, vous pouvez faire :

$body = Flight::request()->getBody();

Entrée JSON

Si vous envoyez une requête avec le type application/json et les données {"id": 123} elles seront disponibles via la propriété data :

$id = Flight::request()->data->id;

$_GET

Vous pouvez accéder au tableau $_GET via la propriété query :

$id = Flight::request()->query['id'];

$_POST

Vous pouvez accéder au tableau $_POST via la propriété data :

$id = Flight::request()->data['id'];

$_COOKIE

Vous pouvez accéder au tableau $_COOKIE via la propriété cookies :

$myCookieValue = Flight::request()->cookies['myCookieName'];

$_SERVER

Il existe un raccourci disponible pour accéder au tableau $_SERVER via la méthode getVar() :


$host = Flight::request()->getVar['HTTP_HOST'];

Accéder aux fichiers téléchargés via $_FILES

Vous pouvez accéder aux fichiers téléchargés via la propriété files :

$uploadedFile = Flight::request()->files['myFile'];

Traitement des téléchargements de fichiers

Vous pouvez traiter les téléchargements de fichiers en utilisant le framework avec quelques méthodes d'aide. Cela revient essentiellement à obtenir les données du fichier de la requête et à les déplacer vers un nouvel emplacement.

Flight::route('POST /upload', function(){
    // Si vous aviez un champ d'entrée comme <input type="file" name="myFile">
    $uploadedFileData = Flight::request()->getUploadedFiles();
    $uploadedFile = $uploadedFileData['myFile'];
    $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename());
});

Si vous avez plusieurs fichiers téléchargés, vous pouvez les parcourir :

Flight::route('POST /upload', function(){
    // Si vous aviez un champ d'entrée comme <input type="file" name="myFiles[]">
    $uploadedFiles = Flight::request()->getUploadedFiles()['myFiles'];
    foreach ($uploadedFiles as $uploadedFile) {
        $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename());
    }
});

Note de sécurité : Validez toujours et assainissez les entrées de l'utilisateur, en particulier lors du traitement des téléchargements de fichiers. Validez toujours le type d'extensions que vous autoriserez à être téléchargées, mais vous devriez également valider les "octets magiques" du fichier pour vous assurer qu'il s'agit effectivement du type de fichier que l'utilisateur prétend avoir. Il existe des articles et bibliothèques disponibles pour vous aider avec cela.

En-têtes de requête

Vous pouvez accéder aux en-têtes de la requête en utilisant la méthode getHeader() ou getHeaders() :


// Peut-être avez-vous besoin de l'en-tête d'Authorization
$host = Flight::request()->getHeader('Authorization');
// ou
$host = Flight::request()->header('Authorization');

// Si vous devez récupérer tous les en-têtes
$headers = Flight::request()->getHeaders();
// ou
$headers = Flight::request()->headers();

Corps de la requête

Vous pouvez accéder au corps brut de la requête en utilisant la méthode getBody() :

$body = Flight::request()->getBody();

Méthode de requête

Vous pouvez accéder à la méthode de requête en utilisant la propriété method ou la méthode getMethod() :

$method = Flight::request()->method; // appelle en réalité getMethod()
$method = Flight::request()->getMethod();

Remarque : La méthode getMethod() récupère d'abord la méthode à partir de $_SERVER['REQUEST_METHOD'], puis elle peut être écrasée par $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] si elle existe ou $_REQUEST['_method'] si elle existe.

URLs de requête

Il existe quelques méthodes d'aide pour assembler des parties d'une URL pour votre commodité.

URL complète

Vous pouvez accéder à l'URL de requête complète en utilisant la méthode getFullUrl() :

$url = Flight::request()->getFullUrl();
// https://example.com/some/path?foo=bar

URL de base

Vous pouvez accéder à l'URL de base en utilisant la méthode getBaseUrl() :

$url = Flight::request()->getBaseUrl();
// Remarque, pas de barre oblique de fin.
// https://example.com

Analyse des requêtes

Vous pouvez passer une URL à la méthode parseQuery() pour analyser la chaîne de requête en un tableau associatif :

$query = Flight::request()->parseQuery('https://example.com/some/path?foo=bar');
// ['foo' => 'bar']

Learn/frameworkmethods

Méthodes du Cadre

Flight est conçu pour être facile à utiliser et à comprendre. Ce qui suit est l'ensemble complet des méthodes du cadre. Il se compose de méthodes centrales, qui sont des méthodes statiques régulières, et de méthodes extensibles, qui sont des méthodes mappées qui peuvent être filtrées ou remplacées.

Méthodes Principales

Flight::map(string $name, callable $callback, bool $pass_route = false) // Crée une méthode de cadre personnalisée.
Flight::register(string $name, string $class, array $params = [], ?callable $callback = null) // Enregistre une classe à une méthode de cadre.
Flight::before(string $name, callable $callback) // Ajoute un filtre avant une méthode de cadre.
Flight::after(string $name, callable $callback) // Ajoute un filtre après une méthode de cadre.
Flight::path(string $path) // Ajoute un chemin pour le chargement automatique des classes.
Flight::get(string $key) // Obtient une variable.
Flight::set(string $key, mixed $value) // Définit une variable.
Flight::has(string $key) // Vérifie si une variable est définie.
Flight::clear(array|string $key = []) // Efface une variable.
Flight::init() // Initialise le cadre à ses réglages par défaut.
Flight::app() // Obtient l'instance de l'objet d'application

Méthodes Extensibles

Flight::start() // Lance le cadre.
Flight::stop() // Arrête le cadre et envoie une réponse.
Flight::halt(int $code = 200, string $message = '') // Arrête le cadre avec un code d'état et un message facultatif.
Flight::route(string $pattern, callable $callback, bool $pass_route = false) // Associe un modèle d'URL à un rappel.
Flight::group(string $pattern, callable $callback) // Crée un regroupement pour les URL, le modèle doit être une chaîne de caractères.
Flight::redirect(string $url, int $code) // Redirige vers une autre URL.
Flight::render(string $file, array $data, ?string $key = null) // Rend un fichier de modèle.
Flight::error(Throwable $error) // Envoie une réponse HTTP 500.
Flight::notFound() // Envoie une réponse HTTP 404.
Flight::etag(string $id, string $type = 'string') // Effectue une mise en cache HTTP ETag.
Flight::lastModified(int $time) // Effectue une mise en cache HTTP modifiée récemment.
Flight::json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envoie une réponse JSON.
Flight::jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envoie une réponse JSONP.

Toutes les méthodes personnalisées ajoutées avec map et register peuvent également être filtrées.

Learn/api

Méthodes API du Framework

Flight est conçu pour être facile à utiliser et à comprendre. Voici l'ensemble complet des méthodes du framework. Il se compose de méthodes principales, qui sont des méthodes statiques régulières, et de méthodes extensibles, qui sont des méthodes mappées pouvant être filtrées ou remplacées.

Méthodes Principales

Ces méthodes sont essentielles au framework et ne peuvent pas être écrasées.

Flight::map(string $name, callable $callback, bool $pass_route = false) // Crée une méthode personnalisée pour le framework.
Flight::register(string $name, string $class, array $params = [], ?callable $callback = null) // Enregistre une classe à une méthode du framework.
Flight::unregister(string $name) // Désenregistre une classe d'une méthode du framework.
Flight::before(string $name, callable $callback) // Ajoute un filtre avant une méthode du framework.
Flight::after(string $name, callable $callback) // Ajoute un filtre après une méthode du framework.
Flight::path(string $path) // Ajoute un chemin pour le chargement automatique des classes.
Flight::get(string $key) // Obtiens une variable définie par Flight::set().
Flight::set(string $key, mixed $value) // Définit une variable dans le moteur de Flight.
Flight::has(string $key) // Vérifie si une variable est définie.
Flight::clear(array|string $key = []) // Efface une variable.
Flight::init() // Initialise le framework avec ses paramètres par défaut.
Flight::app() // Obtient l'instance de l'objet d'application
Flight::request() // Obtient l'instance de l'objet de requête
Flight::response() // Obtient l'instance de l'objet de réponse
Flight::router() // Obtient l'instance de l'objet de routage
Flight::view() // Obtient l'instance de l'objet de vue

Méthodes Extensibles

Flight::start() // Démarre le framework.
Flight::stop() // Arrête le framework et envoie une réponse.
Flight::halt(int $code = 200, string $message = '') // Arrête le framework avec un code d'état facultatif et un message.
Flight::route(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Associe un schéma d'URL à un rappel.
Flight::post(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Associe un schéma d'URL de requête POST à un rappel.
Flight::put(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Associe un schéma d'URL de requête PUT à un rappel.
Flight::patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Associe un schéma d'URL de requête PATCH à un rappel.
Flight::delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Associe un schéma d'URL de requête DELETE à un rappel.
Flight::group(string $pattern, callable $callback) // Crée un regroupement pour les URLs, le schéma doit être une chaîne de caractères.
Flight::getUrl(string $name, array $params = []) // Génère une URL basée sur un alias de route.
Flight::redirect(string $url, int $code) // Redirige vers une autre URL.
Flight::download(string $filePath) // Télécharge un fichier.
Flight::render(string $file, array $data, ?string $key = null) // Rend un fichier de modèle.
Flight::error(Throwable $error) // Envoie une réponse HTTP 500.
Flight::notFound() // Envoie une réponse HTTP 404.
Flight::etag(string $id, string $type = 'string') // Effectue la mise en cache HTTP ETag.
Flight::lastModified(int $time) // Effectue la mise en cache HTTP de la dernière modification.
Flight::json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envoie une réponse JSON.
Flight::jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envoie une réponse JSONP.
Flight::jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envoie une réponse JSON et arrête le framework.

Toutes les méthodes personnalisées ajoutées avec map et register peuvent également être filtrées. Pour des exemples sur la façon de mapper ces méthodes, consultez le guide Étendre Flight.

Learn/why_frameworks

Pourquoi un Framework?

Certains programmeurs sont farouchement opposés à l'utilisation de frameworks. Ils soutiennent que les frameworks sont gonflés, lents et difficiles à apprendre. Ils disent que les frameworks sont inutiles et que vous pouvez écrire un meilleur code sans eux. Il y a certainement quelques points valides à faire valoir sur les inconvénients de l'utilisation des frameworks. Cependant, il y a aussi de nombreux avantages à utiliser des frameworks.

Raisons d'utiliser un Framework

Voici quelques raisons pour lesquelles vous pourriez envisager d'utiliser un framework:

Flight est un micro-framework. Cela signifie qu'il est petit et léger. Il ne fournit pas autant de fonctionnalités que des frameworks plus grands comme Laravel ou Symfony. Cependant, il fournit une grande partie des fonctionnalités dont vous avez besoin pour construire des applications web. Il est également facile à apprendre et à utiliser. Cela en fait un bon choix pour construire rapidement et facilement des applications web. Si vous êtes novice en frameworks, Flight est un excellent framework pour débutants. Cela vous aidera à découvrir les avantages de l'utilisation des frameworks sans vous submerger avec trop de complexité. Après avoir acquis de l'expérience avec Flight, il sera plus facile de passer à des frameworks plus complexes comme Laravel ou Symfony, cependant Flight peut toujours vous aider à créer une application robuste et réussie.

Qu'est-ce que le Routage?

Le routage est au cœur du framework Flight, mais qu'est-ce que c'est exactement? Le routage est le processus de prendre une URL et de la faire correspondre à une fonction spécifique dans votre code. C'est ainsi que vous pouvez faire en sorte que votre site Web fasse différentes choses en fonction de l'URL demandée. Par exemple, vous pouvez vouloir afficher le profil d'un utilisateur lorsqu'il visite /utilisateur/1234, mais affichez une liste de tous les utilisateurs lorsqu'ils visitent /utilisateurs. Tout cela se fait grâce au routage.

Cela pourrait fonctionner un peu comme ceci:

Et Pourquoi est-ce Important?

Avoir un routeur centralisé approprié peut réellement rendre votre vie beaucoup plus facile! Il peut être difficile de le voir au début. Voici quelques raisons:

Je suis sûr que vous êtes familier avec la manière scriptée de créer un site web. Vous pourriez avoir un fichier appelé index.php qui comporte une multitude de déclarations if pour vérifier l'URL et puis exécuter une fonction spécifique en fonction de l'URL. C'est une forme de routage, mais ce n'est pas très organisé et cela peut rapidement devenir incontrôlable. Le système de routage de Flight est une méthode beaucoup plus organisée et puissante pour gérer le routage.

Comme ceci ?


// /utilisateur/voir_profil.php?id=1234
if ($_GET['id']) {
    $id = $_GET['id'];
    voirProfilUtilisateur($id);
}

// /utilisateur/editer_profil.php?id=1234
if ($_GET['id']) {
    $id = $_GET['id'];
    editerProfilUtilisateur($id);
}

// etc...

Ou comme cela ?


// index.php
Flight::route('/utilisateur/@id', [ 'ControlleurUtilisateur', 'voirProfilUtilisateur' ]);
Flight::route('/utilisateur/@id/editer', [ 'ControlleurUtilisateur', 'editerProfilUtilisateur' ]);

// Peut-être dans votre app/controllers/ControlleurUtilisateur.php
class ControlleurUtilisateur {
    public function voirProfilUtilisateur($id) {
        // faire quelque chose
    }

    public function editerProfilUtilisateur($id) {
        // faire quelque chose
    }
}

Espérons que vous commencez à voir les avantages d'utiliser un système de routage centralisé. C'est beaucoup plus facile à gérer et à comprendre à long terme!

Demandes et Réponses

Flight fournit un moyen simple et facile de gérer les demandes et les réponses. C'est le cœur de ce qu'un framework web fait. Il prend une demande de navigateur d'utilisateur, la traite, puis envoie une réponse. C'est ainsi que vous pouvez construire des applications web qui font des choses comme afficher un profil d'utilisateur, permettre à un utilisateur de se connecter, ou permettre à un utilisateur de poster un nouveau billet de blog.

Demandes

Une demande est ce que le navigateur de l'utilisateur envoie à votre serveur lorsqu'ils visitent votre site. Cette demande contient des informations sur ce que l'utilisateur veut faire. Par exemple, elle peut contenir des informations sur l'URL que l'utilisateur souhaite visiter, les données que l'utilisateur souhaite envoyer à votre serveur, ou le type de données que l'utilisateur souhaite recevoir de votre serveur. Il est important de savoir qu'une demande est en lecture seule. Vous ne pouvez pas changer la demande, mais vous pouvez la lire.

Flight fournit un moyen simple d'accéder aux informations sur la demande. Vous pouvez accéder aux informations sur la demande en utilisant la méthode Flight::request() Cette méthode renvoie un objet Request qui contient des informations sur la demande. Vous pouvez utiliser cet objet pour accéder aux informations sur la demande, telles que l'URL, la méthode, ou les données que l'utilisateur a envoyées à votre serveur.

Réponses

Une réponse est ce que votre serveur envoie à nouveau au navigateur de l'utilisateur lorsqu'ils visitent votre site. Cette réponse contient des informations sur ce que votre serveur veut faire. Par exemple, elle peut contenir des informations sur le type de données que votre serveur souhaite envoyer à l'utilisateur, le type de données que votre serveur souhaite recevoir de l'utilisateur, ou le type de données que votre serveur souhaite stocker sur l'ordinateur de l'utilisateur.

Flight fournit un moyen simple d'envoyer une réponse au navigateur de l'utilisateur. Vous pouvez envoyer une réponse en utilisant la méthode Flight::response() Cette méthode prend un objet Response en argument et envoie la réponse au navigateur de l'utilisateur. Vous pouvez utiliser cet objet pour envoyer une réponse au navigateur de l'utilisateur, telle que HTML, JSON ou un fichier. Flight vous aide à générer automatiquement certaines parties de la réponse pour faciliter les choses, mais finalement vous avez le contrôle sur ce que vous renvoyez à l'utilisateur.

Learn/httpcaching

Mise en cache HTTP

Flight offre une prise en charge intégrée pour la mise en cache au niveau HTTP. Si la condition de mise en cache est remplie, Flight renverra une réponse HTTP 304 Non modifié. La prochaine fois que
le client demande la même ressource, il sera invité à utiliser sa version mise en cache localement.

Dernière modification

Vous pouvez utiliser la méthode lastModified et transmettre un horodatage UNIX pour définir la date et l'heure à laquelle une page a été modifiée pour la dernière fois. Le client continuera d'utiliser sa mise en cache jusqu'à ce que que la valeur de la dernière modification soit modifiée.

Flight::route('/actualites', function () {
  Flight::lastModified(1234567890);
  echo 'Ce contenu sera mis en cache.';
});

ETag

La mise en cache ETag est similaire à Dernière modification, sauf que vous pouvez spécifier n'importe quel identifiant que vous souhaitez pour la ressource :

Flight::route('/actualites', function () {
  Flight::etag('mon-identifiant-unique');
  echo 'Ce contenu sera mis en cache.';
});

Gardez à l'esprit que l'appel à lastModified ou etag définira et vérifiera à la fois la valeur de la mise en cache. Si la valeur de mise en cache est la même entre les demandes, Flight enverra immédiatement une réponse HTTP 304 et arrêtera le traitement.

Learn/responses

Réponses

Flight aide à générer une partie des en-têtes de réponse pour vous, mais vous avez le contrôle sur ce que vous renvoyez à l'utilisateur. Parfois, vous pouvez accéder directement à l'objet Response, mais la plupart du temps, vous utiliserez l'instance de Flight pour envoyer une réponse.

Envoi d'une réponse de base

Flight utilise ob_start() pour mettre en tampon la sortie. Cela signifie que vous pouvez utiliser echo ou print pour envoyer une réponse à l'utilisateur, et Flight le capturera et le renverra à l'utilisateur avec les en-têtes appropriés.


// Cela enverra "Bonjour, le monde !" au navigateur de l'utilisateur
Flight::route('/', function() {
    echo "Bonjour, le monde !";
});

// HTTP/1.1 200 OK
// Content-Type: text/html
//
// Bonjour, le monde !

En alternative, vous pouvez appeler la méthode write() pour ajouter du contenu au corps également.


// Cela enverra "Bonjour, le monde !" au navigateur de l'utilisateur
Flight::route('/', function() {
    // verbeux, mais fait parfois le travail quand vous en avez besoin
    Flight::response()->write("Bonjour, le monde !");

    // si vous voulez récupérer le corps que vous avez défini à ce stade
    // vous pouvez le faire comme ceci
    $body = Flight::response()->getBody();
});

Codes d'état

Vous pouvez définir le code d'état de la réponse en utilisant la méthode status :

Flight::route('/@id', function($id) {
    if($id == 123) {
        Flight::response()->status(200);
        echo "Bonjour, le monde !";
    } else {
        Flight::response()->status(403);
        echo "Interdit";
    }
});

Si vous voulez obtenir le code d'état actuel, vous pouvez utiliser la méthode status sans arguments :

Flight::response()->status(); // 200

Définition du corps de la réponse

Vous pouvez définir le corps de la réponse en utilisant la méthode write, cependant, si vous faites un echo ou un print, cela sera capturé et envoyé comme corps de réponse via le tampon de sortie.

Flight::route('/', function() {
    Flight::response()->write("Bonjour, le monde !");
});

// identique à

Flight::route('/', function() {
    echo "Bonjour, le monde !";
});

Effacer le corps de la réponse

Si vous voulez effacer le corps de la réponse, vous pouvez utiliser la méthode clearBody :

Flight::route('/', function() {
    if($someCondition) {
        Flight::response()->write("Bonjour, le monde !");
    } else {
        Flight::response()->clearBody();
    }
});

Exécution d'un rappel sur le corps de la réponse

Vous pouvez exécuter un rappel sur le corps de la réponse en utilisant la méthode addResponseBodyCallback :

Flight::route('/utilisateurs', function() {
    $db = Flight::db();
    $utilisateurs = $db->fetchAll("SELECT * FROM utilisateurs");
    Flight::render('tableau_utilisateurs', ['utilisateurs' => $utilisateurs]);
});

// Cela compressera toutes les réponses pour n'importe quelle route
Flight::response()->addResponseBodyCallback(function($body) {
    return gzencode($body, 9);
});

Vous pouvez ajouter plusieurs rappels et ils seront exécutés dans l'ordre où ils ont été ajoutés. Étant donné que cela peut accepter n'importe quelle callable, cela peut accepter un tableau de classe [ $class, 'method' ], une fermeture $strReplace = function($body) { str_replace('salut', 'bonjour', $body); };, ou un nom de fonction 'minifier' si vous aviez une fonction pour minifier votre code HTML par exemple.

Remarque : Les rappels de route ne fonctionneront pas si vous utilisez l'option de configuration flight.v2.output_buffering.

Rappel de route spécifique

Si vous voulez que cela s'applique uniquement à une route spécifique, vous pouvez ajouter le rappel dans la route elle-même :

Flight::route('/utilisateurs', function() {
    $db = Flight::db();
    $utilisateurs = $db->fetchAll("SELECT * FROM utilisateurs");
    Flight::render('tableau_utilisateurs', ['utilisateurs' => $utilisateurs]);

    // Cela compressera uniquement la réponse pour cette route
    Flight::response()->addResponseBodyCallback(function($body) {
        return gzencode($body, 9);
    });
});

Option Middleware

Vous pouvez également utiliser un middleware pour appliquer le rappel à toutes les routes via le middleware :

// Middleware de Minification.php
class MiddlewareMinification {
    public function before() {
        // Appliquer le rappel ici sur l'objet response().
        Flight::response()->addResponseBodyCallback(function($body) {
            return $this->minify($body);
        });
    }

    protected function minify(string $body): string {
        // minifier le corps d'une manière ou d'une autre
        return $body;
    }
}

// index.php
Flight::group('/utilisateurs', function() {
    Flight::route('', function() { /* ... */ });
    Flight::route('/@id', function($id) { /* ... */ });
}, [ new MiddlewareMinification() ]);

Définition d'un en-tête de réponse

Vous pouvez définir un en-tête tel que le type de contenu de la réponse en utilisant la méthode header :


// Cela enverra "Bonjour, le monde !" au navigateur de l'utilisateur en texte brut
Flight::route('/', function() {
    Flight::response()->header('Content-Type', 'text/plain');
    // ou
    Flight::response()->setHeader('Content-Type', 'text/plain');
    echo "Bonjour, le monde !";
});

JSON

Flight prend en charge l'envoi de réponses JSON et JSONP. Pour envoyer une réponse JSON vous transmettez des données à encoder en JSON :

Flight::json(['id' => 123]);

JSON avec code d'état

Vous pouvez également transmettre un code d'état en tant que deuxième argument :

Flight::json(['id' => 123], 201);

JSON avec formatage agréable

Vous pouvez également transmettre un argument à la dernière position pour activer le formatage agréable :

Flight::json(['id' => 123], 200, true, 'utf-8', JSON_PRETTY_PRINT);

Si vous modifiez les options transmises à Flight::json() et que vous voulez une syntaxe plus simple, vous pouvez simplement remapper la méthode JSON :

Flight::map('json', function($data, $code = 200, $options = 0) {
    Flight::_json($data, $code, true, 'utf-8', $options);
}

// Et maintenant cela peut être utilisé comme ceci
Flight::json(['id' => 123], 200, JSON_PRETTY_PRINT);

JSON et Arrêt de l'exécution (v3.10.0)

Si vous voulez envoyer une réponse JSON et arrêter l'exécution, vous pouvez utiliser la méthode jsonHalt. Ceci est utile pour les cas où vous vérifiez peut-être un type d'autorisation et si l'utilisateur n'est pas autorisé, vous pouvez envoyer immédiatement une réponse JSON, effacer le contenu du corps existant et arrêter l'exécution.

Flight::route('/utilisateurs', function() {
    $autorise = certaineVerificationDautorisation();
    // Vérifier si l'utilisateur est autorisé
    if($autorise === false) {
        Flight::jsonHalt(['erreur' => 'Non autorisé'], 401);
    }

    // Continuer avec le reste de la route
});

Avant v3.10.0, vous auriez dû faire quelque chose comme ceci :

Flight::route('/utilisateurs', function() {
    $autorise = certaineVerificationDautorisation();
    // Vérifier si l'utilisateur est autorisé
    if($autorise === false) {
        Flight::halt(401, json_encode(['error' => 'Non autorisé']));
    }

    // Continuer avec le reste de la route
});

JSONP

Pour les requêtes JSONP, vous pouvez éventuellement transmettre le nom du paramètre de requête que vous utilisez pour définir votre fonction de rappel :

Flight::jsonp(['id' => 123], 'q');

Ainsi, lors d'une requête GET en utilisant ?q=ma_fonction, vous devriez recevoir la sortie :

ma_fonction({"id":123});

Si vous ne transmettez pas de nom de paramètre de requête, il sera par défaut à jsonp.

Rediriger vers une autre URL

Vous pouvez rediriger la demande actuelle en utilisant la méthode redirect() et en transmettant une nouvelle URL :

Flight::redirect('/nouvel/emplacement');

Par défaut, Flight envoie un code d'état HTTP 303 ("See Other"). Vous pouvez éventuellement définir un code personnalisé :

Flight::redirect('/nouvel/emplacement', 401);

Arrêt

Vous pouvez arrêter le framework à tout moment en appelant la méthode halt :

Flight::halt();

Vous pouvez également spécifier un code d'état HTTP facultatif et un message :

Flight::halt(200, 'Reviens tout de suite...');

Appeler halt va supprimer tout le contenu de réponse jusqu'à ce point. Si vous voulez arrêter le framework et envoyer le contenu de réponse actuel, utilisez la méthode stop :

Flight::stop();

Effacer les données de réponse

Vous pouvez effacer le corps de la réponse et les en-têtes en utilisant la méthode clear(). Cela effacera tous les en-têtes assignés à la réponse, effacera le corps de la réponse, et définira le code d'état à 200.

Flight::response()->clear();

Effacer uniquement le corps de la réponse

Si vous voulez uniquement effacer le corps de la réponse, vous pouvez utiliser la méthode clearBody() :

// Cela conservera toujours tous les en-têtes définis sur l'objet response().
Flight::response()->clearBody();

Mise en cache HTTP

Flight offre une prise en charge intégrée de la mise en cache au niveau HTTP. Si la condition de mise en cache est remplie, Flight renverra une réponse HTTP 304 Not Modified. La prochaine fois que le client demandera la même ressource, il sera invité à utiliser sa version mise en cache localement.

Mise en cache au niveau de la route

Si vous voulez mettre en cache toute votre réponse, vous pouvez utiliser la méthode cache() et transmettre le temps à mettre en cache.


// Cela mettra en cache la réponse pendant 5 minutes
Flight::route('/actualites', function () {
  Flight::response()->cache(time() + 300);
  echo 'Ce contenu sera mis en cache.';
});

// Alternativement, vous pouvez utiliser une chaîne que vous transmettriez
// à la méthode strtotime()
Flight::route('/actualites', function () {
  Flight::response()->cache('+5 minutes');
  echo 'Ce contenu sera mis en cache.';
});

Modifié pour la dernière fois

Vous pouvez utiliser la méthode lastModified et transmettre un horodatage UNIX pour définir la date et l'heure à laquelle une page a été modifiée pour la dernière fois. Le client continuera d'utiliser sa mise en cache jusqu'à ce que la valeur de la dernière modification soit modifiée.

Flight::route('/actualites', function () {
  Flight::lastModified(1234567890);
  echo 'Ce contenu sera mis en cache.';
});

ETag

La mise en cache ETag est similaire à Last-Modified, sauf que vous pouvez spécifier n'importe quel identifiant que vous souhaitez pour la ressource :

Flight::route('/actualites', function () {
  Flight::etag('mon-identifiant-unique');
  echo 'Ce contenu sera mis en cache.';
});

Gardez à l'esprit que l'appel à lastModified ou etag va à la fois définir et vérifier la valeur de la mise en cache. Si la valeur de mise en cache est la même entre les requêtes, Flight enverra immédiatement une réponse HTTP 304 et arrêtera le traitement.

Télécharger un fichier

Il y a une méthode d'aide pour télécharger un fichier. Vous pouvez utiliser la méthode download et transmettre le chemin.

Flight::route('/telechargement', function () {
  Flight::download('/chemin/vers/fichier.txt');
});

Learn/frameworkinstance

Instance de Framework

Au lieu d'exécuter Flight en tant que classe statique globale, vous pouvez éventuellement l'exécuter en tant qu'instance d'objet.

require 'flight/autoload.php';

$app = Flight::app();

$app->route('/', function () {
  echo 'hello world!';
});

$app->start();

Donc, au lieu d'appeler la méthode statique, vous appelleriez la méthode d'instance avec le même nom sur l'objet Engine.

Learn/redirects

Redirection

Vous pouvez rediriger la requête actuelle en utilisant la méthode redirect et en passant une nouvelle URL :

Flight::redirect('/nouvel/emplacement');

Par défaut, Flight envoie un code d'état HTTP 303. Vous pouvez éventuellement définir un code personnalisé :

Flight::redirect('/nouvel/emplacement', 401);

Learn/views

Vues

Flight fournit par défaut quelques fonctionnalités de base de templating. Pour afficher un template de vue, appelez la méthode render avec le nom du fichier template et des données de template optionnelles :

Flight::render('hello.php', ['name' => 'Bob']);

Les données de template que vous transmettez sont automatiquement injectées dans le template et peuvent être référencées comme une variable locale. Les fichiers de template sont simplement des fichiers PHP. Si le contenu du fichier template hello.php est :

Hello, <?= $name ?>!

La sortie serait :

Hello, Bob!

Vous pouvez également définir manuellement des variables de vue en utilisant la méthode set :

Flight::view()->set('name', 'Bob');

La variable name est désormais disponible dans toutes vos vues. Vous pouvez simplement faire :

Flight::render('hello');

Notez que lors de la spécification du nom du template dans la méthode render, vous pouvez omettre l'extension .php.

Par défaut, Flight recherchera un répertoire views pour les fichiers de template. Vous pouvez définir un chemin alternatif pour vos templates en configurant ce qui suit :

Flight::set('flight.views.path', '/chemin/vers/views');

Mises en page

Il est courant pour les sites web d'avoir un seul fichier de template de mise en page avec un contenu interchangeable. Pour afficher le contenu à utiliser dans une mise en page, vous pouvez transmettre un paramètre optionnel à la méthode render.

Flight::render('header', ['heading' => 'Hello'], 'headerContent');
Flight::render('body', ['body' => 'World'], 'bodyContent');

Votre vue aura ensuite des variables enregistrées appelées headerContent et bodyContent. Vous pouvez ensuite afficher votre mise en page en faisant :

Flight::render('layout', ['title' => 'Page d\'accueil']);

Si les fichiers de template ressemblent à ceci :

header.php :

<h1><?= $heading ?></h1>

body.php :

<div><?= $body ?></div>

layout.php :

<html>
  <head>
    <title><?= $title ?></title>
  </head>
  <body>
    <?= $headerContent ?>
    <?= $bodyContent ?>
  </body>
</html>

La sortie serait :

<html>
  <head>
    <title>Page d'accueil</title>
  </head>
  <body>
    <h1>Hello</h1>
    <div>World</div>
  </body>
</html>

Vues Personnalisées

Flight vous permet de remplacer simplement le moteur de vue par défaut en enregistrant votre propre classe de vue. Voici comment vous utiliseriez le moteur de template Smarty pour vos vues :

// Charger la bibliothèque Smarty
require './Smarty/libs/Smarty.class.php';

// Enregistrer Smarty en tant que classe de vue
// Transmettre également une fonction de rappel pour configurer Smarty au chargement
Flight::register('view', Smarty::class, [], function (Smarty $smarty) {
  $smarty->setTemplateDir('./templates/');
  $smarty->setCompileDir('./templates_c/');
  $smarty->setConfigDir('./config/');
  $smarty->setCacheDir('./cache/');
});

// Assigner des données de template
Flight::view()->assign('name', 'Bob');

// Afficher le template
Flight::view()->display('hello.tpl');

Pour plus de complétude, vous devriez également remplacer la méthode de rendu par défaut de Flight :

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

Learn/templates

Vues HTML et Modèles

Flight fournit par défaut une certaine fonctionnalité de templating de base.

Si vous avez besoin de besoins de templating plus complexes, consultez les exemples Smarty et Latte dans la section Vues personnalisées.

Moteur de vue par défaut

Pour afficher un modèle de vue, appelez la méthode render avec le nom du fichier modèle et des données de modèle optionnelles :

Flight::render('hello.php', ['name' => 'Bob']);

Les données de modèle que vous transmettez sont automatiquement injectées dans le modèle et peuvent être référencées comme une variable locale. Les fichiers de modèle sont simplement des fichiers PHP. Si le contenu du fichier modèle hello.php est le suivant :

Bonjour, <?= $name ?>!

La sortie serait :

Bonjour, Bob!

Vous pouvez également définir manuellement des variables de vue en utilisant la méthode set :

Flight::view()->set('name', 'Bob');

La variable name est maintenant disponible dans toutes vos vues. Vous pouvez simplement faire :

Flight::render('hello');

Notez que lors de la spécification du nom du modèle dans la méthode render, vous pouvez omettre l'extension .php.

Par défaut, Flight recherchera un répertoire views pour les fichiers de modèle. Vous pouvez définir un chemin alternatif pour vos modèles en définissant la configuration suivante :

Flight::set('flight.views.path', '/chemin/vers/vues');

Mises en page

Il est courant que les sites web aient un seul fichier de modèle de mise en page avec un contenu changeant. Pour afficher le contenu à utiliser dans une mise en page, vous pouvez transmettre un paramètre optionnel à la méthode render.

Flight::render('header', ['heading' => 'Bonjour'], 'headerContent');
Flight::render('body', ['body' => 'Monde'], 'bodyContent');

Votre vue aura alors des variables enregistrées appelées headerContent et bodyContent. Vous pouvez ensuite afficher votre mise en page en faisant :

Flight::render('layout', ['title' => 'Page d'accueil']);

Si les fichiers de modèle ressemblent à ceci :

header.php :

<h1><?= $heading ?></h1>

body.php :

<div><?= $body ?></div>

layout.php :

<html>
  <head>
    <title><?= $title ?></title>
  </head>
  <body>
    <?= $headerContent ?>
    <?= $bodyContent ?>
  </body>
</html>

La sortie serait :

<html>
  <head>
    <title>Page d'accueil</title>
  </head>
  <body>
    <h1>Bonjour</h1>
    <div>Monde</div>
  </body>
</html>

Moteurs de vue personnalisés

Flight vous permet de remplacer simplement le moteur de vue par défaut en enregistrant votre propre classe de vue.

Smarty

Voici comment vous utiliseriez le Smarty moteur de template pour vos vues :

// Charger la bibliothèque Smarty
require './Smarty/libs/Smarty.class.php';

// Enregistrer Smarty comme classe de vue
// Passez également une fonction de rappel pour configurer Smarty lors du chargement
Flight::register('view', Smarty::class, [], function (Smarty $smarty) {
  $smarty->setTemplateDir('./templates/');
  $smarty->setCompileDir('./templates_c/');
  $smarty->setConfigDir('./config/');
});

// Assigner des données de modèle
Flight::view()->assign('name', 'Bob');

// Afficher le modèle
Flight::view()->display('hello.tpl');

Pour plus d'exhaustivité, vous devriez également remplacer la méthode render par défaut de Flight :

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

Latte

Voici comment vous utiliseriez le Latte moteur de template pour vos vues :


// Enregistrer Latte comme classe de vue
// Passez également une fonction de rappel pour configurer Latte lors du chargement
Flight::register('view', Latte\Engine::class, [], function (Latte\Engine $latte) {
  // C'est ici que Latte mettra en cache vos modèles pour accélérer les choses
    // Une chose intéressante à propos de Latte est qu'il rafraîchit automatiquement votre
    // mémoire cache lorsque vous apportez des modifications à vos modèles !
    $latte->setTempDirectory(__DIR__ . '/../cache/');

    // Indiquez à Latte où se trouvera le répertoire racine de vos vues.
    $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../views/'));
});

// Et enveloppez-le pour pouvoir utiliser correctement Flight::render()
Flight::map('render', function(string $template, array $data): void {
  // C'est comme $latte_engine->render($template, $data);
  echo Flight::view()->render($template, $data);
});

Learn/flight_vs_fat_free

Vol / FF (F3)

Qu'est-ce que Fat-Free?

Fat-Free (affectueusement connu sous le nom de F3) est un micro-framework PHP puissant et facile à utiliser conçu pour vous aider à construire des applications web dynamiques et robustes - rapidement!

Vol se compare à Fat-Free de nombreuses manières et est probablement le cousin le plus proche en termes de fonctionnalités et de simplicité. Fat-Free a beaucoup de fonctionnalités que Vol n'a pas, mais il a aussi beaucoup de fonctionnalités que Flight a. Fat-Free commence à montrer son âge et n'est pas aussi populaire qu'auparavant.

Les mises à jour deviennent moins fréquentes et la communauté n'est plus aussi active qu'auparavant. Le code est assez simple, mais parfois le manque de discipline syntaxique peut le rendre difficile à lire et à comprendre. Il fonctionne pour PHP 8.3, mais le code lui-même ressemble toujours à s'il vivait dans PHP 5.3.

Avantages par rapport à Vol

Inconvénients par rapport à Vol

Learn/extending

Extension

Flight est conçu pour être un framework extensible. Le framework est livré avec un ensemble de méthodes et de composants par défaut, mais vous permet de mapper vos propres méthodes, d'enregistrer vos propres classes, voire de remplacer des classes et des méthodes existantes.

Si vous recherchez un DIC (Conteneur d'injection de dépendances), passez à la page du Conteneur d'injection de dépendances .

Mappage des méthodes

Pour mapper votre propre méthode personnalisée, utilisez la fonction map :

// Mapper votre méthode
Flight::map('hello', function (string $name) {
  echo "bonjour $name!";
});

// Appeler votre méthode personnalisée
Flight::hello('Bob');
');

Bien qu'il soit possible de créer des méthodes personnalisées simples, il est recommandé de simplement créer des fonctions standard en PHP. Cela a la saisie semi-automatique dans les IDE et est plus facile à lire. L'équivalent du code ci-dessus serait :

function hello(string $name) {
  echo "bonjour $name!";
}

hello('Bob');

Cela est plus couramment utilisé lorsque vous devez transmettre des variables à votre méthode pour obtenir une valeur attendue. Utiliser la méthode register() comme ci-dessous est plus destiné à transmettre une configuration et ensuite appeler votre classe préconfigurée.

Enregistrement des classes

Pour enregistrer votre propre classe et la configurer, utilisez la fonction register :

// Enregistrer votre classe
Flight::register('user', User::class);

// Obtenir une instance de votre classe
$user = Flight::user();

La méthode d'enregistrement vous permet également de transmettre des paramètres au constructeur de votre classe. Ainsi, lorsque vous chargez votre classe personnalisée, elle sera pré-initialisée. Vous pouvez définir les paramètres du constructeur en passant un tableau supplémentaire. Voici un exemple de chargement d'une connexion de base de données :

// Enregistrer la classe avec des paramètres du constructeur
Flight::register('db', PDO::class, ['mysql:host=localhost;dbname=test', 'user', 'pass']);

// Obtenir une instance de votre classe
// Cela va créer un objet avec les paramètres définis
//
// new PDO('mysql:host=localhost;dbname=test','user','pass');
//
$db = Flight::db();

// et si vous en avez besoin plus tard dans votre code, vous appelez simplement la même méthode à nouveau
class SomeController {
  public function __construct() {
    $this->db = Flight::db();
  }
}

Si vous passez en paramètre un callback supplémentaire, il sera exécuté immédiatement après la construction de la classe. Cela vous permet d'effectuer toute procédure de configuration pour votre nouvel objet. La fonction de rappel prend un paramètre, une instance du nouvel objet.

// Le callback recevra l'objet qui a été construit
Flight::register(
  'db',
  PDO::class,
  ['mysql:host=localhost;dbname=test', 'user', 'pass'],
  function (PDO $db) {
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
);

Par défaut, chaque fois que vous chargez votre classe, vous obtiendrez une instance partagée. Pour obtenir une nouvelle instance d'une classe, passez simplement false en tant que paramètre :

// Instance partagée de la classe
$shared = Flight::db();

// Nouvelle instance de la classe
$new = Flight::db(false);

Gardez à l'esprit que les méthodes mappées ont la priorité sur les classes enregistrées. Si vous déclarez les deux en utilisant le même nom, seule la méthode mappée sera invoquée.

Remplacement des méthodes du framework

Flight vous permet de remplacer sa fonctionnalité par défaut pour répondre à vos propres besoins, sans avoir à modifier le code. Vous pouvez afficher toutes les méthodes que vous pouvez remplacer ici.

Par exemple, lorsque Flight ne peut pas faire correspondre une URL à une route, il invoque la méthode notFound qui envoie une réponse générique HTTP 404. Vous pouvez remplacer ce comportement en utilisant la méthode map :

Flight::map('notFound', function() {
  // Afficher une page d'erreur personnalisée 404
  include 'errors/404.html';
});

Flight vous permet également de remplacer les composants principaux du framework. Par exemple, vous pouvez remplacer la classe Routeur par défaut par votre propre classe personnalisée :

// Enregistrer votre classe personnalisée
Flight::register('router', MyRouter::class);

// Lorsque Flight charge l'instance du Routeur, il chargera votre classe
$myrouter = Flight::router();

Cependant les méthodes du framework comme map et register ne peuvent pas être remplacées. Vous obtiendrez une erreur si vous essayez de le faire.

Learn/json

JSON

Flight fournit un support pour l'envoi de réponses JSON et JSONP. Pour envoyer une réponse JSON, vous transmettez des données à encoder en JSON:

Flight::json(['id' => 123]);

Pour les requêtes JSONP, vous pouvez éventuellement spécifier le nom du paramètre de requête que vous utilisez pour définir votre fonction de rappel:

Flight::jsonp(['id' => 123], 'q');

Ainsi, lors de l'envoi d'une requête GET en utilisant ?q=my_func, vous devriez recevoir la sortie:

my_func({"id":123});

Si vous ne spécifiez pas de nom de paramètre de requête, il sera par défaut jsonp.

Learn/flight_vs_slim

Vol Flight vs Slim

Qu'est-ce que Slim?

Slim est un micro-framework PHP qui vous aide à écrire rapidement des applications web et des APIs simples mais puissantes.

Beaucoup des inspirations pour certaines fonctionnalités de la v3 de Vol sont en fait venues de Slim. Regrouper les routes et exécuter des middlewares dans un ordre spécifique sont deux fonctionnalités qui ont été inspirées par Slim. Slim v3 est sorti orienté vers la simplicité, mais il y a eu des avis divergents concernant la v4.

Avantages par rapport à Vol

Inconvénients par rapport à Vol

Learn/autoloading

Chargement automatique

Le chargement automatique est un concept en PHP où vous spécifiez un répertoire ou des répertoires à partir desquels charger des classes. Cela est bien plus bénéfique que d'utiliser require ou include pour charger des classes. C'est également une exigence pour utiliser des packages Composer.

Par défaut, toute classe Flight est chargée automatiquement pour vous grâce à composer. Cependant, si vous voulez charger automatiquement vos propres classes, vous pouvez utiliser la méthode Flight::path() pour spécifier un répertoire à partir duquel charger des classes.

Exemple de base

Supposons que nous avons une structure d'arborescence de répertoires comme suit :

# Chemin d'exemple
/home/user/project/my-flight-project/
├── app
│   ├── cache
│   ├── config
│   ├── controllers - contient les contrôleurs pour ce projet
│   ├── translations
│   ├── UTILS - contient des classes uniquement pour cette application (tout est en majuscules à des fins d'exemple ultérieur)
│   └── views
└── public
    └── css
    └── js
    └── index.php

Vous avez peut-être remarqué que c'est la même structure de fichiers que ce site de documentation.

Vous pouvez spécifier chaque répertoire à charger à partir de cette façon :

/**
 * public/index.php
 */

// Ajouter un chemin à l'autoload
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');

/**
 * app/controllers/MyController.php
 */

// Pas de nécessité d'espace de noms

// Toutes les classes chargées automatiquement sont recommandées d'être en Pascal Case (chaque mot en majuscule, pas d'espaces)
// À partir de la version 3.7.2, vous pouvez utiliser Pascal_Snake_Case pour vos noms de classes en exécutant Loader::setV2ClassLoading(false);
class MyController {

    public function index() {
        // faire quelque chose
    }
}

Espaces de noms

Si vous avez des espaces de noms, l'implémentation en devient en fait très facile. Vous devriez utiliser la méthode Flight::path() pour spécifier le répertoire racine (pas le document root ou le dossier public/) de votre application.

/**
 * public/index.php
 */

// Ajouter un chemin à l'autoload
Flight::path(__DIR__.'/../');

Maintenant, voici à quoi pourrait ressembler votre contrôleur. Regardez l'exemple ci-dessous, mais prêtez attention aux commentaires pour des informations importantes.

/**
 * app/controllers/MyController.php
 */

// les espaces de noms sont requis
// les espaces de noms doivent suivre la même structure de répertoire
// les espaces de noms doivent suivre la même casse que la structure de répertoire
// les espaces de noms et les répertoires ne peuvent pas avoir de tirets bas (à moins que Loader::setV2ClassLoading(false) ne soit défini)
namespace app\controllers;

// Toutes les classes chargées automatiquement sont recommandées d'être en Pascal Case (chaque mot en majuscule, pas d'espaces)
// À partir de la version 3.7.2, vous pouvez utiliser Pascal_Snake_Case pour vos noms de classes en exécutant Loader::setV2ClassLoading(false);
class MyController {

    public function index() {
        // faire quelque chose
    }
}

Et si vous vouliez charger automatiquement une classe dans votre répertoire utils, vous feriez essentiellement la même chose :

/**
 * app/UTILS/ArrayHelperUtil.php
 */

// l'espace de noms doit correspondre à la structure du répertoire et à la casse (notez que le répertoire UTILS est tout en majuscules
//     comme dans l'arborescence de fichiers ci-dessus)
namespace app\UTILS;

class ArrayHelperUtil {

    public function changeArrayCase(array $array) {
        // faire quelque chose
    }
}

Tirets bas dans les noms de classes

À partir de la version 3.7.2, vous pouvez utiliser Pascal_Snake_Case pour vos noms de classes en exécutant Loader::setV2ClassLoading(false);. Cela vous permettra d'utiliser des tirets bas dans vos noms de classes. Ce n'est pas recommandé, mais c'est disponible pour ceux qui en ont besoin.

/**
 * public/index.php
 */

// Ajouter un chemin à l'autoload
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');
Loader::setV2ClassLoading(false);

/**
 * app/controllers/My_Controller.php
 */

// Pas de nécessité d'espace de noms

class My_Controller {

    public function index() {
        // faire quelque chose
    }
}

Learn/troubleshooting

Dépannage

Cette page vous aidera à résoudre les problèmes courants que vous pourriez rencontrer lors de l'utilisation de Flight.

Problèmes Courants

404 Non Trouvé ou Comportement de Route Inattendu

Si vous voyez une erreur 404 Non Trouvé (mais vous jurez sur votre vie qu'elle est vraiment là et ce n'est pas une faute de frappe), en fait il pourrait s'agir d'un problème avec le fait de renvoyer une valeur dans votre point de terminaison de route au lieu de simplement l'afficher. La raison de ceci est intentionnelle mais pourrait surprendre certains développeurs.


Flight::route('/bonjour', function(){
    // Cela pourrait provoquer une erreur 404 Non Trouvée
    return 'Bonjour le monde';
});

// Ce que vous voulez probablement
Flight::route('/bonjour', function(){
    echo 'Bonjour le monde';
});

La raison de ceci est due à un mécanisme spécial intégré dans le routeur qui gère la sortie retournée comme un signal pour "passer à la route suivante". Vous pouvez voir le comportement documenté dans la section Routing.

Classe Non Trouvée (chargement automatique ne fonctionne pas)

Il pourrait y avoir plusieurs raisons pour que cela ne se produise pas. Voici quelques exemples, mais assurez-vous également de consulter la section sur le chargement automatique.

Nom de Fichier Incorrect

Le plus courant est que le nom de la classe ne correspond pas au nom du fichier.

Si vous avez une classe nommée MaClasse, alors le fichier devrait être nommé MaClasse.php. Si vous avez une classe nommée MaClasse et que le fichier est nommé maclasse.php, alors le chargeur automatique ne pourra pas le trouver.

Espace de Noms Incorrect

Si vous utilisez des espaces de noms, alors l'espace de noms doit correspondre à la structure des répertoires.

// code

// si votre MyController est dans le répertoire app/controllers et qu'il est namespaced
// cela ne fonctionnera pas.
Flight::route('/bonjour', 'MyController->bonjour');

// vous devrez choisir l'une de ces options
Flight::route('/bonjour', 'app\controllers\MyController->bonjour');
// ou si vous avez une déclaration use en haut

use app\controllers\MyController;

Flight::route('/bonjour', [ MyController::class, 'bonjour' ]);
// peut également être écrit
Flight::route('/bonjour', MyController::class.'->bonjour');
// aussi...
Flight::route('/bonjour', [ 'app\controllers\MyController', 'bonjour' ]);

path() non défini

Dans l'application squelette, cela est défini à l'intérieur du fichier config.php, mais pour que vos classes soient trouvées, vous devez vous assurer que la méthode path() est définie (probablement à la racine de votre répertoire) avant d'essayer de l'utiliser.


// Ajouter un chemin à l'autoload
Flight::path(__DIR__.'/../');

Install

Installation

Téléchargement des fichiers.

Si vous utilisez Composer, vous pouvez exécuter la commande suivante :

composer require flightphp/core

OU vous pouvez télécharger les fichiers directement et les extraire vers votre répertoire web.

Configuration de votre serveur Web.

Apache

Pour Apache, modifiez votre fichier .htaccess avec ce qui suit :

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

Remarque : Si vous devez utiliser flight dans un sous-répertoire, ajoutez la ligne RewriteBase /sous-repertoire/ juste après RewriteEngine On.

Remarque : Si vous souhaitez protéger tous les fichiers serveur, comme un fichier de base de données ou d'environnement. Ajoutez ceci à votre fichier .htaccess :

RewriteEngine On
RewriteRule ^(.*)$ index.php

Nginx

Pour Nginx, ajoutez ce qui suit à votre déclaration du serveur :

serveur {
  location / {
    try_files $uri $uri/ /index.php;
  }
}

Créez votre fichier index.php.

<?php

// Si vous utilisez Composer, exigez l'autoload.
require 'vendor/autoload.php';
// si vous n'utilisez pas Composer, chargez le framework directement
// require 'flight/Flight.php';

// Ensuite, définissez une route et attribuez une fonction pour gérer la requête.
Flight::route('/', function () {
  echo 'hello world!';
});

// Enfin, démarrez le framework.
Flight::start();

License

La Licence MIT (MIT)
=====================

Droits d'auteur © `2024` `@mikecao, @n0nag0n`

La permission est accordée, gratuitement, à toute personne
obtenant une copie de ce logiciel et de la documentation associée
(fichiers du “Logiciel”), d'utiliser le Logiciel sans aucune
restriction, y compris, sans s'y limiter, les droits d'utiliser,
de copier, de modifier, de fusionner, de publier, de distribuer,
de concéder sous licence et/ou de vendre des copies du Logiciel,
et de permettre aux personnes auxquelles le Logiciel est fourni
de le faire, sous réserve des conditions suivantes :

L'avis de droit d'auteur ci-dessus et le présent avis de
permission doivent être inclus dans toutes les copies ou les
parties substantielles du Logiciel.

LE LOGICIEL EST FOURNI “TEL QUEL”, SANS GARANTIE D'AUCUNE
SORTES, EXPRESSE OU IMPLICITE, Y COMPRIS, MAIS SANS S'Y LIMITER,
LES GARANTIES DE QUALITÉ MARCHANDE, D'ADÉQUATION À UN USAGE
PARTICULIER ET D'ABSENCE DE CONTREFAÇON. EN AUCUN CAS, LES
AUTEURS OU LES TITULAIRES DES DROITS D'AUTEUR NE SAURAIENT ÊTRE
TENUS RESPONSABLES DE TOUTE RÉCLAMATION, DOMMAGE OU AUTRE
RESPONSABILITÉ, QUE CE SOIT DANS UNE ACTION DE CONTRAT, DE TORT
OU AUTRE, DÉCOULANT DE, HORS DE OU EN RELATION AVEC LE LOGICIEL
OU L'UTILISATION OU D'AUTRES TRANSACTIONS DANS LE LOGICIEL.

About

Qu'est-ce que Flight ?

Flight est un framework rapide, simple et extensible pour PHP. Il est assez polyvalent et peut être utilisé pour construire n'importe quel type d'application web. Il est conçu avec la simplicité à l'esprit et est écrit d'une manière qui est facile à comprendre et à utiliser.

Flight est un excellent framework pour les débutants qui découvrent PHP et qui veulent apprendre à construire des applications web. C'est aussi un excellent framework pour les développeurs expérimentés qui veulent plus de contrôle sur leurs applications web. Il est conçu pour construire facilement une API RESTful, une simple application web ou une application web complexe.

Démarrage rapide

<?php

// si installé avec composer
require 'vendor/autoload.php';
// ou si installé manuellement par fichier zip
// require 'flight/Flight.php';

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

Flight::route('/json', function() {
  Flight::json(['hello' => 'world']);
});

Flight::start();

Assez simple, n'est-ce pas ? Apprenez-en plus sur Flight dans la documentation !

Application squelette/modèle

Il existe une application exemple qui peut vous aider à démarrer avec le framework Flight. Rendez-vous sur flightphp/skeleton pour des instructions sur la façon de commencer ! Vous pouvez également visiter la page des exemples pour trouver de l'inspiration sur certaines des choses que vous pouvez réaliser avec Flight.

Communauté

Nous sommes sur Matrix Chat avec nous à #flight-php-framework:matrix.org.

Contribution

Il y a deux façons de contribuer à Flight :

  1. Vous pouvez contribuer au framework de base en visitant le dépôt principal.
  2. Vous pouvez contribuer à la documentation. Ce site de documentation est hébergé sur Github. Si vous remarquez une erreur ou souhaitez améliorer quelque chose, n'hésitez pas à le corriger et à soumettre une demande de tirage ! Nous essayons de rester à jour, mais les mises à jour et les traductions de langue sont les bienvenues.

Prérequis

Flight nécessite PHP 7.4 ou supérieur.

Remarque : PHP 7.4 est pris en charge car au moment de la rédaction (2024), PHP 7.4 est la version par défaut pour certaines distributions LTS de Linux. Forcer un passage à PHP >8 causerait beaucoup de maux de tête pour ces utilisateurs. Le framework prend également en charge PHP >8.

Licence

Flight est publié sous la licence MIT.

Awesome-plugins/php_cookie

Cookies

overclokk/cookie est une bibliothèque simple pour gérer les cookies au sein de votre application.

Installation

L'installation est simple avec composer.

composer require overclokk/cookie

Utilisation

L'utilisation est aussi simple que d'enregistrer une nouvelle méthode sur la classe Flight.


use Overclokk\Cookie\Cookie;

/*
 * Définissez dans votre fichier bootstrap ou public/index.php
 */

Flight::register('cookie', Cookie::class);

/**
 * ExampleController.php
 */

class ExampleController {
    public function login() {
        // Définir un cookie

        // vous voudrez que ce soit faux pour obtenir une nouvelle instance
        // utilisez le commentaire ci-dessous si vous souhaitez l'autocomplétion
        /** @var \Overclokk\Cookie\Cookie $cookie */
        $cookie = Flight::cookie(false);
        $cookie->set(
            'stay_logged_in', // nom du cookie
            '1', // la valeur que vous souhaitez définir
            86400, // nombre de secondes pendant lesquelles le cookie doit durer
            '/', // chemin où le cookie sera disponible
            'example.com', // domaine où le cookie sera disponible
            true, // le cookie ne sera transmis que sur une connexion sécurisée HTTPS
            true // le cookie ne sera disponible que via le protocole HTTP
        );

        // éventuellement, si vous voulez conserver les valeurs par défaut
        // et avoir un moyen rapide de définir un cookie pour une longue durée
        $cookie->forever('stay_logged_in', '1');
    }

    public function home() {
        // Vérifiez si vous avez le cookie
        if (Flight::cookie()->has('stay_logged_in')) {
            // placez-les dans la zone du tableau de bord par exemple.
            Flight::redirect('/dashboard');
        }
    }
}

Awesome-plugins/php_encryption

Chiffrement PHP

defuse/php-encryption est une bibliothèque qui peut être utilisée pour chiffrer et déchiffrer des données. Il est assez simple de commencer à chiffrer et déchiffrer des données. Ils ont un didacticiel qui aide à expliquer les bases de l'utilisation de la bibliothèque ainsi que les implications importantes en matière de sécurité concernant le chiffrement.

Installation

L'installation est simple avec Composer.

composer require defuse/php-encryption

Configuration

Ensuite, vous devrez générer une clé de chiffrement.

vendor/bin/generate-defuse-key

Cela affichera une clé que vous devrez conserver en sécurité. Vous pourriez conserver la clé dans votre fichier app/config/config.php dans le tableau en bas du fichier. Ce n'est pas l'endroit parfait, mais c'est au moins quelque chose.

Utilisation

Maintenant que vous avez la bibliothèque et une clé de chiffrement, vous pouvez commencer à chiffrer et déchiffrer des données.


use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

/*
 * Défini dans votre fichier bootstrap ou public/index.php
 */

// Méthode de chiffrement
Flight::map('encrypt', function($raw_data) {
    $encryption_key = /* $config['encryption_key'] or a file_get_contents of where you put the key */;
    return Crypto::encrypt($raw_data, Key::loadFromAsciiSafeString($encryption_key));
});

// Méthode de déchiffrement
Flight::map('decrypt', function($encrypted_data) {
    $encryption_key = /* $config['encryption_key'] or a file_get_contents of where you put the key */;
    try {
        $raw_data = Crypto::decrypt($encrypted_data, Key::loadFromAsciiSafeString($encryption_key));
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
        // Une attaque ! Soit la mauvaise clé a été chargée, soit le texte chiffré a
        // changé depuis sa création -- corrompu dans la base de données ou
        // intentionnellement modifié par Eve essayant de mener une attaque.

        // ... gérer ce cas de manière adaptée à votre application ...
    }
    return $raw_data;
});

Flight::route('/encrypt', function() {
    $encrypted_data = Flight::encrypt('Ceci est un secret');
    echo $encrypted_data;
});

Flight::route('/decrypt', function() {
    $encrypted_data = '...'; // Obtenir les données chiffrées de quelque part
    $decrypted_data = Flight::decrypt($encrypted_data);
    echo $decrypted_data;
});

Awesome-plugins/php_file_cache

Wruczek/PHP-File-Cache

Classe de mise en cache de fichiers PHP légère, simple et autonome

Avantages

Cliquez ici pour voir le code.

Installation

Installez via composer:

composer require wruczek/php-file-cache

Utilisation

L'utilisation est assez simple.

use Wruczek\PhpFileCache\PhpFileCache;

$app = Flight::app();

// Vous passez le répertoire dans lequel le cache sera stocké dans le constructeur
$app->register('cache', PhpFileCache::class, [ __DIR__ . '/../cache/' ], function(PhpFileCache $cache) {

    // Cela garantit que le cache n'est utilisé que en mode production
    // ENVIRONMENT est une constante définie dans votre fichier d'amorçage ou ailleurs dans votre application
    $cache->setDevMode(ENVIRONMENT === 'development');
});

Ensuite, vous pouvez l'utiliser dans votre code comme ceci :


// Obtenir l'instance du cache
$cache = Flight::cache();
$data = $cache->refreshIfExpired('simple-cache-test', function () {
    return date("H:i:s"); // retourne les données à mettre en cache
}, 10); // 10 secondes

// ou
$data = $cache->retrieve('simple-cache-test');
if(empty($data)) {
    $data = date("H:i:s");
    $cache->store('simple-cache-test', $data, 10); // 10 secondes
}

Documentation

Visitez https://github.com/Wruczek/PHP-File-Cache pour la documentation complète et assurez-vous de consulter le dossier examples.

Awesome-plugins/permissions

FlightPHP/Autorisations

Il s'agit d'un module d'autorisations qui peut être utilisé dans vos projets si vous avez plusieurs rôles dans votre application et que chaque rôle a une fonctionnalité légèrement différente. Ce module vous permet de définir des autorisations pour chaque rôle, puis de vérifier si l'utilisateur actuel a l'autorisation d'accéder à une certaine page ou d'effectuer une certaine action.

Cliquez ici pour accéder au dépôt sur GitHub.

Installation

Exécutez composer require flightphp/permissions et c'est parti!

Utilisation

Tout d'abord, vous devez configurer vos autorisations, puis vous indiquez à votre application ce que signifient les autorisations. En fin de compte, vous vérifierez vos autorisations avec $Permissions->has(), ->can(), ou is(). has() et can() ont la même fonctionnalité, mais sont nommées différemment pour rendre votre code plus lisible.

Exemple de base

Supposons que vous ayez une fonctionnalité dans votre application qui vérifie si un utilisateur est connecté. Vous pouvez créer un objet d'autorisations comme ceci:

// index.php
require 'vendor/autoload.php';

// some code 

// then you probably have something that tells you who the current role is of the person
// likely you have something where you pull the current role
// from a session variable which defines this
// after someone logs in, otherwise they will have a 'guest' or 'public' role.
$current_role = 'admin';

// setup permissions
$permission = new \flight\Permission($current_role);
$permission->defineRule('loggedIn', function($current_role) {
    return $current_role !== 'guest';
});

// You'll probably want to persist this object in Flight somewhere
Flight::set('permission', $permission);

Ensuite, dans un contrôleur quelque part, vous pourriez avoir quelque chose comme ceci.

<?php

// some controller
class SomeController {
    public function someAction() {
        $permission = Flight::get('permission');
        if ($permission->has('loggedIn')) {
            // do something
        } else {
            // do something else
        }
    }
}

Vous pouvez également utiliser ceci pour suivre s'ils ont l'autorisation de faire quelque chose dans votre application. Par exemple, si vous avez un moyen pour les utilisateurs d'interagir avec des publications sur votre logiciel, vous pouvez vérifier s'ils ont l'autorisation d'effectuer certaines actions.

$current_role = 'admin';

// setup permissions
$permission = new \flight\Permission($current_role);
$permission->defineRule('post', function($current_role) {
    if($current_role === 'admin') {
        $permissions = ['create', 'read', 'update', 'delete'];
    } else if($current_role === 'editor') {
        $permissions = ['create', 'read', 'update'];
    } else if($current_role === 'author') {
        $permissions = ['create', 'read'];
    } else if($current_role === 'contributor') {
        $permissions = ['create'];
    } else {
        $permissions = [];
    }
    return $permissions;
});
Flight::set('permission', $permission);

Ensuite, dans un contrôleur quelque part...

class PostController {
    public function create() {
        $permission = Flight::get('permission');
        if ($permission->can('post.create')) {
            // do something
        } else {
            // do something else
        }
    }
}

Injection de dépendances

Vous pouvez injecter des dépendances dans la fonction de fermeture qui définit les autorisations. C'est utile si vous avez un type de bascule, d'identifiant ou tout autre point de données que vous voulez vérifier. Le même principe s'applique aux appels de type Classe->Méthode, sauf que vous définissez les arguments dans la méthode.

Fonctions de fermeture

$Permission->defineRule('order', function(string $current_role, MyDependency $MyDependency = null) {
    // ... code
});

// dans votre fichier de contrôleur
public function createOrder() {
    $MyDependency = Flight::myDependency();
    $permission = Flight::get('permission');
    if ($permission->can('order.create', $MyDependency)) {
        // do something
    } else {
        // do something else
    }
}

Classes

namespace MyApp;

class Permissions {

    public function order(string $current_role, MyDependency $MyDependency = null) {
        // ... code
    }
}

Raccourci pour définir des autorisations avec des classes

Vous pouvez également utiliser des classes pour définir vos autorisations. C'est utile si vous avez beaucoup d'autorisations et que vous voulez garder votre code propre. Vous pouvez faire quelque chose comme ceci:

<?php

// code de démarrage
$Permissions = new \flight\Permission($current_role);
$Permissions->defineRule('order', 'MyApp\Permissions->order');

// myapp/Permissions.php
namespace MyApp;

class Permissions {

    public function order(string $current_role, int $user_id) {
        // En supposant que vous avez configuré cela au préalable
        /** @var \flight\database\PdoWrapper $db */
        $db = Flight::db();
        $allowed_permissions = [ 'read' ]; // tout le monde peut consulter une commande
        if($current_role === 'manager') {
            $allowed_permissions[] = 'create'; // les gestionnaires peuvent créer des commandes
        }
        $some_special_toggle_from_db = $db->fetchField('SELECT some_special_toggle FROM settings WHERE id = ?', [ $user_id ]);
        if($some_special_toggle_from_db) {
            $allowed_permissions[] = 'update'; // si l'utilisateur a une bascule spéciale, il peut mettre à jour des commandes
        }
        if($current_role === 'admin') {
            $allowed_permissions[] = 'delete'; // les administrateurs peuvent supprimer des commandes
        }
        return $allowed_permissions;
    }
}

L'astuce est que vous pouvez également utiliser un raccourci (qui peut également être mis en cache!!!) où vous dites simplement à la classe d'autorisations de mapper toutes les méthodes d'une classe en autorisations. Ainsi, si vous avez une méthode nommée order() et une méthode nommée company(), cela sera automatiquement cartographié pour que vous puissiez simplement exécuter $Permissions->has('order.read') ou $Permissions->has('company.read') et cela fonctionnera. Définir cela est très difficile, donc suivez moi ici. Vous avez juste besoin de faire ceci:

Créez la classe des autorisations que vous souhaitez regrouper.

class MyPermissions {
    public function order(string $current_role, int $order_id = 0): array {
        // code pour déterminer les autorisations
        return $permissions_array;
    }

    public function company(string $current_role, int $company_id): array {
        // code pour déterminer les autorisations
        return $permissions_array;
    }
}

Puis rendez les autorisations découvrables en utilisant cette bibliothèque.

$Permissions = new \flight\Permission($current_role);
$Permissions->defineRulesFromClassMethods(MyApp\Permissions::class);
Flight::set('permissions', $Permissions);

Enfin, appelez l'autorisation dans votre code pour vérifier si l'utilisateur est autorisé à effectuer une autorisation donnée.

class SomeController {
    public function createOrder() {
        if(Flight::get('permissions')->can('order.create') === false) {
            die('Vous ne pouvez pas créer une commande. Désolé!');
        }
    }
}

Mise en cache

Pour activer la mise en cache, consultez la bibliothèque simple wruczak/phpfilecache. Un exemple pour l'activer est ci-dessous.


// cet $app peut faire partie de votre code, ou
// vous pouvez simplement passer null et il
// récupérera de Flight::app() dans le constructeur
$app = Flight::app();

// Pour l'instant, cela accepte cela comme cache de fichier. D'autres peuvent facilement
// être ajoutés à l'avenir. 
$Cache = new Wruczek\PhpFileCache\PhpFileCache;

$Permissions = new \flight\Permission($current_role, $app, $Cache);
$Permissions->defineRulesFromClassMethods(MyApp\Permissions::class, 3600); // 3600 est le nombre de secondes pendant lesquels conserver cette mise en cache. Laissez ceci vide pour ne pas utiliser la mise en cache

Awesome-plugins/index

Super plugins

Flight est incroyablement extensible. Il existe un certain nombre de plugins qui peuvent être utilisés pour ajouter des fonctionnalités à votre application Flight. Certains sont officiellement pris en charge par l'équipe Flight et d'autres sont des bibliothèques micro/lite pour vous aider à démarrer.

Mise en cache

La mise en cache est un excellent moyen d'accélérer votre application. Il existe un certain nombre de bibliothèques de mise en cache qui peuvent être utilisées avec Flight.

Débogage

Le débogage est crucial lorsque vous développez dans votre environnement local. Il existe quelques plugins qui peuvent améliorer votre expérience de débogage.

Bases de données

Les bases de données sont essentielles pour la plupart des applications. C'est ainsi que vous stockez et récupérez des données. Certaines bibliothèques de bases de données ne sont que des enveloppes pour écrire des requêtes et d'autres sont des ORM complets.

Session

Les sessions ne sont pas vraiment utiles pour les API mais pour le développement d'une application web, les sessions peuvent être cruciales pour maintenir l'état et les informations de connexion.

Modèles

Les modèles sont essentiels pour toute application web avec une interface utilisateur. Il existe un certain nombre de moteurs de modèles qui peuvent être utilisés avec Flight.

Contribution

Vous avez un plugin que vous aimeriez partager? Soumettez une pull request pour l'ajouter à la liste!

Awesome-plugins/pdo_wrapper

Classe d'aide PdoWrapper PDO

Flight est livré avec une classe d'aide pour PDO. Il vous permet d'interroger facilement votre base de données avec toute la bizarrerie préparée/execute/fetchAll(). Cela simplifie grandement la façon dont vous pouvez interroger votre base de données. Chaque résultat de ligne est renvoyé sous forme de classe Collection de Flight qui vous permet d'accéder à vos données via une syntaxe de tableau ou une syntaxe d'objet.

Enregistrer la classe d'aide PDO

// Enregistrer la classe d'aide PDO
Flight::register('db', \flight\database\PdoWrapper::class, ['mysql:host=localhost;dbname=cool_db_name', 'user', 'pass', [
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'utf8mb4\'',
        PDO::ATTR_EMULATE_PREPARES => false,
        PDO::ATTR_STRINGIFY_FETCHES => false,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ]
]);

Utilisation

Cet objet étend PDO, donc toutes les méthodes normales de PDO sont disponibles. Les méthodes suivantes sont ajoutées pour faciliter l'interrogation de la base de données :

runQuery(string $sql, array $params = []): PDOStatement

Utilisez ceci pour les INSERT, les UPDATES, ou si vous envisagez d'utiliser un SELECT dans une boucle while

$db = Flight::db();
$statement = $db->runQuery("SELECT * FROM table WHERE something = ?", [ $something ]);
while($row = $statement->fetch()) {
    // ...
}

// Ou pour écrire dans la base de données
$db->runQuery("INSERT INTO table (name) VALUES (?)", [ $name ]);
$db->runQuery("UPDATE table SET name = ? WHERE id = ?", [ $name, $id ]);

fetchField(string $sql, array $params = []): mixed

Extraie le premier champ de la requête

$db = Flight::db();
$count = $db->fetchField("SELECT COUNT(*) FROM table WHERE something = ?", [ $something ]);

fetchRow(string $sql, array $params = []): array

Récupère une ligne de la requête

$db = Flight::db();
$row = $db->fetchRow("SELECT id, name FROM table WHERE id = ?", [ $id ]);
echo $row['name'];
// or
echo $row->name;

fetchAll(string $sql, array $params = []): array

Récupère toutes les lignes de la requête

$db = Flight::db();
$rows = $db->fetchAll("SELECT id, name FROM table WHERE something = ?", [ $something ]);
foreach($rows as $row) {
    echo $row['name'];
    // or
    echo $row->name;
}

Remarque avec la syntaxe IN()

Il existe également un wrapper utile pour les déclarations IN(). Vous pouvez simplement passer un point d'interrogation unique en guise de paramètre pour IN() puis un tableau de valeurs. Voici un exemple de ce à quoi cela pourrait ressembler :

$db = Flight::db();
$name = 'Bob';
$company_ids = [1,2,3,4,5];
$rows = $db->fetchAll("SELECT id, name FROM table WHERE name = ? AND company_id IN (?)", [ $name, $company_ids ]);

Exemple complet

// Exemple de route et comment vous utiliseriez ce wrapper
Flight::route('/utilisateurs', function () {
    // Obtenir tous les utilisateurs
    $users = Flight::db()->fetchAll('SELECT * FROM users');

    // Diffuser tous les utilisateurs
    $statement = Flight::db()->runQuery('SELECT * FROM users');
    while ($user = $statement->fetch()) {
        echo $user['name'];
        // ou echo $user->name;
    }

    // Obtenir un seul utilisateur
    $user = Flight::db()->fetchRow('SELECT * FROM users WHERE id = ?', [123]);

    // Obtenir une seule valeur
    $count = Flight::db()->fetchField('SELECT COUNT(*) FROM users');

    // Syntaxe spéciale IN() pour aider (assurez-vous que IN est en majuscules)
    $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [[1,2,3,4,5]]);
    // vous pourriez aussi faire ceci
    $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [ '1,2,3,4,5']);

    // Insérer un nouvel utilisateur
    Flight::db()->runQuery("INSERT INTO users (name, email) VALUES (?, ?)", ['Bob', 'bob@example.com']);
    $insert_id = Flight::db()->lastInsertId();

    // Mettre à jour un utilisateur
    Flight::db()->runQuery("UPDATE users SET name = ? WHERE id = ?", ['Bob', 123]);

    // Supprimer un utilisateur
    Flight::db()->runQuery("DELETE FROM users WHERE id = ?", [123]);

    // Obtenir le nombre de lignes affectées
    $statement = Flight::db()->runQuery("UPDATE users SET name = ? WHERE name = ?", ['Bob', 'Sally']);
    $affected_rows = $statement->rowCount();

});

Awesome-plugins/session

Ghostff/Session

PHP Gestionnaire de session (non bloquant, flash, segment, chiffrement de session). Utilise PHP open_ssl pour le chiffrement/déchiffrement optionnel des données de session. Prise en charge des fichiers, MySQL, Redis et Memcached.

Cliquez ici pour voir le code.

Installation

Installez avec composer.

composer require ghostff/session

Configuration de base

Vous n'êtes pas obligé de passer quoi que ce soit pour utiliser les paramètres par défaut de votre session. Vous pouvez en savoir plus sur d'autres paramètres dans le Lisez-moi Github.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('session', Session::class);

// une chose à retenir est que vous devez valider votre session à chaque chargement de page
// ou vous devrez exécuter auto_commit dans votre configuration.

Exemple Simple

Voici un exemple simple de la manière dont vous pourriez utiliser ceci.

Flight::route('POST /login', function() {
    $session = Flight::session();

    // effectuez votre logique de connexion ici
    // validez le mot de passe, etc.

    // si la connexion réussit
    $session->set('is_logged_in', true);
    $session->set('user', $user);

    // à chaque fois que vous écrivez dans la session, vous devez la valider délibérément.
    $session->commit();
});

// Cette vérification pourrait être dans la logique de page restreinte, ou enveloppée dans un middleware.
Flight::route('/page-restreinte', function() {
    $session = Flight::session();

    if(!$session->get('is_logged_in')) {
        Flight::redirect('/login');
    }

    // effectuez votre logique de page restreinte ici
});

// la version du middleware
Flight::route('/page-restreinte', function() {
    // logique de page régulière
})->addMiddleware(function() {
    $session = Flight::session();

    if(!$session->get('is_logged_in')) {
        Flight::redirect('/login');
    }
});

Exemple Plus Complexe

Voici un exemple plus complexe de la manière dont vous pourriez utiliser ceci.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

// définissez un chemin personnalisé pour votre fichier de configuration de session et donnez-lui une chaîne aléatoire pour l'identifiant de session
$app->register('session', Session::class, [ 'chemin/vers/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) {
        // ou vous pouvez remplacer manuellement les options de configuration
        $session->updateConfiguration([
            // si vous voulez stocker vos données de session dans une base de données (utile si vous souhaitez quelque chose comme la fonctionnalité "déconnectez-moi de tous les appareils")
            Session::CONFIG_DRIVER        => Ghostff\Session\Drivers\MySql::class,
            Session::CONFIG_ENCRYPT_DATA  => true,
            Session::CONFIG_SALT_KEY      => hash('sha256', 'mon-S3CR3T-sel-super'), // veuillez changer ceci pour quelque chose d'autre
            Session::CONFIG_AUTO_COMMIT   => true, // faites-le uniquement si c'est nécessaire et/ou s'il est difficile de valider() votre session.
                                                   // de plus, vous pourriez faire Flight::after('start', function() { Flight::session()->commit(); });
            Session::CONFIG_MYSQL_DS         => [
                'driver'    => 'mysql',             # Pilote de base de données pour le dns PDO ex.(mysql:host=...;dbname=...)
                'host'      => '127.0.0.1',         # Hôte de la base de données
                'db_name'   => 'ma_base_de_données_app',   # Nom de la base de données
                'db_table'  => 'sessions',          # Table de la base de données
                'db_user'   => 'root',              # Nom d'utilisateur de la base de données
                'db_pass'   => '',                  # Mot de passe de la base de données
                'persistent_conn'=> false,          # Éviter les frais généraux de l'établissement d'une nouvelle connexion à chaque fois qu'un script doit dialoguer avec une base de données, ce qui donne une application web plus rapide. TROUVEZ LE CÔTÉ OBSCUR PAR VOUS-MÊME
            ]
        ]);
    }
);

Au Secours ! Mes données de session ne persistent pas !

Vous définissez vos données de session et elles ne persistent pas entre les requêtes ? Vous avez peut-être oublié de valider vos données de session. Vous pouvez le faire en appelant $session->commit() après avoir défini vos données de session.

Flight::route('POST /login', function() {
    $session = Flight::session();

    // effectuez votre logique de connexion ici
    // valider le mot de passe, etc.

    // si la connexion réussit
    $session->set('is_logged_in', true);
    $session->set('user', $user);

    // à chaque fois que vous écrivez dans la session, vous devez la valider délibérément.
    $session->commit();
});

L'autre façon de contourner cela est lorsque vous configurez votre service de session, vous devez définir auto_commit sur true dans votre configuration. Cela validera automatiquement vos données de session après chaque requête.


$app->register('session', Session::class, [ 'chemin/vers/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) {
        $session->updateConfiguration([
            Session::CONFIG_AUTO_COMMIT   => true,
        ]);
    }
);

De plus, vous pourriez faire Flight::after('start', function() { Flight::session()->commit(); }); pour valider vos données de session après chaque requête.

Documentation

Consultez le Lisez-moi Github pour la documentation complète. Les options de configuration sont bien documentées dans le fichier default_config.php lui-même. Le code est simple à comprendre si vous souhaitiez parcourir ce package vous-même.

Awesome-plugins/runway

Piste

Runway est une application CLI qui vous aide à gérer vos applications Flight. Il peut générer des contrôleurs, afficher toutes les routes, et bien plus encore. Il est basé sur l'excellente bibliothèque adhocore/php-cli.

Cliquez ici pour voir le code.

Installation

Installez avec composer.

composer require flightphp/runway

Configuration de Base

La première fois que vous exécutez Runway, il vous guidera à travers un processus de configuration et créera un fichier de configuration .runway.json à la racine de votre projet. Ce fichier contiendra certaines configurations nécessaires pour que Runway fonctionne correctement.

Utilisation

Runway dispose de plusieurs commandes que vous pouvez utiliser pour gérer votre application Flight. Il y a deux façons faciles d'utiliser Runway.

  1. Si vous utilisez le projet de base, vous pouvez exécuter php runway [commande] depuis la racine de votre projet.
  2. Si vous utilisez Runway comme un paquet installé via composer, vous pouvez exécuter vendor/bin/runway [commande] depuis la racine de votre projet.

Pour n'importe quelle commande, vous pouvez ajouter le drapeau --help pour obtenir plus d'informations sur comment utiliser la commande.

php runway routes --help

Voici quelques exemples :

Générer un Contrôleur

Selon la configuration dans votre fichier .runway.json, l'emplacement par défaut générera un contrôleur pour vous dans le répertoire app/controllers/.

php runway make:controller MyController

Générer un Modèle Active Record

Selon la configuration dans votre fichier .runway.json, l'emplacement par défaut générera un contrôleur pour vous dans le répertoire app/records/.

php runway make:record users

Par exemple, si vous avez la table users avec le schéma suivant : id, name, email, created_at, updated_at, un fichier similaire au suivant sera créé dans le fichier app/records/UserRecord.php :

<?php

declare(strict_types=1);

namespace app\records;

/**
 * Class ActiveRecord pour la table des utilisateurs.
 * @link https://docs.flightphp.com/awesome-plugins/active-record
 * 
 * @property int $id
 * @property string $name
 * @property string $email
 * @property string $created_at
 * @property string $updated_at
 * // vous pouvez également ajouter des relations ici une fois que vous les définissez dans le tableau $relations
 * @property CompanyRecord $company Exemple d'une relation
 */
class UserRecord extends \flight\ActiveRecord
{
    /**
     * @var array $relations Définir les relations pour le modèle
     *   https://docs.flightphp.com/awesome-plugins/active-record#relationships
     */
    protected array $relations = [];

    /**
     * Constructeur
     * @param mixed $databaseConnection La connexion à la base de données
     */
    public function __construct($databaseConnection)
    {
        parent::__construct($databaseConnection, 'users');
    }
}

Afficher Toutes les Routes

Cela affichera toutes les routes actuellement enregistrées avec Flight.

php runway routes

Si vous souhaitez uniquement visualiser des routes spécifiques, vous pouvez ajouter un drapeau pour filtrer les routes.

# Afficher uniquement les routes GET
php runway routes --get

# Afficher uniquement les routes POST
php runway routes --post

# etc.

Personnaliser Runway

Si vous êtes en train de créer un paquet pour Flight, ou si vous voulez ajouter vos propres commandes personnalisées dans votre projet, vous pouvez le faire en créant un répertoire src/commands/, flight/commands/, app/commands/, ou commands/ pour votre projet/paquet.

Pour créer une commande, vous étendez simplement la classe AbstractBaseCommand et implémentez au minimum une méthode __construct et une méthode execute.

<?php

declare(strict_types=1);

namespace flight\commands;

class ExampleCommand extends AbstractBaseCommand
{
    /**
     * Constructeur
     *
     * @param array<string,mixed> $config Config JSON de .runway-config.json
     */
    public function __construct(array $config)
    {
        parent::__construct('make:example', 'Crée un exemple pour la documentation', $config);
        $this->argument('<funny-gif>', 'Le nom du gif drôle');
    }

    /**
     * Exécute la fonction
     *
     * @return void
     */
    public function execute(string $controller)
    {
        $io = $this->app()->io();

        $io->info('Création de l\'exemple...');

        // Faites quelque chose ici

        $io->ok('Exemple créé !');
    }
}

Consultez la Documentation de adhocore/php-cli pour plus d'informations sur la façon de créer vos propres commandes personnalisées dans votre application Flight !

Awesome-plugins/tracy_extensions

Tracy Flight Panel Extensions

Il s'agit d'un ensemble d'extensions pour rendre le travail avec Flight un peu plus riche.

C'est le panneau

Barre Flight

Et chaque panneau affiche des informations très utiles sur votre application !

Données Flight Base de données Flight Requête Flight

Cliquez ici pour voir le code.

Installation

Exécutez composer require flightphp/tracy-extensions --dev et c'est parti !

Configuration

Il y a très peu de configuration à faire pour démarrer. Vous devrez initialiser le débogueur Tracy avant d'utiliser ceci https://tracy.nette.org/en/guide:

<?php

use Tracy\Debugger;
use flight\debug\tracy\TracyExtensionLoader;

// code d'amorçage
require __DIR__ . '/vendor/autoload.php';

Debugger::enable();
// Vous devrez peut-être spécifier votre environnement avec Debugger::enable(Debugger::DEVELOPMENT)

// si vous utilisez des connexions à la base de données dans votre application, il y a un
// wrapper PDO requis à utiliser UNIQUEMENT EN DÉVELOPPEMENT (pas en production s'il vous plaît !)
// Il a les mêmes paramètres qu'une connexion PDO normale
$pdo = new PdoQueryCapture('sqlite:test.db', 'user', 'pass');
// ou si vous attachez ceci au framework Flight
Flight::register('db', PdoQueryCapture::class, ['sqlite:test.db', 'user', 'pass']);
// maintenant à chaque fois que vous exécutez une requête, il capturera le temps, la requête et les paramètres

// Cela connecte les points
if(Debugger::$showBar === true) {
    // Cela doit être faux sinon Tracy ne peut pas rendre correctement :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app());
}

// plus de code

Flight::start();

Configuration Supplémentaire

Données de Session

Si vous avez un gestionnaire de session personnalisé (comme ghostff/session), vous pouvez passer n'importe quel tableau de données de session à Tracy et il l'affichera automatiquement pour vous. Vous le transmettez avec la clé session_data dans le deuxième paramètre du constructeur TracyExtensionLoader.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('session', Session::class);

if(Debugger::$showBar === true) {
    // Cela doit être faux sinon Tracy ne peut pas rendre correctement :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app(), [ 'session_data' => Flight::session()->getAll() ]);
}

// routes et autres choses...

Flight::start();

Latte

Si vous avez Latte installé dans votre projet, vous pouvez utiliser le panneau Latte pour analyser vos modèles. Vous pouvez transmettre l'instance de Latte au constructeur TracyExtensionLoader avec la clé latte dans le deuxième paramètre.



use Latte\Engine;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('latte', Engine::class, [], function($latte) {
    $latte->setTempDirectory(__DIR__ . '/temp');

    // c'est ici que vous ajoutez le panneau Latte à Tracy
    $latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
});

if(Debugger::$showBar === true) {
    // Cela doit être faux sinon Tracy ne peut pas rendre correctement :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app());
}

Awesome-plugins/tracy

Tracy

Tracy est un gestionnaire d'erreurs incroyable qui peut être utilisé avec Flight. Il dispose de plusieurs panneaux qui peuvent vous aider à déboguer votre application. Il est également très facile à étendre et à ajouter vos propres panneaux. L'équipe de Flight a créé quelques panneaux spécifiquement pour les projets Flight avec le plugin flightphp/tracy-extensions.

Installation

Installez avec composer. Et vous voudrez en fait installer ceci sans la version dev car Tracy est livré avec un composant de gestion des erreurs de production.

composer require tracy/tracy

Configuration de base

Il existe quelques options de configuration de base pour commencer. Vous pouvez en savoir plus à leur sujet dans la Documentation de Tracy.


require 'vendor/autoload.php';

use Tracy\Debugger;

// Activer Tracy
Debugger::enable();
// Debugger::enable(Debugger::DEVELOPMENT) // parfois vous devez être explicite (également Debugger::PRODUCTION)
// Debugger::enable('23.75.345.200'); // vous pouvez également fournir un tableau d'adresses IP

// C'est là que les erreurs et exceptions seront journalisées. Assurez-vous que ce répertoire existe et est accessible en écriture.
Debugger::$logDirectory = __DIR__ . '/../log/';
Debugger::$strictMode = true; // afficher toutes les erreurs
// Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // toutes les erreurs sauf les avis obsolètes
if (Debugger::$showBar) {
    $app->set('flight.content_length', false); // si la barre de débogage est visible, alors la longueur du contenu ne peut pas être définie par Flight

    // Ceci est spécifique à l'extension Tracy pour Flight si vous l'avez incluse
    // sinon mettez en commentaire.
    new TracyExtensionLoader($app);
}

Conseils utiles

Lorsque vous déboguez votre code, il y a quelques fonctions très utiles pour afficher des données pour vous.

Awesome-plugins/active_record

Flight Active Record

Un enregistrement actif est la mise en correspondance d'une entité de base de données avec un objet PHP. En termes simples, si vous avez une table d'utilisateurs dans votre base de données, vous pouvez "traduire" une ligne de cette table en une classe User et un objet $user dans votre code source. Voir exemple de base.

Cliquez ici pour accéder au dépôt sur GitHub.

Exemple de Base

Supposons que vous ayez la table suivante :

CREATE TABLE users (
    id INTEGER PRIMARY KEY, 
    name TEXT, 
    password TEXT 
);

Maintenant, vous pouvez configurer une nouvelle classe pour représenter cette table :

/**
 * Une classe ActiveRecord est généralement au singulier
 * 
 * Il est fortement recommandé d'ajouter les propriétés de la table en commentaires ici
 * 
 * @property int    $id
 * @property string $name
 * @property string $password
 */ 
class User extends flight\ActiveRecord {
    public function __construct($connexion_base_de_donnees)
    {
        // vous pouvez le définir de cette façon
        parent::__construct($connexion_base_de_donnees, 'users');
        // ou de cette façon
        parent::__construct($connexion_base_de_donnees, null, [ 'table' => 'users']);
    }
}

Maintenant regardez la magie opérer !

// pour sqlite
$connexion_base_de_donnees = new PDO('sqlite:test.db'); // c'est juste un exemple, vous utiliseriez probablement une véritable connexion à une base de données

// pour mysql
$connexion_base_de_donnees = new PDO('mysql:host=localhost;dbname=test_db&charset=utf8bm4', 'nom_utilisateur', 'mot_de_passe');

// ou mysqli
$connexion_base_de_donnees = new mysqli('localhost', 'nom_utilisateur', 'mot_de_passe', 'test_db');
// ou mysqli avec création non basée sur un objet
$connexion_base_de_donnees = mysqli_connect('localhost', 'nom_utilisateur', 'mot_de_passe', 'test_db');

$user = new User($connexion_base_de_donnees);
$user->name = 'Bobby Tables';
$user->password = password_hash('un mot de passe génial');
$user->insert();
// ou $user->save();

echo $user->id; // 1

$user->name = 'Joseph Mamma';
$user->password = password_hash('encore un mot de passe génial!!!');
$user->insert();
// ne peut pas utiliser $user->save() ici sinon il pensera qu'il s'agit d'une mise à jour !

echo $user->id; // 2

Et c'était aussi simple d'ajouter un nouvel utilisateur ! Maintenant qu'il y a une ligne utilisateur dans la base de données, comment la récupérer ?

$user->find(1); // trouve l'identifiant = 1 dans la base de données et le renvoie.
echo $user->name; // 'Bobby Tables'

Et si vous voulez trouver tous les utilisateurs ?

$users = $user->findAll();

Et avec une certaine condition ?

$users = $user->like('name', '%mamma%')->findAll();

Vous voyez à quel point c'est amusant ? Installons-le et commençons !

Installation

Installez simplement avec Composer

composer require flightphp/active-record 

Utilisation

Cela peut être utilisé comme une bibliothèque autonome ou avec le Framework PHP Flight. C'est complètement à vous.

Autonome

Assurez-vous simplement de passer une connexion PDO au constructeur.

$connexion_pdo = new PDO('sqlite:test.db'); // c'est juste un exemple, vous utiliseriez probablement une véritable connexion à une base de données

$User = new User($connexion_pdo);

Je ne veux pas toujours définir votre connexion à la base de données dans le constructeur? Voir Gestion de la connexion à la base de données pour d'autres idées!

Enregistrer en tant que méthode dans Flight

Si vous utilisez le Framework PHP Flight, vous pouvez enregistrer la classe ActiveRecord en tant que service, mais honnêtement, vous n'êtes pas obligé.

Flight::register('user', 'User', [ $connexion_pdo ]);

// ensuite vous pouvez l'utiliser comme ceci dans un contrôleur, une fonction, etc.

Flight::user()->find(1);

Méthodes runway

runway est un outil CLI pour Flight qui a une commande personnalisée pour cette bibliothèque.

# Utilisation
php runway make:record nom_table_base_de_données [nom_classe]

# Exemple
php runway make:record utilisateurs

Cela créera une nouvelle classe dans le répertoire app/records/ en tant que UserRecord.php avec le contenu suivant :

<?php

declare(strict_types=1);

namespace app\records;

/**
 * Classe ActiveRecord pour la table des utilisateurs.
 * @link https://docs.flightphp.com/awesome-plugins/active-record
 *
 * @property int $id
 * @property string $username
 * @property string $email
 * @property string $password_hash
 * @property string $created_dt
 */
class UserRecord extends \flight\ActiveRecord
{
    /**
     * @var array $relations Définir les relations pour le modèle
     *   https://docs.flightphp.com/awesome-plugins/active-record#relationships
     */
    protected array $relations = [
        // 'nom_relation' => [ self::HAS_MANY, 'RelatedClass', 'foreign_key' ],
    ];

    /**
     * Constructeur
     * @param mixed $connexionBaseDeDonnées La connexion à la base de données
     */
    public function __construct($connexionBaseDeDonnées)
    {
        parent::__construct($connexionBaseDeDonnées, 'users');
    }
}

Fonctions CRUD

find($id = null) : boolean|ActiveRecord

Trouve un enregistrement et l'attribue à l'objet actuel. Si vous passez un $id de quelque sorte, il effectuera une recherche sur la clé primaire avec cette valeur. Si rien n'est passé, il cherchera simplement le premier enregistrement dans la table.

En outre, vous pouvez lui passer d'autres méthodes d'aide pour interroger votre table.

// trouver un enregistrement avec certaines conditions préalables
$user->notNull('password')->orderBy('id DESC')->find();

// trouver un enregistrement par un identifiant spécifique
$id = 123;
$user->find($id);

findAll(): array<int,ActiveRecord>

Trouve tous les enregistrements dans la table que vous spécifiez.

$user->findAll();

isHydrated(): boolean (v0.4.0)

Retourne true si l'enregistrement actuel a été hydraté (récupéré de la base de données).

$user->find(1);
// si un enregistrement est trouvé avec des données...
$user->isHydrated(); // true

insert(): boolean|ActiveRecord

Insère l'enregistrement actuel dans la base de données.

$user = new User($connexion_pdo);
$user->name = 'démo';
$user->password = md5('démo');
$user->insert();
Clés primaires basées sur du texte

Si vous avez une clé primaire basée sur du texte (comme un UUID), vous pouvez définir la valeur de la clé primaire avant l'insertion de deux manières.

$user = new User($connexion_pdo, [ 'primaryKey' => 'uuid' ]);
$user->uuid = 'quelque-uuid';
$user->name = 'démo';
$user->password = md5('démo');
$user->insert(); // ou $user->save();

ou vous pouvez avoir la clé primaire générée automatiquement pour vous via des événements.

class User extends flight\ActiveRecord {
    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users', [ 'primaryKey' => 'uuid' ]);
        // vous pouvez également définir la clé primaire de cette manière au lieu du tableau ci-dessus.
        $this->primaryKey = 'uuid';
    }

    protected function beforeInsert(self $self) {
        $self->uuid = uniqid(); // ou comment vous devez générer vos identifiants uniques
    }
}

Si vous ne définissez pas la clé primaire avant l'insertion, elle sera définie sur le rowid et la base de données la générera pour vous, mais elle ne persistera pas car ce champ peut ne pas exister dans votre table. C'est pourquoi il est recommandé d'utiliser l'événement pour gérer automatiquement cela pour vous.

update(): boolean|ActiveRecord

Met à jour l'enregistrement actuel dans la base de données.

$user->greaterThan('id', 0)->orderBy('id desc')->find();
$user->email = 'test@example.com';
$user->update();

save(): boolean|ActiveRecord

Insère ou met à jour l'enregistrement actuel dans la base de données. Si l'enregistrement a un identifiant, il sera mis à jour, sinon il sera inséré.

$user = new User($connexion_pdo);
$user->name = 'démo';
$user->password = md5('démo');
$user->save();

Remarque : Si vous avez des relations définies dans la classe, elles sauvegarderont également récursivement ces relations si elles ont été définies, instanciées et ont des données à mettre à jour. (v0.4.0 et ultérieur)

delete(): boolean

Supprime l'enregistrement actuel de la base de données.

$user->gt('id', 0)->orderBy('id desc')->find();
$user->delete();

Vous pouvez également supprimer plusieurs enregistrements en exécutant une recherche au préalable.

$user->like('name', 'Bob%')->delete();

dirty(array $dirty = []): ActiveRecord

Les données non valides se réfèrent aux données modifiées dans un enregistrement.

$user->greaterThan('id', 0)->orderBy('id desc')->find();

// rien n'est "non valide" à ce stade.

$user->email = 'test@example.com'; // maintenant l'e-mail est considéré comme "non valide" car il a changé.
$user->update();
// maintenant il n'y a pas de données invalides car elles ont été mises à jour et persistées dans la base de données

$user->password = password_hash('un autre mot de passe'); // maintenant c'est non valide
$user->dirty(); // en ne passant rien, toutes les entrées non valides seront effacées.
$user->update(); // rien ne sera mis à jour car rien n'a été capturé comme non valide.

$user->dirty([ 'name' => 'quelque chose', 'password' => password_hash('un mot de passe différent') ]);
$user->update(); // à la fois le nom et le mot de passe sont mis à jour.

copyFrom(array $data): ActiveRecord (v0.4.0)

C'est un alias de la méthode dirty(). C'est un peu plus clair sur ce que vous faites.

$user->copyFrom([ 'name' => 'quelque chose', 'password' => password_hash('un mot de passe différent') ]);
$user->update(); // à la fois le nom et le mot de passe sont mis à jour.

isDirty(): boolean (v0.4.0)

Retourne true si l'enregistrement actuel a été modifié.

$user->greaterThan('id', 0)->orderBy('id desc')->find();
$user->email = 'test@exemple.com';
$user->isDirty(); // true

reset(bool $include_query_data = true): ActiveRecord

Réinitialise l'enregistrement actuel à son état initial. C'est vraiment utile à utiliser dans des comportements de boucle. Si vous passez true, cela réinitialisera également les données de la requête utilisées pour trouver l'objet actuel (comportement par défaut).

$users = $user->greaterThan('id', 0)->orderBy('id desc')->find();
$user_company = new UserCompany($connexion_pdo);

foreach($users as $user) {
    $user_company->reset(); // commencer avec une page propre
    $user_company->user_id = $user->id;
    $user_company->company_id = $some_company_id;
    $user_company->insert();
}

getBuiltSql(): string (v0.4.1)

Après avoir exécuté une méthode find(), findAll(), insert(), update() ou save(), vous pouvez obtenir le SQL qui a été construit et l'utiliser à des fins de débogage.

Méthodes de requête SQL

select(string $field1 [, string $field2 ... ])

Vous pouvez sélectionner uniquement quelques colonnes dans une table si vous le souhaitez (c'est plus performant sur des tables très larges avec de nombreuses colonnes)

$user->select('id', 'name')->find();

from(string $table)

Vous pouvez techniquement choisir une autre table aussi ! Pourquoi pas ?

$user->select('id', 'name')->from('user')->find();

join(string $table_name, string $join_condition)

Vous pouvez même joindre une autre table dans la base de données.

$user->join('contacts', 'contacts.user_id = users.id')->find();

where(string $where_conditions)

Vous pouvez définir des arguments where personnalisés (vous ne pouvez pas définir de paramètres dans cette instruction where)

$user->where('id=1 AND name="démo"')->find();

Remarque de sécurité - Vous pourriez être tenté de faire quelque chose comme $user->where("id = '{$id}' AND name = '{$name}'")->find();. S'il vous plaît, NE FAITES PAS CELA !!! Cela est susceptible de ce qu'on appelle des attaques par injection SQL. Il y a beaucoup d'articles en ligne, veuillez faire une recherche sur Google avec "attaques par injection SQL php" et vous trouverez de nombreux articles sur ce sujet. La bonne façon de gérer cela avec cette bibliothèque est au lieu de cette méthode where(), vous feriez quelque chose de plus comme $user->eq('id', $id)->eq('name', $name)->find(); Si vous devez absolument le faire, la bibliothèque PDO a $pdo->quote($var) pour l'échapper pour vous. Seulement après avoir utilisé quote() pouvez-vous l'utiliser dans une instruction where().

group(string $group_by_statement)/groupBy(string $group_by_statement)

Regroupez vos résultats par une condition particulière.

$user->select('COUNT(*) as count')->groupBy('name')->findAll();

order(string $order_by_statement)/orderBy(string $order_by_statement)

Triez la requête renvoyée d'une certaine manière.

$user->orderBy('name DESC')->find();

limit(string $limit)/limit(int $offset, int $limit)

Limite la quantité d'enregistrements renvoyés. Si un deuxième entier est donné, il sera utilisé comme décalage, la limite fonctionne comme en SQL.

$user->orderby('name DESC')->limit(0, 10)->findAll();

Conditions WHERE

equal(string $field, mixed $value) / eq(string $field, mixed $value)

field = $value

$user->eq('id', 1)->find();

notEqual(string $field, mixed $value) / ne(string $field, mixed $value)

field <> $value

$user->ne('id', 1)->find();

isNull(string $field)

Là où field IS NULL

$user->isNull('id')->find();

isNotNull(string $field) / notNull(string $field)

Là où field IS NOT NULL

$user->isNotNull('id')->find();

greaterThan(string $field, mixed $value) / gt(string $field, mixed $value)

field > $value

$user->gt('id', 1)->find();

lessThan(string $field, mixed $value) / lt(string $field, mixed $value)

field < $value

$user->lt('id', 1)->find();

greaterThanOrEqual(string $field, mixed $value) / ge(string $field, mixed $value) / gte(string $field, mixed $value)

field >= $value

$user->ge('id', 1)->find();

lessThanOrEqual(string $field, mixed $value) / le(string $field, mixed $value) / lte(string $field, mixed $value)

field <= $value

$user->le('id', 1)->find();

like(string $field, mixed $value) / notLike(string $field, mixed $value)

field LIKE $value ou field NOT LIKE $value

$user->like('name', 'de')->find();

in(string $field, array $values) / notIn(string $field, array $values)

field IN($value)ou field NOT IN($value)

$user->in('id', [1, 2])->find();

between(string $field, array $values)

field BETWEEN $value AND $value1

$user->between('id', [1, 2])->find();

Relations

Vous pouvez définir plusieurs types de relations en utilisant cette bibliothèque. Vous pouvez définir des relations un à plusieurs et un à un entre les tables. Cela nécessite une configuration supplémentaire dans la classe auparavant.

La configuration du tableau $relations n'est pas difficile, mais deviner la syntaxe correcte peut être déroutant.

protected array $relations = [
    // vous pouvez nommer la clé comme vous le souhaitez. Le nom de l'ActiveRecord est probablement bon. Ex : user, contact, client
    'user' => [
        // requis
        // self::HAS_MANY, self::HAS_ONE, self::BELONGS_TO
        self::HAS_ONE, // c'est le type de relation

        // requis
        'Certaine_Classe', // c'est la classe ActiveRecord "autre" à laquelle cela fera référence

        // requis
        // selon le type de relation
        // self::HAS_ONE = la clé étrangère qui fait référence à la jointure
        // self::HAS_MANY = la clé étrangère qui fait référence à la jointure
        // self::BELONGS_TO = la clé locale qui fait référence à la jointure
        'cle_primaire_ou_etrangere',
        // juste pour info, cela se joint également uniquement à la clé primaire du modèle "autre"

        // optionnel
        [ 'eq' => [ 'client_id', 5 ], 'select' => 'COUNT(*) as count', 'limit' 5 ], // conditions supplémentaires que vous souhaitez lors de la jointure de la relation
        // $record->eq('client_id', 5)->select('COUNT(*) as count')->limit(5))

        // optionnel
        'nom_de_référence_arrière' // c'est si vous voulez renvoyer cette relation en arrière vers elle-même Ex: $user->contact->user;
    ];
]
class User extends ActiveRecord{
    protected array $relations = [
        'contacts' => [ self::HAS_MANY, Contact::class, 'user_id' ],
        'contact' => [ self::HAS_ONE, Contact::class, 'user_id' ],
    ];

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }
}

class Contact extends ActiveRecord{
    protected array $relations = [
        'user' => [ self::BELONGS_TO, User::class, 'user_id' ],
        'user_with_backref' => [ self::BELONGS_TO, User::class, 'user_id', [], 'contact' ],
    ];
    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'contacts');
    }
}

Maintenant que les références sont configurées, vous pouvez les utiliser très facilement !

$user = new User($pdo_connection);

// trouve l'utilisateur le plus récent.
$user->notNull('id')->orderBy('id desc')->find();

// obtenir les contacts en utilisant la relation :
foreach($user->contacts as $contact) {
    echo $contact->id;
}

// ou nous pouvons faire le chemin inverse.
$contact = new Contact();

// trouve un contact
$contact->find();

// obtenir l'utilisateur en utilisant la relation :
echo $contact->user->name; // c'est le nom d'utilisateur

Vraiment cool non ?

Définition de Données Personnalisées

Parfois, vous devez attacher quelque chose d'unique à votre ActiveRecord tel qu'un calcul personnalisé qui pourrait être plus facile à attacher à l'objet pour ensuite être passé à un modèle par exemple.

setCustomData(string $field, mixed $value)

Vous attachez les données personnalisées avec la méthode setCustomData().

$user->setCustomData('nombre_de_vues_page', $nombre_de_vues_page);

Et ensuite, vous le référencez simplement comme une propriété d'objet normale.

echo $user->nombre_de_vues_page;

Evénements

Une autre fonctionnalité super géniale de cette bibliothèque concerne les événements. Les événements sont déclenchés à certains moments en fonction de certaines méthodes que vous appelez. Ils sont très très utiles pour configurer les données automatiquement.

onConstruct(ActiveRecord $ActiveRecord, array &config)

C'est vraiment utile si vous devez définir une connexion par défaut ou quelque chose comme ça.

// index.php ou bootstrap.php
Flight::register('db', 'PDO', [ 'sqlite:test.db' ]);

//
//
//

// User.php
class User extends flight\ActiveRecord {

    protected function onConstruct(self $self, array &$config) { // n'oubliez pas la référence &
        // vous pourriez le faire pour définir automatiquement la connexion
        $config['connexion'] = Flight::db();
        // ou cela
        $self->transformAndPersistConnection(Flight::db());

        // Vous pouvez également définir le nom de la table de cette manière.
        $config['table'] = 'users';
    } 
}

beforeFind(ActiveRecord $ActiveRecord)

Cela sera probablement utile uniquement si vous avez besoin d'une manipulation de requête à chaque fois.

class User extends flight\ActiveRecord {

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }

    protected function beforeFind(self $self) {
        // toujours exécuter id >= 0 si c'est votre truc
        $self->gte('id', 0); 
    } 
}

afterFind(ActiveRecord $ActiveRecord)

Celui-ci sera probablement plus utile si vous devez exécuter une logique à chaque fois que cet enregistrement est récupéré. Voulez-vous décrypter quelque chose ? Devez-vous exécuter une requête de décompte personnalisée à chaque fois (pas performant mais peu importe) ?

class User extends flight\ActiveRecord {

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }

    protected function afterFind(self $self) {
        // décryptage de quelque chose
        $self->secret = votrefonctiondedécryptage($self->secret, $une_clé);

        // stocker quelque chose de personnalisé comme une requête ???
        $self->setCustomData('nombre_vues', $self->select('COUNT(*) count')->from('vues_utilisateur')->eq('user_id', $self->id)['count']; 
    } 
}

beforeFindAll(ActiveRecord $ActiveRecord)

Cela sera probablement utile uniquement si vous avez besoin d'une manipulation de requête à chaque fois.

class User extends flight\ActiveRecord {

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }

    protected function beforeFindAll(self $self) {
        // toujours exécuter id >= 0 si c'est votre truc
        $self->gte('id', 0); 
    } 
}

afterFindAll(array<int,ActiveRecord> $results)

Similaire à afterFind() mais vous pouvez le faire pour tous les enregistrements !

class User extends flight\ActiveRecord {

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }

    protected function afterFindAll(array $results) {

        foreach($results as $self) {
            // faites quelque chose de cool comme afterFind()
        }
    } 
}

beforeInsert(ActiveRecord $ActiveRecord)

Vraiment utile si vous avez besoin de définir des valeurs par défaut à chaque fois.

class User extends flight\ActiveRecord {

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }

    protected function beforeInsert(self $self) {
        // définir certaines valeurs par défaut
        if(!$self->created_date) {
            $self->created_date = gmdate('Y-m-d');
        }

        if(!$self->password) {
            $self->password = password_hash((string) microtime(true));
        }
    } 
}

afterInsert(ActiveRecord $ActiveRecord)

Peut-être avez-vous un cas d'utilisation pour modifier des données après leur insertion ?

class User extends flight\ActiveRecord {

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }

    protected function afterInsert(self $self) {
        // vous voyez
        Flight::cache()->set('identifiant_insertion_plus_récents', $self->id);
        // ou autre chose....
    } 
}

beforeUpdate(ActiveRecord $ActiveRecord)

Vraiment utile si vous avez des valeurs par défaut à définir à chaque mise à jour.

class User extends flight\ActiveRecord {

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }

    protected function beforeInsert(self $self) {
        // définir certaines valeurs par défaut
        if(!$self->updated_date) {
            $self->updated_date = gmdate('Y-m-d');
        }
    } 
}

afterUpdate(ActiveRecord $ActiveRecord)

Peut-être avez-vous un cas d'utilisation pour modifier des données après leur mise à jour ?

class User extends flight\ActiveRecord {

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }

    protected function afterInsert(self $self) {
        // vous voyez
        Flight::cache()->set('identifiant_utilisateur_plus_récemment_mis_à_jour', $self->id);
        // ou autre chose....
    } 
}

beforeSave(ActiveRecord $ActiveRecord)/afterSave(ActiveRecord $ActiveRecord)

C'est utile si vous voulez que des événements se produisent à la fois lors des insertions ou des mises à jour. Je vais vous épargner la longue explication, mais je suis sûr que vous pouvez deviner ce que c'est.

class User extends flight\ActiveRecord {

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }

    protected function beforeSave(self $self) {
        $self->last_updated = gmdate('Y-m-d H:i:s');
    } 
}

beforeDelete(ActiveRecord $ActiveRecord)/afterDelete(ActiveRecord $ActiveRecord)

Je ne sais pas ce que vous voulez faire ici, mais aucune autocritique ici ! Allez-y !

class User extends flight\ActiveRecord {

    public function __construct($connexion_base_de_donnees)
    {
        parent::__construct($connexion_base_de_donnees, 'users');
    }

    protected function beforeDelete(self $self) {
        echo 'Il fut un brave soldat... :cry-face:';
    } 
}

Gestion de la connexion à la base de données

Lorsque vous utilisez cette bibliothèque, vous pouvez définir la connexion à la base de données de différentes manières. Vous pouvez définir la connexion dans le constructeur, vous pouvez la définir via une variable de configuration $config['connexion'] ou vous pouvez la définir via setDatabaseConnection() (v0.4.1).

$connexion_pdo = new PDO('sqlite:test.db'); // par exemple
$user = new User($connexion_pdo);
// ou
$user = new User(null, [ 'connexion' => $connexion_pdo ]);
// ou
$user = new User();
$user->setDatabaseConnection($connexion_pdo);

Si vous souhaitez éviter de définir toujours une $connexion_base_de_donnees chaque fois que vous appelez un ActiveRecord, il existe des moyens de contourner cela !

// index.php ou bootstrap.php
// Définissez ceci en tant que classe enregistrée dans Flight
Flight::register('db', 'PDO', [ 'sqlite:test.db' ]);

// User.php
class User extends flight\ActiveRecord {

    public function __construct(array $config = [])
    {
        $connexion_base_de_donnees = $config['connexion'] ?? Flight::db();
        parent::__construct($connexion_base_de_donnees, 'users', $config);
    }
}

// Et maintenant, aucun argument requis !
$user = new User();

Remarque : Si vous envisagez de faire des tests unitaires, le faire de cette façon peut poser quelques défis pour les tests unitaires, mais dans l'ensemble, car vous pouvez injecter votre connexion avec setDatabaseConnection() ou $config['connexion'], ce n'est pas si mal.

Si vous devez rafraîchir la connexion à la base de données, par exemple si vous exécutez un script CLI de longue durée et devez rafraîchir la connexion de temps en temps, vous pouvez réinitialiser la connexion avec $votre_enregistrement->setDatabaseConnection($connexion_pdo).

Awesome-plugins/latte

Latte

Latte est un moteur de templates complet qui est très facile à utiliser et se rapproche plus d'une syntaxe PHP que Twig ou Smarty. Il est également très facile à étendre et à ajouter vos propres filtres et fonctions.

Installation

Installez avec composer.

composer require latte/latte

Configuration de base

Il existe quelques options de configuration de base pour démarrer. Vous pouvez en savoir plus à leur sujet dans la Documentation de Latte.


use Latte\Engine as LatteEngine;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('latte', LatteEngine::class, [], function(LatteEngine $latte) use ($app) {

    // C'est ici que Latte mettra en cache vos templates pour accélérer les choses
    // Une chose intéressante à propos de Latte est qu'il rafraîchira automatiquement votre
    // cache lorsque vous apportez des modifications à vos templates !
    $latte->setTempDirectory(__DIR__ . '/../cache/');

    // Indiquez à Latte où se trouvera le répertoire racine pour vos vues.
    // $app->get('flight.views.path') est défini dans le fichier config.php
    //   Vous pourriez également simplement faire quelque chose comme `__DIR__ . '/../views/'`
    $latte->setLoader(new \Latte\Loaders\FileLoader($app->get('flight.views.path')));
});

Exemple de mise en page simple

Voici un exemple simple d'un fichier de mise en page. C'est le fichier qui sera utilisé pour envelopper toutes vos autres vues.

<!-- app/views/layout.latte -->
<!doctype html>
<html lang="en">
    <head>
        <title>{$title ? $title . ' - '}Mon application</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <nav>
                <!-- vos éléments de navigation ici -->
            </nav>
        </header>
        <div id="content">
            <!-- C'est là que se trouve la magie -->
            {block content}{/block}
        </div>
        <div id="footer">
            &copy; Droits d'auteur
        </div>
    </body>
</html>

Et maintenant nous avons votre fichier qui va être rendu à l'intérieur de ce bloc de contenu :

<!-- app/views/home.latte -->
<!-- Ceci indique à Latte que ce fichier est "à l'intérieur" du fichier layout.latte -->
{extends layout.latte}

<!-- C'est le contenu qui sera rendu à l'intérieur du layout à l'intérieur du block de contenu -->
{block content}
    <h1>Page d'accueil</h1>
    <p>Bienvenue dans mon application !</p>
{/block}

Ensuite, lorsque vous allez rendre ceci à l'intérieur de votre fonction ou contrôleur, vous feriez quelque chose comme ceci :

// itinéraire simple
Flight::route('/', function () {
    Flight::latte()->render('home.latte', [
        'title' => 'Page d'accueil'
    ]);
});

// ou si vous utilisez un contrôleur
Flight::route('/', [HomeController::class, 'index']);

// HomeController.php
class HomeController
{
    public function index()
    {
        Flight::latte()->render('home.latte', [
            'title' => 'Page d'accueil'
        ]);
    }
}

Consultez la Documentation de Latte pour plus d'informations sur comment utiliser Latte à son plein potentiel!

Awesome-plugins/awesome_plugins

Plugins Impressionnants

Flight est incroyablement extensible. Il existe plusieurs plugins qui peuvent être utilisés pour ajouter des fonctionnalités à votre application Flight. Certains sont officiellement pris en charge par l'équipe Flight et d'autres sont des bibliothèques micro/lite pour vous aider à démarrer.

Authentification/Autorisation

L'authentification et l'autorisation sont cruciales pour toute application qui nécessite des contrôles sur qui peut accéder à quoi.

Mise en cache

La mise en cache est un excellent moyen d'accélérer votre application. Il existe plusieurs bibliothèques de mise en cache qui peuvent être utilisées avec Flight.

CLI

Les applications CLI sont un excellent moyen d'interagir avec votre application. Vous pouvez les utiliser pour générer des contrôleurs, afficher toutes les routes, et plus encore.

Cookies

Les cookies sont un excellent moyen de stocker de petites données côté client. Ils peuvent être utilisés pour stocker les préférences de l'utilisateur, les paramètres de l'application, et plus encore.

Débogage

Le débogage est essentiel lorsque vous développez en environnement local. Il existe quelques plugins qui peuvent améliorer votre expérience de débogage.

Bases de données

Les bases de données sont au cœur de la plupart des applications. C'est ainsi que vous stockez et récupérez des données. Certaines bibliothèques de base de données ne sont que des wrappers simples pour écrire des requêtes, et d'autres sont des ORM complets.

Chiffrement

Le chiffrement est essentiel pour toute application qui stocke des données sensibles. Chiffrer et déchiffrer les données n'est pas très difficile, mais stocker correctement la clé de chiffrement peut être difficile. La chose la plus importante est de ne jamais stocker votre clé de chiffrement dans un répertoire public ou de la commit dans votre dépôt de code.

Session

Les sessions ne sont pas vraiment utiles pour les API, mais pour développer une application Web, les sessions peuvent être cruciales pour maintenir l'état et les informations de connexion.

Mise en forme

La mise en forme est essentielle pour toute application Web avec une interface utilisateur. Il existe plusieurs moteurs de mise en forme qui peuvent être utilisés avec Flight.

Contribution

Vous avez un plugin que vous aimeriez partager ? Soumettez une pull request pour l'ajouter à la liste !

Media

Médias

Nous avons essayé de rassembler ce que nous pouvons sur les différents types de médias autour d'internet concernant Flight. Voir ci-dessous pour différentes ressources que vous pouvez utiliser pour en savoir plus sur Flight.

Articles

Vidéos

Examples

Besoin d'un démarrage rapide ?

Vous avez deux options pour commencer avec Flight :

Besoin d'inspiration ?

Bien que ceux-ci ne soient pas officiellement sponsorisés par l'équipe Flight, ils pourraient vous donner des idées sur la façon de structurer vos propres projets construits avec Flight !

Voulez-vous partager votre propre exemple ?

Si vous avez un projet que vous souhaitez partager, veuillez soumettre une demande de tirage pour l'ajouter à cette liste !

Install/install

Installation

Téléchargement des fichiers

Assurez-vous d'avoir PHP installé sur votre système. Sinon, cliquez ici pour obtenir des instructions sur la façon de l'installer pour votre système.

Si vous utilisez Composer, vous pouvez exécuter la commande suivante:

composer require flightphp/core

OU vous pouvez télécharger les fichiers directement et les extraire dans votre répertoire Web.

Configurez votre serveur Web

Serveur de développement PHP intégré

C'est de loin la manière la plus simple de démarrer. Vous pouvez utiliser le serveur intégré pour exécuter votre application et même utiliser SQLite pour une base de données (tant que sqlite3 est installé sur votre système) et ne nécessitez pas grand-chose ! Exécutez simplement la commande suivante une fois PHP installé:

php -S localhost:8000

Ensuite, ouvrez votre navigateur et allez à http://localhost:8000.

Si vous souhaitez rendre le répertoire de documents de votre projet dans un répertoire différent (Ex: votre projet est ~/myproject, mais votre répertoire de documents est ~/myproject/public/), vous pouvez exécuter la commande suivante une fois dans le répertoire ~/myproject:

php -S localhost:8000 -t public/

Ensuite, ouvrez votre navigateur et allez à http://localhost:8000.

Apache

Assurez-vous qu'Apache est déjà installé sur votre système. Sinon, recherchez comment installer Apache sur votre système.

Pour Apache, éditez votre fichier .htaccess avec ce qui suit:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

Remarque: Si vous avez besoin d'utiliser Flight dans un sous-répertoire, ajoutez la ligne RewriteBase /sous-repertoire/ juste après RewriteEngine On.

Remarque: Si vous souhaitez protéger tous les fichiers du serveur, comme un fichier de base de données ou un fichier env. Mettez ceci dans votre fichier .htaccess:

RewriteEngine On
RewriteRule ^(.*)$ index.php

Nginx

Assurez-vous que Nginx est déjà installé sur votre système. Sinon, recherchez comment installer Nginx sur votre système.

Pour Nginx, ajoutez ce qui suit à la déclaration de votre serveur:

server {
  location / {
    try_files $uri $uri/ /index.php;
  }
}

Créez votre fichier index.php

<?php

// Si vous utilisez Composer, requirez l'autoloader.
require 'vendor/autoload.php';
// si vous n'utilisez pas Composer, chargez le framework directement
// require 'flight/Flight.php';

// Ensuite, définissez une route et attribuez une fonction pour gérer la requête.
Flight::route('/', function () {
  echo 'bonjour le monde!';
});

// Enfin, démarrez le framework.
Flight::start();

Installation de PHP

Si vous avez déjà php installé sur votre système, passez ces instructions et passez à la section de téléchargement

Bien sûr ! Voici les instructions pour installer PHP sur macOS, Windows 10/11, Ubuntu et Rocky Linux. Je vais également inclure des détails sur l'installation de différentes versions de PHP.