Learn

Apprendre À Propos De Flight

Flight est un cadre 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 construit en gardant à l'esprit la simplicité et est écrit d'une manière facile à comprendre et à utiliser.

Concepts Importants Du Cadre

Pourquoi un Cadre?

Voici un bref article sur pourquoi vous devriez utiliser un cadre. Il est judicieux de comprendre les avantages d'utiliser un cadre avant de commencer à en utiliser un.

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

Sujets Principaux

Chargement Automatique

Apprenez comment charger automatiquement vos propres classes dans votre application.

Itinéraire

Apprenez comment gérer les itinéraires pour votre application Web. Cela inclut également le regroupement des itinéraires, les paramètres d'itinéraire et le middleware.

Middleware

Apprenez comment utiliser le 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 comment envoyer des réponses à vos utilisateurs.

Modèles HTML

Apprenez comment 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 cadre pour votre application.

Extension de Flight

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

Événements et Filtrage

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

Conteneur d'Injection de Dépendances

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

API du Cadre

Apprenez les méthodes de base du cadre.

Migration vers v3

La compatibilité ascendante a en grande partie été maintenue, mais il y a quelques changements dont vous devriez être conscient lors de la migration de v2 à v3.

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/migrating_to_v3

Migration vers v3

La compatibilité ascendante a été maintenue pour la plupart, mais il y a quelques changements dont vous devez être conscient lors de la migration de v2 à v3.

Comportement de l'output buffering (3.5.0)

Output buffering 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 "gestionnaire" 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) casse le modèle MVC. Ce changement vise à être plus en phase avec le modèle MVC et à rendre le framework plus prévisible et plus facile à utiliser.

Dans v2, l'output buffering était géré d'une manière où il ne fermait pas de manière cohérente son propre tampon de sortie, ce qui rendait les tests unitaires et le streaming plus difficiles. Pour la majorité des utilisateurs, ce changement ne vous affectera peut-être pas réellement. Cependant, si vous affichez du contenu en dehors des callables et des contrôleurs (par exemple dans un hook), vous risquez probablement de rencontrer des problèmes. Afficher du contenu dans des hooks, et avant que le framework ne s'exécute réellement a pu fonctionner par le passé, mais cela ne fonctionnera plus à 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 fonctionnera 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 celle-ci provoqueront une erreur
    echo '<html><head><title>Ma page</title></head><body>';
});

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

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

Flight::after('start', function(){
    // cela provoquera 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 ancien code tel qu'il est sans le réécrire pour le faire fonctionner avec v3 ? Oui, vous le pouvez ! Vous pouvez activer le comportement de rendu v2 en définissant 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 à 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 avez directement appelé 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épendance puissent être utilisés plus facilement. Si vous devez invoquer une méthode similaire à ce que Dispatcher faisait, vous pouvez utiliser manuellement quelque chose comme $result = $class->$method(...$params); ou call_user_func_array() à la place.

Learn/configuration

Configuration

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

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

Paramètres de configuration disponibles

Voici la liste de tous les paramètres de configuration disponibles :

Variables

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

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

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.

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 sur le serveur web. Vous pouvez activer cela en modifiant la configuration :

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

Non trouvé

Lorsqu'une URL est introuvable, Flight appelle la méthode notFound. Le comportement par défaut est d'envoyer une réponse HTTP 404 Not Found 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 cruciale 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 propose un certain nombre de 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 les en-têtes pour prévenir le clickjacking, le XSS et d'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 le XSS
// Remarque : cet en-tête peut devenir très complexe, donc vous devrez
// 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 le XSS
Flight::response()->header('X-XSS-Protection', '1; mode=block');

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

// Définir l'en-tête Referrer-Policy pour contrôler la quantité d'informations d'origine envoyées
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 quelles fonctionnalités et APIs peuvent ê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
// Pour info, cette chaîne de caractères vide agit comme un middleware global pour
// toutes les routes. Bien sûr, vous pourriez faire la même chose et l'ajouter juste
// à des routes spécifiques.
Flight::group('', function(Router $router) {
    $router->get('/users', [ 'UserController', 'getUsers' ]);
    // plus de routes
}, [ new SecurityHeadersMiddleware() ]);

Demandes de falsification de requête inter-sites (CSRF)

La falsification de requête inter-sites (CSRF) est un type d'attaque où un site web malveillant peut faire envoyer une requête au site web d'un utilisateur par le biais de son navigateur. Cela peut être utilisé pour effectuer des actions sur votre site web 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 lorsque le formulaire est soumis.

// 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)
// 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, 'Jetno CSRF invalide');
        }
    }
});

Ou vous pouvez utiliser une classe de 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, 'Jetno 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() ]);

Cross Site Scripting (XSS)

Le Cross Site Scripting (XSS) est un type d'attaque où un site web malveillant peut injecter du code dans votre site web. La plupart de ces vulnérabilités proviennent des valeurs de formulaires que vos utilisateurs 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 code JavaScript ou 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 astucieux et essaie d'utiliser ceci comme son nom
$name = '<script>alert("XSS")</script>';

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

// Si vous utilisez quelque chose comme Latte enregistré en tant que votre classe de vue, il échappera également automatiquement cela.
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 à vos trousses. Vous pouvez utiliser des instructions préparées dans vos objets PDO pour prévenir l'injection 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 facilement être fait en une seule 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 juste de ne JAMAIS faire quelque chose comme ceci...
$users = Flight::db()->fetchAll("SELECT * FROM users WHERE username = '{$username}' LIMIT 5");
// car que se passe-t-il si $username = "' OR 1=1; -- "; 
// Après la construction de la requête, cela 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,
// c'est une attaque d'injection de SQL très courante qui renverra tous les utilisateurs.

CORS

Le partage des ressources inter-origines (CORS) est un mécanisme qui permet à de nombreuses ressources (par ex., polices, JavaScript, etc.) sur une page web d'être demandées à partir d'un autre domaine en dehors du domaine d'origine de la ressource. Flight n'a pas de fonctionnalité intégrée, mais cela peut facilement être géré avec des middlewares ou des filtres d'événements similaires à CSRF.

// app/middleware/CorsMiddleware.php

namespace app\middleware;

class CorsMiddleware
{
    public function before(array $params): void
    {
        $response = Flight::response();
        if (isset($_SERVER['HTTP_ORIGIN'])) {
            $this->allowOrigins();
            $response->header('Access-Control-Allow-Credentials: true');
            $response->header('Access-Control-Max-Age: 86400');
        }

        if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
            if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
                $response->header(
                    'Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS'
                );
            }
            if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
                $response->header(
                    "Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}"
                );
            }
            $response->send();
            exit(0);
        }
    }

    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',
        ];

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

// index.php ou où vous avez vos routes
Flight::route('/users', function() {
    $users = Flight::db()->fetchAll('SELECT * FROM users');
    Flight::json($users);
})->addMiddleware(new CorsMiddleware());

Conclusion

La sécurité est primordiale et il est important de vous assurer que vos applications web sont sécurisées. Flight offre un certain nombre de fonctionnalités pour vous aider à sécuriser vos applications web, mais il est important d'être toujours vigilant et de vous assurer de faire tout ce qui est en votre pouvoir pour protéger les données de vos utilisateurs. 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 middlewares 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 "pourquoi un framework ?" pour une explication plus approfondie.

Le routage de base dans Flight est réalisé en associant un motif d'URL à 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 correspondant à une requête sera invoquée.

Rappels/Fonctions

Le rappel peut être n'importe quel objet appelable. Vous pouvez donc utiliser une fonction normale :

function bonjour(){
    echo 'Bonjour le monde !';
}

Flight::route('/', 'bonjour');

Classes

Vous pouvez également utiliser une méthode statique d'une classe :

class Salutation {
    public static function bonjour() {
        echo 'Bonjour le monde !';
    }
}

Flight::route('/', [ 'Salutation','bonjour' ]);

Ou en créant d'abord un objet puis en appelant la méthode :


// Greeting.php
class Salutation
{
    public function __construct() {
        $this->name = 'Jean Dupont';
    }

    public function bonjour() {
        echo "Bonjour, {$this->name} !";
    }
}

// index.php
$salutation = new Salutation();

Flight::route('/', [ $salutation, 'bonjour' ]);
// Vous pouvez également le faire sans créer d'abord l'objet
// Remarque : Aucun argument ne sera injecté dans le constructeur
Flight::route('/', [ 'Salutation', 'bonjour' ]);

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épendance

Introduction

Le Conteneur d'Injection de Dépendance (CID) 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. Certains exemples de bibliothèques CID sont : Dice, Pimple, PHP-DI, et league/container.

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

Exemple de Base

L'ancienne méthode de faire les choses pourrait ressembler à 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 constater 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 se développe, vous constaterez que vous créez le même objet PDO en plusieurs endroits. C'est là qu'un CID est utile.

Voici le même exemple en utilisant un CID (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éaffecter à lui-même comme ci-dessous!
$container = $container->addRule('PDO', [
    // shared signifie que le même objet sera renvoyé à 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 pourriez 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('/entreprise/@id', 'CompanyController->view');
Flight::route('/organisation/@id', 'OrganizationController->view');
Flight::route('/catégorie/@id', 'CategoryController->view');
Flight::route('/paramètres', 'SettingsController->view');

Le bonus supplémentaire de l'utilisation d'un CID 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 écrivez des tests pour votre application !

PSR-11

Flight peut également utiliser tout conteneur conforme à PSR-11. Cela signifie que vous pouvez utiliser n'importe quel conteneur qui implémente l'interface PSR-11. Voici un exemple en 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();

Cela peut être un peu plus verbeux que l'exemple Dice précédent, mais cela fonctionne toujours avec les mêmes avantages !

Gestionnaire CID Personnalisé

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

De plus, il existe 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/middlewares, voici comment vous le 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/middlewares

class MonControleur {
    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 quelque chose 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 MaClassePersonnalisée {
    public function parseChose() {
        return 'chose';
    }
}

class UserController {

    protected MaClassePersonnalisée $MaClassePersonnalisée;

    public function __construct(MaClassePersonnalisée $MaClassePersonnalisée) {
        $this->MaClassePersonnalisée = $MaClassePersonnalisée;
    }

    public function index() {
        echo $this->MaClassePersonnalisée->parseChose();
    }
}

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

Learn/middleware

Middleware de Route

Flight prend en charge le middleware de route et de groupe de route. Le middleware est une fonction qui est exécutée avant (ou après) le rappel de la route. C'est une excellente façon 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 de middleware "après", sauf pour les 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 y a quelques notes très importantes sur le middleware dont vous devez être conscient avant de les utiliser :

Classes de Middleware

Le middleware peut également être enregistré en tant que classe. Si vous avez besoin de la fonctionnalité "après", vous devez utiliser une classe.

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

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

$MonMiddleware = new MonMiddleware();
Flight::route('/chemin', function() { echo 'Me voici!'; })->addMiddleware($MonMiddleware); // aussi ->addMiddleware([ $MonMiddleware, $MonMiddleware2 ]);

Flight::start();

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

Regroupement de Middleware

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


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

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

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


// ajouté à la fin de la méthode de groupe
Flight::group('', function() {
    Flight::route('/utilisateurs', function() { echo 'utilisateurs'; }, false, 'utilisateurs');
    Flight::route('/utilisateurs/@id', function($id) { echo 'utilisateur :'.$id; }, false, 'vue_utilisateur');
}, [ new MiddlewareAuthApi() ]);

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 demande HTTP dans un objet unique, qui peut être accédé en faisant:

$request = Flight::request();

L'objet de demande fournit les propriétés suivantes:

Vous pouvez accéder aux propriétés query, data, cookies et files sous forme de tableaux ou d'objets.

Ainsi, 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 brut de la requête

Pour obtenir le corps brut de la demande HTTP, par exemple lors du traitement de demandes PUT, vous pouvez faire:

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

Entrée JSON

Si vous envoyez une demande avec le type application/json et les données {"id": 123} ils seront disponibles à partir de la propriété data:

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

Accès à $_SERVEUR

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


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

Accès aux en-têtes de la demande

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


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

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

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 de l'API du cadre

Flight est conçu pour être facile à utiliser et à comprendre. Ce qui suit est l'ensemble complet des méthodes pour le cadre. Il se compose de méthodes de base, 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 de base

Ces méthodes sont fondamentales pour le cadre et ne peuvent pas être remplacées.

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

Méthodes extensibles

Flight::start() // Démarre 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 facultatifs.
Flight::route(string $motif, callable $rappel, bool $pass_route = false, string $alias = '') // Associe un motif URL à un rappel.
Flight::post(string $motif, callable $rappel, bool $pass_route = false, string $alias = '') // Associe un motif URL de requête POST à un rappel.
Flight::put(string $motif, callable $rappel, bool $pass_route = false, string $alias = '') // Associe un motif URL de requête PUT à un rappel.
Flight::patch(string $motif, callable $rappel, bool $pass_route = false, string $alias = '') // Associe un motif URL de requête PATCH à un rappel.
Flight::delete(string $motif, callable $rappel, bool $pass_route = false, string $alias = '') // Associe un motif URL de requête DELETE à un rappel.
Flight::group(string $motif, callable $rappel) // Crée un regroupement pour les URL, le motif doit être une chaîne.
Flight::getUrl(string $nom, 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::render(string $fichier, array $données, ?string $clé = null) // Rend un fichier de modèle.
Flight::error(Throwable $erreur) // Envoie une réponse HTTP 500.
Flight::notFound() // Envoie une réponse HTTP 404.
Flight::etag(string $id, string $type = 'chaîne') // Effectue la mise en cache HTTP ETag.
Flight::lastModified(int $temps) // Effectue la mise en cache HTTP de dernière modification.
Flight::json(mixed $donnees, int $code = 200, bool $encoder = true, string $jeu_caractères = 'utf8', int $option) // Envoie une réponse JSON.
Flight::jsonp(mixed $donnees, string $param = 'jsonp', int $code = 200, bool $encoder = true, string $jeu_caractères = '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/why_frameworks

Pourquoi un Framework ?

Certains programmeurs sont catégoriquement 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 des points valides à faire concernant 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 importants comme Laravel ou Symfony. Cependant, il fournit beaucoup 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 des applications web rapidement et facilement. Si vous êtes nouveau aux frameworks, Flight est un excellent framework pour débutants pour commencer. Cela vous aidera à découvrir les avantages de l'utilisation des frameworks sans vous submerger de 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 permettre de 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 des choses différentes en fonction de l'URL demandée. Par exemple, vous pouvez vouloir afficher le profil d'un utilisateur lorsqu'il visite /utilisateur/1234, mais afficher une liste de tous les utilisateurs lorsqu'ils visitent /utilisateurs. Tout cela se fait via le routage.

Ça pourrait fonctionner quelque chose comme ça :

Et pourquoi est-ce important ?

Avoir un routeur centralisé adéquat peut réellement rendre votre vie beaucoup plus facile ! Cela pourrait être difficile à voir au début. Voici quelques raisons pour lesquelles :

Je suis sûr que vous êtes familier avec la manière script par script de créer un site web. Vous pourriez avoir un fichier appelé index.php qui contient un tas de déclarations if pour vérifier l'URL, 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 ça peut rapidement devenir incontrôlable. Le système de routage de Flight est une manière beaucoup plus organisée et puissante de gérer le routage.

Ceci ?


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

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

// etc...

Ou ça ?


// index.php
Flight::route('/utilisateur/@id', ['UserController', 'voirProfilUtilisateur']);
Flight::route('/utilisateur/@id/editer', ['UserController', 'éditerProfilUtilisateur']);

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

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

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

Requêtes et Réponses

Flight fournit un moyen simple et facile de gérer les requêtes et réponses. C'est le cœur de ce qu'un framework web fait. Il prend une requête du navigateur d'un utilisateur, la traite, puis renvoie une réponse. C'est ainsi que vous pouvez construire des applications web qui font des choses comme afficher le profil d'un utilisateur, permettre à un utilisateur de se connecter, ou permettre à un utilisateur de publier un nouvel article de blog.

Requêtes

Une requête est ce que le navigateur d'un utilisateur envoie à votre serveur lorsqu'il visite votre site web. Cette requête contient des informations sur ce que l'utilisateur veut faire. Par exemple, elle pourrait contenir des informations sur quelle URL l'utilisateur veut visiter, quelles données l'utilisateur veut envoyer à votre serveur, ou quel type de données l'utilisateur veut recevoir de votre serveur. Il est important de savoir qu'une requête est en lecture seule. Vous ne pouvez pas modifier la requête, mais vous pouvez la lire.

Flight fournit un moyen simple d'accéder aux informations sur la requête. Vous pouvez accéder aux informations sur la requête en utilisant la méthode Flight::request(). Cette méthode renvoie un objet Request qui contient des informations sur la requête. Vous pouvez utiliser cet objet pour accéder aux informations sur la requête, 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 renvoie au navigateur d'un utilisateur lorsqu'il visite votre site web. Cette réponse contient des informations sur ce que votre serveur veut faire. Par exemple, elle pourrait contenir des informations sur quel type de données votre serveur veut envoyer à l'utilisateur, quel type de données votre serveur veut recevoir de l'utilisateur, ou quel type de données votre serveur veut Stocker sur l'ordinateur de l'utilisateur.

Flight fournit un moyen simple d'envoyer une réponse au navigateur d'un utilisateur. Vous pouvez envoyer une réponse en utilisant la méthode Flight::response(). Cette méthode prend un objet Response en tant qu'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, comme du HTML, du JSON, ou un fichier. Flight vous aide à générer automatiquement certaines parties de la réponse pour faciliter les choses, mais vous avez finalement 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 la plupart du 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 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 la capturera pour la renvoyer à l'utilisateur avec les en-têtes appropriés.


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

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

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


// Cela enverra "Bonjour, monde !" au navigateur de l'utilisateur
Flight::route('/', function() {
    // verbeux, mais fait parfois le travail quand vous en avez besoin
    Flight::response()->write("Bonjour, 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, 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 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, monde !" au navigateur de l'utilisateur en texte brut
Flight::route('/', function() {
    Flight::response()->header('Content-Type', 'text/plain');
    echo "Bonjour, 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]);

JSONP

Pour les demandes 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, en effectuant une requête GET en utilisant ?q=my_func, vous devriez recevoir la sortie:

my_func({"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 requête 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 ("Voir autre"). 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 facultativement un code d'état HTTP et un message:

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

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

Flight::stop();

Mise en cache HTTP

Flight fournit 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 Non modifié. La prochaine fois que le client demandera la même ressource, il lui sera demandé d'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 une durée de mise 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 passeriez
// à 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 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 vous voulez 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 de lastModified ou etag définira et vérifiera à la fois la valeur de cache. Si la valeur de cache est la même entre les requêtes, Flight enverra immédiatement une réponse HTTP 304 et arrêtera le traitement.

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

Flight fournit par défaut certaines fonctionnalités de base de templating.

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

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

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

Les données du 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 de modèle 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 maintenant disponible dans toutes vos vues. Ainsi, 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 configurant ce qui suit :

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

Dispositions

Il est courant que les sites web aient un seul fichier de modèle de disposition avec du contenu interchangeant. Pour rendre le contenu à utiliser dans une disposition, 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 alors des variables sauvegardées appelées headerContent et bodyContent. Vous pouvez ensuite rendre votre disposition 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>Hello</h1>
    <div>World</div>
  </body>
</html>

Vues Personnalisées

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

Smarty

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

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

// Afficher le modèle
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);
});

Latte

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


// Enregistrer Latte en tant que classe de vue
// Passe é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
    // 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 emballez-le pour que vous puissiez utiliser correctement Flight::render()
Flight::map('render', function(string $template, array $data): void {
  // C'est comme si $latte_engine->render($template, $data);
  echo Flight::view()->render($template, $data);
});

Learn/extending

Étendre

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 il vous permet de mapper vos propres méthodes, enregistrer vos propres classes ou même remplacer des classes et des méthodes existantes.

Si vous recherchez un conteneur d'injection de dépendances (Dependency Injection Container), rendez-vous sur la page du Conteneur d'injection de dépendances.

Mapper des méthodes

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

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

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

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

Enregistrer des classes

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

// Enregistrer votre classe
Flight::register('utilisateur', Utilisateur::class);

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

La méthode d'enregistrement vous permet également de passer 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 de 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, il vous suffit d'appeler à nouveau la même méthode
class UnController {
  public function __construct() {
    $this->db = Flight::db();
  }
}

Si vous passez un paramètre de rappel 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 rappel 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, il vous suffit de passer false comme paramètre :

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

// Nouvelle instance de la classe
$nouveau = 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.

Remplacer les méthodes du framework

Flight vous permet de remplacer sa fonctionnalité par défaut pour répondre à vos besoins, sans avoir à modifier de 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 HTTP 404 générique. Vous pouvez remplacer ce comportement en utilisant la méthode map :

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

Flight vous permet également de remplacer des 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 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/autoloading

Chargement automatique

Le chargement automatique est un concept en PHP où vous spécifiez un répertoire ou des répertoires à 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 les packages Composer.

Par défaut, toute classe Flight est chargée automatiquement grâce à Composer. Cependant, si vous souhaitez 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 ayons une 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 en majuscules à des fins d'exemple ultérieur)
│   └── views
└── public
    └── css
    └── js
    └── index.php

Vous avez peut-être remarqué que cette structure de fichiers est similaire à celle de ce site de documentation.

Vous pouvez spécifier chaque répertoire à partir duquel charger comme ceci :


/**
 * public/index.php
 */

// Ajouter un chemin au chargeur automatique
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');

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

// pas de namespace requis

// Il est recommandé que toutes les classes chargées automatiquement soient en Pascal Case (chaque mot en majuscule, sans espaces)
// Il est obligatoire de ne pas avoir de trait de soulignement dans le nom de votre classe
class MyController {

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

Espaces de noms

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


/**
 * public/index.php
 */

// Ajouter un chemin au chargeur automatique
Flight::path(__DIR__.'/../');

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

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

// les espaces de noms sont requis
// les espaces de noms sont identiques à la structure du répertoire
// les espaces de noms doivent suivre la même casse que la structure du répertoire
// les espaces de noms et les répertoires ne peuvent pas contenir de traits de soulignement
namespace app\controllers;

// Il est recommandé que toutes les classes chargées automatiquement soient en Pascal Case (chaque mot en majuscule, sans espaces)
// Il est obligatoire de ne pas avoir de trait de soulignement dans le nom de votre classe
class MyController {

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

Et si vous vouliez charger automatiquement une classe dans votre répertoire utils, vous feriez à peu près 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 en majuscules
//     comme dans l'arborescence des fichiers ci-dessus)
namespace app\UTILS;

class ArrayHelperUtil {

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

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

Le MIT License (MIT)

Copyright © 2023 @mikecao, @n0nag0n

La permission est hereby accordée, gratuitement, à toute personne obtenant une copie de ce logiciel et de la documentation associée les fichiers (le "Logiciel"), pour traiter dans le Logiciel sans limitation, y compris sans limitation les droits d'utilisation, de copie, de modification, de fusion, de publication, de distribution, de sous-licence et/ou de vente des copies du Logiciel, et de permettre à toute personne à qui le Logiciel est fourni de le faire, sous réserve des conditions suivantes:

L'avis de droit d'auteur ci-dessus et cet avis d'autorisation doivent être inclus dans toutes les copies ou parties substantielles du Logiciel.

LE LOGICIEL EST FOURNI "TEL QUEL", SANS GARANTIE D'AUCUNE SORTE, EXPRESSE OU IMPLICITE, Y COMPRIS MAIS SANS S'Y LIMITER LES GARANTIES DE QUALITE MARCHANDE, D'ADEQUATION A UNE FIN PARTICULIERE ET NONCONTREFAÇON. EN AUCUN CAS LES AUTEURS OU LE DROIT D'AUTEUR LES TITULAIRES NE PEUVENT ÊTRE TENUS RESPONSABLES POUR TOUTE RECLAMATION, DOMMAGES OU AUTRES RESPONSABILITES, QU'IL S'AGISSE D'UNE ACTION CONTRACTUELLE, DÉLIT OU AUTRE, SURVENANT DE, HORS DE OU EN RELATION AVEC LE LOGICIEL OU L'UTILISATION OU L' 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 tout type d'application web. Il est conçu en gardant à l'esprit la simplicité et est écrit d'une manière facile à comprendre et à utiliser.

Flight est un excellent framework pour les débutants qui sont nouveaux en PHP et 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 application web simple 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 'bonjour le monde!';
});

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 démarrer ! Vous pouvez également visiter la page des exemples pour vous inspirer sur certaines choses que vous pouvez faire avec Flight.

Communauté

Nous sommes sur Matrix ! Discutez avec nous sur #flight-php-framework:matrix.org.

Contribution

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

  1. Vous pouvez contribuer au framework principal 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 pull request ! Nous essayons de rester à jour, mais les mises à jour et les traductions de langues sont les bienvenues.

Conditions requises

Flight nécessite PHP 7.4 ou supérieur.

Remarque : PHP 7.4 est pris en charge car, au moment de la rédaction actuelle (2024), PHP 7.4 est la version par défaut pour certaines distributions Linux LTS. 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 en fichier PHP légère, simple et autonome

Avantages

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 === 'développement');
});

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"); // retourner 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 obtenir la documentation complète et assurez-vous de consulter le dossier examples.

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

Class d’aide PdoWrapper pour PDO

Flight est livré avec une classe d’aide pour PDO. Elle vous permet d'interroger facilement votre base de données avec toute la folie de préparation/execution/fetchAll(). Cela simplifie grandement la façon dont vous pouvez interroger votre base de données. Chaque ligne de résultat est renvoyée sous forme de classe Flight Collection qui vous permet d'accéder à vos données via la syntaxe de tableau ou la 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 les requêtes à la base de données:

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

Utilisez ceci pour les INSERT, les UPDATES, ou si vous prévoyez 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 l'écriture 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

Récupère 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'];
// ou
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'];
    // ou
    echo $row->name;
}

Note avec la syntaxe IN()

Cela a également une enveloppe utile pour les instructions IN(). Vous pouvez simplement passer un point d'interrogation unique en tant que marque de position pour IN() et ensuite 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 utiliser cet enrouleur
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'];
        // or 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 cela
    $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

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

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 avec 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 un auto-commit dans votre configuration.

Exemple simple

Voici un exemple simple de la façon dont vous pourriez l'utiliser.

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 écriture 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 intergiciel.
Flight::route('/some-restricted-page', function() {
    $session = Flight::session();

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

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

// la version intergiciel
Flight::route('/some-restricted-page', 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 façon dont vous pourriez l'utiliser.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

// définir un chemin personnalisé vers le fichier de configuration de votre session et attribuer une chaîne aléatoire pour l'identifiant de session
$app->register('session', Session::class, [ 'chemin/vers/fichier_configuration_session.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 voulez quelque chose comme "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-super-S3CR3T-sel'), // veuillez changer ceci pour quelque chose d'autre
            Session::CONFIG_AUTO_COMMIT   => true, // faites-le seulement s'il est nécessaire et/ou s'il est difficile de commettre() 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 dns PDO par exemple (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,          # Évitez les frais généraux liés à l'établissement d'une nouvelle connexion à chaque fois qu'un script doit parler à une base de données, ce qui se traduit par une application web plus rapide. TROUVEZ LE PENDANT TOI-MÊME
            ]
        ]);
    }
);

Documentation

Visitez 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 souhaitez parcourir ce package vous-même.

Awesome-plugins/tracy_extensions

Tracy Flight Panel Extensions

=====

Ceci est un ensemble d'extensions pour rendre le travail avec Flight un peu plus riche.

C'est le Panneau

Barre de vol

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

Données de vol Base de données de vol Demande de vol

Installation

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

Configuration

Il y a très peu de configuration que vous devez faire pour commencer. Vous devrez initier le débogueur Tracy avant d'utiliser cette 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 de 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 régulière
$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 false sinon Tracy ne peut pas réellement se rendre :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app());
}

// plus de code

Flight::start();

Configuration Additionnelle

Données de Session

Si vous avez un gestionnaire de session personnalisé (tel que ghostff/session), vous pouvez transmettre n'importe quel tableau de données de session à Tracy et il l'affichera automatiquement pour vous. Vous le passez 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 false sinon Tracy ne peut pas réellement se rendre :(
    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 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 false sinon Tracy ne peut pas réellement se rendre :(
    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 cartographie d'une entité de base de données vers un objet PHP. En termes simples, si vous avez une table utilisateurs dans votre base de données, vous pouvez "traduire" une ligne de cette table vers une classe User et un objet $user dans votre code source. Voir exemple de base.

Exemple de Base

Supposons que vous avez 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 comme commentaires ici
 * 
 * @property int    $id
 * @property string $name
 * @property string $password
 */ 
class User extends flight\ActiveRecord {
    public function __construct($database_connection)
    {
        // vous pouvez le configurer de cette manière
        parent::__construct($database_connection, 'users');
        // ou de cette manière
        parent::__construct($database_connection, null, [ 'table' => 'users']);
    }
}

Maintenant, regardez la magie opérer!

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

// pour mysql
$database_connection = new PDO('mysql:host=localhost;dbname=test_db&charset=utf8bm4', 'username', 'password');

// ou mysqli
$database_connection = new mysqli('localhost', 'username', 'password', 'test_db');
// ou mysqli avec une création non basée sur un objet
$database_connection = mysqli_connect('localhost', 'username', 'password', 'test_db');

$user = new User($database_connection);
$user->name = 'Bobby Tables';
$user->password = password_hash('quel mot de passe cool');
$user->insert();
// ou $user->save();

echo $user->id; // 1

$user->name = 'Joseph Mamma';
$user->password = password_hash('quel mot de passe cool à nouveau !!!');
$user->insert();
// impossible d'utiliser $user->save() ici sinon il pensera que c'est une mise à jour !

echo $user->id; // 2

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

$user->find(1); // trouve id = 1 dans la base de données et la 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();

Voyez comme 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. Complètement à vous.

Autonome

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

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

$User = new User($pdo_connection);

Framework PHP Flight

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

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

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

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

Fonctions CRUD

find($id = null) : boolean|ActiveRecord

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

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

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

// trouver un enregistrement par un ID 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)

Renvoie 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(); // vrai

insert(): boolean|ActiveRecord

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

$user = new User($pdo_connection);
$user->name = 'démonstration';
$user->password = md5('démonstration');
$user->insert();

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($pdo_connection);
$user->name = 'démonstration';
$user->password = md5('démonstration');
$user->save();

Remarque : Si vous avez des relations définies dans la classe, elles enregistreront récursivement ces relations également si elles ont été définies, instanciées et ont des données à mettre à jour. (v0.4.0 et supé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 sales se rapportent aux données qui ont été modifiées dans un enregistrement.

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

// rien n'est "sale" à ce stade.

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

$user->password = password_hash('nouveaumotdepasse'); // maintenant c'est sale
$user->dirty(); // ne rien passer effacera toutes les entrées sales.
$user->update(); // rien ne sera mis à jour car rien n'a été capturé comme étant sale.

$user->dirty([ 'name' => 'quelquechose', '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)

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

$user->copyFrom([ 'name' => 'quelquechose', '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)

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

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

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, il réinitialisera également les données de la requête qui ont été utilisées pour trouver l'objet actuel (comportement par défaut).

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

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é généré 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-unes des 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 diable 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émonstration"')->find();

Note 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 CECI !!! Cela est susceptible de ce que l'on appelle des attaques par injection SQL. Il y a beaucoup d'articles en ligne, veuillez rechercher "attaques par injection SQL php" et vous trouverez beaucoup d'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 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(), vous pouvez 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)

Limitez le nombre d'enregistrements renvoyés. Si un deuxième entier est donné, il sera compensé, limit comme en SQL.

$user->orderby('name DESC')->limit(0, 10)->findAll();

Conditions WHERE

equal(string $field, mixed $value) / eq(string $field, mixed $value)

champ = $valeur

$user->eq('id', 1)->find();

notEqual(string $field, mixed $value) / ne(string $field, mixed $value)

champ <> $valeur

$user->ne('id', 1)->find();

isNull(string $field)

champ IS NULL

$user->isNull('id')->find();

isNotNull(string $field) / notNull(string $field)

champ IS NOT NULL

$user->isNotNull('id')->find();

greaterThan(string $field, mixed $value) / gt(string $field, mixed $value)

champ > $valeur

$user->gt('id', 1)->find();

lessThan(string $field, mixed $value) / lt(string $field, mixed $value)

champ < $valeur

$user->lt('id', 1)->find();

greaterThanOrEqual(string $field, mixed $value) / ge(string $field, mixed $value) / gte(string $field, mixed $value)

champ >= $valeur

$user->ge('id', 1)->find();

lessThanOrEqual(string $field, mixed $value) / le(string $field, mixed $value) / lte(string $field, mixed $value)

champ <= $valeur

$user->le('id', 1)->find();

like(string $field, mixed $value) / notLike(string $field, mixed $value)

champ LIKE $valeur ou champ NOT LIKE $valeur

$user->like('name', 'de')->find();

in(string $field, array $values) / notIn(string $field, array $values)

champ IN($valeur) ou champ NOT IN($valeur)

$user->in('id', [1, 2])->find();

between(string $field, array $values)

champ ENTRE $valeur ET $valeur1

$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 petite configuration supplémentaire dans la classe au préalable.

Définir le 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 la 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

        // obligatoire
        'Some_Class', // c'est la classe ActiveRecord "autre" à laquelle cela fera référence

        // obligatoire
        // en fonction du 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
        'clé_locale_ou_étrangère',
        // juste pour info, cela rejoint é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
        'back_reference_name' // c'est si vous voulez faire référence à cette relation en arrière à lui-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($database_connection)
    {
        parent::__construct($database_connection, '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($database_connection)
    {
        parent::__construct($database_connection, 'contacts');
    }
}

Maintenant que les références sont configurées, nous pouvons les utiliser très facilement !

$user = new User($pdo_connection);

// trouver l'utilisateur le plus récent.
$user->notNull('id')->orderBy('id desc')->find();

// obtenir des contacts en utilisant la relation :
foreach($user->contacts as $contact) {
    echo $contact->id;
}

// ou nous pouvons aller dans l'autre sens.
$contact = new Contact();

// trouver un contact
$contact->find();

// obtenir l'utilisateur en utilisant la relation :
echo $contact->user->name; cela est le nom de l'utilisateur

Assez cool, n'est-ce pas ?

Configuration de Données Personnalisées

Parfois, vous pouvez avoir besoin d'attacher quelque chose d'unique à votre ActiveRecord tel qu'un calcul personnalisé qui pourrait être plus simple à attacher à l'objet qui serait ensuite 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_vues_page', $nombre_vues_page);

Et ensuite vous le référencez simplement comme une propriété d'objet normale.

echo $user->nombre_vues_page;

Événements

Encore une fonctionnalité super géniale de cette bibliothèque concerne les événements. Les événements se déclenchent à certains moments en fonction de certaines méthodes que vous appelez. Ils sont très très utiles pour configurer automatiquement des données pour vous.

onConstruct(ActiveRecord $ActiveRecord, array &config)

Ceci 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 faire ceci pour définir automatiquement la connexion
        $config['connexion'] = Flight::db();
        // ou ceci
        $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 est probablement seulement utile 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) {
        // exécutez toujours id >= 0 si c'est votre truc
        $self->gte('id', 0); 
    } 
}

afterFind(ActiveRecord $ActiveRecord)

Celui-ci est probablement plus utile si vous avez toujours besoin d'exécuter une certaine logique à chaque fois que cet enregistrement est récupéré. Avez-vous besoin de décrypter quelque chose ? Avez-vous besoin d'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 = votreFonctionDeDecryptage($self->secret, $une_clé);

        // peut-être stocker quelque chose de personnalisé comme une requête ?
        $self->setCustomData('nombre_vues', $self->select('COUNT(*) count')->from('vues_utilisateur')->eq('id_utilisateur', $self->id)['count']; 
    } 
}

beforeFindAll(ActiveRecord $ActiveRecord)

Cela est probablement seulement utile 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) {
        // exécutez toujours id >= 0 si c'est votre truc
        $self->gte('id', 0); 
    } 
}

afterFindAll(array<int,ActiveRecord> $results)

Similaire à afterFind() mais vous permet de 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 besoin de changer 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 de jouer
        Flight::cache()->set('identifiant_inseré_le_plus_récemment', $self->id);
        // ou quoi que ce soit d'autre....
    } 
}

beforeUpdate(ActiveRecord $ActiveRecord)

Vraiment utile si vous avez besoin de définir des valeurs par défaut à 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 de jouer
        Flight::cache()->set('identifiant_utilisateur_les_plus_récents', $self->id);
        // ou quoi que ce soit d'autre....
    } 
}

beforeSave(ActiveRecord $ActiveRecord)/afterSave(ActiveRecord $ActiveRecord)

Cela est utile si vous voulez que des événements se produisent à la fois lors des insertions ou des mises à jour. Je vous épargne 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->dernière_mise_à_jour = gmdate('Y-m-d H:i:s');
    } 
}

beforeDelete(ActiveRecord $ActiveRecord)/afterDelete(ActiveRecord $ActiveRecord)

Je ne suis pas sûr de ce que vous voudriez faire ici, mais pas de jugements ici ! Vous y allez !

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 était un brave soldat... :cry-face:';
    } 
}

Gestion de la Connexion à la Base de Données

Lorsque vous utilisez cette bibliothèque, vous pouvez configurer la connexion à la base de données de plusieurs 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 devez actualiser la connexion à la base de données, par exemple si vous exécutez un script CLI de longue durée et devez actualiser la connexion de temps en temps, vous pouvez réinitialiser la connexion avec $votre_enregistrement->setDatabaseConnection($connexion_pdo).

Contribuer

S'il vous plaît faites-le. :D

Configuration

Lorsque vous contribuez, assurez-vous de lancer composer test-coverage pour maintenir une couverture de 100% des tests (ce n'est pas une véritable couverture de test unitaire, mais plutôt des tests d'intégration).

Assurez-vous également de lancer composer beautify et composer phpcs pour corriger les erreurs de formatage.

Licence

MIT

Awesome-plugins/latte

Latte

Latte est un moteur de template complet, très facile à utiliser et qui se rapproche plus de la syntaxe PHP que Twig ou Smarty. Il est également très facile à étendre et à ajouter vos propres filtres et fonctions.

Installation

Installer avec composer.

composer require latte/latte

Configuration de base

Il existe quelques options de configuration de base pour commencer. 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 modèles pour accélérer les choses
    // Une chose intéressante à propos de Latte est qu'il rafraîchit automatiquement
    // votre 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($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 enveloppera toutes vos autres vues.

<!-- app/views/layout.latte -->
<!doctype html>
<html lang="fr">
    <head>
        <title>{$title ? $title . ' - '}My App</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <nav>
                <!-- vos éléments de navigation ici -->
            </nav>
        </header>
        <div id="content">
            <!-- C'est le magique ici -->
            {block content}{/block}
        </div>
        <div id="footer">
            &copy; Droit d'auteur
        </div>
    </body>
</html>

Et maintenant nous avons votre fichier qui sera rendu à l'intérieur de ce bloc de contenu :

<!-- app/views/home.latte -->
<!-- Cela dit à Latte que ce fichier est "à l'intérieur" du fichier layout.latte -->
{extends layout.latte}

<!-- Ceci est le contenu qui sera rendu à l'intérieur de la mise en page dans le bloc de contenu -->
{block content}
    <h1>Page d'accueil</h1>
    <p>Bienvenue sur 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 :

// route 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.

Mise en cache

La mise en cache est un excellent moyen de rendre votre application plus rapide. Il existe plusieurs bibliothèques de mise en cache qui peuvent être utilisées avec Flight.

Cookies

Les cookies sont un excellent moyen de stocker de petits morceaux de 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 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 wrappers simples pour écrire des requêtes, tandis que d'autres sont des ORM complets.

Chiffrement

Le chiffrement est crucial 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 commettre dans votre dépôt de code.

Session

Les sessions ne sont pas vraiment utiles pour les API, mais pour le développement d'une application web, elles 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 plusieurs 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!

Examples

Besoin d'un démarrage rapide?

Rendez-vous sur le dépôt flightphp/skeleton pour commencer! Il s'agit d'un projet qui comprend un fichier unique de page contenant tout ce dont vous avez besoin pour exécuter votre application. Il inclut également un exemple plus complet avec des contrôleurs et des vues.

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 manière de structurer vos propres projets construits avec Flight!

Vous voulez partager votre propre exemple?

Si vous avez un projet que vous souhaitez partager, veuillez soumettre une demande d'extraction pour l'ajouter à cette liste!