Learn
En apprendre davantage sur Flight
Flight est un framework rapide, simple et extensible pour PHP. Il est assez polyvalent et peut être utilisé pour construire n'importe quel type d'application web. Il est conçu dans un souci de simplicité et est écrit de manière à être facile à comprendre et à utiliser.
Concepts importants du framework
Pourquoi un framework ?
Voici un bref article sur pourquoi vous devriez utiliser un framework. C'est une bonne idée de comprendre les avantages de l'utilisation d'un framework avant de commencer à en utiliser un.
De plus, un excellent tutoriel a été créé par @lubiana. Bien qu'il ne traite pas en détail de Flight spécifiquement, ce guide vous aidera à comprendre certains des concepts majeurs entourant un framework et pourquoi ils sont bénéfiques à utiliser. Vous pouvez trouver le tutoriel ici.
Flight comparé à d'autres frameworks
Si vous migrez d'un autre framework tel que Laravel, Slim, Fat-Free ou Symfony vers Flight, cette page vous aidera à comprendre les différences entre les deux.
Sujets principaux
Autoloading
Apprenez comment autoload vos propres classes dans votre application.
Routing
Apprenez comment gérer les routes de votre application web. Cela inclut également le regroupement de routes, les paramètres de route et le middleware.
Middleware
Apprenez comment utiliser le middleware pour filtrer les requêtes et les réponses dans votre application.
Requests
Apprenez comment gérer les requêtes et les réponses dans votre application.
Responses
Apprenez comment envoyer des réponses à vos utilisateurs.
Events
Apprenez comment utiliser le système d'événements pour ajouter des événements personnalisés à votre application.
HTML Templates
Apprenez comment utiliser le moteur de vue intégré pour rendre vos modèles HTML.
Security
Apprenez comment sécuriser votre application contre les menaces de sécurité courantes.
Configuration
Apprenez comment configurer le framework pour votre application.
Extending Flight
Apprenez comment étendre le framework en ajoutant vos propres méthodes et classes.
Events and Filtering
Apprenez comment utiliser le système d'événements pour ajouter des hooks à vos méthodes et aux méthodes internes du framework.
Dependency Injection Container
Apprenez comment utiliser des conteneurs d'injection de dépendances (DIC) pour gérer les dépendances de votre application.
Framework API
Découvrez les méthodes de base du framework.
Migrating to v3
La compatibilité ascendante a pour la plupart été maintenue, mais il y a quelques changements dont vous devez être conscient lors de la migration de v2 vers v3.
Troubleshooting
Il existe des problèmes courants auxquels vous pourriez être confronté lors de l'utilisation de Flight. Cette page vous aidera à résoudre ces problèmes.
Learn/stopping
Arrêt
Vous pouvez arrêter le cadre à tout moment en appelant la méthode halt
:
Flight::halt();
Vous pouvez également spécifier un code d'état HTTP
et un message facultatif:
Flight::halt(200, 'Je reviens bientôt...');
Appeler halt
permettra de supprimer tout contenu de réponse jusqu'à ce point. Si vous souhaitez arrêter
le cadre et afficher la réponse actuelle, utilisez la méthode stop
:
Flight::stop();
Learn/errorhandling
Gestion des erreurs
Erreurs et exceptions
Toutes les erreurs et exceptions sont capturées par Flight et transmises à la méthode error
.
Le comportement par défaut est d'envoyer une réponse générique d'erreur de serveur interne HTTP 500
avec des informations sur l'erreur.
Vous pouvez remplacer ce comportement pour vos propres besoins:
Flight::map('error', function (Throwable $error) {
// Gérer l'erreur
echo $error->getTraceAsString();
});
Par défaut, les erreurs ne sont pas enregistrées sur le serveur web. Vous pouvez activer cela en modifiant la configuration:
Flight::set('flight.log_errors', true);
Non trouvé
Lorsqu'une URL ne peut être trouvée, Flight appelle la méthode notFound
. Le comportement par défaut
est d'envoyer une réponse HTTP 404 Non trouvé
avec un message simple.
Vous pouvez remplacer ce comportement pour vos propres besoins:
Flight::map('notFound', function () {
// Gérer non trouvé
});
Learn/flight_vs_laravel
Flight vs Laravel
Qu'est-ce que Laravel?
Laravel est un framework complet qui possède toutes les fonctionnalités et une incroyable écosystème axé sur les développeurs, mais au détriment des performances et de la complexité. Le but de Laravel est de procurer au développeur le plus haut niveau de productivité et de simplifier les tâches courantes. Laravel est un excellent choix pour les développeurs qui souhaitent construire une application web d'entreprise complète. Cela comporte certains compromis, notamment en termes de performances et de complexité. Apprendre les bases de Laravel peut être facile, mais acquérir une maîtrise du framework peut prendre du temps.
Il existe tellement de modules Laravel que les développeurs ont souvent l'impression que la seule façon de résoudre les problèmes est d'utiliser ces modules, alors qu'en fait vous pourriez simplement utiliser une autre bibliothèque ou écrire votre propre code.
Avantages par rapport à Flight
- Laravel dispose d'un vaste écosystème de développeurs et de modules pouvant être utilisés pour résoudre les problèmes courants.
- Laravel dispose d'un ORM complet pouvant être utilisé pour interagir avec votre base de données.
- Laravel possède une quantité incroyable de documentation et de tutoriels pouvant être utilisés pour apprendre le framework.
- Laravel possède un système d'authentification intégré pouvant être utilisé pour sécuriser votre application.
- Laravel propose des podcasts, des conférences, des réunions, des vidéos et d'autres ressources pouvant être utilisés pour apprendre le framework.
- Laravel est conçu pour un développeur expérimenté désireux de construire une application web d'entreprise complète.
Inconvénients par rapport à Flight
- Laravel a beaucoup plus de fonctionnalités sous le capot que Flight. Cela entraîne un coût dramatique en termes de performances. Consultez les tests de TechEmpower pour plus d'informations.
- Flight est destiné à un développeur cherchant à créer une application web légère, rapide et facile à utiliser.
- Flight est orienté vers la simplicité et la facilité d'utilisation.
- L'une des caractéristiques principales de Flight est qu'il fait de son mieux pour maintenir la compatibilité ascendante. Laravel provoque beaucoup de frustration entre les versions majeures.
- Flight est destiné aux développeurs qui se lancent dans l'univers des frameworks pour la première fois.
- Flight n'a pas de dépendances, alors que Laravel a une quantité atroce de dépendances.
- Flight peut également gérer des applications de niveau entreprise, mais n'a pas autant de code superflu que Laravel. Cela exigera également plus de discipline de la part du développeur pour maintenir les choses organisées et bien structurées.
- Flight donne plus de contrôle au développeur sur l'application, tandis que Laravel a énormément de magie en coulisses qui peut être frustrante.
Learn/migrating_to_v3
Migration vers v3
La compatibilité ascendante a été en grande partie maintenue, mais il y a des changements dont vous devez être conscient lorsque vous migrez de la v2 à la v3.
Comportement de l'Empaquetage de Sortie (3.5.0)
Empaquetage de sortie est le processus par lequel la sortie générée par un script PHP est stockée dans un tampon (interne à PHP) avant d'être envoyée au client. Cela vous permet de modifier la sortie avant qu'elle ne soit envoyée au client.
Dans une application MVC, le contrôleur est le "manager" et il gère ce que fait la vue. Avoir une sortie générée en dehors du contrôleur (ou dans le cas de Flight parfois une fonction anonyme) rompt avec le modèle MVC. Ce changement vise à être plus en conformité avec le modèle MVC et à rendre le framework plus prévisible et plus facile à utiliser.
Dans la v2, l'empaquetage de sortie était géré d'une manière où il ne fermait pas systématiquement son propre tampon de sortie, ce qui rendait les tests unitaires et le streaming plus difficiles. Pour la majorité des utilisateurs, ce changement ne devrait pas vraiment vous affecter. Cependant, si vous émettez du contenu en dehors des appels de fonction et des contrôleurs (par exemple dans un hook), vous risquez probablement de rencontrer des problèmes. Émettre du contenu dans les hooks, et avant que le framework ne s'exécute réellement, a pu fonctionner par le passé, mais cela ne fonctionnera pas à l'avenir.
Où vous pourriez rencontrer des problèmes
// index.php
require 'vendor/autoload.php';
// juste un exemple
define('START_TIME', microtime(true));
function hello() {
echo 'Bonjour le monde';
}
Flight::map('hello', 'hello');
Flight::after('hello', function(){
// cela ira en réalité
echo '<p>Cette phrase Bonjour le monde vous est offerte par la lettre "B"</p>';
});
Flight::before('start', function(){
// des choses comme cela vont causer une erreur
echo '<html><head><title>Ma Page</title></head><body>';
});
Flight::route('/', function(){
// c'est en réalité tout à fait bien
echo 'Bonjour le monde';
// Cela devrait également fonctionner
Flight::hello();
});
Flight::after('start', function(){
// cela va causer une erreur
echo '<div>Votre page s'est chargée en '.(microtime(true) - START_TIME).' secondes</div></body></html>';
});
Activation du Comportement de Rendu v2
Pouvez-vous conserver votre vieux code tel quel sans le réécrire pour le faire fonctionner avec la v3? Oui, vous le pouvez! Vous pouvez activer le comportement de rendu v2 en paramétrant l'option de configuration flight.v2.output_buffering
sur true
. Cela vous permettra de continuer à utiliser l'ancien comportement de rendu, mais il est recommandé de le corriger pour l'avenir. Dans la v4 du framework, cela sera supprimé.
// index.php
require 'vendor/autoload.php';
Flight::set('flight.v2.output_buffering', true);
Flight::before('start', function(){
// Maintenant cela fonctionnera parfaitement
echo '<html><head><title>Ma page</title></head><body>';
});
// plus de code
Changements du Dispatcher (3.7.0)
Si vous appelez directement des méthodes statiques pour Dispatcher
telles que Dispatcher::invokeMethod()
, Dispatcher::execute()
, etc., vous devrez mettre à jour votre code pour ne pas appeler directement ces méthodes. Dispatcher
a été converti pour être plus orienté objet afin que les conteneurs d'injection de dépendances puissent être utilisés plus facilement. Si vous avez besoin d'appeler une méthode de manière similaire à la manière dont le Dispatcher le faisait, vous pouvez utiliser manuellement quelque chose comme $result = $class->$method(...$params);
ou call_user_func_array()
à la place.
Changements de halt()
stop()
redirect()
et error()
(3.10.0)
Avant la version 3.10.0, le comportement par défaut était d'effacer à la fois les en-têtes et le corps de la réponse. Cela a été modifié pour effacer uniquement le corps de la réponse. Si vous devez également effacer les en-têtes, vous pouvez utiliser Flight::response()->clear()
.
Learn/configuration
Configuration
Vous pouvez personnaliser certains comportements de Flight en définissant des valeurs de configuration à travers la méthode set
.
Flight::set('flight.log_errors', true);
Paramètres de configuration disponibles
La liste suivante présente tous les paramètres de configuration disponibles :
- flight.base_url
?string
- Remplace l'URL de base de la requête. (par défaut : null) - flight.case_sensitive
bool
- Correspondance sensible à la casse pour les URLs. (par défaut : false) - flight.handle_errors
bool
- Autoriser Flight à gérer toutes les erreurs en interne. (par défaut : true) - flight.log_errors
bool
- Enregistrer les erreurs dans le fichier journal d'erreurs du serveur web. (par défaut : false) - flight.views.path
string
- Répertoire contenant les fichiers de modèle de vue. (par défaut : ./views) - flight.views.extension
string
- Extension du fichier de modèle de vue. (par défaut : .php) - flight.content_length
bool
- Définir l'en-têteContent-Length
. (par défaut : true) - flight.v2.output_buffering
bool
- Utiliser la mise en mémoire tampon de sortie héritée. Voir migration vers v3. (par défaut : false)
Configuration du Chargeur
Il y a également un autre paramètre de configuration pour le chargeur. Cela vous permettra de charger automatiquement les classes avec _
dans le nom de la classe.
// Activer le chargement de classe avec des tirets bas
// Par défaut à true
Loader::$v2ClassLoading = false;
Variables
Flight vous permet de sauvegarder des variables afin qu'elles puissent être utilisées n'importe où dans votre application.
// Sauvegardez votre variable
Flight::set('id', 123);
// Ailleurs dans votre application
$id = Flight::get('id');
Pour vérifier si une variable a été définie, vous pouvez faire :
if (Flight::has('id')) {
// Faire quelque chose
}
Vous pouvez effacer une variable en faisant :
// Efface la variable id
Flight::clear('id');
// Effacer toutes les variables
Flight::clear();
Flight utilise également des variables à des fins de configuration.
Flight::set('flight.log_errors', true);
Gestion des Erreurs
Erreurs et Exceptions
Toutes les erreurs et exceptions sont capturées par Flight et transmises à la méthode error
.
Le comportement par défaut est d'envoyer une réponse générique HTTP 500 Erreur Interne du Serveur
avec des informations sur l'erreur.
Vous pouvez remplacer ce comportement selon vos besoins :
Flight::map('error', function (Throwable $error) {
// Gérer l'erreur
echo $error->getTraceAsString();
});
Par défaut, les erreurs ne sont pas enregistrées dans le serveur web. Vous pouvez activer cela en modifiant la configuration :
Flight::set('flight.log_errors', true);
Introuvable
Lorsqu'une URL est introuvable, Flight appelle la méthode notFound
. Le comportement par défaut est d'envoyer une réponse HTTP 404 Non Trouvé
avec un message simple.
Vous pouvez remplacer ce comportement selon vos besoins :
Flight::map('notFound', function () {
// Gérer l'introuvable
});
Learn/security
Sécurité
La sécurité est un élément important en ce qui concerne les applications web. Vous voulez vous assurer que votre application est sécurisée et que les données de vos utilisateurs sont sûres. Flight fournit plusieurs fonctionnalités pour vous aider à sécuriser vos applications web.
En-têtes
Les en-têtes HTTP sont l'un des moyens les plus simples de sécuriser vos applications web. Vous pouvez utiliser des en-têtes pour prévenir le clickjacking, le XSS et d'autres attaques. Il existe plusieurs moyens d'ajouter ces en-têtes à votre application.
Deux excellents sites à consulter 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éfinissez l'en-tête X-Frame-Options pour prévenir le clickjacking
Flight::response()->header('X-Frame-Options', 'SAMEORIGIN');
// Définissez l'en-tête Content-Security-Policy pour prévenir le XSS
// Remarque : cet en-tête peut devenir très complexe, donc vous voudrez
// consulter des exemples sur internet pour votre application
Flight::response()->header("Content-Security-Policy", "default-src 'self'");
// Définissez l'en-tête X-XSS-Protection pour prévenir le XSS
Flight::response()->header('X-XSS-Protection', '1; mode=block');
// Définissez l'en-tête X-Content-Type-Options pour prévenir le sniffing MIME
Flight::response()->header('X-Content-Type-Options', 'nosniff');
// Définissez l'en-tête Referrer-Policy pour contrôler la quantité d'informations sur le référent
Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade');
// Définissez l'en-tête Strict-Transport-Security pour forcer HTTPS
Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
// Définissez 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 comme un Filtre
Vous pouvez également les ajouter dans un filtre/crochet comme le suivant :
// Ajoutez 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 comme un Middleware
Vous pouvez également les ajouter comme une classe middleware. C'est un bon moyen 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ù que vous ayez vos routes
// FYI, ce groupe de chaîne vide agit comme un middleware global pour
// toutes les routes. Bien sûr, vous pourriez faire la même chose et juste ajouter
// cela uniquement à des routes spécifiques.
Flight::group('', function(Router $router) {
$router->get('/users', [ 'UserController', 'getUsers' ]);
// plus de routes
}, [ new SecurityHeadersMiddleware() ]);
Contre les attaques CSRF (Cross Site Request Forgery)
Le Cross Site Request Forgery (CSRF) est un type d'attaque où un site web malveillant peut amener le navigateur d'un utilisateur à envoyer une requête à votre site web. Cela peut être utilisé pour effectuer des actions sur votre site web sans que l'utilisateur ne 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érez un jeton CSRF et stockez-le dans la session de l'utilisateur
// (en supposant que vous avez créé un objet de session et l'avez attaché à Flight)
// consultez la documentation de la session pour plus d'informations
Flight::register('session', \Ghostff\Session\Session::class);
// Vous n'avez besoin de générer qu'un seul jeton par session (afin qu'il fonctionne
// à travers 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>
Utiliser Latte
Vous pouvez également définir une fonction personnalisée pour afficher le jeton CSRF dans vos modèles Latte.
// Définissez une fonction personnalisée pour afficher le jeton CSRF
// Remarque : La vue a été configurée avec Latte en tant que 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, non ?
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') {
// capturez le jeton csrf à partir des valeurs du formulaire
$token = Flight::request()->data->csrf_token;
if($token !== Flight::session()->get('csrf_token')) {
Flight::halt(403, 'Jeton CSRF invalide');
// ou pour une réponse JSON
Flight::jsonHalt(['error' => 'Jeton CSRF invalide'], 403);
}
}
});
Ou vous pouvez utiliser une classe middleware :
// app/middleware/CsrfMiddleware.php
namespace app\middleware;
class CsrfMiddleware
{
public function before(array $params): void
{
if(Flight::request()->method == 'POST') {
$token = Flight::request()->data->csrf_token;
if($token !== Flight::session()->get('csrf_token')) {
Flight::halt(403, 'Jeton CSRF invalide');
}
}
}
}
// index.php ou où que vous ayez 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 opportunités proviennent des valeurs de formulaire que vos utilisateurs finaux rempliront. Vous ne devez jamais faire confiance à la sortie de vos utilisateurs ! Supposons toujours qu'ils soient les meilleurs hackers du monde. Ils peuvent injecter du JavaScript ou du HTML malveillant dans votre page. Ce code peut être utilisé pour voler des informations de 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 assez intelligent pour essayer d'utiliser ceci comme son nom
$name = '<script>alert("XSS")</script>';
// Cela va échapper à la sortie
Flight::view()->set('name', $name);
// Cela va produire : <script>alert("XSS")</script>
// Si vous utilisez quelque chose comme Latte enregistré en tant que votre classe de vue, cela échappera également automatiquement ceci.
Flight::view()->render('template', ['name' => $name]);
Injection SQL
L'injection SQL est un type d'attaque où un utilisateur malveillant peut injecter du code SQL dans votre base de données. Cela peut être utilisé pour voler des informations de votre base de données ou effectuer des actions sur votre base de données. Encore une fois, vous ne devez jamais faire confiance à l'entrée de vos utilisateurs ! Supposons toujours qu'ils soient en guerre. Vous pouvez utiliser des instructions préparées dans vos objets PDO
pour prévenir l'injection SQL.
// En supposant que vous ayez Flight::db() enregistré comme votre 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 que vous ne ferez jamais JAMAIS quelque chose comme ça...
$users = Flight::db()->fetchAll("SELECT * FROM users WHERE username = '{$username}' LIMIT 5");
// parce que si $username = "' OR 1=1; -- ";
// Après la requête, ça ressemble à ça
// 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 SQL très courante qui retourne tous les utilisateurs.
CORS
Le Cross-Origin Resource Sharing (CORS) est un mécanisme qui permet de demander de nombreuses ressources (par exemple, des polices, du JavaScript, etc.) sur une page web à partir d'un autre domaine que celui dont la ressource est originaire. Flight n'a pas de fonctionnalité intégrée, mais cela peut facilement être géré avec un crochet à exécuter avant que la méthode Flight::start()
ne soit appelée.
// app/utils/CorsUtil.php
namespace app\utils;
class CorsUtil
{
public function set(array $params): void
{
$request = Flight::request();
$response = Flight::response();
if ($request->getVar('HTTP_ORIGIN') !== '') {
$this->allowOrigins();
$response->header('Access-Control-Allow-Credentials', 'true');
$response->header('Access-Control-Max-Age', '86400');
}
if ($request->method === 'OPTIONS') {
if ($request->getVar('HTTP_ACCESS_CONTROL_REQUEST_METHOD') !== '') {
$response->header(
'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD'
);
}
if ($request->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') !== '') {
$response->header(
"Access-Control-Allow-Headers",
$request->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')
);
}
$response->status(200);
$response->send();
exit;
}
}
private function allowOrigins(): void
{
// personnalisez vos hôtes autorisés ici.
$allowed = [
'capacitor://localhost',
'ionic://localhost',
'http://localhost',
'http://localhost:4200',
'http://localhost:8080',
'http://localhost:8100',
];
$request = Flight::request();
if (in_array($request->getVar('HTTP_ORIGIN'), $allowed, true) === true) {
$response = Flight::response();
$response->header("Access-Control-Allow-Origin", $request->getVar('HTTP_ORIGIN'));
}
}
}
// index.php ou où que vous ayez vos routes
$CorsUtil = new CorsUtil();
// Cela doit être exécuté avant que le démarrage ne s'exécute.
Flight::before('start', [ $CorsUtil, 'setupCors' ]);
Gestion des Erreurs
Cachez les détails sensibles des erreurs en production pour éviter de divulguer des informations aux attaquants.
// Dans votre bootstrap.php ou index.php
// dans flightphp/skeleton, cela se trouve dans app/config/config.php
$environment = ENVIRONMENT;
if ($environment === 'production') {
ini_set('display_errors', 0); // Désactiver l'affichage des erreurs
ini_set('log_errors', 1); // Logger les erreurs à la place
ini_set('error_log', '/path/to/error.log');
}
// Dans vos routes ou contrôleurs
// Utilisez Flight::halt() pour des réponses d'erreur contrôlées
Flight::halt(403, 'Accès refusé');
Assainissement des Entrées
Ne faites jamais confiance aux entrées des utilisateurs. Assainissez-les avant de les traiter pour éviter que des données malveillantes ne se glissent.
// Supposons une requête $_POST avec $_POST['input'] et $_POST['email']
// Assainissez une entrée de chaîne
$clean_input = filter_var(Flight::request()->data->input, FILTER_SANITIZE_STRING);
// Assainissez un email
$clean_email = filter_var(Flight::request()->data->email, FILTER_SANITIZE_EMAIL);
Hachage de Mot de Passe
Stockez les mots de passe de manière sécurisée et vérifiez-les en toute sécurité en utilisant les fonctions intégrées de PHP.
$password = Flight::request()->data->password;
// Hachez un mot de passe lors du stockage (par exemple, lors de l'enregistrement)
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
// Vérifiez un mot de passe (par exemple, lors de la connexion)
if (password_verify($password, $stored_hash)) {
// Le mot de passe correspond
}
Limitation de Taux
Protégez-vous contre les attaques de force brute en limitant les taux de requêtes avec un cache.
// En supposant que vous ayez flightphp/cache installé et enregistré
// Utilisation de flightphp/cache dans un middleware
Flight::before('start', function() {
$cache = Flight::cache();
$ip = Flight::request()->ip;
$key = "rate_limit_{$ip}";
$attempts = (int) $cache->retrieve($key);
if ($attempts >= 10) {
Flight::halt(429, 'Trop de requêtes');
}
$cache->set($key, $attempts + 1, 60); // Réinitialiser après 60 secondes
});
Conclusion
La sécurité est un élément important et il est essentiel de s'assurer que vos applications web sont sécurisées. Flight propose un certain nombre de fonctionnalités pour vous aider à sécuriser vos applications web, mais il est important de toujours être vigilant et de s'assurer que vous faites tout ce qui est en votre pouvoir pour garder les données de vos utilisateurs en sécurité. Supposez toujours le pire et ne faites jamais confiance à l'entrée de vos utilisateurs. Échappez toujours à la sortie et utilisez des instructions préparées pour prévenir l'injection SQL. Utilisez toujours des middleware pour protéger vos routes contre les attaques CSRF et CORS. Si vous faites toutes ces choses, vous serez bien en route 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 souhaitez en savoir plus sur le routage ? Consultez la page "pourquoi un framework?" pour une explication plus approfondie.
Le routage de base dans Flight se fait en faisant correspondre un modèle d'URL avec une fonction de rappel ou un tableau d'une classe et d'une méthode.
Flight::route('/', function(){
echo 'bonjour le monde!';
});
Les routes sont appariées dans l'ordre où elles sont définies. La première route correspondant à une requête sera invoquée.
Fonctions de rappel
Le rappel peut être n'importe quel objet qui est appelable. Vous pouvez donc utiliser une fonction régulière :
function hello() {
echo 'bonjour le monde!';
}
Flight::route('/', 'hello');
Classes
Vous pouvez également utiliser une méthode statique d'une classe :
class Greeting {
public static function hello() {
echo 'bonjour le monde!';
}
}
Flight::route('/', [ 'Greeting','hello' ]);
Ou en créant d'abord un objet puis en appelant la méthode :
// Greeting.php
class Greeting
{
public function __construct() {
$this->name = 'John Doe';
}
public function hello() {
echo "Bonjour, {$this->name}!";
}
}
// index.php
$greeting = new Greeting();
Flight::route('/', [ $greeting, 'hello' ]);
// Vous pouvez également faire cela sans créer d'abord l'objet
// Remarque : Aucun argument ne sera injecté dans le constructeur
Flight::route('/', [ 'Greeting', 'hello' ]);
// De plus, vous pouvez utiliser cette syntaxe plus courte
Flight::route('/', 'Greeting->hello');
// ou
Flight::route('/', Greeting::class.'->hello');
Injection de dépendance via DIC (Conteneur d'Injection de Dépendance)
Si vous souhaitez utiliser l'injection de dépendance via un conteneur (PSR-11, PHP-DI, Dice, etc.), le seul type de routes où cela est disponible est soit en créant directement l'objet vous-même et en utilisant le conteneur pour créer votre objet, soit vous pouvez utiliser des chaînes pour définir la classe et la méthode à appeler. Vous pouvez consulter la page Injection de Dépendance pour plus d'informations.
Voici un exemple rapide :
use flight\database\PdoWrapper;
// Greeting.php
class Greeting
{
protected PdoWrapper $pdoWrapper;
public function __construct(PdoWrapper $pdoWrapper) {
$this->pdoWrapper = $pdoWrapper;
}
public function hello(int $id) {
// faire quelque chose avec $this->pdoWrapper
$name = $this->pdoWrapper->fetchField("SELECT name FROM users WHERE id = ?", [ $id ]);
echo "Bonjour, monde! Mon nom est {$name}!";
}
}
// index.php
// Configurez le conteneur avec tous les paramètres dont vous avez besoin
// Consultez la page d'Injection de Dépendance pour plus d'informations sur PSR-11
$dice = new \Dice\Dice();
// N'oubliez pas de réassigner la variable avec '$dice = '!!!!!
$dice = $dice->addRule('flight\database\PdoWrapper', [
'shared' => true,
'constructParams' => [
'mysql:host=localhost;dbname=test',
'root',
'password'
]
]);
// Enregistrez le gestionnaire de conteneur
Flight::registerContainerHandler(function($class, $params) use ($dice) {
return $dice->create($class, $params);
});
// Routes comme d'habitude
Flight::route('/hello/@id', [ 'Greeting', 'hello' ]);
// ou
Flight::route('/hello/@id', 'Greeting->hello');
// ou
Flight::route('/hello/@id', 'Greeting::hello');
Flight::start();
Routage par méthode
Par défaut, les modèles de route sont associés à toutes les méthodes de requête. Vous pouvez répondre à des méthodes spécifiques en plaçant un identifiant avant l'URL.
Flight::route('GET /', function () {
echo 'J\'ai reçu une requête GET.';
});
Flight::route('POST /', function () {
echo 'J\'ai reçu une requête POST.';
});
// Vous ne pouvez pas utiliser Flight::get() pour les routes, car c'est une méthode
// pour obtenir des variables, pas pour créer une route.
// Flight::post('/', function() { /* code */ });
// Flight::patch('/', function() { /* code */ });
// Flight::put('/', function() { /* code */ });
// Flight::delete('/', function() { /* code */ });
Vous pouvez également mapper plusieurs méthodes à un seul rappel en utilisant un délimiteur |
:
Flight::route('GET|POST /', function () {
echo 'J\'ai reçu soit une requête GET soit une requête POST.';
});
De plus, vous pouvez obtenir l'objet Routeur qui a quelques méthodes d'aide à utiliser :
$router = Flight::router();
// mappe toutes les méthodes
$router->map('/', function() {
echo 'bonjour le monde!';
});
// Requête GET
$router->get('/users', function() {
echo 'utilisateurs';
});
// $router->post();
// $router->put();
// $router->delete();
// $router->patch();
Expressions régulières
Vous pouvez utiliser des expressions régulières dans vos routes :
Flight::route('/user/[0-9]+', function () {
// Cela correspondra à /user/1234
});
Bien que cette méthode soit disponible, il est recommandé d'utiliser des paramètres nommés, ou des paramètres nommés avec des expressions régulières, car ils sont plus lisibles et plus faciles à maintenir.
Paramètres nommés
Vous pouvez spécifier des paramètres nommés dans vos routes qui seront transmis à votre fonction de rappel. C'est plus pour la lisibilité de la route qu'autre chose. Veuillez voir la section ci-dessous sur l'avertissement important.
Flight::route('/@name/@id', function (string $name, string $id) {
echo "bonjour, $name ($id)!";
});
Vous pouvez également inclure des expressions régulières avec vos paramètres nommés en utilisant le délimiteur :
:
Flight::route('/@name/@id:[0-9]{3}', function (string $name, string $id) {
// Cela correspondra à /bob/123
// Mais ne correspondra pas à /bob/12345
});
Remarque : La correspondance des groupes regex
()
avec des paramètres positionnels n'est pas prise en charge. :'(
Avertissement important
Bien que dans l'exemple ci-dessus, il semble que @name
soit directement lié à la variable $name
, ce n'est pas le cas. L'ordre des paramètres dans la fonction de rappel détermine ce qui y est passé. Donc, si vous deviez changer l'ordre des paramètres dans la fonction de rappel, les variables seraient également échangées. Voici un exemple :
Flight::route('/@name/@id', function (string $id, string $name) {
echo "bonjour, $name ($id)!";
});
Et si vous accédez à l'URL suivante : /bob/123
, la sortie sera bonjour, 123 (bob)!
.
Veuillez faire attention lorsque vous configurez vos routes et vos fonctions de rappel.
Paramètres optionnels
Vous pouvez spécifier des paramètres nommés qui sont optionnels pour la correspondance en englobant des segments entre parenthèses.
Flight::route(
'/blog(/@year(/@month(/@day)))',
function(?string $year, ?string $month, ?string $day) {
// Cela correspondra aux URL suivantes :
// /blog/2012/12/10
// /blog/2012/12
// /blog/2012
// /blog
}
);
Tout paramètre optionnel qui n'est pas apparié sera transmis comme NULL
.
Jokers
La correspondance ne se fait que sur des segments individuels d'URL. Si vous souhaitez correspondre à plusieurs segments, vous pouvez utiliser le joker *
.
Flight::route('/blog/*', function () {
// Cela correspondra à /blog/2000/02/01
});
Pour envoyer toutes les demandes à un seul rappel, vous pouvez faire :
Flight::route('*', function () {
// Faire quelque chose
});
Passage
Vous pouvez passer l'exécution à la prochaine route correspondante en retournant true
depuis votre fonction de rappel.
Flight::route('/user/@name', function (string $name) {
// Vérifiez certaines conditions
if ($name !== "Bob") {
// Continuez à la prochaine route
return true;
}
});
Flight::route('/user/*', function () {
// Cela sera appelé
});
Alias de route
Vous pouvez attribuer un alias à une route, afin que l'URL puisse être générée dynamiquement plus tard dans votre code (comme un modèle par exemple).
Flight::route('/users/@id', function($id) { echo 'utilisateur:'.$id; }, false, 'user_view');
// plus tard dans le code quelque part
Flight::getUrl('user_view', [ 'id' => 5 ]); // renverra '/users/5'
C'est particulièrement utile si votre URL venait à changer. Dans l'exemple ci-dessus, disons que les utilisateurs ont été déplacés vers /admin/users/@id
à la place.
Avec l'alias en place, vous n'avez pas à changer partout où vous référencez l'alias car l'alias renverra maintenant /admin/users/5
comme dans l'exemple ci-dessus.
L'alias de route fonctionne également dans les groupes :
Flight::group('/users', function() {
Flight::route('/@id', function($id) { echo 'utilisateur:'.$id; }, false, 'user_view');
});
// plus tard dans le code quelque part
Flight::getUrl('user_view', [ 'id' => 5 ]); // renverra '/users/5'
Informations sur la route
Si vous souhaitez inspecter les informations sur la route correspondante, vous pouvez demander à ce que l'objet de la route soit transmis à votre fonction de rappel en passant true
en tant que troisième paramètre dans la méthode de route. L'objet de route sera toujours le dernier paramètre passé à votre fonction de rappel.
Flight::route('/', function(\flight\net\Route $route) {
// Tableau des méthodes HTTP correspondantes
$route->methods;
// Tableau des paramètres nommés
$route->params;
// Expression régulière correspondante
$route->regex;
// Contient le contenu de tout '*' utilisé dans le modèle d'URL
$route->splat;
// Montre le chemin d'URL....si vous en avez vraiment besoin
$route->pattern;
// Montre quel middleware est attribué à cela
$route->middleware;
// Montre l'alias attribué à cette route
$route->alias;
}, true);
Groupement de routes
Il peut y avoir des fois où vous souhaitez regrouper des routes liées ensemble (comme /api/v1
).
Vous pouvez le faire en utilisant la méthode group
:
Flight::group('/api/v1', function () {
Flight::route('/users', function () {
// Correspond à /api/v1/users
});
Flight::route('/posts', function () {
// Correspond à /api/v1/posts
});
});
Vous pouvez même imbriquer des groupes de groupes :
Flight::group('/api', function () {
Flight::group('/v1', function () {
// Flight::get() obtient des variables, il ne définit pas une route ! Voir le contexte de l'objet ci-dessous
Flight::route('GET /users', function () {
// Correspond à GET /api/v1/users
});
Flight::post('/posts', function () {
// Correspond à POST /api/v1/posts
});
Flight::put('/posts/1', function () {
// Correspond à PUT /api/v1/posts
});
});
Flight::group('/v2', function () {
// Flight::get() obtient des variables, il ne définit pas une route ! Voir le contexte de l'objet ci-dessous
Flight::route('GET /users', function () {
// Correspond à GET /api/v2/users
});
});
});
Groupement avec contexte d'objet
Vous pouvez toujours utiliser le groupement de routes avec l'objet Engine
de la manière suivante :
$app = new \flight\Engine();
$app->group('/api/v1', function (Router $router) {
// utilisez la variable $router
$router->get('/users', function () {
// Correspond à GET /api/v1/users
});
$router->post('/posts', function () {
// Correspond à POST /api/v1/posts
});
});
Routage de ressources
Vous pouvez créer un ensemble de routes pour une ressource en utilisant la méthode resource
. Cela créera un ensemble de routes pour une ressource qui suit les conventions RESTful.
Pour créer une ressource, faites ce qui suit :
Flight::resource('/users', UsersController::class);
Et ce qui se passera en arrière-plan, c'est qu'il créera les routes suivantes :
[
'index' => 'GET ',
'create' => 'GET /create',
'store' => 'POST ',
'show' => 'GET /@id',
'edit' => 'GET /@id/edit',
'update' => 'PUT /@id',
'destroy' => 'DELETE /@id'
]
Et votre contrôleur ressemblera à ceci :
class UsersController
{
public function index(): void
{
}
public function show(string $id): void
{
}
public function create(): void
{
}
public function store(): void
{
}
public function edit(string $id): void
{
}
public function update(string $id): void
{
}
public function destroy(string $id): void
{
}
}
Remarque : Vous pouvez visualiser les nouvelles routes ajoutées avec
runway
en exécutantphp runway routes
.
Personnalisation des routes de ressources
Il existe plusieurs options pour configurer les routes de ressources.
Alias de base
Vous pouvez configurer l'aliasBase
. Par défaut, l'alias est la dernière partie de l'URL spécifiée.
Par exemple, /users/
donnerait un aliasBase
de users
. Lorsque ces routes sont créées, les alias sont users.index
, users.create
, etc. Si vous souhaitez changer l'alias, définissez l'aliasBase
à la valeur que vous souhaitez.
Flight::resource('/users', UsersController::class, [ 'aliasBase' => 'user' ]);
Seulement et Excepté
Vous pouvez également spécifier quelles routes vous souhaitez créer en utilisant les options only
et except
.
Flight::resource('/users', UsersController::class, [ 'only' => [ 'index', 'show' ] ]);
Flight::resource('/users', UsersController::class, [ 'except' => [ 'create', 'store', 'edit', 'update', 'destroy' ] ]);
Ce sont essentiellement des options de liste blanche et de liste noire afin que vous puissiez spécifier quelles routes vous souhaitez créer.
Middleware
Vous pouvez également spécifier un middleware à exécuter sur chacune des routes créées par la méthode resource
.
Flight::resource('/users', UsersController::class, [ 'middleware' => [ MyAuthMiddleware::class ] ]);
Streaming
Vous pouvez désormais diffuser des réponses au client en utilisant la méthode streamWithHeaders()
.
Cela est utile pour l'envoi de fichiers volumineux, de processus longs ou la génération de grandes réponses.
Diffuser une route est géré un peu différemment d'une route normale.
Remarque : La diffusion de réponses n'est disponible que si vous avez
flight.v2.output_buffering
défini sur false.
Diffusion avec en-têtes manuels
Vous pouvez diffuser une réponse au client en utilisant la méthode stream()
sur une route. Si vous faites cela, vous devez définir toutes les méthodes à la main avant de sortir quoi que ce soit au client. Cela se fait avec la fonction php header()
ou la méthode Flight::response()->setRealHeader()
.
Flight::route('/@filename', function($filename) {
// Évidemment, vous devez assainir le chemin et ce genre de choses.
$fileNameSafe = basename($filename);
// Si vous avez des en-têtes supplémentaires à définir ici après l'exécution de la route
// vous devez les définir avant que quoi que ce soit ne soit écho.
// Ils doivent tous être un appel brut à la fonction header() ou
// un appel à Flight::response()->setRealHeader()
header('Content-Disposition: attachment; filename="'.$fileNameSafe.'"');
// ou
Flight::response()->setRealHeader('Content-Disposition', 'attachment; filename="'.$fileNameSafe.'"');
$fileData = file_get_contents('/some/path/to/files/'.$fileNameSafe);
// Gestion des erreurs et ce genre de choses
if(empty($fileData)) {
Flight::halt(404, 'Fichier introuvable');
}
// définissez manuellement la longueur du contenu si vous le souhaitez
header('Content-Length: '.filesize($filename));
// Diffusez les données au client
echo $fileData;
// C'est la ligne magique ici
})->stream();
Diffusion avec en-têtes
Vous pouvez également utiliser la méthode streamWithHeaders()
pour définir les en-têtes avant de commencer à diffuser.
Flight::route('/stream-users', function() {
// vous pouvez ajouter tous les en-têtes supplémentaires que vous voulez ici
// vous devez juste utiliser header() ou Flight::response()->setRealHeader()
// peu importe comment vous tirez vos données, juste comme exemple...
$users_stmt = Flight::db()->query("SELECT id, first_name, last_name FROM users");
echo '{';
$user_count = count($users);
while($user = $users_stmt->fetch(PDO::FETCH_ASSOC)) {
echo json_encode($user);
if(--$user_count > 0) {
echo ',';
}
// Ceci est requis pour envoyer les données au client
ob_flush();
}
echo '}';
// Voici comment vous définirez les en-têtes avant de commencer à diffuser.
})->streamWithHeaders([
'Content-Type' => 'application/json',
'Content-Disposition' => 'attachment; filename="users.json"',
// code d'état optionnel, par défaut à 200
'status' => 200
]);
Learn/flight_vs_symfony
Vol Flight vs Symfony
Qu'est-ce que Symfony?
Symfony est un ensemble de composants PHP réutilisables et un framework PHP pour les projets web.
La base standard sur laquelle les meilleures applications PHP sont construites. Choisissez l'un des 50 composants autonomes disponibles pour vos propres applications.
Accélérez la création et la maintenance de vos applications web PHP. Mettez fin aux tâches de codage répétitives et profitez du pouvoir de contrôler votre code.
Avantages par rapport à Flight
- Symfony a un écosystème énorme de développeurs et de modules pouvant être utilisés pour résoudre les problèmes courants.
- Symfony dispose d'un ORM complet (Doctrine) qui peut être utilisé pour interagir avec votre base de données.
- Symfony dispose d'une grande quantité de documentation et de tutoriels pouvant être utilisés pour apprendre le framework.
- Symfony propose des podcasts, des conférences, des réunions, des vidéos et d'autres ressources pouvant être utilisés pour apprendre le framework.
- Symfony est destiné à un développeur expérimenté qui cherche à construire une application web d'entreprise complète.
Inconvénients par rapport à Flight
- Symfony a beaucoup plus de fonctionnalités sous le capot que Flight. Cela se fait à un coût dramatique en termes de performances. Consultez les tests de TechEmpower pour plus d'informations.
- Flight est destiné à un développeur cherchant à construire une application web légère, rapide et facile à utiliser.
- Flight est axé sur la simplicité et la facilité d'utilisation.
- L'une des fonctionnalités principales de Flight est de faire de son mieux pour maintenir la compatibilité ascendante.
- Flight n'a aucune dépendance, tandis que Symfony a tout un tas de dépendances
- Flight est destiné aux développeurs qui s'aventurent dans le monde des frameworks pour la première fois.
- Flight peut également gérer des applications de niveau entreprise, mais il n'a pas autant d'exemples et de tutoriels que Symfony. Cela demandera également plus de discipline de la part du développeur pour maintenir l'organisation et la structure.
- Flight donne au développeur plus de contrôle sur l'application, tandis que Symfony peut introduire de la magie en coulisses.
Learn/flight_vs_another_framework
Comparaison de Flight à un autre Framework
Si vous migrez d'un autre framework tel que Laravel, Slim, Fat-Free, ou Symfony vers Flight, cette page vous aidera à comprendre les différences entre les deux.
Laravel
Laravel est un framework complet qui possède toutes les fonctionnalités et une incroyable écosystème axé sur les développeurs, mais cela a un coût en termes de performances et de complexité.
Voir la comparaison entre Laravel et Flight.
Slim
Slim est un micro-framework similaire à Flight. Il est conçu pour être léger et facile à utiliser, mais peut être un peu plus complexe que Flight.
Voir la comparaison entre Slim et Flight.
Fat-Free
Fat-Free est un framework full-stack dans un package beaucoup plus petit. Bien qu'il possède tous les outils nécessaires, il a une architecture des données qui peut rendre certains projets plus complexes qu'ils ne le devraient.
Voir la comparaison entre Fat-Free et Flight.
Symfony
Symfony est un framework modulaire de niveau entreprise conçu pour être flexible et scalable. Pour les petits projets ou les nouveaux développeurs, Symfony peut être un peu intimidant.
Voir la comparaison entre Symfony et Flight.
Learn/variables
Variables
Flight permet de sauvegarder des variables afin qu'elles puissent être utilisées n'importe où dans votre application.
// Sauvegardez votre variable
Flight::set('id', 123);
// Ailleurs dans votre application
$id = Flight::get('id');
Pour vérifier si une variable a été définie, vous pouvez faire :
if (Flight::has('id')) {
// Faire quelque chose
}
Vous pouvez effacer une variable en faisant :
// Efface la variable id
Flight::clear('id');
// Efface toutes les variables
Flight::clear();
Flight utilise également des variables à des fins de configuration.
Flight::set('flight.log_errors', true);
Learn/dependency_injection_container
Conteneur d'injection de dépendances
Introduction
Le Conteneur d'injection de dépendances (DIC) est un outil puissant qui vous permet de gérer les dépendances de votre application. C'est un concept clé dans les frameworks PHP modernes et est utilisé pour gérer l'instanciation et la configuration des objets. Quelques exemples de bibliothèques DIC sont : Dice, Pimple, PHP-DI et league/container.
Un DIC est un moyen sophistiqué de dire qu'il vous permet de créer et de gérer vos classes dans un emplacement centralisé. C'est utile lorsque vous avez besoin de passer le même objet à plusieurs classes (comme vos contrôleurs). Un exemple simple pourrait aider à mieux comprendre cela.
Exemple de base
L'ancienne manière de faire ressemblait à ceci :
require 'vendor/autoload.php';
// classe pour gérer les utilisateurs de la base de données
class UserController {
protected PDO $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
public function view(int $id) {
$stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $id]);
print_r($stmt->fetch());
}
}
$User = new UserController(new PDO('mysql:host=localhost;dbname=test', 'user', 'pass'));
Flight::route('/user/@id', [ $UserController, 'view' ]);
Flight::start();
Vous pouvez voir dans le code ci-dessus que nous créons un nouvel objet PDO
et le passons
à notre classe UserController
. C'est bien pour une petite application, mais à mesure que votre
application grandit, vous constaterez que vous créez le même objet PDO
à plusieurs
endroits. C'est là qu'un DIC s'avère utile.
Voici le même exemple utilisant un DIC (en utilisant Dice) :
require 'vendor/autoload.php';
// même classe que ci-dessus. Rien n'a changé
class UserController {
protected PDO $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
public function view(int $id) {
$stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $id]);
print_r($stmt->fetch());
}
}
// créer un nouveau conteneur
$container = new \Dice\Dice;
// n'oubliez pas de le réassigner comme ci-dessous !
$container = $container->addRule('PDO', [
// shared signifie que le même objet sera retourné à chaque fois
'shared' => true,
'constructParams' => ['mysql:host=localhost;dbname=test', 'user', 'pass' ]
]);
// Cela enregistre le gestionnaire de conteneur pour que Flight sache l'utiliser.
Flight::registerContainerHandler(function($class, $params) use ($container) {
return $container->create($class, $params);
});
// maintenant nous pouvons utiliser le conteneur pour créer notre UserController
Flight::route('/user/@id', [ 'UserController', 'view' ]);
// ou alternativement vous pouvez définir la route comme ceci
Flight::route('/user/@id', 'UserController->view');
// ou
Flight::route('/user/@id', 'UserController::view');
Flight::start();
Je parie que vous pouvez penser qu'il y a beaucoup de code supplémentaire ajouté à l'exemple.
La magie opère lorsque vous avez un autre contrôleur qui a besoin de l'objet PDO
.
// Si tous vos contrôleurs ont un constructeur qui a besoin d'un objet PDO
// chacune des routes ci-dessous l'injectera automatiquement !!!
Flight::route('/company/@id', 'CompanyController->view');
Flight::route('/organization/@id', 'OrganizationController->view');
Flight::route('/category/@id', 'CategoryController->view');
Flight::route('/settings', 'SettingsController->view');
Le bonus supplémentaire d'utiliser un DIC est que les tests unitaires deviennent beaucoup plus faciles. Vous pouvez créer un objet simulé et le passer à votre classe. C'est un énorme avantage lorsque vous rédigez des tests pour votre application!
PSR-11
Flight peut également utiliser n'importe quel conteneur compatible avec PSR-11. Cela signifie que vous pouvez utiliser n'importe un conteneur qui implémente l'interface PSR-11. Voici un exemple utilisant le conteneur PSR-11 de League :
require 'vendor/autoload.php';
// même classe UserController que ci-dessus
$container = new \League\Container\Container();
$container->add(UserController::class)->addArgument(PdoWrapper::class);
$container->add(PdoWrapper::class)
->addArgument('mysql:host=localhost;dbname=test')
->addArgument('user')
->addArgument('pass');
Flight::registerContainerHandler($container);
Flight::route('/user', [ 'UserController', 'view' ]);
Flight::start();
Bien que cela puisse être un peu plus verbeux que l'exemple Dice précédent, cela fonctionne tout de même avec les mêmes avantages!
Gestionnaire DIC personnalisé
Vous pouvez également créer votre propre gestionnaire DIC. C'est utile si vous avez un conteneur personnalisé que vous voulez utiliser qui n'est pas PSR-11 (Dice). Consultez l' exemple de base pour savoir comment faire cela.
De plus, il y a quelques valeurs par défaut utiles qui faciliteront votre vie lors de l'utilisation de Flight.
Instance du moteur
Si vous utilisez l'instance Engine
dans vos contrôleurs/middleware, voici
comment vous la configureriez :
// Quelque part dans votre fichier d'amorçage
$engine = Flight::app();
$container = new \Dice\Dice;
$container = $container->addRule('*', [
'substitutions' => [
// C'est ici que vous passez l'instance
Engine::class => $engine
]
]);
$engine->registerContainerHandler(function($class, $params) use ($container) {
return $container->create($class, $params);
});
// Maintenant vous pouvez utiliser l'instance Engine dans vos contrôleurs/middleware
class MyController {
public function __construct(Engine $app) {
$this->app = $app;
}
public function index() {
$this->app->render('index');
}
}
Ajout d'autres classes
Si vous avez d'autres classes que vous voulez ajouter au conteneur, avec Dice c'est facile car elles seront automatiquement résolues par le conteneur. Voici un exemple :
$container = new \Dice\Dice;
// Si vous n'avez pas besoin d'injecter quoi que ce soit dans votre classe
// vous n'avez pas besoin de définir quoi que ce soit !
Flight::registerContainerHandler(function($class, $params) use ($container) {
return $container->create($class, $params);
});
class MyCustomClass {
public function parseThing() {
return 'thing';
}
}
class UserController {
protected MyCustomClass $MyCustomClass;
public function __construct(MyCustomClass $MyCustomClass) {
$this->MyCustomClass = $MyCustomClass;
}
public function index() {
echo $this->MyCustomClass->parseThing();
}
}
Flight::route('/user', 'UserController->index');
Learn/middleware
Middleware de Route
Flight prend en charge les middleware de route et de groupe de route. Un middleware est une fonction qui est exécutée avant (ou après) le rappel de la route. C'est un excellent moyen d'ajouter des vérifications d'authentification API dans votre code, ou de valider que l'utilisateur a la permission d'accéder à la route.
Middleware de Base
Voici un exemple de base :
// Si vous ne fournissez qu'une fonction anonyme, elle sera exécutée avant le rappel de la route. Il n'y a pas de fonctions middleware "après" à l'exception des classes (voir ci-dessous)
Flight::route('/chemin', function() { echo 'Me voici !'; })->addMiddleware(function() {
echo 'Middleware en premier !';
});
Flight::start();
// Cela affichera "Middleware en premier ! Me voici !"
Il est important de noter quelques points essentiels concernant les middleware avant de les utiliser :
- Les fonctions middleware sont exécutées dans l'ordre où elles sont ajoutées à la route. L'exécution est similaire à la manière dont Slim Framework gère cela.
- Les "before" sont exécutés dans l'ordre ajouté, et les "after" sont exécutés dans l'ordre inverse.
- Si votre fonction middleware renvoie false, toute l'exécution est arrêtée et une erreur 403 Forbidden est déclenchée. Vous voudrez probablement gérer cela de manière plus gracieuse avec un
Flight::redirect()
ou quelque chose de similaire. - Si vous avez besoin de paramètres de votre route, ils seront transmis dans un tableau unique à votre fonction middleware (
function($params) { ... }
oupublic function before($params) {}
). La raison en est que vous pouvez structurer vos paramètres en groupes et dans certains de ces groupes, vos paramètres peuvent en fait apparaître dans un ordre différent qui casserait la fonction middleware en faisant référence au mauvais paramètre. De cette manière, vous pouvez y accéder par nom au lieu de la position. - Si vous passez seulement le nom du middleware, il sera automatiquement exécuté par le container d'injection de dépendance et le middleware sera exécuté avec les paramètres nécessaires. Si vous n'avez pas de container d'injection de dépendance enregistré, il passera l'instance
flight\Engine
dans le__construct()
.
Classes Middleware
Les middleware peuvent également être enregistrés sous forme de classe. Si vous avez besoin de la fonctionnalité "after", vous devez utiliser une classe.
class MyMiddleware {
public function before($params) {
echo 'Middleware en premier !';
}
public function after($params) {
echo 'Middleware en dernier !';
}
}
$MyMiddleware = new MyMiddleware();
Flight::route('/chemin', function() { echo 'Me voici ! '; })->addMiddleware($MyMiddleware); // également ->addMiddleware([ $MyMiddleware, $MyMiddleware2 ]);
Flight::start();
// Cela affichera "Middleware en premier ! Me voici ! Middleware en dernier !"
Gestion des Erreurs de Middleware
Disons que vous avez un middleware d'authentification et que vous souhaitez rediriger l'utilisateur vers une page de connexion s'il n'est pas authentifié. Vous avez quelques options à votre disposition :
- Vous pouvez renvoyer false depuis la fonction middleware et Flight renverra automatiquement une erreur 403 Forbidden, mais sans personnalisation.
- Vous pouvez rediriger l'utilisateur vers une page de connexion en utilisant
Flight::redirect()
. - Vous pouvez créer une erreur personnalisée à l'intérieur du middleware et arrêter l'exécution de la route.
Exemple de Base
Voici un exemple simple avec return false; :
class MyMiddleware {
public function before($params) {
if (isset($_SESSION['user']) === false) {
return false;
}
// comme c'est vrai, tout continue simplement
}
}
Exemple de Redirection
Voici un exemple de redirection de l'utilisateur vers une page de connexion :
class MyMiddleware {
public function before($params) {
if (isset($_SESSION['user']) === false) {
Flight::redirect('/login');
exit;
}
}
}
Exemple d'Erreur Personnalisée
Disons que vous devez déclencher une erreur JSON car vous construisez une API. Vous pouvez le faire de cette manière :
class MyMiddleware {
public function before($params) {
$authorization = Flight::request()->headers['Authorization'];
if(empty($authorization)) {
Flight::jsonHalt(['error' => 'Vous devez être connecté pour accéder à cette page.'], 403);
// ou
Flight::json(['error' => 'Vous devez être connecté pour accéder à cette page.'], 403);
exit;
// ou
Flight::halt(403, json_encode(['error' => 'Vous devez être connecté pour accéder à cette page.']);
}
}
}
Regroupement de Middleware
Vous pouvez ajouter un groupe de route, puis chaque route de ce groupe aura également le même middleware. C'est utile si vous devez regrouper un ensemble de routes par exemple avec un middleware d'Auth pour vérifier la clé API dans l'en-tête.
// ajouté à la fin de la méthode group
Flight::group('/api', function() {
// Cette route en apparence "vide" correspondra en fait à /api
Flight::route('', function() { echo 'api'; }, false, 'api');
// Cela correspondra à /api/utilisateurs
Flight::route('/utilisateurs', function() { echo 'utilisateurs'; }, false, 'utilisateurs');
// Cela correspondra à /api/utilisateurs/1234
Flight::route('/utilisateurs/@id', function($id) { echo 'utilisateur :'.$id; }, false, 'vue_utilisateur');
}, [ new ApiAuthMiddleware() ]);
Si vous souhaitez appliquer un middleware global à toutes vos routes, vous pouvez ajouter un groupe "vide" :
// ajouté à la fin de la méthode group
Flight::group('', function() {
// C'est toujours /utilisateurs
Flight::route('/utilisateurs', function() { echo 'utilisateurs'; }, false, 'utilisateurs');
// Et c'est toujours /utilisateurs/1234
Flight::route('/utilisateurs/@id', function($id) { echo 'utilisateur :'.$id; }, false, 'vue_utilisateur');
}, [ new ApiAuthMiddleware() ]);
Learn/filtering
Filtrage
Flight vous permet de filtrer les méthodes avant et après leur appel. Il n'y a pas de crochets prédéfinis que vous devez mémoriser. Vous pouvez filtrer n'importe quelle des méthodes par défaut du framework ainsi que n'importe quelle méthode personnalisée que vous avez mappée.
Une fonction de filtre ressemble à ceci :
function (array &$params, string &$output): bool {
// Code de filtre
}
En utilisant les variables passées en paramètre, vous pouvez manipuler les paramètres d'entrée et/ou la sortie.
Vous pouvez faire exécuter un filtre avant une méthode en faisant :
Flight::before('start', function (array &$params, string &$output): bool {
// Faire quelque chose
});
Vous pouvez faire exécuter un filtre après une méthode en faisant :
Flight::after('start', function (array &$params, string &$output): bool {
// Faire quelque chose
});
Vous pouvez ajouter autant de filtres que vous le souhaitez à n'importe quelle méthode. Ils seront appelés dans l'ordre où ils sont déclarés.
Voici un exemple du processus de filtrage :
// Mapper une méthode personnalisée
Flight::map('hello', function (string $name) {
return "Bonjour, $name!";
});
// Ajouter un filtre avant
Flight::before('hello', function (array &$params, string &$output): bool {
// Manipuler le paramètre
$params[0] = 'Fred';
return true;
});
// Ajouter un filtre après
Flight::after('hello', function (array &$params, string &$output): bool {
// Manipuler la sortie
$output .= " Passez une bonne journée !";
return true;
});
// Appeler la méthode personnalisée
echo Flight::hello('Bob');
Cela devrait afficher :
Bonjour Fred ! Passez une bonne journée !
Si vous avez défini plusieurs filtres, vous pouvez interrompre la chaîne en renvoyant false
dans l'une de vos fonctions de filtre :
Flight::before('start', function (array &$params, string &$output): bool {
echo 'un';
return true;
});
Flight::before('start', function (array &$params, string &$output): bool {
echo 'deux';
// Cela mettra fin à la chaîne
return false;
});
// Cela ne sera pas appelé
Flight::before('start', function (array &$params, string &$output): bool {
echo 'trois';
return true;
});
Notez que les méthodes de base telles que map
et register
ne peuvent pas être filtrées car elles
sont appelées directement et n'exécutent pas de manière dynamique.
Learn/requests
Requêtes
Flight encapsule la requête HTTP dans un seul objet, qui peut être accédé en faisant :
$request = Flight::request();
Cas d'utilisation typiques
Lorsque vous travaillez avec une requête dans une application web, vous voudrez généralement
extraire un en-tête, ou un paramètre $_GET
ou $_POST
, ou peut-être même le corps brut de la requête. Flight fournit une interface simple pour faire toutes ces choses.
Voici un exemple d'obtention d'un paramètre de chaîne de requête :
Flight::route('/search', function(){
$keyword = Flight::request()->query['keyword'];
echo "Vous recherchez : $keyword";
// interroger une base de données ou autre chose avec le $keyword
});
Voici un exemple d'un formulaire avec une méthode POST :
Flight::route('POST /submit', function(){
$name = Flight::request()->data['name'];
$email = Flight::request()->data['email'];
echo "Vous avez soumis : $name, $email";
// enregistrer dans une base de données ou autre chose avec le $name et $email
});
Propriétés de l'objet de requête
L'objet de requête fournit les propriétés suivantes :
- body - Le corps brut de la requête HTTP
- url - L'URL demandée
- base - Le sous-répertoire parent de l'URL
- method - La méthode de requête (GET, POST, PUT, DELETE)
- referrer - L'URL de référence
- ip - Adresse IP du client
- ajax - Si la requête est une requête AJAX
- scheme - Le protocole du serveur (http, https)
- user_agent - Informations sur le navigateur
- type - Le type de contenu
- length - La longueur du contenu
- query - Paramètres de chaîne de requête
- data - Données POST ou données JSON
- cookies - Données de cookie
- files - Fichiers téléchargés
- secure - Si la connexion est sécurisée
- accept - Paramètres d'acceptation HTTP
- proxy_ip - Adresse IP proxy du client. Scanne le tableau
$_SERVER
pourHTTP_CLIENT_IP
,HTTP_X_FORWARDED_FOR
,HTTP_X_FORWARDED
,HTTP_X_CLUSTER_CLIENT_IP
,HTTP_FORWARDED_FOR
,HTTP_FORWARDED
dans cet ordre. - host - Le nom d'hôte de la requête
Vous pouvez accéder aux propriétés query
, data
, cookies
et files
comme des tableaux ou des objets.
Donc, pour obtenir un paramètre de chaîne de requête, vous pouvez faire :
$id = Flight::request()->query['id'];
Ou vous pouvez faire :
$id = Flight::request()->query->id;
CORPS DE LA REQUÊTE BRUTE
Pour obtenir le corps brut de la requête HTTP, par exemple lors du traitement des requêtes PUT, vous pouvez faire :
$body = Flight::request()->getBody();
Entrée JSON
Si vous envoyez une requête avec le type application/json
et les données {"id": 123}
elles seront disponibles via la propriété data
:
$id = Flight::request()->data->id;
$_GET
Vous pouvez accéder au tableau $_GET
via la propriété query
:
$id = Flight::request()->query['id'];
$_POST
Vous pouvez accéder au tableau $_POST
via la propriété data
:
$id = Flight::request()->data['id'];
$_COOKIE
Vous pouvez accéder au tableau $_COOKIE
via la propriété cookies
:
$myCookieValue = Flight::request()->cookies['myCookieName'];
$_SERVER
Il existe un raccourci disponible pour accéder au tableau $_SERVER
via la méthode getVar()
:
$host = Flight::request()->getVar['HTTP_HOST'];
Accéder aux fichiers téléchargés via $_FILES
Vous pouvez accéder aux fichiers téléchargés via la propriété files
:
$uploadedFile = Flight::request()->files['myFile'];
Traitement des téléchargements de fichiers
Vous pouvez traiter les téléchargements de fichiers en utilisant le framework avec quelques méthodes d'aide. Cela revient essentiellement à obtenir les données du fichier de la requête et à les déplacer vers un nouvel emplacement.
Flight::route('POST /upload', function(){
// Si vous aviez un champ d'entrée comme <input type="file" name="myFile">
$uploadedFileData = Flight::request()->getUploadedFiles();
$uploadedFile = $uploadedFileData['myFile'];
$uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename());
});
Si vous avez plusieurs fichiers téléchargés, vous pouvez les parcourir :
Flight::route('POST /upload', function(){
// Si vous aviez un champ d'entrée comme <input type="file" name="myFiles[]">
$uploadedFiles = Flight::request()->getUploadedFiles()['myFiles'];
foreach ($uploadedFiles as $uploadedFile) {
$uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename());
}
});
Note de sécurité : Validez toujours et assainissez les entrées de l'utilisateur, en particulier lors du traitement des téléchargements de fichiers. Validez toujours le type d'extensions que vous autoriserez à être téléchargées, mais vous devriez également valider les "octets magiques" du fichier pour vous assurer qu'il s'agit effectivement du type de fichier que l'utilisateur prétend avoir. Il existe des articles et bibliothèques disponibles pour vous aider avec cela.
En-têtes de requête
Vous pouvez accéder aux en-têtes de la requête en utilisant la méthode getHeader()
ou getHeaders()
:
// Peut-être avez-vous besoin de l'en-tête d'Authorization
$host = Flight::request()->getHeader('Authorization');
// ou
$host = Flight::request()->header('Authorization');
// Si vous devez récupérer tous les en-têtes
$headers = Flight::request()->getHeaders();
// ou
$headers = Flight::request()->headers();
Corps de la requête
Vous pouvez accéder au corps brut de la requête en utilisant la méthode getBody()
:
$body = Flight::request()->getBody();
Méthode de requête
Vous pouvez accéder à la méthode de requête en utilisant la propriété method
ou la méthode getMethod()
:
$method = Flight::request()->method; // appelle en réalité getMethod()
$method = Flight::request()->getMethod();
Remarque : La méthode getMethod()
récupère d'abord la méthode à partir de $_SERVER['REQUEST_METHOD']
, puis elle peut être écrasée
par $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']
si elle existe ou $_REQUEST['_method']
si elle existe.
URLs de requête
Il existe quelques méthodes d'aide pour assembler des parties d'une URL pour votre commodité.
URL complète
Vous pouvez accéder à l'URL de requête complète en utilisant la méthode getFullUrl()
:
$url = Flight::request()->getFullUrl();
// https://example.com/some/path?foo=bar
URL de base
Vous pouvez accéder à l'URL de base en utilisant la méthode getBaseUrl()
:
$url = Flight::request()->getBaseUrl();
// Remarque, pas de barre oblique de fin.
// https://example.com
Analyse des requêtes
Vous pouvez passer une URL à la méthode parseQuery()
pour analyser la chaîne de requête en un tableau associatif :
$query = Flight::request()->parseQuery('https://example.com/some/path?foo=bar');
// ['foo' => 'bar']
Learn/frameworkmethods
Méthodes du Cadre
Flight est conçu pour être facile à utiliser et à comprendre. Ce qui suit est l'ensemble complet des méthodes du cadre. Il se compose de méthodes centrales, qui sont des méthodes statiques régulières, et de méthodes extensibles, qui sont des méthodes mappées qui peuvent être filtrées ou remplacées.
Méthodes Principales
Flight::map(string $name, callable $callback, bool $pass_route = false) // Crée une méthode de cadre personnalisée.
Flight::register(string $name, string $class, array $params = [], ?callable $callback = null) // Enregistre une classe à une méthode de cadre.
Flight::before(string $name, callable $callback) // Ajoute un filtre avant une méthode de cadre.
Flight::after(string $name, callable $callback) // Ajoute un filtre après une méthode de cadre.
Flight::path(string $path) // Ajoute un chemin pour le chargement automatique des classes.
Flight::get(string $key) // Obtient une variable.
Flight::set(string $key, mixed $value) // Définit une variable.
Flight::has(string $key) // Vérifie si une variable est définie.
Flight::clear(array|string $key = []) // Efface une variable.
Flight::init() // Initialise le cadre à ses réglages par défaut.
Flight::app() // Obtient l'instance de l'objet d'application
Méthodes Extensibles
Flight::start() // Lance le cadre.
Flight::stop() // Arrête le cadre et envoie une réponse.
Flight::halt(int $code = 200, string $message = '') // Arrête le cadre avec un code d'état et un message facultatif.
Flight::route(string $pattern, callable $callback, bool $pass_route = false) // Associe un modèle d'URL à un rappel.
Flight::group(string $pattern, callable $callback) // Crée un regroupement pour les URL, le modèle doit être une chaîne de caractères.
Flight::redirect(string $url, int $code) // Redirige vers une autre URL.
Flight::render(string $file, array $data, ?string $key = null) // Rend un fichier de modèle.
Flight::error(Throwable $error) // Envoie une réponse HTTP 500.
Flight::notFound() // Envoie une réponse HTTP 404.
Flight::etag(string $id, string $type = 'string') // Effectue une mise en cache HTTP ETag.
Flight::lastModified(int $time) // Effectue une mise en cache HTTP modifiée récemment.
Flight::json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envoie une réponse JSON.
Flight::jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envoie une réponse JSONP.
Toutes les méthodes personnalisées ajoutées avec map
et register
peuvent également être filtrées.
Learn/api
Méthodes de l'API du Framework
Flight est conçu pour être facile à utiliser et à comprendre. Ce qui suit est l'ensemble complet des méthodes pour le framework. Il est composé 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 pouvant être filtrées ou remplacées.
Méthodes de base
Ces méthodes sont essentielles au framework et ne peuvent pas être remplacées.
Flight::map(string $name, callable $callback, bool $pass_route = false) // Crée une méthode personnalisée du framework.
Flight::register(string $name, string $class, array $params = [], ?callable $callback = null) // Enregistre une classe à une méthode du framework.
Flight::unregister(string $name) // Désenregistre une classe à une méthode du framework.
Flight::before(string $name, callable $callback) // Ajoute un filtre avant une méthode du framework.
Flight::after(string $name, callable $callback) // Ajoute un filtre après une méthode du framework.
Flight::path(string $path) // Ajoute un chemin pour le chargement automatique des classes.
Flight::get(string $key) // Obtient une variable définie par Flight::set().
Flight::set(string $key, mixed $value) // Définit une variable dans le moteur Flight.
Flight::has(string $key) // Vérifie si une variable est définie.
Flight::clear(array|string $key = []) // Efface une variable.
Flight::init() // Initialise le framework avec ses paramètres par défaut.
Flight::app() // Obtient l'instance de l'objet 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 framework.
Flight::stop() // Arrête le framework et envoie une réponse.
Flight::halt(int $code = 200, string $message = '') // Arrête le framework avec un code de statut et un message optionnels.
Flight::route(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Mappe un motif d'URL à un callback.
Flight::post(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Mappe un motif d'URL de requête POST à un callback.
Flight::put(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Mappe un motif d'URL de requête PUT à un callback.
Flight::patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Mappe un motif d'URL de requête PATCH à un callback.
Flight::delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Mappe un motif d'URL de requête DELETE à un callback.
Flight::group(string $pattern, callable $callback) // Crée un regroupement pour les urls, le motif doit être une chaîne.
Flight::getUrl(string $name, array $params = []) // Génère une URL basée sur un alias de route.
Flight::redirect(string $url, int $code) // Redirige vers une autre URL.
Flight::download(string $filePath) // Télécharge un fichier.
Flight::render(string $file, array $data, ?string $key = null) // Rend un fichier de modèle.
Flight::error(Throwable $error) // Envoie une réponse HTTP 500.
Flight::notFound() // Envoie une réponse HTTP 404.
Flight::etag(string $id, string $type = 'string') // Effectue un cache HTTP ETag.
Flight::lastModified(int $time) // Effectue un cache HTTP de dernière modification.
Flight::json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envoie une réponse JSON.
Flight::jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envoie une réponse JSONP.
Flight::jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envoie une réponse JSON et arrête le framework.
Flight::onEvent(string $event, callable $callback) // Enregistre un écouteur d'événements.
Flight::triggerEvent(string $event, ...$args) // Déclenche un événement.
Toute méthode personnalisée ajoutée avec map
et register
peut également être filtrée. Pour des exemples sur la façon de mapper ces méthodes, consultez le guide Étendre Flight.
Learn/why_frameworks
Pourquoi un Framework?
Certains programmeurs sont farouchement opposés à l'utilisation de frameworks. Ils soutiennent que les frameworks sont gonflés, lents et difficiles à apprendre. Ils disent que les frameworks sont inutiles et que vous pouvez écrire un meilleur code sans eux. Il y a certainement quelques points valides à faire valoir sur les inconvénients de l'utilisation des frameworks. Cependant, il y a aussi de nombreux avantages à utiliser des frameworks.
Raisons d'utiliser un Framework
Voici quelques raisons pour lesquelles vous pourriez envisager d'utiliser un framework:
- Développement Rapide: Les frameworks offrent beaucoup de fonctionnalités prêtes à l'emploi. Cela signifie que vous pouvez développer des applications web plus rapidement. Vous n'avez pas à écrire autant de code car le framework fournit une grande partie des fonctionnalités dont vous avez besoin.
- Cohérence: Les frameworks offrent une manière cohérente de faire les choses. Cela facilite votre compréhension du fonctionnement du code et facilite la compréhension de votre code par d'autres développeurs. Si vous le faites script par script, vous pourriez perdre de la cohérence entre les scripts, surtout si vous travaillez avec une équipe de développeurs.
- Sécurité: Les frameworks proposent des fonctionnalités de sécurité qui aident à protéger vos applications web contre les menaces courantes en matière de sécurité. Cela signifie que vous n'avez pas à vous soucier autant de la sécurité car le framework s'occupe en grande partie de cela pour vous.
- Communauté: Les frameworks ont de grandes communautés de développeurs qui contribuent au framework. Cela signifie que vous pouvez obtenir de l'aide d'autres développeurs lorsque vous avez des questions ou des problèmes. Cela signifie également qu'il y a beaucoup de ressources disponibles pour vous aider à apprendre comment utiliser le framework.
- Meilleures Pratiques: Les frameworks sont construits en utilisant les meilleures pratiques. Cela signifie que vous pouvez apprendre du framework et utiliser les mêmes meilleures pratiques dans votre propre code. Cela peut vous aider à devenir un meilleur programmeur. Parfois, vous ne savez pas ce que vous ne savez pas et cela peut vous jouer des tours à la fin.
- Extensibilité: Les frameworks sont conçus pour être étendus. Cela signifie que vous pouvez ajouter votre propre fonctionnalité au framework. Cela vous permet de construire des applications web adaptées à vos besoins spécifiques.
Flight est un micro-framework. Cela signifie qu'il est petit et léger. Il ne fournit pas autant de fonctionnalités que des frameworks plus grands comme Laravel ou Symfony. Cependant, il fournit une grande partie des fonctionnalités dont vous avez besoin pour construire des applications web. Il est également facile à apprendre et à utiliser. Cela en fait un bon choix pour construire rapidement et facilement des applications web. Si vous êtes novice en frameworks, Flight est un excellent framework pour débutants. Cela vous aidera à découvrir les avantages de l'utilisation des frameworks sans vous submerger avec trop de complexité. Après avoir acquis de l'expérience avec Flight, il sera plus facile de passer à des frameworks plus complexes comme Laravel ou Symfony, cependant Flight peut toujours vous aider à créer une application robuste et réussie.
Qu'est-ce que le Routage?
Le routage est au cœur du framework Flight, mais qu'est-ce que c'est exactement? Le routage est le processus de prendre une URL et de la faire correspondre à une fonction spécifique dans votre code.
C'est ainsi que vous pouvez faire en sorte que votre site Web fasse différentes choses en fonction de l'URL demandée. Par exemple, vous pouvez vouloir afficher le profil d'un utilisateur lorsqu'il
visite /utilisateur/1234
, mais affichez une liste de tous les utilisateurs lorsqu'ils visitent /utilisateurs
. Tout cela se fait grâce au routage.
Cela pourrait fonctionner un peu comme ceci:
- Un utilisateur se rend sur votre navigateur et tape
http://exemple.com/utilisateur/1234
. - Le serveur reçoit la demande, examine l'URL et la transmet à votre code d'application Flight.
- Disons que dans votre code Flight vous avez quelque chose comme
Flight::route('/utilisateur/@id', [ 'ControlleurUtilisateur', 'voirProfilUtilisateur' ]);
. Votre code d'application Flight examine l'URL et constate qu'elle correspond à une route que vous avez définie, puis exécute le code que vous avez défini pour cette route. - Le routeur de Flight exécutera ensuite et appellera la méthode
voirProfilUtilisateur($id)
dans la classeControlleurUtilisateur
, en passant le1234
en tant qu'argument$id
dans la méthode. - Le code dans votre méthode
voirProfilUtilisateur()
s'exécutera alors et fera ce que vous lui avez dit de faire. Vous pourriez finir par afficher un peu de HTML pour la page de profil de l'utilisateur, ou s'il s'agit d'une API RESTful, vous pourriez afficher une réponse JSON avec les informations de l'utilisateur. - Flight emballe tout cela joliment, génère les en-têtes de réponse et les envoie de retour au navigateur de l'utilisateur.
- L'utilisateur est comblé de joie et se fait un câlin chaleureux!
Et Pourquoi est-ce Important?
Avoir un routeur centralisé approprié peut réellement rendre votre vie beaucoup plus facile! Il peut être difficile de le voir au début. Voici quelques raisons:
- Routage Centralisé: Vous pouvez regrouper tous vos itinéraires en un seul endroit. Cela facilite la visualisation de tous les itinéraires que vous avez et de ce qu'ils font. Cela facilite également leur modification si nécessaire.
- Paramètres de Route: Vous pouvez utiliser des paramètres de route pour transmettre des données à vos méthodes de route. C'est un excellent moyen de garder votre code propre et organisé.
- Groupes de Routes: Vous pouvez regrouper des itinéraires ensemble. C'est idéal pour maintenir votre code organisé et pour appliquer middleware à un groupe d'itinéraires.
- Alias de Route: Vous pouvez attribuer un alias à un itinéraire, de sorte que l'URL puisse être générée dynamiquement plus tard dans votre code (comme un modèle par exemple). Ex : au lieu de coder en dur
/utilisateur/1234
dans votre code, vous pourriez plutôt référencer l'aliasvue_utilisateur
et transmettre l'id
en tant que paramètre. C'est merveilleux au cas où vous décideriez de le changer en/admin/utilisateur/1234
plus tard. Vous n'aurez pas à changer toutes vos URLs codées en dur, juste l'URL attachée à la route. - Middlewares de Route: Vous pouvez ajouter des middlewares à vos itinéraires. Les middlewares sont incroyablement efficaces pour ajouter des comportements spécifiques à votre application, comme l'authentification qu'un certain utilisateur peut accéder à un itinéraire ou à un groupe d'itinéraires.
Je suis sûr que vous êtes familier avec la manière scriptée de créer un site web. Vous pourriez avoir un fichier appelé index.php
qui comporte une multitude de déclarations if
pour vérifier l'URL et puis exécuter une fonction spécifique en fonction de l'URL. C'est une forme de routage, mais ce n'est pas très organisé et cela peut rapidement devenir incontrôlable. Le système de routage de Flight est une méthode beaucoup plus organisée et puissante pour gérer le routage.
Comme ceci ?
// /utilisateur/voir_profil.php?id=1234
if ($_GET['id']) {
$id = $_GET['id'];
voirProfilUtilisateur($id);
}
// /utilisateur/editer_profil.php?id=1234
if ($_GET['id']) {
$id = $_GET['id'];
editerProfilUtilisateur($id);
}
// etc...
Ou comme cela ?
// index.php
Flight::route('/utilisateur/@id', [ 'ControlleurUtilisateur', 'voirProfilUtilisateur' ]);
Flight::route('/utilisateur/@id/editer', [ 'ControlleurUtilisateur', 'editerProfilUtilisateur' ]);
// Peut-être dans votre app/controllers/ControlleurUtilisateur.php
class ControlleurUtilisateur {
public function voirProfilUtilisateur($id) {
// faire quelque chose
}
public function editerProfilUtilisateur($id) {
// faire quelque chose
}
}
Espérons que vous commencez à voir les avantages d'utiliser un système de routage centralisé. C'est beaucoup plus facile à gérer et à comprendre à long terme!
Demandes et Réponses
Flight fournit un moyen simple et facile de gérer les demandes et les réponses. C'est le cœur de ce qu'un framework web fait. Il prend une demande de navigateur d'utilisateur, la traite, puis envoie une réponse. C'est ainsi que vous pouvez construire des applications web qui font des choses comme afficher un profil d'utilisateur, permettre à un utilisateur de se connecter, ou permettre à un utilisateur de poster un nouveau billet de blog.
Demandes
Une demande est ce que le navigateur de l'utilisateur envoie à votre serveur lorsqu'ils visitent votre site. Cette demande contient des informations sur ce que l'utilisateur veut faire. Par exemple, elle peut contenir des informations sur l'URL que l'utilisateur souhaite visiter, les données que l'utilisateur souhaite envoyer à votre serveur, ou le type de données que l'utilisateur souhaite recevoir de votre serveur. Il est important de savoir qu'une demande est en lecture seule. Vous ne pouvez pas changer la demande, mais vous pouvez la lire.
Flight fournit un moyen simple d'accéder aux informations sur la demande. Vous pouvez accéder aux informations sur la demande en utilisant la méthode Flight::request()
Cette méthode renvoie un objet Request
qui contient des informations sur la demande. Vous pouvez utiliser cet objet pour accéder aux informations sur la demande,
telles que l'URL, la méthode, ou les données que l'utilisateur a envoyées à votre serveur.
Réponses
Une réponse est ce que votre serveur envoie à nouveau au navigateur de l'utilisateur lorsqu'ils visitent votre site. Cette réponse contient des informations sur ce que votre serveur veut faire. Par exemple, elle peut contenir des informations sur le type de données que votre serveur souhaite envoyer à l'utilisateur, le type de données que votre serveur souhaite recevoir de l'utilisateur, ou le type de données que votre serveur souhaite stocker sur l'ordinateur de l'utilisateur.
Flight fournit un moyen simple d'envoyer une réponse au navigateur de l'utilisateur. Vous pouvez envoyer une réponse en utilisant la méthode Flight::response()
Cette méthode prend un objet Response
en argument et envoie la réponse au navigateur de l'utilisateur. Vous pouvez utiliser cet objet pour envoyer une réponse au
navigateur de l'utilisateur, telle que HTML, JSON ou un fichier. Flight vous aide à générer automatiquement certaines parties de la réponse pour faciliter les choses,
mais finalement vous avez le contrôle sur ce que vous renvoyez à l'utilisateur.
Learn/httpcaching
Mise en cache HTTP
Flight offre une prise en charge intégrée pour la mise en cache au niveau HTTP. Si la condition de mise en cache
est remplie, Flight renverra une réponse HTTP 304 Non modifié
. La prochaine fois que
le client demande la même ressource, il sera invité à utiliser sa version mise en cache localement.
Dernière modification
Vous pouvez utiliser la méthode lastModified
et transmettre un horodatage UNIX pour définir la date
et l'heure à laquelle une page a été modifiée pour la dernière fois. Le client continuera d'utiliser sa mise en cache jusqu'à ce que
que la valeur de la dernière modification soit modifiée.
Flight::route('/actualites', function () {
Flight::lastModified(1234567890);
echo 'Ce contenu sera mis en cache.';
});
ETag
La mise en cache ETag
est similaire à Dernière modification
, sauf que vous pouvez spécifier n'importe quel identifiant
que vous souhaitez pour la ressource :
Flight::route('/actualites', function () {
Flight::etag('mon-identifiant-unique');
echo 'Ce contenu sera mis en cache.';
});
Gardez à l'esprit que l'appel à lastModified
ou etag
définira et vérifiera à la fois
la valeur de la mise en cache. Si la valeur de mise en cache est la même entre les demandes, Flight enverra immédiatement
une réponse HTTP 304
et arrêtera le traitement.
Learn/responses
Réponses
Flight aide à générer une partie des en-têtes de réponse pour vous, mais vous gardez le contrôle sur ce que vous renvoyez à l'utilisateur. Parfois, vous pouvez accéder directement à l'objet Response
, mais la plupart du temps, vous utiliserez l'instance Flight
pour envoyer une réponse.
Envoi d'une réponse de base
Flight utilise ob_start() pour mettre en mémoire tampon la sortie. Cela signifie que vous pouvez utiliser echo
ou print
pour envoyer une réponse à l'utilisateur et Flight la capturera et la renverra avec les en-têtes appropriés.
// Cela enverra "Hello, World!" au navigateur de l'utilisateur
Flight::route('/', function() {
echo "Hello, World!";
});
// HTTP/1.1 200 OK
// Content-Type: text/html
//
// Hello, World!
En alternative, vous pouvez appeler la méthode write()
pour ajouter au corps également.
// Cela enverra "Hello, World!" au navigateur de l'utilisateur
Flight::route('/', function() {
// verbeux, mais cela fait souvent le travail lorsque vous en avez besoin
Flight::response()->write("Hello, World!");
// si vous souhaitez 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 "Hello, World!";
} else {
Flight::response()->status(403);
echo "Interdit";
}
});
Si vous souhaitez obtenir le code d'état actuel, vous pouvez utiliser la méthode status
sans aucun argument :
Flight::response()->status(); // 200
Définir un corps de réponse
Vous pouvez définir le corps de la réponse en utilisant la méthode write
, cependant, si vous echo ou print quelque chose,
il sera capturé et envoyé comme corps de réponse via la mise en mémoire tampon de sortie.
Flight::route('/', function() {
Flight::response()->write("Hello, World!");
});
// même que
Flight::route('/', function() {
echo "Hello, World!";
});
Effacer un corps de réponse
Si vous souhaitez effacer le corps de la réponse, vous pouvez utiliser la méthode clearBody
:
Flight::route('/', function() {
if($someCondition) {
Flight::response()->write("Hello, World!");
} else {
Flight::response()->clearBody();
}
});
Exécution d'un rappel sur le corps de réponse
Vous pouvez exécuter un rappel sur le corps de réponse en utilisant la méthode addResponseBodyCallback
:
Flight::route('/users', function() {
$db = Flight::db();
$users = $db->fetchAll("SELECT * FROM users");
Flight::render('users_table', ['users' => $users]);
});
// Cela gérera toutes les réponses pour n'importe quelle route
Flight::response()->addResponseBodyCallback(function($body) {
return gzencode($body, 9);
});
Vous pouvez ajouter plusieurs rappels et ils seront exécutés dans l'ordre dans lequel ils ont été ajoutés. Étant donné que cela peut accepter tout callable, cela peut accepter un tableau de classe [ $class, 'method' ]
, une closure $strReplace = function($body) { str_replace('hi', 'there', $body); };
, ou un nom de fonction 'minify'
si vous aviez une fonction pour minifier votre code html par exemple.
Remarque : Les rappels de route ne fonctionneront pas si vous utilisez l'option de configuration flight.v2.output_buffering
.
Rappel de route spécifique
Si vous souhaitez que cela s'applique uniquement à une route spécifique, vous pouvez ajouter le rappel dans la route elle-même :
Flight::route('/users', function() {
$db = Flight::db();
$users = $db->fetchAll("SELECT * FROM users");
Flight::render('users_table', ['users' => $users]);
// Cela gérera uniquement la réponse pour cette route
Flight::response()->addResponseBodyCallback(function($body) {
return gzencode($body, 9);
});
});
Option Middleware
Vous pouvez également utiliser un middleware pour appliquer le rappel à toutes les routes via middleware :
// MinifyMiddleware.php
class MinifyMiddleware {
public function before() {
// Appliquez le rappel ici sur l'objet response().
Flight::response()->addResponseBodyCallback(function($body) {
return $this->minify($body);
});
}
protected function minify(string $body): string {
// minifiez le corps d'une certaine manière
return $body;
}
}
// index.php
Flight::group('/users', function() {
Flight::route('', function() { /* ... */ });
Flight::route('/@id', function($id) { /* ... */ });
}, [ new MinifyMiddleware() ]);
Définir un en-tête de réponse
Vous pouvez définir un en-tête comme le type de contenu de la réponse en utilisant la méthode header
:
// Cela enverra "Hello, World!" au navigateur de l'utilisateur en texte brut
Flight::route('/', function() {
Flight::response()->header('Content-Type', 'text/plain');
// ou
Flight::response()->setHeader('Content-Type', 'text/plain');
echo "Hello, World!";
});
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]);
Remarque : Par défaut, Flight enverra un en-tête
Content-Type: application/json
avec la réponse. Il utilisera également les constantesJSON_THROW_ON_ERROR
etJSON_UNESCAPED_SLASHES
lors de l'encodage du JSON.
JSON avec code d'état
Vous pouvez également passer un code d'état en tant que deuxième argument :
Flight::json(['id' => 123], 201);
JSON avec formatage
Vous pouvez également passer un argument à la dernière position pour activer le formatage :
Flight::json(['id' => 123], 200, true, 'utf-8', JSON_PRETTY_PRINT);
Si vous modifiez les options passées dans Flight::json()
et souhaitez une syntaxe plus simple, vous pouvez
simplement remapper la méthode JSON :
Flight::map('json', function($data, $code = 200, $options = 0) {
Flight::_json($data, $code, true, 'utf-8', $options);
}
// Et maintenant cela peut être utilisé comme ceci
Flight::json(['id' => 123], 200, JSON_PRETTY_PRINT);
JSON et arrêter l'exécution (v3.10.0)
Si vous souhaitez envoyer une réponse JSON et arrêter l'exécution, vous pouvez utiliser la méthode jsonHalt
.
Ceci est utile pour les cas où vous vérifiez peut-être un certain type d'autorisation et si
l'utilisateur n'est pas autorisé, vous pouvez envoyer une réponse JSON immédiatement, effacer le contenu du corps existant
et arrêter l'exécution.
Flight::route('/users', function() {
$authorized = someAuthorizationCheck();
// Vérifiez si l'utilisateur est autorisé
if($authorized === false) {
Flight::jsonHalt(['error' => 'Non autorisé'], 401);
}
// Continuez avec le reste de la route
});
Avant v3.10.0, vous auriez dû faire quelque chose comme ceci :
Flight::route('/users', function() {
$authorized = someAuthorizationCheck();
// Vérifiez si l'utilisateur est autorisé
if($authorized === false) {
Flight::halt(401, json_encode(['error' => 'Non autorisé']));
}
// Continuez avec le reste de la route
});
JSONP
Pour les requêtes JSONP, vous pouvez facultativement passer le nom du paramètre de requête que vous utilisez pour définir votre fonction de rappel :
Flight::jsonp(['id' => 123], 'q');
Ainsi, lorsque vous effectuez une requête GET en utilisant ?q=my_func
, vous devriez recevoir la sortie :
my_func({"id":123});
Si vous ne passez pas de nom de paramètre de requête, il sera par défaut jsonp
.
Rediriger vers une autre URL
Vous pouvez rediriger la demande actuelle en utilisant la méthode redirect()
et en passant
une nouvelle URL :
Flight::redirect('/new/location');
Par défaut, Flight envoie un code d'état HTTP 303 ("Voir autre"). Vous pouvez éventuellement définir un code personnalisé :
Flight::redirect('/new/location', 401);
Arrêt
Vous pouvez arrêter le framework à tout moment en appelant la méthode halt
:
Flight::halt();
Vous pouvez également spécifier un code de statut HTTP
et un message optionnels :
Flight::halt(200, 'Soyez de retour bientôt...');
Appeler halt
annulera tout contenu de réponse jusqu'à ce point. Si vous souhaitez arrêter
le framework et afficher la réponse actuelle, utilisez la méthode stop
:
Flight::stop();
Effacer les données de réponse
Vous pouvez effacer le corps et les en-têtes de réponse en utilisant la méthode clear()
. Cela effacera
tous les en-têtes assignés à la réponse, effacera le corps de la réponse et définira le code d'état sur 200
.
Flight::response()->clear();
Effacer uniquement le corps de réponse
Si vous voulez uniquement effacer le corps de la réponse, vous pouvez utiliser la méthode clearBody()
:
// Cela conservera toujours tous les en-têtes définis sur l'objet response().
Flight::response()->clearBody();
Mise en cache HTTP
Flight fournit un support intégré pour la mise en cache au niveau HTTP. Si la condition de mise en cache
est remplie, Flight retournera une réponse HTTP 304 Non modifié
. La prochaine fois que le
client demandera la même ressource, il sera invité à utiliser sa version mise en cache localement.
Mise en cache au niveau de la route
Si vous souhaitez mettre en cache l'ensemble de votre réponse, vous pouvez utiliser la méthode cache()
et passer le temps à mettre en cache.
// Cela mettra en cache la réponse pendant 5 minutes
Flight::route('/news', 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('/news', function () {
Flight::response()->cache('+5 minutes');
echo 'Ce contenu sera mis en cache.';
});
Dernière modification
Vous pouvez utiliser la méthode lastModified
et passer un horodatage UNIX pour définir la date
et l'heure de la dernière modification d'une page. Le client continuera à utiliser son cache jusqu'à
ce que la valeur de dernière modification soit changée.
Flight::route('/news', function () {
Flight::lastModified(1234567890);
echo 'Ce contenu sera mis en cache.';
});
ETag
La mise en cache ETag
est similaire à Last-Modified
, sauf que vous pouvez spécifier n'importe quel identifiant que
vous souhaitez pour la ressource :
Flight::route('/news', function () {
Flight::etag('mon-id-unique');
echo 'Ce contenu sera mis en cache.';
});
Gardez à l'esprit que l'appel de lastModified
ou etag
définira et vérifiera
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.
Télécharger un fichier (v3.12.0)
Il existe une méthode d'assistance pour télécharger un fichier. Vous pouvez utiliser la méthode download
et passer le chemin.
Flight::route('/download', function () {
Flight::download('/path/to/file.txt');
});
Learn/frameworkinstance
Instance de Framework
Au lieu d'exécuter Flight en tant que classe statique globale, vous pouvez éventuellement l'exécuter en tant qu'instance d'objet.
require 'flight/autoload.php';
$app = Flight::app();
$app->route('/', function () {
echo 'hello world!';
});
$app->start();
Donc, au lieu d'appeler la méthode statique, vous appelleriez la méthode d'instance avec le même nom sur l'objet Engine.
Learn/redirects
Redirection
Vous pouvez rediriger la requête actuelle en utilisant la méthode redirect
et en passant
une nouvelle URL :
Flight::redirect('/nouvel/emplacement');
Par défaut, Flight envoie un code d'état HTTP 303. Vous pouvez éventuellement définir un code personnalisé :
Flight::redirect('/nouvel/emplacement', 401);
Learn/events
Système d'Événements dans Flight PHP (v3.15.0+)
Flight PHP introduit un système d'événements léger et intuitif qui vous permet d'enregistrer et de déclencher des événements personnalisés dans votre application. Avec l'ajout de Flight::onEvent()
et Flight::triggerEvent()
, vous pouvez désormais vous intégrer aux moments clés du cycle de vie de votre application ou définir vos propres événements pour rendre votre code plus modulaire et extensible. Ces méthodes font partie des méthodes mappables de Flight, ce qui signifie que vous pouvez remplacer leur comportement pour l'adapter à vos besoins.
Ce guide couvre tout ce que vous devez savoir pour commencer avec les événements, y compris pourquoi ils sont précieux, comment les utiliser, et des exemples pratiques pour aider les débutants à comprendre leur puissance.
Pourquoi Utiliser des Événements ?
Les événements vous permettent de séparer différentes parties de votre application afin qu'elles ne dépendent pas trop les unes des autres. Cette séparation—souvent appelée découplage—rend votre code plus facile à mettre à jour, à étendre ou à déboguer. Au lieu d'écrire tout dans un seul gros morceau, vous pouvez diviser votre logique en plus petits morceaux indépendants qui réagissent à des actions spécifiques (événements).
Imaginez que vous construisez une application de blog :
- Lorsqu'un utilisateur poste un commentaire, vous pourriez vouloir :
- Enregistrer le commentaire dans la base de données.
- Envoyer un e-mail au propriétaire du blog.
- Consigner l'action pour la sécurité.
Sans événements, vous feriez tout cela dans une seule fonction. Avec des événements, vous pouvez le diviser : une partie enregistre le commentaire, une autre déclenche un événement comme 'comment.posted'
, et des écouteurs séparés gèrent l'e-mail et la journalisation. Cela maintient votre code plus propre et vous permet d'ajouter ou de supprimer des fonctionnalités (comme des notifications) sans toucher à la logique principale.
Utilisations Courantes
- Journalisation : Enregistrer des actions comme des connexions ou des erreurs sans encombrer votre code principal.
- Notifications : Envoyer des e-mails ou des alertes lorsque quelque chose se produit.
- Mises à jour : Actualiser les caches ou notifier d'autres systèmes des changements.
Enregistrer des Écouteurs d'Événements
Pour écouter un événement, utilisez Flight::onEvent()
. Cette méthode vous permet de définir ce qui doit se passer lorsqu'un événement se produit.
Syntaxe
Flight::onEvent(string $event, callable $callback): void
$event
: Un nom pour votre événement (par exemple,'user.login'
).$callback
: La fonction à exécuter lorsque l'événement est déclenché.
Comment Ça Fonctionne
Vous "vous abonnez" à un événement en disant à Flight quoi faire quand il se produit. Le callback peut accepter des arguments passés depuis le déclencheur d'événements.
Le système d'événements de Flight est synchrone, ce qui signifie que chaque écouteur d'événements est exécuté en séquence, l'un après l'autre. Lorsque vous déclenchez un événement, tous les écouteurs enregistrés pour cet événement s'exécuteront jusqu'à leur terme avant que votre code ne continue. Il est important de comprendre cela car cela diffère des systèmes d'événements asynchrones où les écouteurs peuvent s'exécuter en parallèle ou à un moment ultérieur.
Exemple Simple
Flight::onEvent('user.login', function ($username) {
echo "Bienvenue de nouveau, $username !";
});
Ici, lorsque l'événement 'user.login'
est déclenché, il saluera l'utilisateur par son nom.
Points Clés
- Vous pouvez ajouter plusieurs écouteurs au même événement—ils s'exécuteront dans l'ordre où vous les avez enregistrés.
- Le callback peut être une fonction, une fonction anonyme, ou une méthode d'une classe.
Déclenchement d'Événements
Pour faire se produire un événement, utilisez Flight::triggerEvent()
. Cela demande à Flight d'exécuter tous les écouteurs enregistrés pour cet événement, en passant toute donnée que vous fournissez.
Syntaxe
Flight::triggerEvent(string $event, ...$args): void
$event
: Le nom de l'événement que vous déclenchez (doit correspondre à un événement enregistré)....$args
: Arguments optionnels à envoyer aux écouteurs (peut être n'importe quel nombre d'arguments).
Exemple Simple
$username = 'alice';
Flight::triggerEvent('user.login', $username);
Cela déclenche l'événement 'user.login'
et envoie 'alice'
à l'écouteur que nous avons défini plus tôt, qui produira : Bienvenue de nouveau, alice !
.
Points Clés
- Si aucun écouteur n'est enregistré, rien ne se passe—votre application ne se brisera pas.
- Utilisez l'opérateur de propagation (
...
) pour passer plusieurs arguments de manière flexible.
Enregistrement d'Écouteurs d'Événements
...
Arrêter d'autres Écouteurs :
Si un écouteur renvoie false
, aucun autre écouteur pour cet événement ne sera exécuté. Cela vous permet d'arrêter la chaîne d'événements en fonction de conditions spécifiques. Rappelez-vous, l'ordre des écouteurs est important, car le premier à renvoyer false
arrêtera les autres de s'exécuter.
Exemple :
Flight::onEvent('user.login', function ($username) {
if (isBanned($username)) {
logoutUser($username);
return false; // Arrête les écouteurs suivants
}
});
Flight::onEvent('user.login', function ($username) {
sendWelcomeEmail($username); // ceci n'est jamais envoyé
});
Remplacer les Méthodes d'Événements
Flight::onEvent()
et Flight::triggerEvent()
sont disponibles pour être étendus, ce qui signifie que vous pouvez redéfinir leur fonctionnement. C'est formidable pour les utilisateurs avancés qui souhaitent personnaliser le système d'événements, comme ajouter des journaux ou changer la façon dont les événements sont dispatchés.
Exemple : Personnaliser onEvent
Flight::map('onEvent', function (string $event, callable $callback) {
// Enregistrer chaque enregistrement d'événement
error_log("Nouvel écouteur d'événement ajouté pour : $event");
// Appeler le comportement par défaut (supposant un système d'événements interne)
Flight::_onEvent($event, $callback);
});
Maintenant, chaque fois que vous enregistrez un événement, il l'enregistre avant de continuer.
Pourquoi Remplacer ?
- Ajouter du débogage ou de la surveillance.
- Restreindre les événements dans certains environnements (par exemple, désactiver lors des tests).
- Intégrer une autre bibliothèque d'événements.
Où Mettre Vos Événements
En tant que débutant, vous pourriez vous demander : où dois-je enregistrer tous ces événements dans mon application ? La simplicité de Flight signifie qu'il n'y a pas de règle stricte—vous pouvez les placer où cela a du sens pour votre projet. Cependant, les garder organisés vous aide à maintenir votre code à mesure que votre application grandit. Voici quelques options pratiques et meilleures pratiques, adaptées à la légèreté de Flight :
Option 1 : Dans Votre Fichier Principal index.php
Pour de petites applications ou des prototypes rapides, vous pouvez enregistrer des événements directement dans votre fichier index.php
aux côtés de vos routes. Cela garde tout au même endroit, ce qui est bien lorsque la simplicité est votre priorité.
require 'vendor/autoload.php';
// Enregistrer des événements
Flight::onEvent('user.login', function ($username) {
error_log("$username s'est connecté à " . date('Y-m-d H:i:s'));
});
// Définir des routes
Flight::route('/login', function () {
$username = 'bob';
Flight::triggerEvent('user.login', $username);
echo "Connecté !";
});
Flight::start();
- Avantages : Simple, pas de fichiers supplémentaires, idéal pour de petits projets.
- Inconvénients : Peut devenir désordonné à mesure que votre application grandit avec plus d'événements et de routes.
Option 2 : Un Fichier Séparé events.php
Pour une application légèrement plus grande, envisagez de déplacer les enregistrements d'événements dans un fichier dédié comme app/config/events.php
. Incluez ce fichier dans votre index.php
avant vos routes. Cela imite la façon dont les routes sont souvent organisées dans app/config/routes.php
dans les projets Flight.
// app/config/events.php
Flight::onEvent('user.login', function ($username) {
error_log("$username s'est connecté à " . date('Y-m-d H:i:s'));
});
Flight::onEvent('user.registered', function ($email, $name) {
echo "E-mail envoyé à $email : Bienvenue, $name !";
});
// index.php
require 'vendor/autoload.php';
require 'app/config/events.php';
Flight::route('/login', function () {
$username = 'bob';
Flight::triggerEvent('user.login', $username);
echo "Connecté !";
});
Flight::start();
- Avantages : Garde
index.php
concentré sur le routage, organise les événements logiquement, facile à trouver et à éditer. - Inconvénients : Ajoute un peu de structure, ce qui pourrait sembler excessif pour des très petites applications.
Option 3 : Près de Leur Déclenchement
Une autre approche consiste à enregistrer des événements près de leur déclenchement, comme à l'intérieur d'un contrôleur ou d'une définition de route. Cela fonctionne bien si un événement est spécifique à une partie de votre application.
Flight::route('/signup', function () {
// Enregistrer l'événement ici
Flight::onEvent('user.registered', function ($email) {
echo "E-mail de bienvenue envoyé à $email !";
});
$email = 'jane@example.com';
Flight::triggerEvent('user.registered', $email);
echo "Inscrit !";
});
- Avantages : Garde le code lié ensemble, bon pour des fonctionnalités isolées.
- Inconvénients : Éparpille les enregistrements d'événements, rendant plus difficile la vue de tous les événements à la fois ; risque d'inscriptions en double si ce n'est pas prudent.
Meilleure Pratique pour Flight
- Commencer Simple : Pour de toutes petites applications, placez les événements dans
index.php
. C’est rapide et s'aligne sur le minimalisme de Flight. - Grandir Intelligent : À mesure que votre application s'élargit (par exemple, plus de 5-10 événements), utilisez un fichier
app/config/events.php
. C'est une étape naturelle, comme organiser des routes, et garde votre code bien rangé sans ajouter de frameworks complexes. - Évitez la Sur-ingénierie : Ne créez pas une classe ou un répertoire "gestionnaire d'événements" à moins que votre application ne devienne énorme—Flight prospère sur la simplicité, alors gardez-le léger.
Astuce : Groupez par Objectif
Dans events.php
, regroupez les événements liés (par exemple, tous les événements liés aux utilisateurs ensemble) avec des commentaires pour plus de clarté :
// app/config/events.php
// Événements Utilisateur
Flight::onEvent('user.login', function ($username) {
error_log("$username s'est connecté");
});
Flight::onEvent('user.registered', function ($email) {
echo "Bienvenue à $email !";
});
// Événements de Page
Flight::onEvent('page.updated', function ($pageId) {
unset($_SESSION['pages'][$pageId]);
});
Cette structure évolue bien et reste conviviale pour les débutants.
Exemples pour les Débutants
Passons en revue quelques scénarios réels pour montrer comment les événements fonctionnent et pourquoi ils sont utiles.
Exemple 1 : Journaliser une Connexion Utilisateur
// Étape 1 : Enregistrer un écouteur
Flight::onEvent('user.login', function ($username) {
$time = date('Y-m-d H:i:s');
error_log("$username s'est connecté à $time");
});
// Étape 2 : Déclencher cela dans votre application
Flight::route('/login', function () {
$username = 'bob'; // Supposons que cela provienne d'un formulaire
Flight::triggerEvent('user.login', $username);
echo "Salut, $username !";
});
Pourquoi C'est Utile : Le code de connexion n'a pas besoin de se soucier de la journalisation—il déclenche juste l'événement. Vous pouvez plus tard ajouter plus d'écouteurs (par exemple, envoyer un e-mail de bienvenue) sans changer la route.
Exemple 2 : Notifier de Nouveaux Utilisateurs
// Écouteur pour les nouvelles inscriptions
Flight::onEvent('user.registered', function ($email, $name) {
// Simule l'envoi d'un e-mail
echo "E-mail envoyé à $email : Bienvenue, $name !";
});
// Déclencher cela lorsque quelqu'un s'inscrit
Flight::route('/signup', function () {
$email = 'jane@example.com';
$name = 'Jane';
Flight::triggerEvent('user.registered', $email, $name);
echo "Merci pour votre inscription !";
});
Pourquoi C'est Utile : La logique d'inscription se concentre sur la création de l'utilisateur, tandis que l'événement gère les notifications. Vous pourriez ajouter plus d'écouteurs (par exemple, journaliser l'inscription) plus tard.
Exemple 3 : Vider un Cache
// Écouteur pour vider un cache
Flight::onEvent('page.updated', function ($pageId) {
unset($_SESSION['pages'][$pageId]); // Vider le cache de session si applicable
echo "Cache vidé pour la page $pageId.";
});
// Déclencher lors de la modification d'une page
Flight::route('/edit-page/(@id)', function ($pageId) {
// Supposons que nous ayons mis à jour la page
Flight::triggerEvent('page.updated', $pageId);
echo "Page $pageId mise à jour.";
});
Pourquoi C'est Utile : Le code de modification ne se soucie pas du cache—il signale simplement la mise à jour. D'autres parties de l'application peuvent réagir selon leurs besoins.
Meilleures Pratiques
- Nommer les Événements Clairement : Utilisez des noms spécifiques comme
'user.login'
ou'page.updated'
pour qu'il soit évident ce qu'ils font. - Garder les Écouteurs Simples : Ne placez pas de tâches lentes ou complexes dans les écouteurs—gardez votre application rapide.
- Tester Vos Événements : Déclenchez-les manuellement pour vous assurer que les écouteurs fonctionnent comme prévu.
- Utiliser les Événements Judicieusement : Ils sont excellents pour le découplage, mais trop peuvent rendre votre code difficile à suivre—utilisez-les quand cela a du sens.
Le système d'événements dans Flight PHP, avec Flight::onEvent()
et Flight::triggerEvent()
, vous donne un moyen simple mais puissant de construire des applications flexibles. En laissant différentes parties de votre application communiquer entre elles par le biais d'événements, vous pouvez garder votre code organisé, réutilisable et facile à étendre. Que vous enregistriez des actions, envoyiez des notifications ou gériez des mises à jour, les événements vous aident à le faire sans enchevêtrer votre logique. De plus, avec la possibilité de remplacer ces méthodes, vous avez la liberté d'adapter le système à vos besoins. Commencez petit avec un seul événement, et regardez comment cela transforme la structure de votre application !
Événements Intégrés
Flight PHP vient avec quelques événements intégrés que vous pouvez utiliser pour vous accrocher au cycle de vie du framework. Ces événements sont déclenchés à des moments spécifiques dans le cycle de demande/réponse, vous permettant d'exécuter une logique personnalisée lorsqu' certaines actions se produisent.
Liste des Événements Intégrés
flight.request.received
: Déclenché lorsqu'une demande est reçue, analysée et traitée.flight.route.middleware.before
: Déclenché après l'exécution du middleware avant.flight.route.middleware.after
: Déclenché après l'exécution du middleware après.flight.route.executed
: Déclenché après l'exécution et le traitement d'une route.flight.response.sent
: Déclenché après qu'une réponse a été envoyée au client.
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 et Modèles HTML
Flight fournit par défaut quelques fonctionnalités de base de modélisation.
Flight vous permet de remplacer le moteur de vue par défaut simplement en enregistrant votre propre classe de vue. Faites défiler pour voir des exemples d'utilisation de Smarty, Latte, Blade, et plus encore !
Moteur de vue intégré
Pour afficher un modèle de vue, appelez la méthode render
avec le nom du fichier modèle et des données de modèle facultatives :
Flight::render('hello.php', ['name' => 'Bob']);
Les données de modèle que vous passez sont automatiquement injectées dans le modèle et peuvent être référencées comme une variable locale. Les fichiers de modèle sont simplement des fichiers PHP. Si le contenu du fichier modèle hello.php
est :
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. Vous pouvez donc 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 cherchera un répertoire views
pour les fichiers de modèle. Vous pouvez définir un chemin alternatif pour vos modèles en définissant la configuration suivante :
Flight::set('flight.views.path', '/path/to/views');
Dispositions
Il est courant que les sites Web aient un seul fichier modèle de disposition avec un contenu interchangeant. Pour rendre le contenu à utiliser dans une disposition, vous pouvez passer un paramètre facultatif à la méthode render
.
Flight::render('header', ['heading' => 'Hello'], 'headerContent');
Flight::render('body', ['body' => 'World'], 'bodyContent');
Votre vue disposera alors de variables sauvegardées appelées headerContent
et bodyContent
. Vous pouvez ensuite rendre votre disposition en faisant :
Flight::render('layout', ['title' => 'Home Page']);
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>Home Page</title>
</head>
<body>
<h1>Hello</h1>
<div>World</div>
</body>
</html>
Smarty
Voici comment vous utiliseriez le moteur de modèle Smarty pour vos vues :
// Charger la bibliothèque Smarty
require './Smarty/libs/Smarty.class.php';
// Enregistrer Smarty comme classe de vue
// Passer é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 modèle
Flight::view()->assign('name', 'Bob');
// Afficher le modèle
Flight::view()->display('hello.tpl');
Pour être complet, vous devriez également remplacer la méthode render par défaut de Flight :
Flight::map('render', function(string $template, array $data): void {
Flight::view()->assign($data);
Flight::view()->display($template);
});
Latte
Voici comment vous utiliseriez le moteur de modèle Latte pour vos vues :
// Enregistrer Latte comme classe de vue
// Passer également une fonction de rappel pour configurer Latte au 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 actualise automatiquement votre
// cache lorsque vous apportez des modifications à vos modèles !
$latte->setTempDirectory(__DIR__ . '/../cache/');
// Indiquer à Latte où se trouvera le répertoire racine de vos vues.
$latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../views/'));
});
// Et enveloppez le pour que vous puissiez utiliser Flight::render() correctement
Flight::map('render', function(string $template, array $data): void {
// C'est comme $latte_engine->render($template, $data);
echo Flight::view()->render($template, $data);
});
Blade
Voici comment vous utiliseriez le moteur de modèle Blade pour vos vues :
Tout d'abord, vous devez installer la bibliothèque BladeOne via Composer :
composer require eftec/bladeone
Ensuite, vous pouvez configurer BladeOne comme classe de vue dans Flight :
<?php
// Charger la bibliothèque BladeOne
use eftec\bladeone\BladeOne;
// Enregistrer BladeOne comme classe de vue
// Passer également une fonction de rappel pour configurer BladeOne au chargement
Flight::register('view', BladeOne::class, [], function (BladeOne $blade) {
$views = __DIR__ . '/../views';
$cache = __DIR__ . '/../cache';
$blade->setPath($views);
$blade->setCompiledPath($cache);
});
// Assigner des données de modèle
Flight::view()->share('name', 'Bob');
// Afficher le modèle
echo Flight::view()->run('hello', []);
Pour être complet, vous devriez également remplacer la méthode render par défaut de Flight :
<?php
Flight::map('render', function(string $template, array $data): void {
echo Flight::view()->run($template, $data);
});
Dans cet exemple, le fichier modèle hello.blade.php pourrait ressembler à ceci :
<?php
Hello, {{ $name }}!
La sortie serait :
Hello, Bob!
En suivant ces étapes, vous pouvez intégrer le moteur de modèle Blade avec Flight et l'utiliser pour rendre vos vues.
Learn/flight_vs_fat_free
Vol / FF (F3)
Qu'est-ce que Fat-Free?
Fat-Free (affectueusement connu sous le nom de F3) est un micro-framework PHP puissant et facile à utiliser conçu pour vous aider à construire des applications web dynamiques et robustes - rapidement!
Vol se compare à Fat-Free de nombreuses manières et est probablement le cousin le plus proche en termes de fonctionnalités et de simplicité. Fat-Free a beaucoup de fonctionnalités que Vol n'a pas, mais il a aussi beaucoup de fonctionnalités que Flight a. Fat-Free commence à montrer son âge et n'est pas aussi populaire qu'auparavant.
Les mises à jour deviennent moins fréquentes et la communauté n'est plus aussi active qu'auparavant. Le code est assez simple, mais parfois le manque de discipline syntaxique peut le rendre difficile à lire et à comprendre. Il fonctionne pour PHP 8.3, mais le code lui-même ressemble toujours à s'il vivait dans PHP 5.3.
Avantages par rapport à Vol
- Fat-Free a quelques étoiles de plus sur GitHub que Flight.
- Fat-Free a une documentation décente, mais elle manque de clarté dans certains domaines.
- Fat-Free dispose de ressources éparses telles que des tutoriels YouTube et des articles en ligne pouvant être utilisés pour apprendre le framework.
- Fat-Free a quelques plugins utiles intégrés qui sont parfois utiles.
- Fat-Free a un ORM intégré appelé Mapper qui peut être utilisé pour interagir avec votre base de données. Flight a active-record.
- Fat-Free a des Sessions, Caching et la localisation intégrés. Flight nécessite l'utilisation de bibliothèques tierces, mais c'est couvert dans la documentation.
- Fat-Free a un petit groupe de plugins créés par la communauté qui peuvent être utilisés pour étendre le framework. Flight a certains couverts dans les pages de documentation et exemples.
- Fat-Free, comme Flight, n'a pas de dépendances.
- Fat-Free, comme Flight, vise à donner aux développeurs le contrôle sur leur application et une expérience de développement simple.
- Fat-Free maintient la compatibilité ascendante comme Flight le fait (partiellement car les mises à jour deviennent moins fréquentes).
- Fat-Free, comme Flight, est destiné aux développeurs qui s'aventurent pour la première fois dans le monde des frameworks.
- Fat-Free a un moteur de template intégré qui est plus robuste que le moteur de template de Vol. Flight recommande Latte pour y parvenir.
- Fat-Free a une commande de type CLI "route" unique où vous pouvez construire des applications CLI à l'intérieur de Fat-Free lui-même et le traiter comme une requête
GET
. Flight réalise cela avec runway.
Inconvénients par rapport à Vol
- Fat-Free a quelques tests d'implémentation et a même sa propre classe de test qui est très basique. Cependant, ce n'est pas testé à 100% en unité comme Flight.
- Vous devez utiliser un moteur de recherche tel que Google pour effectivement rechercher le site de documentation.
- Flight a un mode sombre sur leur site de documentation. (laisser tomber le micro)
- Fat-Free a quelques modules qui sont lamentablement non maintenus.
- Flight a un simple PdoWrapper qui est un peu plus simple que la classe
DB\SQL
intégrée de Fat-Free. - Flight a un plugin de permissions qui peut être utilisé pour sécuriser votre application. Slim vous demande d'utiliser une bibliothèque tierce.
- Flight a un ORM appelé active-record qui ressemble plus à un ORM que le Mapper de Fat-Free.
Le bénéfice ajouté de
active-record
est que vous pouvez définir des relations entre les enregistrements pour des jointures automatiques là où le Mapper de Fat-Free vous demande de créer des vues SQL. - Étonnamment, Fat-Free n'a pas d'espace de noms racine. Flight est mis en espace de noms tout au long pour ne pas entrer en collision avec votre propre code.
la classe
Cache
est le plus grand contrevenant ici. - Fat-Free n'a pas de middleware. Au lieu de cela, il y a des crochets
beforeroute
etafterroute
qui peuvent être utilisés pour filtrer les requêtes et les réponses dans les contrôleurs. - Fat-Free ne peut pas regrouper les routes.
- Fat-Free a un gestionnaire de conteneur d'injection de dépendance, mais la documentation est incroyablement clairsemée sur la façon de l'utiliser.
- Le débogage peut devenir un peu délicat car pratiquement tout est stocké dans ce qu'on appelle le
HIVE
Learn/extending
Étendre
Flight est conçu pour être un framework extensible. Le framework est accompagné d'un ensemble de méthodes et de composants par défaut, mais il vous permet de mapper vos propres méthodes, d'enregistrer vos propres classes ou même de remplacer des classes et des méthodes existantes.
Si vous recherchez un DIC (Conteneur d'Injection de Dépendances), consultez la page du Conteneur d'Injection de Dépendances.
Mapper des Méthodes
Pour mapper votre propre méthode personnalisée simple, vous utilisez la fonction map
:
// Mapper votre méthode
Flight::map('hello', function (string $name) {
echo "bonjour $name!";
});
// Appeler votre méthode personnalisée
Flight::hello('Bob');
Bien qu'il soit possible de créer des méthodes personnalisées simples, il est recommandé de simplement créer des fonctions standard en PHP. Cela bénéficie de l'autocomplétion dans les IDE et est plus facile à lire. L'équivalent du code ci-dessus serait :
function hello(string $name) {
echo "bonjour $name!";
}
hello('Bob');
Cela est plus 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 plus pour passer des configurations
et ensuite appeler votre classe préconfigurée.
Enregistrement de Classes
Pour enregistrer votre propre classe et la configurer, vous utilisez la fonction register
:
// Enregistrer votre classe
Flight::register('user', User::class);
// Obtenir une instance de votre classe
$user = Flight::user();
La méthode register 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 à la 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 créera 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 la même méthode à nouveau
class SomeController {
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 toutes les procédures de configuration pour votre nouvel objet. La fonction de rappel prend un paramètre, une instance du nouvel objet.
// Le rappel sera passé à 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 suffit de passer false
comme paramètre :
// Instance partagée de la classe
$shared = Flight::db();
// Nouvelle instance de la classe
$new = Flight::db(false);
Gardez à l'esprit que les méthodes mappées ont 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.
Journalisation
Flight n'a pas de système de journalisation intégré, cependant, il est très facile d'utiliser une bibliothèque de journalisation avec Flight. Voici un exemple utilisant la bibliothèque Monolog :
// index.php ou bootstrap.php
// Enregistrer le logger avec Flight
Flight::register('log', Monolog\Logger::class, [ 'name' ], function(Monolog\Logger $log) {
$log->pushHandler(new Monolog\Handler\StreamHandler('path/to/your.log', Monolog\Logger::WARNING));
});
Maintenant qu'il est enregistré, vous pouvez l'utiliser dans votre application :
// Dans votre contrôleur ou route
Flight::log()->warning('Ceci est un message d\'avertissement');
Cela enregistrera un message dans le fichier journal que vous avez spécifié. Que se passe-t-il si vous voulez enregistrer quelque chose lorsqu'une
erreur se produit ? Vous pouvez utiliser la méthode error
:
// Dans votre contrôleur ou route
Flight::map('error', function(Throwable $ex) {
Flight::log()->error($ex->getMessage());
// Afficher votre page d'erreur personnalisée
include 'errors/500.html';
});
Vous pourriez également créer un système APM (Surveillance des Performances d'Application) basique
en utilisant les méthodes before
et after
:
// Dans votre fichier bootstrap
Flight::before('start', function() {
Flight::set('start_time', microtime(true));
});
Flight::after('start', function() {
$end = microtime(true);
$start = Flight::get('start_time');
Flight::log()->info('La requête '.Flight::request()->url.' a pris ' . round($end - $start, 4) . ' secondes');
// Vous pourriez également ajouter vos en-têtes de requête ou de réponse
// pour les enregistrer également (soyez prudent, car cela représenterait une
// grande quantité de données si vous avez beaucoup de requêtes)
Flight::log()->info('En-têtes de Requête: ' . json_encode(Flight::request()->headers));
Flight::log()->info('En-têtes de Réponse: ' . json_encode(Flight::response()->headers));
});
Remplacer les Méthodes du Framework
Flight vous permet de remplacer ses fonctionnalités par défaut pour répondre à vos propres besoins, sans avoir à modifier de code. Vous pouvez voir toutes les méthodes que vous pouvez remplacer ici.
Par exemple, lorsque Flight ne peut pas associer une URL à une route, il invoque la méthode notFound
qui envoie une réponse générique HTTP 404
. Vous pouvez remplacer ce comportement
en utilisant la méthode map
:
Flight::map('notFound', function() {
// Afficher la page personnalisée 404
include 'errors/404.html';
});
Flight vous permet également de remplacer les composants principaux du framework. Par exemple, vous pouvez remplacer la classe Router par défaut par votre propre classe personnalisée :
// Enregistrer votre classe personnalisée
Flight::register('router', MyRouter::class);
// Lorsque Flight charge l'instance Router, il chargera votre classe
$myrouter = Flight::router();
Cependant, les méthodes du framework comme map
et register
ne peuvent pas être remplacées. Vous
obtiendrez une erreur si vous essayez de le faire.
Learn/json
JSON
Flight fournit un support pour l'envoi de réponses JSON et JSONP. Pour envoyer une réponse JSON, vous transmettez des données à encoder en JSON:
Flight::json(['id' => 123]);
Pour les requêtes JSONP, vous pouvez éventuellement spécifier le nom du paramètre de requête que vous utilisez pour définir votre fonction de rappel:
Flight::jsonp(['id' => 123], 'q');
Ainsi, lors de l'envoi d'une requête GET en utilisant ?q=my_func
, vous devriez recevoir la sortie:
my_func({"id":123});
Si vous ne spécifiez pas de nom de paramètre de requête, il sera par défaut jsonp
.
Learn/flight_vs_slim
Vol Flight vs Slim
Qu'est-ce que Slim?
Slim est un micro-framework PHP qui vous aide à écrire rapidement des applications web et des APIs simples mais puissantes.
Beaucoup des inspirations pour certaines fonctionnalités de la v3 de Vol sont en fait venues de Slim. Regrouper les routes et exécuter des middlewares dans un ordre spécifique sont deux fonctionnalités qui ont été inspirées par Slim. Slim v3 est sorti orienté vers la simplicité, mais il y a eu des avis divergents concernant la v4.
Avantages par rapport à Vol
- Slim a une communauté plus large de développeurs, qui à leur tour créent des modules pratiques pour vous aider à ne pas réinventer la roue.
- Slim suit de nombreuses interfaces et normes communes dans la communauté PHP, ce qui augmente l'interopérabilité.
- Slim a une documentation décente et des tutoriels qui peuvent être utilisés pour apprendre le framework (rien ne vaut Laravel ou Symfony cependant).
- Slim dispose de diverses ressources telles que des tutoriels YouTube et des articles en ligne qui peuvent être utilisés pour apprendre le framework.
- Slim vous permet d'utiliser les composants que vous souhaitez pour gérer les fonctionnalités de routage de base car il est conforme à PSR-7.
Inconvénients par rapport à Vol
- Étonnamment, Slim n'est pas aussi rapide que vous pourriez le penser pour un micro-framework. Consultez les benchmarks TechEmpower pour plus d'informations.
- Vol est destiné à un développeur qui cherche à construire une application web légère, rapide et facile à utiliser.
- Vol n'a pas de dépendances, alors que Slim a quelques dépendances que vous devez installer.
- Vol est orienté vers la simplicité et la facilité d'utilisation.
- Une des fonctionnalités principales de Vol est qu'il fait de son mieux pour maintenir la compatibilité ascendante. Le passage de Slim v3 à v4 était un changement majeur.
- Vol est destiné aux développeurs qui se lancent dans l'univers des frameworks pour la première fois.
- Vol peut également être utilisé pour des applications de niveau entreprise, mais il n'a pas autant d'exemples et de tutoriels que Slim. Cela nécessitera également plus de discipline de la part du développeur pour maintenir les choses organisées et bien structurées.
- Vol donne au développeur plus de contrôle sur l'application, tandis que Slim peut introduire de la magie en coulisses.
- Vol dispose d'un simple PdoWrapper qui peut être utilisé pour interagir avec votre base de données. Slim vous oblige à utiliser une bibliothèque tierce.
- Vol possède un plugin de permissions qui peut être utilisé pour sécuriser votre application. Slim vous oblige à utiliser une bibliothèque tierce.
- Vol a un ORM appelé active-record qui peut être utilisé pour interagir avec votre base de données. Slim vous oblige à utiliser une bibliothèque tierce.
- Vol a une application CLI appelée runway qui peut être utilisée pour exécuter votre application à partir de la ligne de commande. Slim ne le fait pas.
Learn/autoloading
Chargement automatique
Le chargement automatique est un concept en PHP où vous spécifiez un répertoire ou des répertoires à partir desquels charger des classes. Cela est bien plus bénéfique que d'utiliser require
ou include
pour charger des classes. C'est également une exigence pour utiliser des packages Composer.
Par défaut, toute classe Flight
est chargée automatiquement pour vous grâce à composer. Cependant, si vous voulez charger automatiquement vos propres classes, vous pouvez utiliser la méthode Flight::path()
pour spécifier un répertoire à partir duquel charger des classes.
Exemple de base
Supposons que nous avons une structure d'arborescence de répertoires comme suit :
# Chemin d'exemple
/home/user/project/my-flight-project/
├── app
│ ├── cache
│ ├── config
│ ├── controllers - contient les contrôleurs pour ce projet
│ ├── translations
│ ├── UTILS - contient des classes uniquement pour cette application (tout est en majuscules à des fins d'exemple ultérieur)
│ └── views
└── public
└── css
└── js
└── index.php
Vous avez peut-être remarqué que c'est la même structure de fichiers que ce site de documentation.
Vous pouvez spécifier chaque répertoire à charger à partir de cette façon :
/**
* public/index.php
*/
// Ajouter un chemin à l'autoload
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');
/**
* app/controllers/MyController.php
*/
// Pas de nécessité d'espace de noms
// Toutes les classes chargées automatiquement sont recommandées d'être en Pascal Case (chaque mot en majuscule, pas d'espaces)
// À partir de la version 3.7.2, vous pouvez utiliser Pascal_Snake_Case pour vos noms de classes en exécutant Loader::setV2ClassLoading(false);
class MyController {
public function index() {
// faire quelque chose
}
}
Espaces de noms
Si vous avez des espaces de noms, l'implémentation en devient en fait très facile. Vous devriez utiliser la méthode Flight::path()
pour spécifier le répertoire racine (pas le document root ou le dossier public/
) de votre application.
/**
* public/index.php
*/
// Ajouter un chemin à l'autoload
Flight::path(__DIR__.'/../');
Maintenant, voici à quoi pourrait ressembler votre contrôleur. Regardez l'exemple ci-dessous, mais prêtez attention aux commentaires pour des informations importantes.
/**
* app/controllers/MyController.php
*/
// les espaces de noms sont requis
// les espaces de noms doivent suivre la même structure de répertoire
// les espaces de noms doivent suivre la même casse que la structure de répertoire
// les espaces de noms et les répertoires ne peuvent pas avoir de tirets bas (à moins que Loader::setV2ClassLoading(false) ne soit défini)
namespace app\controllers;
// Toutes les classes chargées automatiquement sont recommandées d'être en Pascal Case (chaque mot en majuscule, pas d'espaces)
// À partir de la version 3.7.2, vous pouvez utiliser Pascal_Snake_Case pour vos noms de classes en exécutant Loader::setV2ClassLoading(false);
class MyController {
public function index() {
// faire quelque chose
}
}
Et si vous vouliez charger automatiquement une classe dans votre répertoire utils, vous feriez essentiellement la même chose :
/**
* app/UTILS/ArrayHelperUtil.php
*/
// l'espace de noms doit correspondre à la structure du répertoire et à la casse (notez que le répertoire UTILS est tout en majuscules
// comme dans l'arborescence de fichiers ci-dessus)
namespace app\UTILS;
class ArrayHelperUtil {
public function changeArrayCase(array $array) {
// faire quelque chose
}
}
Tirets bas dans les noms de classes
À partir de la version 3.7.2, vous pouvez utiliser Pascal_Snake_Case pour vos noms de classes en exécutant Loader::setV2ClassLoading(false);
.
Cela vous permettra d'utiliser des tirets bas dans vos noms de classes.
Ce n'est pas recommandé, mais c'est disponible pour ceux qui en ont besoin.
/**
* public/index.php
*/
// Ajouter un chemin à l'autoload
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');
Loader::setV2ClassLoading(false);
/**
* app/controllers/My_Controller.php
*/
// Pas de nécessité d'espace de noms
class My_Controller {
public function index() {
// faire quelque chose
}
}
Learn/troubleshooting
Dépannage
Cette page vous aidera à résoudre les problèmes courants que vous pourriez rencontrer lors de l'utilisation de Flight.
Problèmes Courants
404 Non Trouvé ou Comportement de Route Inattendu
Si vous voyez une erreur 404 Non Trouvé (mais vous jurez sur votre vie qu'elle est vraiment là et ce n'est pas une faute de frappe), en fait il pourrait s'agir d'un problème avec le fait de renvoyer une valeur dans votre point de terminaison de route au lieu de simplement l'afficher. La raison de ceci est intentionnelle mais pourrait surprendre certains développeurs.
Flight::route('/bonjour', function(){
// Cela pourrait provoquer une erreur 404 Non Trouvée
return 'Bonjour le monde';
});
// Ce que vous voulez probablement
Flight::route('/bonjour', function(){
echo 'Bonjour le monde';
});
La raison de ceci est due à un mécanisme spécial intégré dans le routeur qui gère la sortie retournée comme un signal pour "passer à la route suivante". Vous pouvez voir le comportement documenté dans la section Routing.
Classe Non Trouvée (chargement automatique ne fonctionne pas)
Il pourrait y avoir plusieurs raisons pour que cela ne se produise pas. Voici quelques exemples, mais assurez-vous également de consulter la section sur le chargement automatique.
Nom de Fichier Incorrect
Le plus courant est que le nom de la classe ne correspond pas au nom du fichier.
Si vous avez une classe nommée MaClasse
, alors le fichier devrait être nommé MaClasse.php
. Si vous avez une classe nommée MaClasse
et que le fichier est nommé maclasse.php
, alors le chargeur automatique ne pourra pas le trouver.
Espace de Noms Incorrect
Si vous utilisez des espaces de noms, alors l'espace de noms doit correspondre à la structure des répertoires.
// code
// si votre MyController est dans le répertoire app/controllers et qu'il est namespaced
// cela ne fonctionnera pas.
Flight::route('/bonjour', 'MyController->bonjour');
// vous devrez choisir l'une de ces options
Flight::route('/bonjour', 'app\controllers\MyController->bonjour');
// ou si vous avez une déclaration use en haut
use app\controllers\MyController;
Flight::route('/bonjour', [ MyController::class, 'bonjour' ]);
// peut également être écrit
Flight::route('/bonjour', MyController::class.'->bonjour');
// aussi...
Flight::route('/bonjour', [ 'app\controllers\MyController', 'bonjour' ]);
path()
non défini
Dans l'application squelette, cela est défini à l'intérieur du fichier config.php
, mais pour que vos classes soient trouvées, vous devez vous assurer que la méthode path()
est définie (probablement à la racine de votre répertoire) avant d'essayer de l'utiliser.
// Ajouter un chemin à l'autoload
Flight::path(__DIR__.'/../');
Install
Installation
Téléchargement des fichiers.
Si vous utilisez Composer, vous pouvez exécuter la commande suivante :
composer require flightphp/core
OU vous pouvez télécharger les fichiers directement et les extraire vers votre répertoire web.
Configuration de votre serveur Web.
Apache
Pour Apache, modifiez votre fichier .htaccess
avec ce qui suit :
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
Remarque : Si vous devez utiliser flight dans un sous-répertoire, ajoutez la ligne
RewriteBase /sous-repertoire/
juste aprèsRewriteEngine 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();
Guides/blog
Créer un blog simple avec Flight PHP
Ce guide vous accompagne pour créer un blog de base en utilisant le framework Flight PHP. Vous allez configurer un projet, définir des routes, gérer des publications avec JSON et les afficher avec le moteur de templates Latte, tout en mettant en avant la simplicité et la flexibilité de Flight. À la fin, vous aurez un blog fonctionnel avec une page d'accueil, des pages de publication individuelles et un formulaire de création.
Prérequis
- PHP 7.4+ : Installé sur votre système.
- Composer : Pour la gestion des dépendances.
- Éditeur de texte : Tout éditeur comme VS Code ou PHPStorm.
- Connaissances de base en PHP et développement web.
Étape 1 : Configurer votre projet
Commencez par créer un nouveau répertoire de projet et installez Flight via Composer.
-
Créer un répertoire :
mkdir flight-blog cd flight-blog
-
Installer Flight :
composer require flightphp/core
-
Créer un répertoire public : Flight utilise un point d'entrée unique (
index.php
). Créez un dossierpublic/
pour cela :mkdir public
-
Base
index.php
: Créezpublic/index.php
avec une route simple « hello world » :<?php require '../vendor/autoload.php'; Flight::route('/', function () { echo 'Bonjour, Flight !'; }); Flight::start();
-
Exécuter le serveur intégré : Testez votre configuration avec le serveur de développement de PHP :
php -S localhost:8000 -t public/
Visitez
http://localhost:8000
pour voir « Bonjour, Flight ! ».
Étape 2 : Organiser la structure de votre projet
Pour une configuration propre, structurez votre projet comme ceci :
flight-blog/
├── app/
│ ├── config/
│ └── views/
├── data/
├── public/
│ └── index.php
├── vendor/
└── composer.json
app/config/
: Fichiers de configuration (ex. : événements, routes).app/views/
: Templates pour le rendu des pages.data/
: Fichier JSON pour stocker les articles du blog.public/
: Racine web avecindex.php
.
Étape 3 : Installer et configurer Latte
Latte est un moteur de templates léger qui s'intègre bien avec Flight.
-
Installer Latte :
composer require latte/latte
-
Configurer Latte dans Flight : Mettez à jour
public/index.php
pour enregistrer Latte comme moteur de vues :<?php require '../vendor/autoload.php'; use Latte\Engine; Flight::register('view', Engine::class, [], function ($latte) { $latte->setTempDirectory(__DIR__ . '/../cache/'); $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../app/views/')); }); Flight::route('/', function () { Flight::view()->render('home.latte', ['title' => 'Mon Blog']); }); Flight::start();
-
Créer un template de mise en page : Dans
app/views/layout.latte
:<!DOCTYPE html> <html> <head> <title>{$title}</title> </head> <body> <header> <h1>Mon Blog</h1> <nav> <a href="/">Accueil</a> | <a href="/create">Créer un Article</a> </nav> </header> <main> {block content}{/block} </main> <footer> <p>© {date('Y')} Blog Flight</p> </footer> </body> </html>
-
Créer un template d'accueil : Dans
app/views/home.latte
:{extends 'layout.latte'} {block content} <h2>{$title}</h2> <ul> {foreach $posts as $post} <li><a href="/post/{$post['slug']}">{$post['title']}</a></li> {/foreach} </ul> {/block}
Redémarrez le serveur si vous en êtes sorti et visitez
http://localhost:8000
pour voir la page rendue. -
Créer un fichier de données :
Utilisez un fichier JSON pour simuler une base de données pour plus de simplicité.
Dans
data/posts.json
:[ { "slug": "premier-article", "title": "Mon Premier Article", "content": "Ceci est mon tout premier article de blog avec Flight PHP !" } ]
Étape 4 : Définir les routes
Séparez vos routes dans un fichier de configuration pour une meilleure organisation.
-
Créer
routes.php
: Dansapp/config/routes.php
:<?php Flight::route('/', function () { Flight::view()->render('home.latte', ['title' => 'Mon Blog']); }); Flight::route('/post/@slug', function ($slug) { Flight::view()->render('post.latte', ['title' => 'Article : ' . $slug, 'slug' => $slug]); }); Flight::route('GET /create', function () { Flight::view()->render('create.latte', ['title' => 'Créer un Article']); });
-
Mettre à jour
index.php
: Incluez le fichier des routes :<?php require '../vendor/autoload.php'; use Latte\Engine; Flight::register('view', Engine::class, [], function ($latte) { $latte->setTempDirectory(__DIR__ . '/../cache/'); $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../app/views/')); }); require '../app/config/routes.php'; Flight::start();
Étape 5 : Stocker et récupérer des articles de blog
Ajoutez les méthodes pour charger et sauvegarder des articles.
-
Ajouter une méthode Posts : Dans
index.php
, ajoutez une méthode pour charger des articles :Flight::map('posts', function () { $file = __DIR__ . '/../data/posts.json'; return json_decode(file_get_contents($file), true); });
-
Mettre à jour les routes : Modifiez
app/config/routes.php
pour utiliser les articles :<?php Flight::route('/', function () { $posts = Flight::posts(); Flight::view()->render('home.latte', [ 'title' => 'Mon Blog', 'posts' => $posts ]); }); Flight::route('/post/@slug', function ($slug) { $posts = Flight::posts(); $post = array_filter($posts, fn($p) => $p['slug'] === $slug); $post = reset($post) ?: null; if (!$post) { Flight::notFound(); return; } Flight::view()->render('post.latte', [ 'title' => $post['title'], 'post' => $post ]); }); Flight::route('GET /create', function () { Flight::view()->render('create.latte', ['title' => 'Créer un Article']); });
Étape 6 : Créer des templates
Mettez à jour vos templates pour afficher des articles.
-
Page de l'article (
app/views/post.latte
) :{extends 'layout.latte'} {block content} <h2>{$post['title']}</h2> <div class="post-content"> <p>{$post['content']}</p> </div> {/block}
Étape 7 : Ajouter la création d'articles
Gérez la soumission du formulaire pour ajouter de nouveaux articles.
-
Formulaire de création (
app/views/create.latte
) :{extends 'layout.latte'} {block content} <h2>{$title}</h2> <form method="POST" action="/create"> <div class="form-group"> <label for="title">Titre :</label> <input type="text" name="title" id="title" required> </div> <div class="form-group"> <label for="content">Contenu :</label> <textarea name="content" id="content" required></textarea> </div> <button type="submit">Sauvegarder l'Article</button> </form> {/block}
-
Ajouter une route POST : Dans
app/config/routes.php
:Flight::route('POST /create', function () { $request = Flight::request(); $title = $request->data['title']; $content = $request->data['content']; $slug = strtolower(str_replace(' ', '-', $title)); $posts = Flight::posts(); $posts[] = ['slug' => $slug, 'title' => $title, 'content' => $content]; file_put_contents(__DIR__ . '/../../data/posts.json', json_encode($posts, JSON_PRETTY_PRINT)); Flight::redirect('/'); });
-
Testez-le :
- Visitez
http://localhost:8000/create
. - Soumettez un nouvel article (par exemple, « Deuxième Article » avec un peu de contenu).
- Vérifiez la page d'accueil pour voir qu'il est répertorié.
- Visitez
Étape 8 : Améliorer avec la gestion des erreurs
Surchargez la méthode notFound
pour une meilleure expérience 404.
Dans index.php
:
Flight::map('notFound', function () {
Flight::view()->render('404.latte', ['title' => 'Page Non Trouvée']);
});
Créez app/views/404.latte
:
{extends 'layout.latte'}
{block content}
<h2>404 - {$title}</h2>
<p>Désolé, cette page n'existe pas !</p>
{/block}
Prochaines étapes
- Ajouter du style : Utilisez le CSS dans vos templates pour un meilleur rendu.
- Base de données : Remplacez
posts.json
par une base de données comme SQLite en utilisantPdoWrapper
. - Validation : Ajoutez des vérifications pour les slugs en double ou les entrées vides.
- Middleware : Implémentez l'authentification pour la création d'articles.
Conclusion
Vous avez construit un blog simple avec Flight PHP ! Ce guide démontre des fonctionnalités clés comme le routage, le rendu de templates avec Latte et la gestion des soumissions de formulaires, le tout en gardant les choses légères. Explorez la documentation de Flight pour des fonctionnalités plus avancées afin de faire progresser votre blog !
License
La Licence MIT (MIT)
=====================
Droits d'auteur © `2024` `@mikecao, @n0nag0n`
La permission est accordée, gratuitement, à toute personne
obtenant une copie de ce logiciel et de la documentation associée
(fichiers du “Logiciel”), d'utiliser le Logiciel sans aucune
restriction, y compris, sans s'y limiter, les droits d'utiliser,
de copier, de modifier, de fusionner, de publier, de distribuer,
de concéder sous licence et/ou de vendre des copies du Logiciel,
et de permettre aux personnes auxquelles le Logiciel est fourni
de le faire, sous réserve des conditions suivantes :
L'avis de droit d'auteur ci-dessus et le présent avis de
permission doivent être inclus dans toutes les copies ou les
parties substantielles du Logiciel.
LE LOGICIEL EST FOURNI “TEL QUEL”, SANS GARANTIE D'AUCUNE
SORTES, EXPRESSE OU IMPLICITE, Y COMPRIS, MAIS SANS S'Y LIMITER,
LES GARANTIES DE QUALITÉ MARCHANDE, D'ADÉQUATION À UN USAGE
PARTICULIER ET D'ABSENCE DE CONTREFAÇON. EN AUCUN CAS, LES
AUTEURS OU LES TITULAIRES DES DROITS D'AUTEUR NE SAURAIENT ÊTRE
TENUS RESPONSABLES DE TOUTE RÉCLAMATION, DOMMAGE OU AUTRE
RESPONSABILITÉ, QUE CE SOIT DANS UNE ACTION DE CONTRAT, DE TORT
OU AUTRE, DÉCOULANT DE, HORS DE OU EN RELATION AVEC LE LOGICIEL
OU L'UTILISATION OU D'AUTRES TRANSACTIONS DANS LE LOGICIEL.
About
Qu'est-ce que Flight?
Flight est un framework rapide, simple et extensible pour PHP. Il est assez polyvalent et peut être utilisé pour construire tout type d'application web. Il est conçu avec simplicité à l'esprit et est écrit de manière à être facile à comprendre et à utiliser.
Flight est un excellent framework pour les débutants qui découvrent PHP et qui souhaitent apprendre à créer des applications web. C'est également un excellent framework pour les développeurs expérimentés qui souhaitent plus de contrôle sur leurs applications web. Il est conçu pour permettre de construire facilement une API RESTful, une application web simple ou une application web complexe.
Démarrage rapide
Installez-le d'abord avec Composer
composer require flightphp/core
ou vous pouvez télécharger un zip du dépôt ici. Vous auriez ensuite un fichier index.php
de base comme suit :
<?php
// si installé avec composer
require 'vendor/autoload.php';
// ou si installé manuellement via un fichier zip
// require 'flight/Flight.php';
Flight::route('/', function() {
echo 'hello world!';
});
Flight::route('/json', function() {
Flight::json(['hello' => 'world']);
});
Flight::start();
C'est tout ! Vous avez une application Flight de base. Vous pouvez maintenant exécuter ce fichier avec php -S localhost:8000
et visiter http://localhost:8000
dans votre navigateur pour voir la sortie.
Est-ce rapide ?
Oui ! Flight est rapide. C'est l'un des frameworks PHP les plus rapides disponibles. Vous pouvez voir tous les benchmarks sur TechEmpower
Voir le benchmark ci-dessous avec quelques autres frameworks PHP populaires.
Framework | Reqs/plaintext/sec | Reqs/JSON/sec |
---|---|---|
Flight | 190,421 | 182,491 |
Yii | 145,749 | 131,434 |
Fat-Free | 139,238 | 133,952 |
Slim | 89,588 | 87,348 |
Phalcon | 95,911 | 87,675 |
Symfony | 65,053 | 63,237 |
Lumen | 40,572 | 39,700 |
Laravel | 26,657 | 26,901 |
CodeIgniter | 20,628 | 19,901 |
Application Skeleton/Boilerplate
Il existe une application d'exemple qui peut vous aider à démarrer avec le framework Flight. Allez sur flightphp/skeleton pour les instructions sur la façon de commencer ! Vous pouvez également visiter la page des exemples pour vous inspirer de certaines des choses que vous pouvez faire avec Flight.
Communauté
Nous sommes sur Matrix Chat
Et Discord
Contributions
Il existe deux façons de contribuer à Flight :
- Vous pouvez contribuer au framework central en visitant le dépôt principal.
- Vous pouvez contribuer à la documentation. Ce site de documentation est hébergé sur Github. Si vous remarquez une erreur ou si vous souhaitez améliorer quelque chose, n'hésitez pas à le corriger et à soumettre une demande de tirage ! Nous essayons de rester à jour, mais les mises à jour et les traductions de langue sont les bienvenues.
Exigences
Flight nécessite PHP 7.4 ou supérieur.
Remarque : PHP 7.4 est pris en charge car au moment de la rédaction (2024), PHP 7.4 est la version par défaut pour certaines distributions Linux LTS. Forcer un passage à PHP >8 causerait beaucoup de problèmes 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
flightphp/cache
Classe de mise en cache en fichier PHP légère, simple et autonome
Avantages
- Légère, autonome et simple
- Tout le code dans un seul fichier - pas de pilotes inutiles.
- Sécurisée - chaque fichier de cache généré a un en-tête php avec die, rendant l'accès direct impossible même si quelqu'un connaît le chemin et que votre serveur n'est pas configuré correctement
- Bien documenté et testé
- Gère correctement la concurrence via flock
- Prend en charge PHP 7.4+
- Gratuit sous une licence MIT
Ce site de documentation utilise cette bibliothèque pour mettre en cache chacune des pages !
Cliquez ici pour voir le code.
Installation
Installez via composer :
composer require flightphp/cache
Utilisation
L'utilisation est assez simple. Cela enregistre un fichier de cache dans le répertoire de cache.
use flight\Cache;
$app = Flight::app();
// Vous passez le répertoire dans lequel le cache sera stocké dans le constructeur
$app->register('cache', Cache::class, [ __DIR__ . '/../cache/' ], function(Cache $cache) {
// Cela garantit que le cache n'est utilisé que lorsque vous êtes en mode production
// ENVIRONMENT est une constante qui est définie dans votre fichier de démarrage ou ailleurs dans votre application
$cache->setDevMode(ENVIRONMENT === 'development');
});
Ensuite, vous pouvez l'utiliser dans votre code comme ceci :
// Obtenir l'instance de 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/flightphp/cache pour une documentation complète et assurez-vous de voir le dossier exemples.
Awesome-plugins/permissions
FlightPHP/Autorisations
Il s'agit d'un module d'autorisations qui peut être utilisé dans vos projets si vous avez plusieurs rôles dans votre application et que chaque rôle a une fonctionnalité légèrement différente. Ce module vous permet de définir des autorisations pour chaque rôle, puis de vérifier si l'utilisateur actuel a l'autorisation d'accéder à une certaine page ou d'effectuer une certaine action.
Cliquez ici pour accéder au dépôt sur GitHub.
Installation
Exécutez composer require flightphp/permissions
et c'est parti!
Utilisation
Tout d'abord, vous devez configurer vos autorisations, puis vous indiquez à votre application ce que signifient les autorisations. En fin de compte, vous vérifierez vos autorisations avec $Permissions->has()
, ->can()
, ou is()
. has()
et can()
ont la même fonctionnalité, mais sont nommées différemment pour rendre votre code plus lisible.
Exemple de base
Supposons que vous ayez une fonctionnalité dans votre application qui vérifie si un utilisateur est connecté. Vous pouvez créer un objet d'autorisations comme ceci:
// index.php
require 'vendor/autoload.php';
// some code
// then you probably have something that tells you who the current role is of the person
// likely you have something where you pull the current role
// from a session variable which defines this
// after someone logs in, otherwise they will have a 'guest' or 'public' role.
$current_role = 'admin';
// setup permissions
$permission = new \flight\Permission($current_role);
$permission->defineRule('loggedIn', function($current_role) {
return $current_role !== 'guest';
});
// You'll probably want to persist this object in Flight somewhere
Flight::set('permission', $permission);
Ensuite, dans un contrôleur quelque part, vous pourriez avoir quelque chose comme ceci.
<?php
// some controller
class SomeController {
public function someAction() {
$permission = Flight::get('permission');
if ($permission->has('loggedIn')) {
// do something
} else {
// do something else
}
}
}
Vous pouvez également utiliser ceci pour suivre s'ils ont l'autorisation de faire quelque chose dans votre application. Par exemple, si vous avez un moyen pour les utilisateurs d'interagir avec des publications sur votre logiciel, vous pouvez vérifier s'ils ont l'autorisation d'effectuer certaines actions.
$current_role = 'admin';
// setup permissions
$permission = new \flight\Permission($current_role);
$permission->defineRule('post', function($current_role) {
if($current_role === 'admin') {
$permissions = ['create', 'read', 'update', 'delete'];
} else if($current_role === 'editor') {
$permissions = ['create', 'read', 'update'];
} else if($current_role === 'author') {
$permissions = ['create', 'read'];
} else if($current_role === 'contributor') {
$permissions = ['create'];
} else {
$permissions = [];
}
return $permissions;
});
Flight::set('permission', $permission);
Ensuite, dans un contrôleur quelque part...
class PostController {
public function create() {
$permission = Flight::get('permission');
if ($permission->can('post.create')) {
// do something
} else {
// do something else
}
}
}
Injection de dépendances
Vous pouvez injecter des dépendances dans la fonction de fermeture qui définit les autorisations. C'est utile si vous avez un type de bascule, d'identifiant ou tout autre point de données que vous voulez vérifier. Le même principe s'applique aux appels de type Classe->Méthode, sauf que vous définissez les arguments dans la méthode.
Fonctions de fermeture
$Permission->defineRule('order', function(string $current_role, MyDependency $MyDependency = null) {
// ... code
});
// dans votre fichier de contrôleur
public function createOrder() {
$MyDependency = Flight::myDependency();
$permission = Flight::get('permission');
if ($permission->can('order.create', $MyDependency)) {
// do something
} else {
// do something else
}
}
Classes
namespace MyApp;
class Permissions {
public function order(string $current_role, MyDependency $MyDependency = null) {
// ... code
}
}
Raccourci pour définir des autorisations avec des classes
Vous pouvez également utiliser des classes pour définir vos autorisations. C'est utile si vous avez beaucoup d'autorisations et que vous voulez garder votre code propre. Vous pouvez faire quelque chose comme ceci:
<?php
// code de démarrage
$Permissions = new \flight\Permission($current_role);
$Permissions->defineRule('order', 'MyApp\Permissions->order');
// myapp/Permissions.php
namespace MyApp;
class Permissions {
public function order(string $current_role, int $user_id) {
// En supposant que vous avez configuré cela au préalable
/** @var \flight\database\PdoWrapper $db */
$db = Flight::db();
$allowed_permissions = [ 'read' ]; // tout le monde peut consulter une commande
if($current_role === 'manager') {
$allowed_permissions[] = 'create'; // les gestionnaires peuvent créer des commandes
}
$some_special_toggle_from_db = $db->fetchField('SELECT some_special_toggle FROM settings WHERE id = ?', [ $user_id ]);
if($some_special_toggle_from_db) {
$allowed_permissions[] = 'update'; // si l'utilisateur a une bascule spéciale, il peut mettre à jour des commandes
}
if($current_role === 'admin') {
$allowed_permissions[] = 'delete'; // les administrateurs peuvent supprimer des commandes
}
return $allowed_permissions;
}
}
L'astuce est que vous pouvez également utiliser un raccourci (qui peut également être mis en cache!!!) où vous dites simplement à la classe d'autorisations de mapper toutes les méthodes d'une classe en autorisations. Ainsi, si vous avez une méthode nommée order()
et une méthode nommée company()
, cela sera automatiquement cartographié pour que vous puissiez simplement exécuter $Permissions->has('order.read')
ou $Permissions->has('company.read')
et cela fonctionnera. Définir cela est très difficile, donc suivez moi ici. Vous avez juste besoin de faire ceci:
Créez la classe des autorisations que vous souhaitez regrouper.
class MyPermissions {
public function order(string $current_role, int $order_id = 0): array {
// code pour déterminer les autorisations
return $permissions_array;
}
public function company(string $current_role, int $company_id): array {
// code pour déterminer les autorisations
return $permissions_array;
}
}
Puis rendez les autorisations découvrables en utilisant cette bibliothèque.
$Permissions = new \flight\Permission($current_role);
$Permissions->defineRulesFromClassMethods(MyApp\Permissions::class);
Flight::set('permissions', $Permissions);
Enfin, appelez l'autorisation dans votre code pour vérifier si l'utilisateur est autorisé à effectuer une autorisation donnée.
class SomeController {
public function createOrder() {
if(Flight::get('permissions')->can('order.create') === false) {
die('Vous ne pouvez pas créer une commande. Désolé!');
}
}
}
Mise en cache
Pour activer la mise en cache, consultez la bibliothèque simple wruczak/phpfilecache. Un exemple pour l'activer est ci-dessous.
// cet $app peut faire partie de votre code, ou
// vous pouvez simplement passer null et il
// récupérera de Flight::app() dans le constructeur
$app = Flight::app();
// Pour l'instant, cela accepte cela comme cache de fichier. D'autres peuvent facilement
// être ajoutés à l'avenir.
$Cache = new Wruczek\PhpFileCache\PhpFileCache;
$Permissions = new \flight\Permission($current_role, $app, $Cache);
$Permissions->defineRulesFromClassMethods(MyApp\Permissions::class, 3600); // 3600 est le nombre de secondes pendant lesquels conserver cette mise en cache. Laissez ceci vide pour ne pas utiliser la mise en cache
Awesome-plugins/simple_job_queue
File d'attente de travail simple
La file d'attente de travail simple est une bibliothèque qui peut être utilisée pour traiter des travaux de manière asynchrone. Elle peut être utilisée avec beanstalkd, MySQL/MariaDB, SQLite et PostgreSQL.
Installation
composer require n0nag0n/simple-job-queue
Utilisation
Pour que cela fonctionne, vous devez avoir un moyen d'ajouter des travaux à la file d'attente et un moyen de traiter les travaux (un travailleur). Ci-dessous, des exemples de la façon d'ajouter un travail à la file d'attente et de traiter le travail.
Ajout à Flight
Ajouter cela à Flight est simple et se fait en utilisant la méthode register()
. Ci-dessous un exemple de la façon d'ajouter cela à Flight.
<?php
require 'vendor/autoload.php';
// Changez ['mysql'] en ['beanstalkd'] si vous voulez utiliser beanstalkd
Flight::register('queue', n0nag0n\Job_Queue::class, ['mysql'], function($Job_Queue) {
// si vous avez déjà une connexion PDO sur Flight::db();
$Job_Queue->addQueueConnection(Flight::db());
// ou si vous utilisez beanstalkd/Pheanstalk
$pheanstalk = Pheanstalk\Pheanstalk::create('127.0.0.1');
$Job_Queue->addQueueConnection($pheanstalk);
});
Ajout d'un nouveau travail
Lorsque vous ajoutez un travail, vous devez spécifier un pipeline (file d'attente). Cela est comparable à un canal dans RabbitMQ ou un tube dans beanstalkd.
<?php
Flight::queue()->selectPipeline('send_important_emails');
Flight::queue()->addJob(json_encode([ 'something' => 'that', 'ends' => 'up', 'a' => 'string' ]));
Exécution d'un travailleur
Voici un exemple de fichier sur comment exécuter un travailleur.
<?php
require 'vendor/autoload.php';
$Job_Queue = new n0nag0n\Job_Queue('mysql');
// Connexion PDO
$PDO = new PDO('mysql:dbname=testdb;host=127.0.0.1', 'user', 'pass');
$Job_Queue->addQueueConnection($PDO);
// ou si vous utilisez beanstalkd/Pheanstalk
$pheanstalk = Pheanstalk\Pheanstalk::create('127.0.0.1');
$Job_Queue->addQueueConnection($pheanstalk);
$Job_Queue->watchPipeline('send_important_emails');
while(true) {
$job = $Job_Queue->getNextJobAndReserve();
// ajustez selon ce qui vous fait dormir mieux la nuit (pour les files d'attente de base de données uniquement, beanstalkd n'a pas besoin de cette instruction conditionnelle)
if(empty($job)) {
usleep(500000);
continue;
}
echo "Traitement de {$job['id']}\n";
$payload = json_decode($job['payload'], true);
try {
$result = doSomethingThatDoesSomething($payload);
if($result === true) {
$Job_Queue->deleteJob($job);
} else {
// cela le retire de la file d'attente prête et le met dans une autre file d'attente qui peut être récupérée et "kickée" plus tard.
$Job_Queue->buryJob($job);
}
} catch(Exception $e) {
$Job_Queue->buryJob($job);
}
}
Gestion des processus longs avec Supervisord
Supervisord est un système de contrôle de processus qui garantit que vos processus travailleurs restent en cours d'exécution en continu. Voici un guide plus complet sur la façon de le configurer avec votre travailleur Simple Job Queue :
Installation de Supervisord
# Sur Ubuntu/Debian
sudo apt-get install supervisor
# Sur CentOS/RHEL
sudo yum install supervisor
# Sur macOS avec Homebrew
brew install supervisor
Création d'un script de travailleur
Tout d'abord, enregistrez votre code de travailleur dans un fichier PHP dédié :
<?php
require 'vendor/autoload.php';
$Job_Queue = new n0nag0n\Job_Queue('mysql');
// Connexion PDO
$PDO = new PDO('mysql:dbname=your_database;host=127.0.0.1', 'username', 'password');
$Job_Queue->addQueueConnection($PDO);
// Définir le pipeline à surveiller
$Job_Queue->watchPipeline('send_important_emails');
// Journaliser le début du travailleur
echo date('Y-m-d H:i:s') . " - Travailleur démarré\n";
while(true) {
$job = $Job_Queue->getNextJobAndReserve();
if(empty($job)) {
usleep(500000); // Dormir pendant 0,5 secondes
continue;
}
echo date('Y-m-d H:i:s') . " - Traitement du travail {$job['id']}\n";
$payload = json_decode($job['payload'], true);
try {
$result = doSomethingThatDoesSomething($payload);
if($result === true) {
$Job_Queue->deleteJob($job);
echo date('Y-m-d H:i:s') . " - Travail {$job['id']} terminé avec succès\n";
} else {
$Job_Queue->buryJob($job);
echo date('Y-m-d H:i:s') . " - Travail {$job['id']} échoué, enterré\n";
}
} catch(Exception $e) {
$Job_Queue->buryJob($job);
echo date('Y-m-d H:i:s') . " - Exception lors du traitement du travail {$job['id']}: {$e->getMessage()}\n";
}
}
Configuration de Supervisord
Créez un fichier de configuration pour votre travailleur :
[program:email_worker]
command=php /path/to/worker.php
directory=/path/to/project
autostart=true
autorestart=true
startretries=3
stderr_logfile=/var/log/simple_job_queue_err.log
stdout_logfile=/var/log/simple_job_queue.log
user=www-data
numprocs=2
process_name=%(program_name)s_%(process_num)02d
Options de configuration clés :
command
: La commande pour exécuter votre travailleurdirectory
: Répertoire de travail pour le travailleurautostart
: Démarrer automatiquement lorsque supervisord démarreautorestart
: Redémarrer automatiquement si le processus se terminestartretries
: Nombre de fois à réessayer de démarrer s'il échouestderr_logfile
/stdout_logfile
: Emplacements des fichiers journauxuser
: Utilisateur système pour exécuter le processusnumprocs
: Nombre d'instances du travailleur à exécuterprocess_name
: Format de nommage pour plusieurs processus de travailleur
Gestion des travailleurs avec Supervisorctl
Après avoir créé ou modifié la configuration :
# Recharger la configuration du superviseur
sudo supervisorctl reread
sudo supervisorctl update
# Contrôler des processus de travailleur spécifiques
sudo supervisorctl start email_worker:*
sudo supervisorctl stop email_worker:*
sudo supervisorctl restart email_worker:*
sudo supervisorctl status email_worker:*
Exécution de plusieurs pipelines
Pour plusieurs pipelines, créez des fichiers de travailleurs et des configurations distincts :
[program:email_worker]
command=php /path/to/email_worker.php
# ... autres configurations ...
[program:notification_worker]
command=php /path/to/notification_worker.php
# ... autres configurations ...
Surveillance et journaux
Vérifiez les journaux pour surveiller l'activité du travailleur :
# Voir les journaux
sudo tail -f /var/log/simple_job_queue.log
# Vérifier le statut
sudo supervisorctl status
Cette configuration garantit que vos travailleurs de tâches continuent d'exécuter même après des plantages, des redémarrages de serveur ou d'autres problèmes, rendant votre système de file d'attente fiable pour les environnements de production.
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.
- Wruczek/PHP-File-Cache - Classe de mise en cache PHP légère, simple et autonome
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.
- tracy/tracy - Il s'agit d'un gestionnaire d'erreurs complet 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.
- flightphp/tracy-extensions - Utilisé avec le gestionnaire d'erreurs Tracy, ce plugin ajoute quelques panneaux supplémentaires pour aider au débogage spécifiquement pour les projets Flight.
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.
- flightphp/core PdoWrapper - Wrapper PDO Flight officiel faisant partie du noyau. Il s'agit d'une enveloppe simple pour simplifier le processus d'écriture de requêtes et de les exécuter. Ce n'est pas un ORM.
- flightphp/active-record - ORM/Mapper ActiveRecord Flight officiel. Excellente petite bibliothèque pour récupérer et stocker facilement des données dans votre base de données.
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.
- Ghostff/Session - Gestionnaire de sessions PHP (non bloquant, flash, segment, chiffrement de session). Utilise PHP open_ssl pour le chiffrement/déchiffrement facultatif des données de session.
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.
- flightphp/core View - Il s'agit d'un moteur de modèles très basique faisant partie du noyau. Il n'est pas recommandé de l'utiliser si vous avez plus de quelques pages dans votre projet.
- latte/latte - Latte est un moteur de modèles complet et très facile à utiliser qui se rapproche plus d'une syntaxe PHP que Twig ou Smarty. Il est également très facile à étendre et à ajouter vos propres filtres et fonctions.
Contribution
Vous avez un plugin que vous aimeriez partager? Soumettez une pull request pour l'ajouter à la liste!
Awesome-plugins/ghost_session
Ghostff/Session
Gestionnaire de session 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.
Cliquez ici pour voir le code.
Installation
Installez avec Composer.
composer require ghostff/session
Configuration de base
Vous n'êtes pas obligé de passer quoi que ce soit pour utiliser les paramètres par défaut avec votre session. Vous pouvez lire davantage sur les paramètres dans le Github Readme.
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
// sinon, vous devrez exécuter auto_commit dans votre configuration.
Exemple simple
Voici un exemple simple de la façon dont vous pourriez utiliser cela.
Flight::route('POST /login', function() {
$session = Flight::session();
// faites votre logique de connexion ici
// validez le mot de passe, etc.
// si la connexion est réussie
$session->set('is_logged_in', true);
$session->set('user', $user);
// chaque fois que vous écrivez dans la session, vous devez la valider délibérément.
$session->commit();
});
// Cette vérification pourrait être dans la logique de la page restreinte, ou encapsulée avec un middleware.
Flight::route('/some-restricted-page', function() {
$session = Flight::session();
if(!$session->get('is_logged_in')) {
Flight::redirect('/login');
}
// faites votre logique de page restreinte ici
});
// la version middleware
Flight::route('/some-restricted-page', function() {
// logique de page normale
})->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 utiliser cela.
use Ghostff\Session\Session;
require 'vendor/autoload.php';
$app = Flight::app();
// définissez un chemin personnalisé vers votre fichier de configuration de session et donnez-lui une chaîne aléatoire pour l'identifiant de session
$app->register('session', Session::class, [ 'path/to/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) {
// ou vous pouvez remplacer manuellement les options de configuration
$session->updateConfiguration([
// si vous souhaitez stocker vos données de session dans une base de données (bien si vous voulez quelque chose comme, "déconnectez-moi de tous les appareils" fonctionnalité)
Session::CONFIG_DRIVER => Ghostff\Session\Drivers\MySql::class,
Session::CONFIG_ENCRYPT_DATA => true,
Session::CONFIG_SALT_KEY => hash('sha256', 'my-super-S3CR3T-salt'), // veuillez changer cela pour quelque chose d'autre
Session::CONFIG_AUTO_COMMIT => true, // ne le faites que si cela le nécessite et/ou s'il est difficile de valider() votre session.
// de plus, vous pourriez faire Flight::after('start', function() { Flight::session()->commit(); });
Session::CONFIG_MYSQL_DS => [
'driver' => 'mysql', # Pilote de base de données pour DNS PDO par ex (mysql:host=...;dbname=...)
'host' => '127.0.0.1', # Hôte de base de données
'db_name' => 'my_app_database', # Nom de la base de données
'db_table' => 'sessions', # Table de 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 le surcoût d'établir une nouvelle connexion chaque fois qu'un script doit communiquer avec une base de données, ce qui entraîne une application web plus rapide. TROUVEZ L'ARRIÈRE-PLAN VOUS-MÊME
]
]);
}
);
Aide ! Mes données de session ne persistent pas !
Vous définissez vos données de session et elles ne persistent pas entre les requêtes ? Vous avez peut-être oublié de valider vos données de session. Vous pouvez le faire en appelant $session->commit()
après avoir défini vos données de session.
Flight::route('POST /login', function() {
$session = Flight::session();
// faites votre logique de connexion ici
// validez le mot de passe, etc.
// si la connexion est réussie
$session->set('is_logged_in', true);
$session->set('user', $user);
// chaque fois que vous écrivez dans la session, vous devez la valider délibérément.
$session->commit();
});
L'autre solution est que lorsque vous configurez votre service de session, vous devez définir auto_commit
sur true
dans votre configuration. Cela validera automatiquement vos données de session après chaque requête.
$app->register('session', Session::class, [ 'path/to/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) {
$session->updateConfiguration([
Session::CONFIG_AUTO_COMMIT => true,
]);
}
);
De plus, vous pourriez faire Flight::after('start', function() { Flight::session()->commit(); });
pour valider vos données de session après chaque requête.
Documentation
Visitez le Github Readme pour la documentation complète. Les options de configuration sont bien documentées dans le fichier default_config.php. Le code est simple à comprendre si vous souhaitez parcourir ce package vous-même.
Awesome-plugins/pdo_wrapper
Classe d'aide PdoWrapper PDO
Flight est livré avec une classe d'aide pour PDO. Il vous permet d'interroger facilement votre base de données avec toute la bizarrerie préparée/execute/fetchAll(). Cela simplifie grandement la façon dont vous pouvez interroger votre base de données. Chaque résultat de ligne est renvoyé sous forme de classe Collection de Flight qui vous permet d'accéder à vos données via une syntaxe de tableau ou une syntaxe d'objet.
Enregistrer la classe d'aide PDO
// Enregistrer la classe d'aide PDO
Flight::register('db', \flight\database\PdoWrapper::class, ['mysql:host=localhost;dbname=cool_db_name', 'user', 'pass', [
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'utf8mb4\'',
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]
]);
Utilisation
Cet objet étend PDO, donc toutes les méthodes normales de PDO sont disponibles. Les méthodes suivantes sont ajoutées pour faciliter l'interrogation de la base de données :
runQuery(string $sql, array $params = []): PDOStatement
Utilisez ceci pour les INSERT, les UPDATES, ou si vous envisagez d'utiliser un SELECT dans une boucle while
$db = Flight::db();
$statement = $db->runQuery("SELECT * FROM table WHERE something = ?", [ $something ]);
while($row = $statement->fetch()) {
// ...
}
// Ou pour écrire dans la base de données
$db->runQuery("INSERT INTO table (name) VALUES (?)", [ $name ]);
$db->runQuery("UPDATE table SET name = ? WHERE id = ?", [ $name, $id ]);
fetchField(string $sql, array $params = []): mixed
Extraie le premier champ de la requête
$db = Flight::db();
$count = $db->fetchField("SELECT COUNT(*) FROM table WHERE something = ?", [ $something ]);
fetchRow(string $sql, array $params = []): array
Récupère une ligne de la requête
$db = Flight::db();
$row = $db->fetchRow("SELECT id, name FROM table WHERE id = ?", [ $id ]);
echo $row['name'];
// or
echo $row->name;
fetchAll(string $sql, array $params = []): array
Récupère toutes les lignes de la requête
$db = Flight::db();
$rows = $db->fetchAll("SELECT id, name FROM table WHERE something = ?", [ $something ]);
foreach($rows as $row) {
echo $row['name'];
// or
echo $row->name;
}
Remarque avec la syntaxe IN()
Il existe également un wrapper utile pour les déclarations IN()
. Vous pouvez simplement passer un point d'interrogation unique en guise de paramètre pour IN()
puis un tableau de valeurs. Voici un exemple de ce à quoi cela pourrait ressembler :
$db = Flight::db();
$name = 'Bob';
$company_ids = [1,2,3,4,5];
$rows = $db->fetchAll("SELECT id, name FROM table WHERE name = ? AND company_id IN (?)", [ $name, $company_ids ]);
Exemple complet
// Exemple de route et comment vous utiliseriez ce wrapper
Flight::route('/utilisateurs', function () {
// Obtenir tous les utilisateurs
$users = Flight::db()->fetchAll('SELECT * FROM users');
// Diffuser tous les utilisateurs
$statement = Flight::db()->runQuery('SELECT * FROM users');
while ($user = $statement->fetch()) {
echo $user['name'];
// ou echo $user->name;
}
// Obtenir un seul utilisateur
$user = Flight::db()->fetchRow('SELECT * FROM users WHERE id = ?', [123]);
// Obtenir une seule valeur
$count = Flight::db()->fetchField('SELECT COUNT(*) FROM users');
// Syntaxe spéciale IN() pour aider (assurez-vous que IN est en majuscules)
$users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [[1,2,3,4,5]]);
// vous pourriez aussi faire ceci
$users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [ '1,2,3,4,5']);
// Insérer un nouvel utilisateur
Flight::db()->runQuery("INSERT INTO users (name, email) VALUES (?, ?)", ['Bob', 'bob@example.com']);
$insert_id = Flight::db()->lastInsertId();
// Mettre à jour un utilisateur
Flight::db()->runQuery("UPDATE users SET name = ? WHERE id = ?", ['Bob', 123]);
// Supprimer un utilisateur
Flight::db()->runQuery("DELETE FROM users WHERE id = ?", [123]);
// Obtenir le nombre de lignes affectées
$statement = Flight::db()->runQuery("UPDATE users SET name = ? WHERE name = ?", ['Bob', 'Sally']);
$affected_rows = $statement->rowCount();
});
Awesome-plugins/migrations
Migrations
Une migration pour votre projet suit toutes les modifications de la base de données impliquées dans votre projet. byjg/php-migration est une bibliothèque centrale très utile pour vous aider à démarrer.
Installing
PHP Library
Si vous souhaitez utiliser uniquement la bibliothèque PHP dans votre projet :
composer require "byjg/migration"
Command Line Interface
L'interface de ligne de commande est autonome et ne nécessite pas d'installation avec votre projet.
Vous pouvez l'installer globalement et créer un lien symbolique
composer require "byjg/migration-cli"
Veuillez visiter byjg/migration-cli pour obtenir plus d'informations sur Migration CLI.
Bases de données prises en charge
Base de données | Pilote | Chaîne de connexion |
---|---|---|
Sqlite | pdo_sqlite | sqlite:///path/to/file |
MySql/MariaDb | pdo_mysql | mysql://username:password@hostname:port/database |
Postgres | pdo_pgsql | pgsql://username:password@hostname:port/database |
Sql Server | pdo_dblib, pdo_sysbase Linux | dblib://username:password@hostname:port/database |
Sql Server | pdo_sqlsrv Windows | sqlsrv://username:password@hostname:port/database |
Comment ça fonctionne ?
La migration de base de données utilise le SQL PUR pour gérer la version de la base de données. Pour faire fonctionner, vous devez :
- Créer les scripts SQL
- Gérer en utilisant la ligne de commande ou l'API.
Les scripts SQL
Les scripts sont divisés en trois ensemble de scripts :
- Le script BASE contient TOUS les commandes SQL pour créer une base de données fraîche ;
- Les scripts UP contiennent toutes les commandes de migration SQL pour "augmenter" la version de la base de données ;
- Les scripts DOWN contiennent toutes les commandes de migration SQL pour "reculer" ou revenir à la version de la base de données ;
Le répertoire des scripts est :
<root dir>
|
+-- base.sql
|
+-- /migrations
|
+-- /up
|
+-- 00001.sql
+-- 00002.sql
+-- /down
|
+-- 00000.sql
+-- 00001.sql
- "base.sql" est le script de base
- Le dossier "up" contient les scripts pour migrer vers la version supérieure. Par exemple : 00002.sql est le script pour faire passer la base de données de la version '1' à '2'.
- Le dossier "down" contient les scripts pour migrer vers la version inférieure. Par exemple : 00001.sql est le script pour faire passer la base de données de la version '2' à '1'. Le dossier "down" est optionnel.
Environnement de développement multi
Si vous travaillez avec plusieurs développeurs et plusieurs branches, il est trop difficile de déterminer quel est le prochain numéro.
Dans ce cas, vous avez le suffixe "-dev" après le numéro de version.
Voyez le scénario :
- Le développeur 1 crée une branche et la version la plus récente est par exemple 42.
- Le développeur 2 crée une branche en même temps et a le même numéro de version de base de données.
Dans les deux cas, les développeurs créeront un fichier appelé 43-dev.sql. Les deux développeurs migreront VERS LE HAUT et VERS LE BAS sans problème et votre version locale sera 43.
Mais le développeur 1 a fusionné vos modifications et créé une version finale 43.sql (git mv 43-dev.sql 43.sql
). Si le développeur 2 met à jour sa branche locale, il aura un fichier 43.sql (du dev 1) et son fichier 43-dev.sql.
S'il essaie de migrer VERS LE HAUT ou VERS LE BAS, le script de migration ne pourra pas se faire et l'alertera qu'il y a DEUX versions 43. Dans ce cas, le développeur 2 devra mettre à jour son fichier pour faire 44-dev.sql et continuer à travailler jusqu'à ce que les modifications soient fusionnées et génèrent une version finale.
Utiliser l'API PHP et l'intégrer dans vos projets
L'utilisation de base est
- Créer une connexion à un objet ConnectionManagement. Pour plus d'informations, voir le composant "byjg/anydataset"
- Créer un objet Migration avec cette connexion et le dossier où les scripts SQL sont situés.
- Utiliser la commande appropriée pour "réinitialiser", "augmenter" ou "reculer" les scripts de migration.
Voici un exemple :
<?php
// Créer l'URI de connexion
// Voir plus : https://github.com/byjg/anydataset#connection-based-on-uri
$connectionUri = new \ByJG\Util\Uri('mysql://migrateuser:migratepwd@localhost/migratedatabase');
// Enregistrer les bases de données ou les bases de données qui peuvent gérer cette URI :
\ByJG\DbMigration\Migration::registerDatabase(\ByJG\DbMigration\Database\MySqlDatabase::class);
// Créer l'instance Migration
$migration = new \ByJG\DbMigration\Migration($connectionUri, '.');
// Ajouter une fonction de rappel de progression pour recevoir des informations sur l'exécution
$migration->addCallbackProgress(function ($action, $currentVersion, $fileInfo) {
echo "$action, $currentVersion, ${fileInfo['description']}\n";
});
// Restaurer la base de données en utilisant le script "base.sql"
// et exécuter TOUS les scripts existants pour augmenter la version de la base de données à la dernière version
$migration->reset();
// Exécuter TOUS les scripts existants pour augmenter ou diminuer la version de la base de données
// depuis la version actuelle jusqu'au numéro de version ;
// Si le numéro de version n'est pas spécifié, effectuez une migration jusqu'à la dernière version de base de données
$migration->update($version = null);
L'objet Migration contrôle la version de la base de données.
Création d'un contrôle de version dans votre projet
<?php
// Enregistrer les bases de données ou les bases de données qui peuvent gérer cette URI :
\ByJG\DbMigration\Migration::registerDatabase(\ByJG\DbMigration\Database\MySqlDatabase::class);
// Créer l'instance Migration
$migration = new \ByJG\DbMigration\Migration($connectionUri, '.');
// Cette commande va créer la table de version dans votre base de données
$migration->createVersion();
Obtenir la version actuelle
<?php
$migration->getCurrentVersion();
Ajouter un rappel pour contrôler la progression
<?php
$migration->addCallbackProgress(function ($command, $version, $fileInfo) {
echo "Exécution de la commande : $command à la version $version - ${fileInfo['description']}, ${fileInfo['exists']}, ${fileInfo['file']}, ${fileInfo['checksum']}\n";
});
Obtenir l'instance du pilote de la base de données
<?php
$migration->getDbDriver();
Pour l'utiliser, veuillez visiter : https://github.com/byjg/anydataset-db
Éviter la migration partielle (non disponible pour MySQL)
Une migration partielle se produit lorsque le script de migration est interrompu au milieu du processus en raison d'une erreur ou d'une interruption manuelle.
La table de migration sera avec le statut partiel en cours
ou partiel en bas
et doit être corrigée manuellement avant de pouvoir migrer à nouveau.
Pour éviter cette situation, vous pouvez spécifier que la migration sera exécutée dans un contexte transactionnel.
Si le script de migration échoue, la transaction sera annulée et la table de migration sera marquée comme complète
et
la version sera la version immédiatement précédente avant le script qui a causé l'erreur.
Pour activer cette fonctionnalité, vous devez appeler la méthode withTransactionEnabled
en passant true
comme paramètre :
<?php
$migration->withTransactionEnabled(true);
REMARQUE : Cette fonctionnalité n'est pas disponible pour MySQL car elle ne prend pas en charge les commandes DDL à l'intérieur d'une transaction. Si vous utilisez cette méthode avec MySQL, la migration l'ignorera silencieusement. Plus d'infos : https://dev.mysql.com/doc/refman/8.0/en/cannot-roll-back.html
Conseils pour écrire des migrations SQL pour Postgres
À propos de la création de déclencheurs et de fonctions SQL
-- DO
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
-- Vérifier que empname et salary sont fournis
IF NEW.empname IS NULL THEN
RAISE EXCEPTION 'empname ne peut pas être nul'; -- peu importe que ces commentaires soient vides ou non
END IF; --
IF NEW.salary IS NULL THEN
RAISE EXCEPTION '% ne peut pas avoir de salaire nul', NEW.empname; --
END IF; --
-- Qui travaille pour nous quand ils doivent le payer ?
IF NEW.salary < 0 THEN
RAISE EXCEPTION '% ne peut pas avoir un salaire négatif', NEW.empname; --
END IF; --
-- Se souvenir de qui a changé la paie quand
NEW.last_date := current_timestamp; --
NEW.last_user := current_user; --
RETURN NEW; --
END; --
$emp_stamp$ LANGUAGE plpgsql;
-- DON'T
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
-- Vérifier que empname et salary sont fournis
IF NEW.empname IS NULL THEN
RAISE EXCEPTION 'empname ne peut pas être nul';
END IF;
IF NEW.salary IS NULL THEN
RAISE EXCEPTION '% ne peut pas avoir de salaire nul', NEW.empname;
END IF;
-- Qui travaille pour nous quand ils doivent le payer ?
IF NEW.salary < 0 THEN
RAISE EXCEPTION '% ne peut pas avoir un salaire négatif', NEW.empname;
END IF;
-- Se souvenir de qui a changé la paie quand
NEW.last_date := current_timestamp;
NEW.last_user := current_user;
RETURN NEW;
END;
$emp_stamp$ LANGUAGE plpgsql;
Puisque le niveau d'abstraction de base de données PDO
ne peut pas exécuter des lots d'instructions SQL,
lorsque byjg/migration
lit un fichier de migration, il doit diviser tout le contenu du fichier SQL aux points-virgules et exécuter les instructions une par une. Cependant, il existe un type d'instruction qui peut avoir plusieurs points-virgules dans son corps : les fonctions.
Afin de pouvoir analyser les fonctions correctement, byjg/migration
2.1.0 a commencé à diviser les fichiers de migration à la séquence point-virgule + EOL
au lieu de simplement le point-virgule. De cette façon, si vous ajoutez un commentaire vide après chaque point-virgule interne d'une définition de fonction, byjg/migration
pourra l'analyser.
Malheureusement, si vous oubliez d'ajouter l'un de ces commentaires, la bibliothèque divisera l'instruction CREATE FUNCTION
en plusieurs parties et la migration échouera.
Éviter le caractère deux-points (:
)
-- DO
CREATE TABLE bookings (
booking_id UUID PRIMARY KEY,
booked_at TIMESTAMPTZ NOT NULL CHECK (CAST(booked_at AS DATE) <= check_in),
check_in DATE NOT NULL
);
-- DON'T
CREATE TABLE bookings (
booking_id UUID PRIMARY KEY,
booked_at TIMESTAMPTZ NOT NULL CHECK (booked_at::DATE <= check_in),
check_in DATE NOT NULL
);
Puisque PDO
utilise le caractère deux-points pour préfixer les paramètres nommés dans les instructions préparées, son utilisation le perturbera dans d'autres contextes.
Par exemple, les instructions PostgreSQL peuvent utiliser ::
pour convertir des valeurs entre types. D'autre part, PDO
lira cela comme un paramètre nommé invalide dans un contexte invalide et échouera lorsqu'il essaiera de l'exécuter.
Le seul moyen de corriger cette incohérence est d'éviter complètement l'utilisation de double points (dans ce cas, PostgreSQL à également une syntaxe alternative : CAST(value AS type)
).
Utiliser un éditeur SQL
Enfin, écrire des migrations SQL manuelles peut être épuisant, mais c'est beaucoup plus facile si vous utilisez un éditeur capable de comprendre la syntaxe SQL, d'offrir la saisie semi-automatique, d'explorer votre schéma de base de données actuel et/ou de reformater automatiquement votre code.
Gérer différentes migrations dans un seul schéma
Si vous devez créer différents scripts de migration et des versions dans le même schéma, cela est possible mais trop risqué et je ne recommande pas du tout.
Pour ce faire, vous devez créer différentes "tables de migration" en passant le paramètre au constructeur.
<?php
$migration = new \ByJG\DbMigration\Migration("db:/uri", "/path", true, "NEW_MIGRATION_TABLE_NAME");
Pour des raisons de sécurité, cette fonctionnalité n'est pas disponible en ligne de commande, mais vous pouvez utiliser la variable d'environnement
MIGRATION_VERSION
pour stocker le nom.
Nous recommandons vraiment de ne pas utiliser cette fonctionnalité. La recommandation est une migration pour un schéma.
Exécution des tests unitaires
Des tests unitaires de base peuvent être exécutés par :
vendor/bin/phpunit
Exécution des tests de base de données
Exécuter des tests d'intégration nécessite que vous ayez les bases de données en marche. Nous avons fourni un docker-compose.yml
de base et vous
pouvez l'utiliser pour démarrer les bases de données pour les tests.
Exécution des bases de données
docker-compose up -d postgres mysql mssql
Exécuter les tests
vendor/bin/phpunit
vendor/bin/phpunit tests/SqliteDatabase*
vendor/bin/phpunit tests/MysqlDatabase*
vendor/bin/phpunit tests/PostgresDatabase*
vendor/bin/phpunit tests/SqlServerDblibDatabase*
vendor/bin/phpunit tests/SqlServerSqlsrvDatabase*
En option, vous pouvez définir l'hôte et le mot de passe utilisés par les tests unitaires
export MYSQL_TEST_HOST=localhost # par défaut localhost
export MYSQL_PASSWORD=newpassword # utilisez '.' si vous souhaitez avoir un mot de passe nul
export PSQL_TEST_HOST=localhost # par défaut localhost
export PSQL_PASSWORD=newpassword # utilisez '.' si vous souhaitez avoir un mot de passe nul
export MSSQL_TEST_HOST=localhost # par défaut localhost
export MSSQL_PASSWORD=Pa55word
export SQLITE_TEST_HOST=/tmp/test.db # par défaut /tmp/test.db
Awesome-plugins/session
FlightPHP Session - Gestionnaire de session léger basé sur des fichiers
Il s'agit d'un plugin de gestion des sessions léger et basé sur des fichiers pour le Flight PHP Framework. Il fournit une solution simple mais puissante pour la gestion des sessions, avec des fonctionnalités telles que des lectures de session non bloquantes, un chiffrement optionnel, une fonctionnalité d'auto-commit et un mode test pour le développement. Les données de session sont stockées dans des fichiers, ce qui le rend idéal pour les applications qui n'ont pas besoin d'une base de données.
Si vous souhaitez utiliser une base de données, consultez le plugin ghostff/session avec de nombreuses fonctionnalités similaires mais avec un backend de base de données.
Visitez le dépôt Github pour le code source complet et des détails.
Installation
Installez le plugin via Composer :
composer require flightphp/session
Utilisation de base
Voici un exemple simple de la façon d'utiliser le plugin flightphp/session
dans votre application Flight :
require 'vendor/autoload.php';
use flight\Session;
$app = Flight::app();
// Enregistrer le service de session
$app->register('session', Session::class);
// Exemple de route avec utilisation de session
Flight::route('/login', function() {
$session = Flight::session();
$session->set('user_id', 123);
$session->set('username', 'johndoe');
$session->set('is_admin', false);
echo $session->get('username'); // Affiche : johndoe
echo $session->get('preferences', 'default_theme'); // Affiche : default_theme
if ($session->get('user_id')) {
Flight::json(['message' => 'L’utilisateur est connecté !', 'user_id' => $session->get('user_id')]);
}
});
Flight::route('/logout', function() {
$session = Flight::session();
$session->clear(); // Efface toutes les données de session
Flight::json(['message' => 'Déconnexion réussie']);
});
Flight::start();
Points clés
- Non-Bloquant : Utilise
read_and_close
pour le démarrage de session par défaut, ce qui empêche les problèmes de verrouillage des sessions. - Auto-Commit : Activé par défaut, donc les modifications sont enregistrées automatiquement à l'arrêt à moins que désactivé.
- Stockage de fichiers : Les sessions sont stockées dans le répertoire temporaire du système sous
/flight_sessions
par défaut.
Configuration
Vous pouvez personnaliser le gestionnaire de session en passant un tableau d'options lors de l'enregistrement :
$app->register('session', Session::class, [
'save_path' => '/custom/path/to/sessions', // Répertoire pour les fichiers de session
'encryption_key' => 'a-secure-32-byte-key-here', // Activer le chiffrement (32 octets recommandés pour AES-256-CBC)
'auto_commit' => false, // Désactiver l'auto-commit pour un contrôle manuel
'start_session' => true, // Démarrer la session automatiquement (par défaut : true)
'test_mode' => false // Activer le mode test pour le développement
]);
Options de configuration
Option | Description | Valeur par défaut |
---|---|---|
save_path |
Répertoire où sont stockés les fichiers de session | sys_get_temp_dir() . '/flight_sessions' |
encryption_key |
Clé pour le chiffrement AES-256-CBC (optionnel) | null (pas de chiffrement) |
auto_commit |
Sauvegarde automatique des données de session à l'arrêt | true |
start_session |
Démarrer la session automatiquement | true |
test_mode |
Exécuter en mode test sans affecter les sessions PHP | false |
test_session_id |
ID de session personnalisé pour le mode test (optionnel) | Généré aléatoirement si non défini |
Utilisation avancée
Commit manuel
Si vous désactivez l'auto-commit, vous devez engager manuellement les modifications :
$app->register('session', Session::class, ['auto_commit' => false]);
Flight::route('/update', function() {
$session = Flight::session();
$session->set('key', 'value');
$session->commit(); // Enregistrer explicitement les modifications
});
Sécurité des sessions avec chiffrement
Activez le chiffrement pour les données sensibles :
$app->register('session', Session::class, [
'encryption_key' => 'your-32-byte-secret-key-here'
]);
Flight::route('/secure', function() {
$session = Flight::session();
$session->set('credit_card', '4111-1111-1111-1111'); // Chiffré automatiquement
echo $session->get('credit_card'); // Déchiffré lors de la récupération
});
Régénération de session
Régénérez l'ID de session pour des raisons de sécurité (par exemple, après une connexion) :
Flight::route('/post-login', function() {
$session = Flight::session();
$session->regenerate(); // Nouvel ID, garder les données
// OU
$session->regenerate(true); // Nouvel ID, supprimer les anciennes données
});
Exemple de middleware
Protégez les routes avec une authentification basée sur la session :
Flight::route('/admin', function() {
Flight::json(['message' => 'Bienvenue sur le panneau d’administration']);
})->addMiddleware(function() {
$session = Flight::session();
if (!$session->get('is_admin')) {
Flight::halt(403, 'Accès refusé');
}
});
Ceci est juste un exemple simple de la façon d'utiliser cela dans un middleware. Pour un exemple plus approfondi, consultez la documentation middleware.
Méthodes
La classe Session
fournit ces méthodes :
set(string $key, $value)
: Stocke une valeur dans la session.get(string $key, $default = null)
: Récupère une valeur, avec une valeur par défaut optionnelle si la clé n’existe pas.delete(string $key)
: Supprime une clé spécifique de la session.clear()
: Supprime toutes les données de la session.commit()
: Sauvegarde les données de session actuelles sur le système de fichiers.id()
: Renvoie l'ID de session actuel.regenerate(bool $deleteOld = false)
: Régénère l’ID de session, en supprimant éventuellement les anciennes données.
Toutes les méthodes sauf get()
et id()
retournent l'instance Session
pour le chaînage.
Pourquoi utiliser ce plugin ?
- Léger : Pas de dépendances externes—juste des fichiers.
- Non-Bloquant : Évite le verrouillage des sessions avec
read_and_close
par défaut. - Securisé : Prend en charge le chiffrement AES-256-CBC pour les données sensibles.
- Flexible : Options d'auto-commit, mode test et contrôle manuel.
- Natifs à Flight : Construit spécifiquement pour le framework Flight.
Détails techniques
- Format de stockage : Les fichiers de session sont préfixés par
sess_
et stockés dans lesave_path
configuré. Les données chiffrées utilisent un préfixeE
, les données en texte clair utilisentP
. - Chiffrement : Utilise AES-256-CBC avec un IV aléatoire par écriture de session lorsqu'une
encryption_key
est fournie. - Collecte des déchets : Implémente
SessionHandlerInterface::gc()
de PHP pour nettoyer les sessions expirées.
Contribuer
Les contributions sont les bienvenues ! Forkez le dépôt, apportez vos modifications et soumettez une demande de tirage. Signalez des bugs ou suggérez des fonctionnalités via le suivi des problèmes de Github.
Licence
Ce plugin est sous licence MIT. Consultez le dépôt Github pour plus de détails.
Awesome-plugins/runway
Piste
Runway est une application CLI qui vous aide à gérer vos applications Flight. Il peut générer des contrôleurs, afficher toutes les routes, et bien plus encore. Il est basé sur l'excellente bibliothèque adhocore/php-cli.
Cliquez ici pour voir le code.
Installation
Installez avec composer.
composer require flightphp/runway
Configuration de Base
La première fois que vous exécutez Runway, il vous guidera à travers un processus de configuration et créera un fichier de configuration .runway.json
à la racine de votre projet. Ce fichier contiendra certaines configurations nécessaires pour que Runway fonctionne correctement.
Utilisation
Runway dispose de plusieurs commandes que vous pouvez utiliser pour gérer votre application Flight. Il y a deux façons faciles d'utiliser Runway.
- Si vous utilisez le projet de base, vous pouvez exécuter
php runway [commande]
depuis la racine de votre projet. - Si vous utilisez Runway comme un paquet installé via composer, vous pouvez exécuter
vendor/bin/runway [commande]
depuis la racine de votre projet.
Pour n'importe quelle commande, vous pouvez ajouter le drapeau --help
pour obtenir plus d'informations sur comment utiliser la commande.
php runway routes --help
Voici quelques exemples :
Générer un Contrôleur
Selon la configuration dans votre fichier .runway.json
, l'emplacement par défaut générera un contrôleur pour vous dans le répertoire app/controllers/
.
php runway make:controller MyController
Générer un Modèle Active Record
Selon la configuration dans votre fichier .runway.json
, l'emplacement par défaut générera un contrôleur pour vous dans le répertoire app/records/
.
php runway make:record users
Par exemple, si vous avez la table users
avec le schéma suivant : id
, name
, email
, created_at
, updated_at
, un fichier similaire au suivant sera créé dans le fichier app/records/UserRecord.php
:
<?php
declare(strict_types=1);
namespace app\records;
/**
* Class ActiveRecord pour la table des utilisateurs.
* @link https://docs.flightphp.com/awesome-plugins/active-record
*
* @property int $id
* @property string $name
* @property string $email
* @property string $created_at
* @property string $updated_at
* // vous pouvez également ajouter des relations ici une fois que vous les définissez dans le tableau $relations
* @property CompanyRecord $company Exemple d'une relation
*/
class UserRecord extends \flight\ActiveRecord
{
/**
* @var array $relations Définir les relations pour le modèle
* https://docs.flightphp.com/awesome-plugins/active-record#relationships
*/
protected array $relations = [];
/**
* Constructeur
* @param mixed $databaseConnection La connexion à la base de données
*/
public function __construct($databaseConnection)
{
parent::__construct($databaseConnection, 'users');
}
}
Afficher Toutes les Routes
Cela affichera toutes les routes actuellement enregistrées avec Flight.
php runway routes
Si vous souhaitez uniquement visualiser des routes spécifiques, vous pouvez ajouter un drapeau pour filtrer les routes.
# Afficher uniquement les routes GET
php runway routes --get
# Afficher uniquement les routes POST
php runway routes --post
# etc.
Personnaliser Runway
Si vous êtes en train de créer un paquet pour Flight, ou si vous voulez ajouter vos propres commandes personnalisées dans votre projet, vous pouvez le faire en créant un répertoire src/commands/
, flight/commands/
, app/commands/
, ou commands/
pour votre projet/paquet.
Pour créer une commande, vous étendez simplement la classe AbstractBaseCommand
et implémentez au minimum une méthode __construct
et une méthode execute
.
<?php
declare(strict_types=1);
namespace flight\commands;
class ExampleCommand extends AbstractBaseCommand
{
/**
* Constructeur
*
* @param array<string,mixed> $config Config JSON de .runway-config.json
*/
public function __construct(array $config)
{
parent::__construct('make:example', 'Crée un exemple pour la documentation', $config);
$this->argument('<funny-gif>', 'Le nom du gif drôle');
}
/**
* Exécute la fonction
*
* @return void
*/
public function execute(string $controller)
{
$io = $this->app()->io();
$io->info('Création de l\'exemple...');
// Faites quelque chose ici
$io->ok('Exemple créé !');
}
}
Consultez la Documentation de adhocore/php-cli pour plus d'informations sur la façon de créer vos propres commandes personnalisées dans votre application Flight !
Awesome-plugins/tracy_extensions
Tracy Flight Panel Extensions
Il s'agit d'un ensemble d'extensions pour rendre le travail avec Flight un peu plus riche.
- Flight - Analyser toutes les variables de Flight.
- Database - Analyser toutes les requêtes qui ont été exécutées sur la page (si vous initialisez correctement la connexion à la base de données).
- Request - Analyser toutes les variables
$_SERVER
et examiner toutes les charges globales ($_GET
,$_POST
,$_FILES
). - Session - Analyser toutes les variables
$_SESSION
si les sessions sont actives.
C'est le panneau
Et chaque panneau affiche des informations très utiles sur votre application !
Cliquez ici pour voir le code.
Installation
Exécutez composer require flightphp/tracy-extensions --dev
et c'est parti !
Configuration
Il y a très peu de configuration à faire pour démarrer. Vous devrez initialiser le débogueur Tracy avant d'utiliser ceci https://tracy.nette.org/en/guide:
<?php
use Tracy\Debugger;
use flight\debug\tracy\TracyExtensionLoader;
// code d'amorçage
require __DIR__ . '/vendor/autoload.php';
Debugger::enable();
// Vous devrez peut-être spécifier votre environnement avec Debugger::enable(Debugger::DEVELOPMENT)
// si vous utilisez des connexions à la base de données dans votre application, il y a un
// wrapper PDO requis à utiliser UNIQUEMENT EN DÉVELOPPEMENT (pas en production s'il vous plaît !)
// Il a les mêmes paramètres qu'une connexion PDO normale
$pdo = new PdoQueryCapture('sqlite:test.db', 'user', 'pass');
// ou si vous attachez ceci au framework Flight
Flight::register('db', PdoQueryCapture::class, ['sqlite:test.db', 'user', 'pass']);
// maintenant à chaque fois que vous exécutez une requête, il capturera le temps, la requête et les paramètres
// Cela connecte les points
if(Debugger::$showBar === true) {
// Cela doit être faux sinon Tracy ne peut pas rendre correctement :(
Flight::set('flight.content_length', false);
new TracyExtensionLoader(Flight::app());
}
// plus de code
Flight::start();
Configuration Supplémentaire
Données de Session
Si vous avez un gestionnaire de session personnalisé (comme ghostff/session), vous pouvez passer n'importe quel tableau de données de session à Tracy et il l'affichera automatiquement pour vous. Vous le transmettez avec la clé session_data
dans le deuxième paramètre du constructeur TracyExtensionLoader
.
use Ghostff\Session\Session;
require 'vendor/autoload.php';
$app = Flight::app();
$app->register('session', Session::class);
if(Debugger::$showBar === true) {
// Cela doit être faux sinon Tracy ne peut pas rendre correctement :(
Flight::set('flight.content_length', false);
new TracyExtensionLoader(Flight::app(), [ 'session_data' => Flight::session()->getAll() ]);
}
// routes et autres choses...
Flight::start();
Latte
Si vous avez Latte installé dans votre projet, vous pouvez utiliser le panneau Latte pour analyser vos modèles. Vous pouvez transmettre l'instance de Latte au constructeur TracyExtensionLoader
avec la clé latte
dans le deuxième paramètre.
use Latte\Engine;
require 'vendor/autoload.php';
$app = Flight::app();
$app->register('latte', Engine::class, [], function($latte) {
$latte->setTempDirectory(__DIR__ . '/temp');
// c'est ici que vous ajoutez le panneau Latte à Tracy
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
});
if(Debugger::$showBar === true) {
// Cela doit être faux sinon Tracy ne peut pas rendre correctement :(
Flight::set('flight.content_length', false);
new TracyExtensionLoader(Flight::app());
}
Awesome-plugins/tracy
Tracy
Tracy est un gestionnaire d'erreurs incroyable qui peut être utilisé avec Flight. Il dispose de plusieurs panneaux qui peuvent vous aider à déboguer votre application. Il est également très facile à étendre et à ajouter vos propres panneaux. L'équipe de Flight a créé quelques panneaux spécifiquement pour les projets Flight avec le plugin flightphp/tracy-extensions.
Installation
Installez avec composer. Et vous voudrez en fait installer ceci sans la version dev car Tracy est livré avec un composant de gestion des erreurs de production.
composer require tracy/tracy
Configuration de base
Il existe quelques options de configuration de base pour commencer. Vous pouvez en savoir plus à leur sujet dans la Documentation de Tracy.
require 'vendor/autoload.php';
use Tracy\Debugger;
// Activer Tracy
Debugger::enable();
// Debugger::enable(Debugger::DEVELOPMENT) // parfois vous devez être explicite (également Debugger::PRODUCTION)
// Debugger::enable('23.75.345.200'); // vous pouvez également fournir un tableau d'adresses IP
// C'est là que les erreurs et exceptions seront journalisées. Assurez-vous que ce répertoire existe et est accessible en écriture.
Debugger::$logDirectory = __DIR__ . '/../log/';
Debugger::$strictMode = true; // afficher toutes les erreurs
// Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // toutes les erreurs sauf les avis obsolètes
if (Debugger::$showBar) {
$app->set('flight.content_length', false); // si la barre de débogage est visible, alors la longueur du contenu ne peut pas être définie par Flight
// Ceci est spécifique à l'extension Tracy pour Flight si vous l'avez incluse
// sinon mettez en commentaire.
new TracyExtensionLoader($app);
}
Conseils utiles
Lorsque vous déboguez votre code, il y a quelques fonctions très utiles pour afficher des données pour vous.
bdump($var)
- Cela affichera la variable dans la barre de Tracy dans un panneau séparé.dumpe($var)
- Cela affichera la variable puis s'arrêtera immédiatement.
Awesome-plugins/active_record
Flight Active Record
Un enregistrement actif est une cartographie d'une entité de base de données à un objet PHP. En d'autres termes, si vous avez une table utilisateurs dans votre base de données, vous pouvez "traduire" une ligne dans cette table en une classe User
et un objet $user
dans votre code. Voir exemple de base.
Cliquez ici pour le dépôt sur GitHub.
Exemple de Base
Assumons que vous ayez la table suivante :
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
password TEXT
);
Maintenant, vous pouvez configurer une nouvelle classe pour représenter cette table :
/**
* Une classe ActiveRecord est généralement singulière
*
* Il est fortement recommandé d'ajouter ici les propriétés de la table en tant que commentaires
*
* @property int $id
* @property string $name
* @property string $password
*/
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
// vous pouvez le définir 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 devriez probablement utiliser une vraie connexion à une 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 création non basée sur des objets
$database_connection = mysqli_connect('localhost', 'username', 'password', 'test_db');
$user = new User($database_connection);
$user->name = 'Bobby Tables';
$user->password = password_hash('some cool password');
$user->insert();
// ou $user->save();
echo $user->id; // 1
$user->name = 'Joseph Mamma';
$user->password = password_hash('some cool password again!!!');
$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 que cela 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); // trouver id = 1 dans la base de données et le renvoyer.
echo $user->name; // 'Bobby Tables'
Et que se passe-t-il si vous souhaitez trouver tous les utilisateurs ?
$users = $user->findAll();
Que dire d'une certaine condition ?
$users = $user->like('name', '%mamma%')->findAll();
Voyez comme c'est amusant ? Installons-le et commençons !
Installation
Il suffit d'installer avec Composer
composer require flightphp/active-record
Usage
Cela peut être utilisé comme une bibliothèque autonome ou avec le Framework PHP Flight. Complètement à vous de choisir.
Autonome
Il suffit de vous assurer que vous passez une connexion PDO au constructeur.
$pdo_connection = new PDO('sqlite:test.db'); // ceci est juste un exemple, vous devriez probablement utiliser une vraie connexion à une base de données
$User = new User($pdo_connection);
Vous ne voulez pas toujours définir votre connexion à la base de données dans le constructeur ? Consultez Gestion des Connexions à la Base de Données pour d'autres idées !
Enregistrer en tant que méthode dans Flight
Si vous utilisez le Framework PHP Flight, vous pouvez enregistrer la classe ActiveRecord en tant que service, mais vous n'êtes vraiment 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);
Méthodes runway
runway est un outil CLI pour Flight qui a une commande personnalisée pour cette bibliothèque.
# Usage
php runway make:record database_table_name [class_name]
# Exemple
php runway make:record users
Cela créera une nouvelle classe dans le répertoire app/records/
sous le nom UserRecord.php
avec le contenu suivant :
<?php
declare(strict_types=1);
namespace app\records;
/**
* Classe ActiveRecord pour la table des utilisateurs.
* @link https://docs.flightphp.com/awesome-plugins/active-record
*
* @property int $id
* @property string $username
* @property string $email
* @property string $password_hash
* @property string $created_dt
*/
class UserRecord extends \flight\ActiveRecord
{
/**
* @var array $relations Définir les relations pour le modèle
* https://docs.flightphp.com/awesome-plugins/active-record#relationships
*/
protected array $relations = [
// 'relation_name' => [ self::HAS_MANY, 'RelatedClass', 'foreign_key' ],
];
/**
* Constructeur
* @param mixed $databaseConnection La connexion à la base de données
*/
public function __construct($databaseConnection)
{
parent::__construct($databaseConnection, 'users');
}
}
Fonctions CRUD
find($id = null) : boolean|ActiveRecord
Trouver un enregistrement et l'assigner à l'objet actuel. Si vous passez un $id
de quelque nature que ce soit, il 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)
Retourne true
si l'enregistrement actuel a été hydraté (récupéré de la base de données).
$user->find(1);
// si un enregistrement est trouvé avec des données...
$user->isHydrated(); // true
insert(): boolean|ActiveRecord
Insère l'enregistrement actuel dans la base de données.
$user = new User($pdo_connection);
$user->name = 'demo';
$user->password = md5('demo');
$user->insert();
Clés Primaires Basées sur du Texte
Si vous avez une clé primaire basée sur du texte (comme un UUID), vous pouvez définir la valeur de la clé primaire avant d'insérer de deux manières.
$user = new User($pdo_connection, [ 'primaryKey' => 'uuid' ]);
$user->uuid = 'some-uuid';
$user->name = 'demo';
$user->password = md5('demo');
$user->insert(); // ou $user->save();
ou vous pouvez laisser la clé primaire être générée automatiquement pour vous via des événements.
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users', [ 'primaryKey' => 'uuid' ]);
// vous pouvez également définir la primaryKey de cette manière au lieu de l'array ci-dessus.
$this->primaryKey = 'uuid';
}
protected function beforeInsert(self $self) {
$self->uuid = uniqid(); // ou comme vous avez besoin de générer vos identifiants uniques
}
}
Si vous ne définissez pas la clé primaire avant d'insérer, elle sera définie sur le rowid
et la
base de données la générera pour vous, mais elle ne sera pas persistante car ce champ peut ne pas exister
dans votre table. C'est pourquoi il est recommandé d'utiliser l'événement pour gérer cela automatiquement.
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 id, il sera mis à jour, sinon il sera inséré.
$user = new User($pdo_connection);
$user->name = 'demo';
$user->password = md5('demo');
$user->save();
Remarque : Si vous avez des relations définies dans la classe, elles seront sauvegardées de manière récursive si elles ont été définies, instanciées et ont des données "sales" à mettre à jour. (v0.4.0 et plus)
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 réfèrent 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'email est considéré comme "sale" puisqu'il a changé.
$user->update();
// maintenant il n'y a pas de données qui sont sales car elles ont été mises à jour et persistées dans la base de données
$user->password = password_hash()'newpassword'); // 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 sale.
$user->dirty([ 'name' => 'something', 'password' => password_hash('a different password') ]);
$user->update(); // à la fois le nom et le mot de passe sont mis à jour.
copyFrom(array $data): ActiveRecord
(v0.4.0)
Ceci est un alias pour la méthode dirty()
. C'est un peu plus clair ce que vous faites.
$user->copyFrom([ 'name' => 'something', 'password' => password_hash('a different password') ]);
$user->update(); // à la fois le nom et le mot de passe sont mis à jour.
isDirty(): boolean
(v0.4.0)
Retourne true
si l'enregistrement actuel a été modifié.
$user->greaterThan('id', 0)->orderBy('id desc')->find();
$user->email = 'test@email.com';
$user->isDirty(); // true
reset(bool $include_query_data = true): ActiveRecord
Réinitialise l'enregistrement actuel à son état initial. C'est vraiment bon à utiliser dans des comportements de type boucle.
Si vous passez true
, il réinitialisera également les données de 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(); // commencez avec une ardoise propre
$user_company->user_id = $user->id;
$user_company->company_id = $some_company_id;
$user_company->insert();
}
getBuiltSql(): string
(v0.4.1)
Après avoir exécuté une méthode find()
, findAll()
, insert()
, update()
ou save()
, vous pouvez obtenir le SQL qui a été construit et l'utiliser à des fins de débogage.
Méthodes de Requête SQL
select(string $field1 [, string $field2 ... ])
Vous pouvez sélectionner uniquement quelques-unes des colonnes d'une table si vous le souhaitez (c'est plus performant sur des tables très larges avec de nombreuses colonnes)
$user->select('id', 'name')->find();
from(string $table)
Vous pouvez techniquement choisir une autre table aussi ! Pourquoi pas ?!
$user->select('id', 'name')->from('user')->find();
join(string $table_name, string $join_condition)
Vous pouvez même joindre à une autre table dans la base de données.
$user->join('contacts', 'contacts.user_id = users.id')->find();
where(string $where_conditions)
Vous pouvez définir quelques arguments where personnalisés (vous ne pouvez pas définir de paramètres dans cette déclaration where)
$user->where('id=1 AND name="demo"')->find();
Remarque de Sécurité - Vous pourriez être tenté de faire quelque chose comme $user->where("id = '{$id}' AND name = '{$name}'")->find();
. S'il vous plaît, NE FAITES PAS CELA !!! Cela est susceptible de ce qu'on appelle des attaques par injection SQL. Il existe de nombreux articles en ligne, s'il vous plaît recherchez "sql injection attacks php" et vous trouverez beaucoup d'articles sur ce sujet. La manière appropriée de gérer cela avec cette bibliothèque est qu'au lieu de cette méthode where()
, vous feriez quelque chose de plus comme $user->eq('id', $id)->eq('name', $name)->find();
Si vous devez absolument faire cela, la bibliothèque PDO
a $pdo->quote($var)
pour l'échapper pour vous. Ce n'est qu'après avoir utilisé quote()
que vous pouvez l'utiliser dans une déclaration where()
.
group(string $group_by_statement)/groupBy(string $group_by_statement)
Groupez 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)
Trier la requête retournée d'une certaine manière.
$user->orderBy('name DESC')->find();
limit(string $limit)/limit(int $offset, int $limit)
Limitez le nombre d'enregistrements retournés. Si un second int est donné, il sera décalé, limite tout comme en SQL.
$user->orderby('name DESC')->limit(0, 10)->findAll();
CONDITIONS WHERE
equal(string $field, mixed $value) / eq(string $field, mixed $value)
Où field = $value
$user->eq('id', 1)->find();
notEqual(string $field, mixed $value) / ne(string $field, mixed $value)
Où field <> $value
$user->ne('id', 1)->find();
isNull(string $field)
Où field IS NULL
$user->isNull('id')->find();
isNotNull(string $field) / notNull(string $field)
Où field IS NOT NULL
$user->isNotNull('id')->find();
greaterThan(string $field, mixed $value) / gt(string $field, mixed $value)
Où field > $value
$user->gt('id', 1)->find();
lessThan(string $field, mixed $value) / lt(string $field, mixed $value)
Où field < $value
$user->lt('id', 1)->find();
greaterThanOrEqual(string $field, mixed $value) / ge(string $field, mixed $value) / gte(string $field, mixed $value)
Où field >= $value
$user->ge('id', 1)->find();
lessThanOrEqual(string $field, mixed $value) / le(string $field, mixed $value) / lte(string $field, mixed $value)
Où field <= $value
$user->le('id', 1)->find();
like(string $field, mixed $value) / notLike(string $field, mixed $value)
Où field LIKE $value
ou field NOT LIKE $value
$user->like('name', 'de')->find();
in(string $field, array $values) / notIn(string $field, array $values)
Où field IN($value)
ou field NOT IN($value)
$user->in('id', [1, 2])->find();
between(string $field, array $values)
Où field BETWEEN $value AND $value1
$user->between('id', [1, 2])->find();
Conditions OR
Il est possible d'envelopper vos conditions dans une déclaration OR. Cela se fait soit avec les méthodes startWrap()
et endWrap()
, soit en remplissant le 3ème paramètre de la condition après le champ et la valeur.
// Méthode 1
$user->eq('id', 1)->startWrap()->eq('name', 'demo')->or()->eq('name', 'test')->endWrap('OR')->find();
// Cela s'évaluera à `id = 1 AND (name = 'demo' OR name = 'test')`
// Méthode 2
$user->eq('id', 1)->eq('name', 'demo', 'OR')->find();
// Cela s'évaluera à `id = 1 OR name = 'demo'`
Relations
Vous pouvez définir plusieurs types de relations à l'aide de cette bibliothèque. Vous pouvez établir des relations un->plusieurs et un->un entre des 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 bon vous semble. Le nom de l'ActiveRecord est probablement bon. Ex : user, contact, client
'user' => [
// requis
// self::HAS_MANY, self::HAS_ONE, self::BELONGS_TO
self::HAS_ONE, // c'est le type de relation
// requis
'Some_Class', // c'est la classe ActiveRecord "autre" à laquelle cela fera référence
// requis
// selon le type de relation
// self::HAS_ONE = la clé étrangère qui référence la jointure
// self::HAS_MANY = la clé étrangère qui référence la jointure
// self::BELONGS_TO = la clé locale qui référence la jointure
'local_or_foreign_key',
// juste pour info, cela ne joint également qu'à 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 à elle-même Ex : $user->contact->user;
];
]
class User extends ActiveRecord{
protected array $relations = [
'contacts' => [ self::HAS_MANY, Contact::class, 'user_id' ],
'contact' => [ self::HAS_ONE, Contact::class, 'user_id' ],
];
public function __construct($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, nous avons les références configurées afin que nous puissions 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 les 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; // c'est le nom de l'utilisateur
Assez cool, non ?
Définir des Données Personnalisées
Parfois, vous pourriez avoir besoin d'attacher quelque chose d'unique à votre ActiveRecord, comme un calcul personnalisé qui serait plus facile à 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('page_view_count', $page_view_count);
Et ensuite, vous le référencez simplement comme une propriété d'objet normale.
echo $user->page_view_count;
Événements
Une autre fonctionnalité super géniale de cette bibliothèque concerne les événements. Les événements sont déclenchés à certains moments en fonction de certaines méthodes que vous appelez. Ils sont très utiles pour vous aider à configurer des données automatiquement.
onConstruct(ActiveRecord $ActiveRecord, array &config)
Cela est vraiment utile si vous avez besoin de définir une connexion par défaut ou quelque chose comme cela.
// 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 cela pour définir automatiquement la connexion
$config['connection'] = 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($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeFind(self $self) {
// toujours exécuter id >= 0 si c'est votre truc
$self->gte('id', 0);
}
}
afterFind(ActiveRecord $ActiveRecord)
Celui-ci est probablement plus utile si vous devez toujours exécuter une logique chaque fois que cet enregistrement est récupéré. Avez-vous besoin de déchiffrer quelque chose ? Avez-vous besoin d'exécuter une requête de comptage personnalisée chaque fois (pas performant mais peu importe) ?
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function afterFind(self $self) {
// déchiffrer quelque chose
$self->secret = yourDecryptFunction($self->secret, $some_key);
// peut-être stocker quelque chose de personnalisé, comme une requête ???
$self->setCustomData('view_count', $self->select('COUNT(*) count')->from('user_views')->eq('user_id', $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($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeFindAll(self $self) {
// toujours exécuter id >= 0 si c'est votre truc
$self->gte('id', 0);
}
}
afterFindAll(array<int,ActiveRecord> $results)
Semblable à afterFind()
mais vous pouvez le faire pour tous les enregistrements à la place !
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function afterFindAll(array $results) {
foreach($results as $self) {
// faites quelque chose de cool comme aprèsFind()
}
}
}
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($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeInsert(self $self) {
// définissez des 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 que vous avez un cas d'utilisation pour changer des données après leur insertion ?
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function afterInsert(self $self) {
// vous faites comme bon vous semble
Flight::cache()->set('most_recent_insert_id', $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 fois qu'une mise à jour a lieu.
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeInsert(self $self) {
// définir des valeurs par défaut
if(!$self->updated_date) {
$self->updated_date = gmdate('Y-m-d');
}
}
}
afterUpdate(ActiveRecord $ActiveRecord)
Peut-être que vous avez un cas d'utilisation pour changer des données après qu'elles aient été mises à jour ?
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function afterInsert(self $self) {
// vous faites comme bon vous semble
Flight::cache()->set('most_recently_updated_user_id', $self->id);
// ou quoi que ce soit d'autre....
}
}
beforeSave(ActiveRecord $ActiveRecord)/afterSave(ActiveRecord $ActiveRecord)
Ceci est utile si vous souhaitez que des événements se produisent lorsque des insertions ou des mises à jour ont lieu. Je vous épargne une longue explication, mais je suis sûr que vous pouvez deviner ce que c'est.
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeSave(self $self) {
$self->last_updated = 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 jugement ! Foncez !
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeDelete(self $self) {
echo 'Il était un brave soldat... :cry-face:';
}
}
Gestion des Connexions à la Base de Données
Lorsque vous utilisez cette bibliothèque, vous pouvez définir 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['connection']
ou vous pouvez la définir via setDatabaseConnection()
(v0.4.1).
$pdo_connection = new PDO('sqlite:test.db'); // par exemple
$user = new User($pdo_connection);
// ou
$user = new User(null, [ 'connection' => $pdo_connection ]);
// ou
$user = new User();
$user->setDatabaseConnection($pdo_connection);
Si vous souhaitez éviter de toujours définir un $database_connection
chaque fois que vous appelez un enregistrement actif, il existe des moyens d'y parvenir !
// index.php ou bootstrap.php
// Réglez cela en tant que classe enregistrée dans Flight
Flight::register('db', 'PDO', [ 'sqlite:test.db' ]);
// User.php
class User extends flight\ActiveRecord {
public function __construct(array $config = [])
{
$database_connection = $config['connection'] ?? Flight::db();
parent::__construct($database_connection, 'users', $config);
}
}
// Et maintenant, aucun argument requis !
$user = new User();
Remarque : Si vous prévoyez des tests unitaires, faire de cette façon peut ajouter quelques défis aux tests unitaires, mais globalement parce que vous pouvez injecter votre connexion avec
setDatabaseConnection()
ou$config['connection']
, cela n'est pas trop mauvais.
Si vous devez rafraîchir la connexion à la base de données, par exemple si vous exécutez un script CLI longue durée et devez rafraîchir la connexion de temps en temps, vous pouvez réinitialiser la connexion avec $your_record->setDatabaseConnection($pdo_connection)
.
Contribuer
S'il vous plaît le faire. :D
Configuration
Lorsque vous contribuez, assurez-vous d'exécuter composer test-coverage
pour maintenir une couverture de test de 100 % (ceci n'est pas une véritable couverture de test unitaire, plus comme un test d'intégration).
Assurez-vous également d'exécuter composer beautify
et composer phpcs
pour corriger les erreurs de linting.
Licence
MIT
Awesome-plugins/latte
Latte
Latte est un moteur de templates complet qui est très facile à utiliser et se rapproche plus d'une syntaxe PHP que Twig ou Smarty. Il est également très facile à étendre et à ajouter vos propres filtres et fonctions.
Installation
Installez avec composer.
composer require latte/latte
Configuration de base
Il existe quelques options de configuration de base pour démarrer. Vous pouvez en savoir plus à leur sujet dans la Documentation de Latte.
use Latte\Engine as LatteEngine;
require 'vendor/autoload.php';
$app = Flight::app();
$app->register('latte', LatteEngine::class, [], function(LatteEngine $latte) use ($app) {
// C'est ici que Latte mettra en cache vos templates pour accélérer les choses
// Une chose intéressante à propos de Latte est qu'il rafraîchira automatiquement votre
// cache lorsque vous apportez des modifications à vos templates !
$latte->setTempDirectory(__DIR__ . '/../cache/');
// Indiquez à Latte où se trouvera le répertoire racine pour vos vues.
// $app->get('flight.views.path') est défini dans le fichier config.php
// Vous pourriez également simplement faire quelque chose comme `__DIR__ . '/../views/'`
$latte->setLoader(new \Latte\Loaders\FileLoader($app->get('flight.views.path')));
});
Exemple de mise en page simple
Voici un exemple simple d'un fichier de mise en page. C'est le fichier qui sera utilisé pour envelopper toutes vos autres vues.
<!-- app/views/layout.latte -->
<!doctype html>
<html lang="en">
<head>
<title>{$title ? $title . ' - '}Mon application</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<nav>
<!-- vos éléments de navigation ici -->
</nav>
</header>
<div id="content">
<!-- C'est là que se trouve la magie -->
{block content}{/block}
</div>
<div id="footer">
© Droits d'auteur
</div>
</body>
</html>
Et maintenant nous avons votre fichier qui va être rendu à l'intérieur de ce bloc de contenu :
<!-- app/views/home.latte -->
<!-- Ceci indique à Latte que ce fichier est "à l'intérieur" du fichier layout.latte -->
{extends layout.latte}
<!-- C'est le contenu qui sera rendu à l'intérieur du layout à l'intérieur du block de contenu -->
{block content}
<h1>Page d'accueil</h1>
<p>Bienvenue dans mon application !</p>
{/block}
Ensuite, lorsque vous allez rendre ceci à l'intérieur de votre fonction ou contrôleur, vous feriez quelque chose comme ceci :
// itinéraire simple
Flight::route('/', function () {
Flight::latte()->render('home.latte', [
'title' => 'Page d'accueil'
]);
});
// ou si vous utilisez un contrôleur
Flight::route('/', [HomeController::class, 'index']);
// HomeController.php
class HomeController
{
public function index()
{
Flight::latte()->render('home.latte', [
'title' => 'Page d'accueil'
]);
}
}
Consultez la Documentation de Latte pour plus d'informations sur comment utiliser Latte à son plein potentiel!
Awesome-plugins/awesome_plugins
Plugins incroyables
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 supportés par l'équipe Flight et d'autres sont des bibliothèques micro/légères pour vous aider à démarrer.
Documentation API
La documentation API est cruciale pour toute API. Elle aide les développeurs à comprendre comment interagir avec votre API et ce à quoi s'attendre en retour. Il existe quelques outils disponibles pour vous aider à générer de la documentation API pour vos projets Flight.
- FlightPHP OpenAPI Generator - Article de blog écrit par Daniel Schreiber sur l'utilisation de la spécification OpenAPI avec FlightPHP pour construire votre API en utilisant une approche API first.
- SwaggerUI - Swagger UI est un excellent outil pour vous aider à générer de la documentation API pour vos projets Flight. Il est très facile à utiliser et peut être personnalisé pour répondre à vos besoins. C'est la bibliothèque PHP pour vous aider à générer la documentation Swagger.
Authentification/Autorisation
L'authentification et l'autorisation sont cruciales pour toute application qui nécessite des contrôles en place sur qui peut accéder à quoi.
- officiel flightphp/permissions - Bibliothèque officielle des autorisations Flight. Cette bibliothèque est un moyen simple d'ajouter des autorisations au niveau des utilisateurs et des applications à votre application.
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.
- officiel flightphp/cache - Classe de mise en cache PHP simple, légère et autonome dans le fichier.
CLI
Les applications CLI sont un excellent moyen d'interagir avec votre application. Vous pouvez les utiliser pour générer des contrôleurs, afficher toutes les routes, et plus encore.
- officiel flightphp/runway - Runway est une application CLI qui vous aide à gérer vos applications Flight.
Cookies
Les cookies sont un excellent moyen de stocker des petites quantités de données côté client. Ils peuvent être utilisés pour stocker les préférences des utilisateurs, les paramètres de l'application, et plus encore.
- overclokk/cookie - PHP Cookie est une bibliothèque PHP qui fournit un moyen simple et efficace de gérer les cookies.
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.
- tracy/tracy - C'est un gestionnaire d'erreurs complet qui peut être utilisé avec Flight. Il possède un certain nombre de panneaux qui peuvent vous aider à déboguer votre application. Il est également très facile à étendre et à ajouter vos propres panneaux.
- flightphp/tracy-extensions - Utilisé avec le gestionnaire d'erreurs Tracy, ce plugin ajoute quelques panneaux supplémentaires pour aider au débogage spécifiquement pour les projets Flight.
Bases de données
Les bases de données sont au cœur de la plupart des applications. C'est ainsi que vous stockez et récupérez des données. Certaines bibliothèques de bases de données sont simplement des wrappers pour écrire des requêtes et d'autres sont des ORM complets.
- officiel flightphp/core PdoWrapper - Wrapper PDO officiel de Flight qui fait partie du cœur. C'est un simple wrapper pour simplifier le processus d'écriture et d'exécution des requêtes. Ce n'est pas un ORM.
- officiel flightphp/active-record - ORM/Mapper ActiveRecord officiel de Flight. Excellente petite bibliothèque pour récupérer et stocker facilement des données dans votre base de données.
- byjg/php-migration - Plugin pour garder une trace de tous les changements de base de données pour votre projet.
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 l'engager dans votre dépôt de code.
- defuse/php-encryption - C'est une bibliothèque qui peut être utilisée pour chiffrer et déchiffrer des données. Commencer à la configurer est assez simple pour commencer à chiffrer et déchiffrer des données.
File d'attente de tâches
Les files d'attente de tâches sont très utiles pour traiter des tâches de manière asynchrone. Cela peut être l'envoi d'e-mails, le traitement d'images, ou tout ce qui n'a pas besoin d'être fait en temps réel.
- n0nag0n/simple-job-queue - Simple Job Queue est une bibliothèque qui peut être utilisée pour traiter des tâches de manière asynchrone. Elle peut être utilisée avec beanstalkd, MySQL/MariaDB, SQLite et PostgreSQL.
Session
Les sessions ne sont pas vraiment utiles pour les API, mais pour construire une application web, les sessions peuvent être cruciales pour maintenir l'état et les informations de connexion.
- officiel flightphp/session - Bibliothèque de session officielle de Flight. C'est une bibliothèque de session simple qui peut être utilisée pour stocker et récupérer les données de session. Elle utilise la gestion des sessions intégrée de PHP.
- Ghostff/Session - Gestionnaire de session PHP (non-bloquant, flash, segment, chiffrement de session). Utilise open_ssl de PHP pour le chiffrement/déchiffrement optionnel des données de session.
Modèle
Le modèle est au cœur de toute application web avec une interface utilisateur. Il existe un certain nombre de moteurs de modèles qui peuvent être utilisés avec Flight.
- déprécié flightphp/core View - C'est un moteur de modèle très basique qui fait partie du cœur. Il n'est pas recommandé de l'utiliser si vous avez plus de quelques pages dans votre projet.
- latte/latte - Latte est un moteur de modèle complet qui est très facile à utiliser et se rapproche d'une syntaxe PHP par rapport à Twig ou Smarty. Il est également très facile à étendre et à ajouter vos propres filtres et fonctions.
Contribuer
Vous avez un plugin que vous aimeriez partager ? Soumettez une demande de tirage pour l'ajouter à la liste !
Media
Média
Nous avons essayé de rassembler ce que nous pouvons des différents types de médias autour d'internet concernant Flight. Voir ci-dessous pour différentes ressources que vous pouvez utiliser pour en savoir plus sur Flight.
Articles et Écrits
- Définir, Générer et Implémenter : Une approche API-first avec OpenAPI Generator et FlightPHP par Daniel Schreiber (2025)
- Meilleurs Micro Frameworks PHP pour 2024 par n0nag0n (2024)
- Créer une API RESTful avec le framework Flight par n0nag0n (2024)
- Créer un blog simple avec Flight Partie 2 par n0nag0n (2024)
- Créer un blog simple avec Flight Partie 1 par n0nag0n (2024)
- 🚀 Créer une API CRUD simple en PHP avec le framework Flight par soheil-khaledabadi (2024)
- Créer une application web PHP avec le micro-framework Flight par Arthur C. Codex (2023)
- Meilleurs Frameworks PHP pour le développement web en 2024 par Ravikiran A S (2023)
- Top 12 Frameworks PHP : Un guide complet pour 2023 par marketing kbk (2023)
- 5 Frameworks PHP que vous n'avez (probablement) jamais entendus par n0nag0n (2022)
- 12 meilleurs frameworks PHP pour les développeurs web à considérer en 2023 par Anna Monus (2022)
- Les meilleurs microframeworks PHP sur un serveur cloud par Shahzeb Ahmed (2021)
- Framework PHP : Top 15 des plus puissants pour votre développement web par AHT Tech (2020)
- Routing PHP facile avec FlightPHP par Lucas Conceição (2019)
- Essayer un nouveau framework PHP (Flight) par Leon (2017)
- Configurer FlightPHP pour travailler avec Backbonejs par Timothy Tocci (2015)
Vidéos et Tutoriels
- Créer une API REST pour les dispositifs IoT utilisant PHP & FlightPHP - API ESP32 par IoT Craft Hub (2024)
- Vidéo d'introduction simple au framework PHP Flight par n0nag0n (2024)
- Définir le code HTTP d'en-tête dans Flightphp (3 solutions !!) par Roel Van de Paar (2024)
- Tutoriel sur le framework PHP Flight. Projet API super facile ! par n0nag0n (2022)
- Application web CRUD avec php et mysql et bootstrap utilisant flight par Devlopteca - Oscar Uh (2021)
- DevOps & SysAdmins : Règle de réécriture lighttpd pour le microframework Flight PHP par Roel Van de Paar (2021)
- Tutoriel API REST Flight PHP #PART2 INSÉRER TABLE Info #Code (Tagalog) par Info Singkat Official (2020)
- Tutoriel API REST Flight PHP #PART1 Info #Code (Tagalog) par Info Singkat Official (2020)
- Comment créer une API REST JSON en PHP - Partie 2 par Codewife (2018)
- Comment créer une API REST JSON en PHP - Partie 1 par Codewife (2018)
- Teste des micro frameworks PHP - Flight PHP, Lumen, Slim 3 et Laravel par Codemarket (2016)
- Tutoriel 1 Flight PHP - Installation par absagg (2014)
- Tutoriel 2 Flight PHP - Route partie 1 par absagg (2014)
Examples
Besoin d'un démarrage rapide ?
Vous avez deux options pour commencer un nouveau projet Flight :
- Boilerplate Complet : Un exemple plus complet avec des contrôleurs et des vues.
- Boilerplate à Fichier Unique : Un fichier unique qui comprend tout ce dont vous avez besoin pour exécuter votre application dans un seul fichier simple.
Exemples fournis par la communauté :
- flightravel : FlightPHP avec des répertoires Laravel, avec des outils PHP + GH Actions
- fleact - Un kit de démarrage FlightPHP avec intégration ReactJS.
- flastro - Un kit de démarrage FlightPHP avec intégration Astro.
- velt - Velt est un modèle de démarrage Svelte rapide et facile avec un backend FlightPHP.
Besoin d'inspiration ?
Bien que ceux-ci ne soient pas officiellement sponsorisés par l'équipe Flight, ils pourraient vous donner des idées sur la façon de structurer vos propres projets construits avec Flight !
- Decay - Flight v3 avec HTMX et SleekDB, tout sur les zombies ! (Démo)
- Blog d'exemple Flight - Flight v3 avec Middleware, Contrôleurs, Active Record et Latte.
- Flight CRUD API RESTful - Projet API CRUD simple utilisant le framework Flight, qui fournit une structure de base pour que les nouveaux utilisateurs puissent rapidement configurer une application PHP avec des opérations CRUD et une connectivité à la base de données. Le projet démontre comment utiliser Flight pour le développement d'API RESTful, en faisant un outil d'apprentissage idéal pour les débutants et un kit de démarrage utile pour les développeurs plus expérimentés.
- Système de Gestion d'École Flight - Flight v3
- Paste Bin avec Commentaires - Flight v3
- Application de Base Skeleton
- Wiki d'Exemple
- L'Application du Framework PHP IT-Innovator
- LittleEducationalCMS (Espagnol)
- API des Pages Jaunes Italiennes
- Système de Gestion de Contenu Générique (avec....très peu de documentation)
- Un petit framework php basé sur Flight et medoo.
- Application MVC Exemple
Voulez-vous partager votre propre exemple ?
Si vous avez un projet que vous souhaitez partager, veuillez soumettre une demande de tirage pour l'ajouter à cette liste !
Install/install
Installation
Téléchargement des fichiers
Assurez-vous d'avoir PHP installé sur votre système. Sinon, cliquez ici pour obtenir des instructions sur la façon de l'installer pour votre système.
Si vous utilisez Composer, vous pouvez exécuter la commande suivante:
composer require flightphp/core
OU vous pouvez télécharger les fichiers directement et les extraire dans votre répertoire Web.
Configurez votre serveur Web
Serveur de développement PHP intégré
C'est de loin la manière la plus simple de démarrer. Vous pouvez utiliser le serveur intégré pour exécuter votre application et même utiliser SQLite pour une base de données (tant que sqlite3 est installé sur votre système) et ne nécessitez pas grand-chose ! Exécutez simplement la commande suivante une fois PHP installé:
php -S localhost:8000
Ensuite, ouvrez votre navigateur et allez à http://localhost:8000
.
Si vous souhaitez rendre le répertoire de documents de votre projet dans un répertoire différent (Ex: votre projet est ~/myproject
, mais votre répertoire de documents est ~/myproject/public/
), vous pouvez exécuter la commande suivante une fois dans le répertoire ~/myproject
:
php -S localhost:8000 -t public/
Ensuite, ouvrez votre navigateur et allez à http://localhost:8000
.
Apache
Assurez-vous qu'Apache est déjà installé sur votre système. Sinon, recherchez comment installer Apache sur votre système.
Pour Apache, éditez votre fichier .htaccess
avec ce qui suit:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
Remarque: Si vous avez besoin d'utiliser Flight dans un sous-répertoire, ajoutez la ligne
RewriteBase /sous-repertoire/
juste aprèsRewriteEngine On
.Remarque: Si vous souhaitez protéger tous les fichiers du serveur, comme un fichier de base de données ou un fichier env. Mettez ceci dans votre fichier
.htaccess
:
RewriteEngine On
RewriteRule ^(.*)$ index.php
Nginx
Assurez-vous que Nginx est déjà installé sur votre système. Sinon, recherchez comment installer Nginx sur votre système.
Pour Nginx, ajoutez ce qui suit à la déclaration de votre serveur:
server {
location / {
try_files $uri $uri/ /index.php;
}
}
Créez votre fichier index.php
<?php
// Si vous utilisez Composer, requirez l'autoloader.
require 'vendor/autoload.php';
// si vous n'utilisez pas Composer, chargez le framework directement
// require 'flight/Flight.php';
// Ensuite, définissez une route et attribuez une fonction pour gérer la requête.
Flight::route('/', function () {
echo 'bonjour le monde!';
});
// Enfin, démarrez le framework.
Flight::start();
Installation de PHP
Si vous avez déjà php
installé sur votre système, passez ces instructions et passez à la section de téléchargement
Bien sûr ! Voici les instructions pour installer PHP sur macOS, Windows 10/11, Ubuntu et Rocky Linux. Je vais également inclure des détails sur l'installation de différentes versions de PHP.
Guides
Guides
Flight PHP est conçu pour être simple mais puissant, et nos guides vous aideront à construire des applications du monde réel étape par étape. Ces tutoriels pratiques vous accompagnent à travers des projets complets pour démontrer comment Flight peut être utilisé efficacement.
Official Guides
Building a Blog
Apprenez à créer une application de blog fonctionnelle avec Flight PHP. Ce guide vous accompagne à travers :
- Mise en place d'une structure de projet
- Travail avec des modèles utilisant Latte
- Implémentation de routes pour les articles
- Stockage et récupération de données
- Gestion des soumissions de formulaires
- Gestion des erreurs de base
Ce tutoriel est parfait pour les débutants qui veulent voir comment toutes les pièces s'assemblent dans une application réelle.
Unofficial Guides
Bien que ces guides ne soient pas officiellement maintenus par l'équipe de Flight, ils constituent des ressources précieuses créées par la communauté. Ils couvrent divers sujets et cas d'utilisation, fournissant des informations supplémentaires sur l'utilisation de Flight PHP.
Creating a RESTful API with Flight Framework
Ce guide vous accompagne dans la création d'une API RESTful en utilisant le framework Flight PHP. Il couvre les bases de la mise en place d'une API, de la définition des routes et du retour de réponses JSON.
Building a Simple Blog
Ce guide vous accompagne dans la création d'un blog basique en utilisant le framework Flight PHP. Il se compose en fait de 2 parties : l'une pour couvrir les bases et l'autre pour aborder des sujets plus avancés et des améliorations pour un blog prêt pour la production.
- Building a Simple Blog with Flight - Part 1 - Commencer avec un blog simple.
- Building a Simple Blog with Flight - Part 2 - Perfectionner le blog pour la production.
Building a Pokémon API in PHP: A Beginner's Guide
Ce guide amusant vous accompagne dans la création d'une API Pokémon simple en utilisant Flight PHP. Il couvre les bases de la mise en place d'une API, de la définition des routes et du retour de réponses JSON.
Contributing
Vous avez une idée de guide ? Vous avez trouvé une erreur ? Nous accueillons les contributions ! Nos guides sont maintenus dans le dépôt de documentation FlightPHP.
Si vous avez construit quelque chose d'intéressant avec Flight et que vous souhaitez le partager sous forme de guide, veuillez soumettre une demande de tirage. Partager vos connaissances aide la communauté Flight à grandir.
Looking for API Documentation?
Si vous cherchez des informations spécifiques sur les fonctionnalités et les méthodes de base de Flight, consultez la section Apprendre de notre documentation.