Flight — це швидкий, простий, розширювальний фреймінг для PHP. Він досить універсальний і може використовуватися для створення будь-якого типу веб-додатків. Він створений з фокусом на простоту і написаний так, що його легко зрозуміти та використовувати.
Ось коротка стаття про те, чому ви повинні використовувати фреймворк. Це хороша ідея зрозуміти переваги використання фреймворку перед тим, як почати його використовувати.
Додатково, відмінний підручник був створений @lubiana. Хоча він не заглиблюється в деталі щодо Flight, ця інструкція допоможе вам зрозуміти деякі основні концепції, що оточують фреймворк, і чому їх вигідно використовувати. Ви можете знайти підручник тут.
Якщо ви мігруєте з іншого фреймворку, наприклад Laravel, Slim, Fat-Free або Symfony до Flight, ця сторінка допоможе вам зрозуміти відмінності між двома.
Дізнайтеся, як автозавантажити свої власні класи у вашому додатку.
Дізнайтеся, як управляти маршрутами для вашого веб-додатку. Це також включає групування маршрутів, параметри маршрутів і посередників.
Дізнайтеся, як використовувати посередників для фільтрації запитів і відповідей у вашому додатку.
Дізнайтеся, як обробляти запити та відповіді у вашому додатку.
Дізнайтеся, як надсилати відповіді вашим користувачам.
Дізнайтеся, як використовувати вбудований механізм подання для рендерингу ваших HTML шаблонів.
Дізнайтеся, як захистити ваш додаток від поширених загроз безпеці.
Дізнайтеся, як налаштувати фреймворк для вашого додатку.
Дізнайтеся, як розширити фреймворк, додавши свої власні методи та класи.
Дізнайтеся, як використовувати систему подій, щоб додати хуки до ваших методів і внутрішніх методів фреймворку.
Дізнайтеся, як використовувати контейнери впровадження залежностей (DIC) для керування залежностями вашого додатку.
Дізнайтеся про основні методи фреймворку.
Зворотна сумісність у більшості випадків була збережена, але є деякі зміни, про які ви повинні знати, мігруючи з v2 на v3.
Існують деякі поширені проблеми, з якими ви можете зіткнутися при використанні Flight. Ця сторінка допоможе вам усунути ці проблеми.
Laravel — це повнофункціональний фреймворк, який має всі можливості та чудову екосистему, орієнтовану на розробників, але з витратами на продуктивність і складність. Метою Laravel є забезпечити розробників найвищим рівнем продуктивності та спростити виконання звичних завдань. Laravel є відмінним вибором для розробників, які прагнуть створити повнофункціональну web-додаток для підприємств. Це має певні компроміси, зокрема щодо продуктивності та складності. Вивчити основи Laravel може бути легко, але досягти майстерності у фреймворку може знадобитися певний час.
Також є багато модулів Laravel, і розробники часто відчувають, що єдиний спосіб вирішити проблеми — це використання цих модулів, тоді як насправді ви могли б просто використовувати іншу бібліотеку або написати свій власний код.
Зворотна сумісність в основному зберігається, але є деякі зміни, про які вам слід знати при міграції з v2 на v3.
Буферизація виходу — це процес, при якому вихід, згенерований PHP-скриптом, зберігається в буфері (внутрішньому для PHP) перед відправкою клієнту. Це дозволяє вам змінювати вихід перед тим, як він буде відправлений клієнту.
В MVC-застосунку Контролер є "менеджером", і він керує тим, що робить представлення. Генерація виходу поза контролером (або в випадку Flight іноді анонімна функція) порушує шаблон MVC. Ця зміна має на меті більше відповідати шаблону MVC і зробити фреймворк більш передбачуваним та легким у використанні.
У v2 буферизація виходу оброблялася таким чином, що вона не завжди закривала свій власний буфер виходу, що ускладнювало юнит-тестування і стримінг. Для більшості користувачів ця зміна може не вплинути на вас. Однак, якщо ви відправляєте контент поза викликами та контролерами (наприклад, у хуку), ви, швидше за все, зіткнетеся з проблемами. Відправка контенту в хуках і до фактичного виконання фреймворку, можливо, працювала раніше, але тепер не буде працювати.
// index.php require 'vendor/autoload.php'; // просто приклад define('START_TIME', microtime(true)); function hello() { echo 'Привіт Світ'; } Flight::map('hello', 'hello'); Flight::after('hello', function(){ // це насправді буде добре echo '<p>Цю фразу Привіт Світ вам приніс лист "H"</p>'; }); Flight::before('start', function(){ // такі речі викличуть помилку echo '<html><head><title>Моя Сторінка</title></head><body>'; }); Flight::route('/', function(){ // це насправді просто добре echo 'Привіт Світ'; // Це також має бути добре Flight::hello(); }); Flight::after('start', function(){ // це викличе помилку echo '<div>Ваша сторінка завантажилася за '.(microtime(true) - START_TIME).' секунд</div></body></html>'; });
Ви все ще можете зберегти свій старий код у тому вигляді, в якому він є, без переписування, щоб заставити його працювати з v3? Так, можете! Ви можете увімкнути поведінку рендерингу v2, встановивши параметр конфігурації flight.v2.output_buffering в true. Це дозволить вам продовжити використовувати стару поведінку рендерингу, але рекомендується виправити це на майбутнє. У v4 фреймворка це буде видалено.
flight.v2.output_buffering
true
// index.php require 'vendor/autoload.php'; Flight::set('flight.v2.output_buffering', true); Flight::before('start', function(){ // Тепер це буде просто добре echo '<html><head><title>Моя Сторінка</title></head><body>'; }); // більше коду
Якщо ви безпосередньо викликали статичні методи для Dispatcher, такі як Dispatcher::invokeMethod(), Dispatcher::execute(), і т.д., вам потрібно буде оновити свій код, щоб не викликати ці методи безпосередньо. Dispatcher був перетворений на об'єктно-орієнтований, щоб контейнери впровадження залежностей могли використовуватися простіше. Якщо вам потрібно викликати метод, подібно до того, як це робив Dispatcher, ви можете вручну використовувати щось на кшталт $result = $class->$method(...$params); або call_user_func_array() замість цього.
Dispatcher
Dispatcher::invokeMethod()
Dispatcher::execute()
$result = $class->$method(...$params);
call_user_func_array()
halt()
stop()
redirect()
error()
За замовчуванням поведінка до 3.10.0 полягала в очищенні як заголовків, так і тіла відповіді. Це було змінено на очищення лише тіла відповіді. Якщо вам потрібно очистити також заголовки, ви можете використовувати Flight::response()->clear().
Flight::response()->clear()
Ви можете налаштувати певні поведінки Flight, встановлюючи значення конфігурації через метод set.
set
Flight::set('flight.log_errors', true);
Нижче наведено список усіх доступних налаштувань конфігурації:
?string
bool
string
Content-Length
Також є ще одне налаштування конфігурації для завантажувача. Це дозволить вам автозавантажувати класи з _ в імені класу.
_
// Увімкнення завантаження класів з підкресленнями // За замовчуванням: true Loader::$v2ClassLoading = false;
Flight дозволяє зберігати змінні, щоб їх можна було використовувати в будь-якому місці вашого додатка.
// Зберігайте вашу змінну Flight::set('id', 123); // В іншому місці вашого додатка $id = Flight::get('id');
Щоб перевірити, чи була встановлена змінна, ви можете зробити:
if (Flight::has('id')) { // Виконати дію }
Ви можете очистити змінну, зробивши:
// Очищає змінну id Flight::clear('id'); // Очищає всі змінні Flight::clear();
Flight також використовує змінні для цілей конфігурації.
Всі помилки та виключення перехоплюються Flight і передаються в метод error. За замовчуванням поведінка полягає в тому, щоб надіслати загальний HTTP 500 Internal Server Error відповідь з деякою інформацією про помилку.
error
HTTP 500 Internal Server Error
Ви можете переозначити цю поведінку для своїх потреб:
Flight::map('error', function (Throwable $error) { // Обробка помилки echo $error->getTraceAsString(); });
За замовчуванням помилки не записуються в веб-сервер. Ви можете активувати це, змінивши конфігурацію:
Коли URL не можна знайти, Flight викликає метод notFound. За замовчуванням поведінка полягає в тому, щоб надіслати відповідь HTTP 404 Not Found з простим повідомленням.
notFound
HTTP 404 Not Found
Flight::map('notFound', function () { // Обробка не знайдено });
Безпека є дуже важливою, коли мова йде про веб-додатки. Ви хочете переконатися, що ваш додаток безпечний і дані ваших користувачів захищені. Flight надає ряд можливостей для допомоги у забезпеченні безпеки ваших веб-додатків.
HTTP-заголовки є одним із найпростіших способів захистити ваші веб-додатки. Ви можете використовувати заголовки, щоб запобігти клікджекингу, XSS та іншим атакам. Існує кілька способів додати ці заголовки до вашого додатка.
Два чудових сайти для перевірки безпеки ваших заголовків - це securityheaders.com та observatory.mozilla.org.
Ви можете вручну додати ці заголовки, використовуючи метод header об'єкта Flight\Response.
header
Flight\Response
// Встановіть заголовок X-Frame-Options, щоб запобігти клікджекингу Flight::response()->header('X-Frame-Options', 'SAMEORIGIN'); // Встановіть заголовок Content-Security-Policy, щоб запобігти XSS // Примітка: цей заголовок може бути дуже складним, тому вам слід // звернутися до прикладів в Інтернеті для вашого додатка Flight::response()->header("Content-Security-Policy", "default-src 'self'"); // Встановіть заголовок X-XSS-Protection для запобігання XSS Flight::response()->header('X-XSS-Protection', '1; mode=block'); // Встановіть заголовок X-Content-Type-Options, щоб запобігти зчитуванню MIME Flight::response()->header('X-Content-Type-Options', 'nosniff'); // Встановіть заголовок Referrer-Policy, щоб контролювати, скільки інформації про реферер надсилається Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade'); // Встановіть заголовок Strict-Transport-Security, щоб примусити використовувати HTTPS Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); // Встановіть заголовок Permissions-Policy, щоб контролювати, які функції та API можуть використовуватися Flight::response()->header('Permissions-Policy', 'geolocation=()');
Ці заголовки можуть бути додані на початку ваших файлів bootstrap.php або index.php.
bootstrap.php
index.php
Ви також можете додати їх у фільтр/перехоплювач, як у наступному:
// Додайте заголовки у фільтр 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=()'); });
Ви також можете додати їх як клас проміжного програмного забезпечення. Це хороший спосіб підтримувати ваш код чистим і організованим.
// 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 або там, де у вас маршрути // Для інформації, цей порожній рядок групи слугує глобальним проміжним програмним забезпеченням для // всіх маршрутів. Звичайно, ви можете зробити те саме і просто додати // це тільки до певних маршрутів. Flight::group('', function(Router $router) { $router->get('/users', [ 'UserController', 'getUsers' ]); // більше маршрутів }, [ new SecurityHeadersMiddleware() ]);
Підробка запиту між сайтами (CSRF) - це тип атаки, при якій шкідливий веб-сайт може змусити браузер користувача надіслати запит на ваш веб-сайт. Це можна використовувати для виконання дій на вашому веб-сайті без відома користувача. Flight не надає вбудованого механізму захисту CSRF, але ви можете легко реалізувати свій власний, використовуючи проміжне програмне забезпечення.
Спочатку вам потрібно згенерувати токен CSRF і зберегти його в сеансі користувача. Ви можете використовувати цей токен у своїх формах та перевіряти його, коли форма надсилається.
// Згенеруйте токен CSRF і збережіть його в сеансі користувача // (припускаючи, що ви створили об'єкт сесії та прикріпили його до Flight) // дивіться документацію з сесій для отримання додаткової інформації Flight::register('session', \Ghostff\Session\Session::class); // Вам потрібно згенерувати лише один токен на сеанс (щоб він працював // у кількох вкладках та запитах для одного й того ж користувача) if(Flight::session()->get('csrf_token') === null) { Flight::session()->set('csrf_token', bin2hex(random_bytes(32)) ); }
<!-- Використовуйте токен CSRF у своїй формі --> <form method="post"> <input type="hidden" name="csrf_token" value="<?= Flight::session()->get('csrf_token') ?>"> <!-- інші поля форми --> </form>
Ви можете також налаштувати функцію для виведення токена CSRF у ваших шаблонах Latte.
// Налаштуйте користувацьку функцію для виведення токена CSRF // Примітка: Подання було налаштовано з Latte як механізмом подання Flight::view()->addFunction('csrf', function() { $csrfToken = Flight::session()->get('csrf_token'); return new \Latte\Runtime\Html('<input type="hidden" name="csrf_token" value="' . $csrfToken . '">'); });
А тепер у ваших шаблонах Latte ви можете використовувати функцію csrf() для виведення токена CSRF.
csrf()
<form method="post"> {csrf()} <!-- інші поля форми --> </form>
Коротко та просто, вірно?
Ви можете перевірити токен CSRF, використовуючи фільтри подій:
// Це проміжне програмне забезпечення перевіряє, чи є запит POST запитом, і якщо так, то перевіряє, чи дійсний токен CSRF Flight::before('start', function() { if(Flight::request()->method == 'POST') { // захопіть токен CSRF з значень форми $token = Flight::request()->data->csrf_token; if($token !== Flight::session()->get('csrf_token')) { Flight::halt(403, 'Недійсний токен CSRF'); // або для відповіді JSON Flight::jsonHalt(['error' => 'Недійсний токен CSRF'], 403); } } });
Або ви можете використовувати клас проміжного програмного забезпечення:
// 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, 'Недійсний токен CSRF'); } } } } // index.php або там, де у вас маршрути Flight::group('', function(Router $router) { $router->get('/users', [ 'UserController', 'getUsers' ]); // більше маршрутів }, [ new CsrfMiddleware() ]);
Міжсайтовий скриптинг (XSS) - це тип атаки, при якій шкідливий веб-сайт може впроваджувати код на вашому веб-сайті. Більшість з цих можливостей виникає з значень форм, які заповнюють ваші кінцеві користувачі. Ви повинні ніколи не довіряти виходу від своїх користувачів! Завжди вважайте, що всі вони є найкращими хакерами у світі. Вони можуть впроваджувати шкідливий JavaScript або HTML на вашу сторінку. Цей код може бути використаний для викрадення інформації у ваших користувачів або виконання дій на вашому веб-сайті. Використовуючи клас подання Flight, ви можете легко екранувати вихід, щоб запобігти атакам XSS.
// Припустимо, що користувач розумний і намагається використовувати це як своє ім'я $name = '<script>alert("XSS")</script>'; // Це екранує вихід Flight::view()->set('name', $name); // Це виведе: <script>alert("XSS")</script> // Якщо ви використовуєте щось на зразок Latte, зареєстрованого як ваш клас подання, це також автоматично екранує це. Flight::view()->render('template', ['name' => $name]);
SQL-ін'єкція - це тип атаки, при якій шкідливий користувач може впроваджувати SQL-код у вашу базу даних. Це можна використовувати для викрадення інформації з вашої бази даних або виконання дій у вашій базі даних. Знову ж таки, ви повинні ніколи не довіряти введенню від своїх користувачів! Завжди вважайте, що вони збираються на злість. Ви можете використовувати підготовлені запити у ваших об'єктах PDO, щоб запобігти SQL-ін'єкції.
PDO
// Припустимо, у вас зареєстровано Flight::db() як ваш об'єкт PDO $statement = Flight::db()->prepare('SELECT * FROM users WHERE username = :username'); $statement->execute([':username' => $username]); $users = $statement->fetchAll(); // Якщо ви використовуєте клас PdoWrapper, це можна легко зробити в один рядок $users = Flight::db()->fetchAll('SELECT * FROM users WHERE username = :username', [ 'username' => $username ]); // Ви можете зробити те саме з об'єктом PDO з заповнювачами ? $statement = Flight::db()->fetchAll('SELECT * FROM users WHERE username = ?', [ $username ]); // Просто пообіцяйте, що ніколи НЕ робитимете щось подібне... $users = Flight::db()->fetchAll("SELECT * FROM users WHERE username = '{$username}' LIMIT 5"); // тому що що, якщо $username = "' OR 1=1; -- "; // Після побудови запиту це виглядає так // SELECT * FROM users WHERE username = '' OR 1=1; -- LIMIT 5 // Це виглядає дивно, але це дійсний запит, який спрацює. Насправді, // це дуже поширена атака SQL-ін'єкцій, яка поверне всіх користувачів.
Обмін ресурсами між походженнями (CORS) - це механізм, який дозволяє багатьом ресурсам (наприклад, шрифтам, JavaScript тощо) на веб-сторінці бути запрошеними з іншого домену, ніж той, з якого походить ресурс. Flight не має вбудованої функціональності, але це можна легко обробити за допомогою хуків, які запускаються перед викликом методу Flight::start().
Flight::start()
// app/utils/CorsUtil.php namespace app\utils; class CorsUtil { public function set(array $params): void { $request = Flight::request(); $response = Flight::response(); if ($request->getVar('HTTP_ORIGIN') !== '') { $this->allowOrigins(); $response->header('Access-Control-Allow-Credentials', 'true'); $response->header('Access-Control-Max-Age', '86400'); } if ($request->method === 'OPTIONS') { if ($request->getVar('HTTP_ACCESS_CONTROL_REQUEST_METHOD') !== '') { $response->header( 'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD' ); } if ($request->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') !== '') { $response->header( "Access-Control-Allow-Headers", $request->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') ); } $response->status(200); $response->send(); exit; } } private function allowOrigins(): void { // налаштуйте тут свої дозволені хости. $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 або там, де ви маєте свої маршрути $CorsUtil = new CorsUtil(); // Це потрібно запустити до того, як запустяться стартові запити. Flight::before('start', [ $CorsUtil, 'setupCors' ]);
Безпека є дуже важливою, і важливо переконатися, що ваші веб-додатки безпечні. Flight надає ряд можливостей, щоб допомогти вам захистити ваші веб-додатки, але важливо завжди залишатися напоготові та переконатися, що ви робите все можливе, щоб захистити дані ваших користувачів. Завжди припускайте найгірше і ніколи не довіряйте введенню від своїх користувачів. Завжди екрануйте вихід і використовуйте підготовлені запити для запобігання SQL-ін'єкції. Завжди використовуйте проміжне програмне забезпечення, щоб захистити свої маршрути від атак CSRF і CORS. Якщо ви зробите всі ці речі, ви будете на хорошому шляху до створення безпечних веб-додатків.
Примітка: Хочете дізнатися більше про маршрутизацію? Перегляньте сторінку "чому фреймворк?" для більш детального пояснення.
Основна маршрутизація в Flight відбувається шляхом зіставлення шаблону URL з функцією зворотного виклику або масивом класу та методу.
Flight::route('/', function(){ echo 'привіт світ!'; });
Маршрути зіставляються в порядку, в якому вони визначені. Перший маршрут, який відповідає запиту, буде викликаний.
В якості колбеку можна використовувати будь-який об'єкт, який можна викликати. Тож ви можете використовувати звичайну функцію:
function hello() { echo 'привіт світ!'; } Flight::route('/', 'hello');
Ви також можете використовувати статичний метод класу:
class Greeting { public static function hello() { echo 'привіт світ!'; } } Flight::route('/', [ 'Greeting', 'hello' ]);
Або, створивши об'єкт спочатку, а потім викликавши метод:
// Greeting.php class Greeting { public function __construct() { $this->name = 'Джон Доу'; } public function hello() { echo "Привіт, {$this->name}!"; } } // index.php $greeting = new Greeting(); Flight::route('/', [ $greeting, 'hello' ]); // Ви також можете зробити це без попереднього створення об'єкта // Примітка: Аргументи не будуть впроваджені в конструктор Flight::route('/', [ 'Greeting', 'hello' ]); // Крім того, ви можете використовувати цей коротший синтаксис Flight::route('/', 'Greeting->hello'); // або Flight::route('/', Greeting::class.'->hello');
Якщо ви хочете використовувати впровадження залежностей через контейнер (PSR-11, PHP-DI, Dice тощо), єдиний тип маршрутів, де це доступно, - це або безпосереднє створення об'єкта самостійно та використання контейнера для створення вашого об'єкта, або ви можете використовувати рядки для визначення класу та методу для виклику. Ви можете перейти на сторінку Впровадження залежностей для отримання додаткової інформації.
Ось швидкий приклад:
use flight\database\PdoWrapper; // Greeting.php class Greeting { protected PdoWrapper $pdoWrapper; public function __construct(PdoWrapper $pdoWrapper) { $this->pdoWrapper = $pdoWrapper; } public function hello(int $id) { // зробіть щось з $this->pdoWrapper $name = $this->pdoWrapper->fetchField("SELECT name FROM users WHERE id = ?", [ $id ]); echo "Привіт, світ! Моє ім'я {$name}!"; } } // index.php // Налаштуйте контейнер з будь-якими параметрами, які вам потрібні // Див. сторінку Впровадження залежностей для отримання додаткової інформації про PSR-11 $dice = new \Dice\Dice(); // Не забудьте переназначити змінну '$dice = '!!!!! $dice = $dice->addRule('flight\database\PdoWrapper', [ 'shared' => true, 'constructParams' => [ 'mysql:host=localhost;dbname=test', 'root', 'password' ] ]); // Зареєструйте обробник контейнера Flight::registerContainerHandler(function($class, $params) use ($dice) { return $dice->create($class, $params); }); // Маршрути, як зазвичай Flight::route('/hello/@id', [ 'Greeting', 'hello' ]); // або Flight::route('/hello/@id', 'Greeting->hello'); // або Flight::route('/hello/@id', 'Greeting::hello'); Flight::start();
За замовчуванням шаблони маршрутів порівнюються з усіма методами запиту. Ви можете реагувати на конкретні методи, поставивши ідентифікатор перед URL.
Flight::route('GET /', function () { echo 'Я отримав GET запит.'; }); Flight::route('POST /', function () { echo 'Я отримав POST запит.'; }); // Ви не можете використовувати Flight::get() для маршрутів, оскільки це метод // для отримання змінних, а не для створення маршруту. // Flight::post('/', function() { /* код */ }); // Flight::patch('/', function() { /* код */ }); // Flight::put('/', function() { /* код */ }); // Flight::delete('/', function() { /* код */ });
Ви також можете мапувати кілька методів на один колбек, використовуючи роздільник |:
|
Flight::route('GET|POST /', function () { echo 'Я отримав або GET, або POST запит.'; });
Крім того, ви можете отримати об’єкт Router, в якому є допоміжні методи для використання:
$router = Flight::router(); // мапує всі методи $router->map('/', function() { echo 'привіт світ!'; }); // GET запит $router->get('/users', function() { echo 'користувачі'; }); // $router->post(); // $router->put(); // $router->delete(); // $router->patch();
Ви можете використовувати регулярні вирази у ваших маршрутах:
Flight::route('/user/[0-9]+', function () { // Це буде відповідати /user/1234 });
Хоча цей метод доступний, рекомендується використовувати названі параметри або названі параметри з регулярними виразами, оскільки вони більш читабельні та прості у підтримці.
Ви можете вказати названі параметри у ваших маршрутах, які будуть передані вашій функції зворотного виклику.
Flight::route('/@name/@id', function (string $name, string $id) { echo "привіт, $name ($id)!"; });
Ви також можете включити регулярні вирази з вашими названими параметрами, використовуючи роздільник ::
:
Flight::route('/@name/@id:[0-9]{3}', function (string $name, string $id) { // Це буде відповідати /bob/123 // Але не відповідатиме /bob/12345 });
Примітка: Із групами відповідності regex () з названими параметрами не підтримується. :'(
()
Ви можете вказати названі параметри, які є необов'язковими для відповідності, обгортаючи сегменти в дужки.
Flight::route( '/blog(/@year(/@month(/@day)))', function(?string $year, ?string $month, ?string $day) { // Це буде відповідати наступним URL: // /blog/2012/12/10 // /blog/2012/12 // /blog/2012 // /blog } );
Будь-які необов'язкові параметри, які не були відповідні, будуть передані як NULL.
NULL
Відповідність відбувається лише на поодиноких сегментах URL. Якщо ви хочете відповідати кількома сегментами, ви можете використовувати дикий символ *.
*
Flight::route('/blog/*', function () { // Це буде відповідати /blog/2000/02/01 });
Щоб маршрутизувати всі запити до одного колбеку, ви можете зробити так:
Flight::route('*', function () { // Виконати щось });
Ви можете передати виконання на наступний відповідний маршрут, повернувши true з вашої функції зворотного виклику.
Flight::route('/user/@name', function (string $name) { // Перевірте якусь умову if ($name !== "Боб") { // Продовжте до наступного маршруту return true; } }); Flight::route('/user/*', function () { // Це буде викликано });
Ви можете присвоїти псевдонім маршруту, щоб URL можна було динамічно генерувати пізніше у вашому коді (наприклад, як шаблон).
Flight::route('/users/@id', function($id) { echo 'користувач:'.$id; }, false, 'user_view'); // пізніше в коді десь Flight::getUrl('user_view', [ 'id' => 5 ]); // поверне '/users/5'
Це особливо корисно, якщо ваш URL випадково змінюється. У наведеному вище прикладі, скажімо, що користувачі були переміщені до /admin/users/@id замість цього. З псевдонімами ви не повинні змінювати місце, де ви посилаєтеся на псевдонім, оскільки псевдонім тепер поверне /admin/users/5, як у вищезгаданому прикладі.
/admin/users/@id
/admin/users/5
Псевдонім маршруту також працює в групах:
Flight::group('/users', function() { Flight::route('/@id', function($id) { echo 'користувач:'.$id; }, false, 'user_view'); }); // пізніше в коді десь Flight::getUrl('user_view', [ 'id' => 5 ]); // поверне '/users/5'
Якщо ви хочете перевірити інформацію про відповідний маршрут, ви можете запросити об'єкт маршруту, щоб передати його вашій функції зворотного виклику, передавши true як третій параметр у методі маршруту. Об'єкт маршруту завжди буде останнім параметром, переданим вашій функції зворотного виклику.
Flight::route('/', function(\flight\net\Route $route) { // Масив методів HTTP, що відповідають $route->methods; // Масив названих параметрів $route->params; // Відповідний регулярний вираз $route->regex; // Містить вміст будь-якого '*' використаного в шаблоні URL $route->splat; // Показує шлях URL.... якщо вам це дійсно потрібно $route->pattern; // Показує, яке середовище призначено цьому $route->middleware; // Показує псевдонім, призначений цьому маршруту $route->alias; }, true);
Можуть бути ситуації, коли ви хочете згрупувати пов'язані маршрути (як-от /api/v1). Ви можете зробити це, використовуючи метод group:
/api/v1
group
Flight::group('/api/v1', function () { Flight::route('/users', function () { // Відповідає /api/v1/users }); Flight::route('/posts', function () { // Відповідає /api/v1/posts }); });
Ви навіть можете вкладати групи груп.
Flight::group('/api', function () { Flight::group('/v1', function () { // Flight::get() отримує змінні, він не встановлює маршрут! Див. контекст об'єкта нижче Flight::route('GET /users', function () { // Відповідає GET /api/v1/users }); Flight::post('/posts', function () { // Відповідає POST /api/v1/posts }); Flight::put('/posts/1', function () { // Відповідає PUT /api/v1/posts }); }); Flight::group('/v2', function () { // Flight::get() отримує змінні, він не встановлює маршрут! Див. контекст об'єкта нижче Flight::route('GET /users', function () { // Відповідає GET /api/v2/users }); }); });
Ви все ще можете використовувати групування маршрутів з об'єктом Engine наступним чином:
Engine
$app = new \flight\Engine(); $app->group('/api/v1', function (Router $router) { // використовуйте змінну $router $router->get('/users', function () { // Відповідає GET /api/v1/users }); $router->post('/posts', function () { // Відповідає POST /api/v1/posts }); });
Тепер ви можете передавати відповіді клієнту, використовуючи метод streamWithHeaders(). Це корисно для відправлення великих файлів, тривалих процесів або генерації великих відповідей. Потокова передача маршруту обробляється трохи інакше, ніж звичайний маршрут.
streamWithHeaders()
Примітка: Потокові відповіді доступні лише в тому випадку, якщо ви маєте flight.v2.output_buffering встановлений на false.
Ви можете потоково передавати відповідь клієнту, використовуючи метод stream() на маршруті. Якщо ви це робите, ви повинні вручну встановити всі методи, перш ніж щось виводити клієнту. Це робиться за допомогою функції php header() або методу Flight::response()->setRealHeader().
stream()
header()
Flight::response()->setRealHeader()
Flight::route('/@filename', function($filename) { // звісно, вам необхідно очистити шлях і т.д. $fileNameSafe = basename($filename); // Якщо у вас є додаткові заголовки для встановлення тут після виконання маршруту // ви повинні визначити їх перед будь-яким виводом. // Вони повинні бути всі сировинним викликом функції header() або // викликом Flight::response()->setRealHeader() header('Content-Disposition: attachment; filename="'.$fileNameSafe.'"'); // або Flight::response()->setRealHeader('Content-Disposition', 'attachment; filename="'.$fileNameSafe.'"'); $fileData = file_get_contents('/some/path/to/files/'.$fileNameSafe); // Обробка помилок і т.д. if(empty($fileData)) { Flight::halt(404, 'Файл не знайдено'); } // вручну встановлюйте довжину вмісту, якщо хочете header('Content-Length: '.filesize($filename)); // Потоково передайте дані клієнту echo $fileData; // Це магічний рядок тут })->stream();
Ви також можете використовувати метод streamWithHeaders(), щоб встановити заголовки перед початком потокової передачі.
Flight::route('/stream-users', function() { // ви можете додати будь-які додаткові заголовки, які хочете // ви просто повинні використовувати header() або Flight::response()->setRealHeader() // однак ви витягуєте свої дані, просто як приклад... $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 ','; } // Це необхідно для відправки даних клієнту ob_flush(); } echo '}'; // Це так ви встановите заголовки перед початком потокової передачі. })->streamWithHeaders([ 'Content-Type' => 'application/json', 'Content-Disposition' => 'attachment; filename="users.json"', // необов'язковий статус-код, за замовчуванням 200 'status' => 200 ]);
Symfony — це набір повторно використовуваних компонентів PHP і PHP фреймворк для веб-проектів.
Стандартна основа, на якій побудовані найкращі PHP додатки. Виберіть будь-який з 50 автономних компонентів, доступних для ваших власних додатків.
Прискорте створення та підтримку ваших PHP веб-додатків. Припиніть повторювані завдання кодування і насолоджуйтесь можливістю контролювати свій код.
Якщо ви мігруєте з іншого фреймворка, такого як Laravel, Slim, Fat-Free або Symfony до Flight, ця сторінка допоможе вам зрозуміти відмінності між цими двома.
Laravel — це повнофункціональний фреймворк, який має всі принади та дивовижну екосистему, орієнтовану на розробників, але вартість цього — продуктивність і складність.
Дивіться порівняння між Laravel і Flight.
Slim — це мікрофреймворк, схожий на Flight. Він розроблений для того, щоб бути легким і простим у використанні, але може бути трохи складнішим, ніж Flight.
Дивіться порівняння між Slim і Flight.
Fat-Free — це повноцінний фреймворк у набагато меншому пакеті. Хоча в ньому є всі інструменти в ящику, він має архітектуру даних, яка може ускладнити деякі проекти більше, ніж потрібно.
Дивіться порівняння між Fat-Free і Flight.
Symfony — це модульний фреймворк корпоративного рівня, який розроблений для того, щоб бути гнучким і масштабованим. Для менших проектів або нових розробників Symfony може бути трохи приголомшуючим.
Дивіться порівняння між Symfony і Flight.
Контейнер для впровадження залежностей (DIC) — це потужний інструмент, який дозволяє вам керувати залежностями вашого застосунку. Це ключова концепція в сучасних PHP фреймворках і використовується для управління створенням та налаштуванням об'єктів. Деякі приклади бібліотек DIC: Dice, Pimple, PHP-DI та league/container.
DIC - це вишуканий спосіб сказати, що він дозволяє вам створювати та керувати вашими класами в централізованому місці. Це корисно, коли вам потрібно передавати один і той же об'єкт кільком класам (як-от вашим контролерам). Простий приклад може допомогти це зрозуміти.
Старий спосіб виконання завдань може виглядати так:
require 'vendor/autoload.php'; // клас для управління користувачами з бази даних 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();
Ви можете побачити з наведеного вище коду, що ми створюємо новий об'єкт PDO і передаємо його нашому класу UserController. Це нормально для малих застосунків, але коли ваш застосунок росте, ви виявите, що створюєте один і той же об'єкт PDO в кількох місцях. Ось тут DIC стає в нагоді.
UserController
Ось той же приклад, використовуючи DIC (використовуючи Dice):
require 'vendor/autoload.php'; // той же клас, що й вище. Нічого не змінилося 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()); } } // створюємо новий контейнер $container = new \Dice\Dice; // не забудьте перепризначити його, як показано нижче! $container = $container->addRule('PDO', [ // спільний означає, що той же об'єкт буде повертатися щоразу 'shared' => true, 'constructParams' => ['mysql:host=localhost;dbname=test', 'user', 'pass' ] ]); // Це реєструє обробник контейнера, щоб Flight знав, що використовувати його. Flight::registerContainerHandler(function($class, $params) use ($container) { return $container->create($class, $params); }); // тепер ми можемо використовувати контейнер для створення нашого UserController Flight::route('/user/@id', [ 'UserController', 'view' ]); // або, альтернативно, ви можете визначити маршрут таким чином Flight::route('/user/@id', 'UserController->view'); // або Flight::route('/user/@id', 'UserController::view'); Flight::start();
Можливо, вам здається, що до прикладу було додано багато зайвого коду. Чарівність виникає, коли у вас є інший контролер, який потребує об'єкт PDO.
// Якщо всі ваші контролери мають конструктор, який потребує об'єкт PDO // кожен з маршрутів нижче автоматично буде мати його впровадженим!!! Flight::route('/company/@id', 'CompanyController->view'); Flight::route('/organization/@id', 'OrganizationController->view'); Flight::route('/category/@id', 'CategoryController->view'); Flight::route('/settings', 'SettingsController->view');
Додатковим бонусом від використання DIC є те, що модульне тестування стає значно легшим. Ви можете створити змодельований об'єкт і передати його своєму класу. Це величезна перевага, коли ви пишете тести для свого застосунку!
Flight може також використовувати будь-який контейнер, сумісний з PSR-11. Це означає, що ви можете використовувати будь-який контейнер, який реалізує інтерфейс PSR-11. Ось приклад, як використовувати контейнер PSR-11 від League:
require 'vendor/autoload.php'; // той же клас UserController, що й вище $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();
Це може бути трохи більш розлогим, ніж попередній приклад з Dice, але все одно виконує свою роботу з такими ж перевагами!
Ви також можете створити власний обробник DIC. Це корисно, якщо у вас є власний контейнер, який ви хочете використовувати, який не є PSR-11 (Dice). Дивіться основний приклад для того, як це зробити.
Крім того, є деякі корисні значення за замовчуванням, які полегшать вам життя при використанні Flight.
Якщо ви використовуєте екземпляр Engine у своїх контролерах/проміжних програмах, ось як ви його налаштуєте:
// Десь у вашому файлі завантаження $engine = Flight::app(); $container = new \Dice\Dice; $container = $container->addRule('*', [ 'substitutions' => [ // Ось тут ви передаєте екземпляр Engine::class => $engine ] ]); $engine->registerContainerHandler(function($class, $params) use ($container) { return $container->create($class, $params); }); // Тепер ви можете використовувати екземпляр Engine у своїх контролерах/проміжних програмах class MyController { public function __construct(Engine $app) { $this->app = $app; } public function index() { $this->app->render('index'); } }
Якщо у вас є інші класи, які ви хочете додати до контейнера, з Dice це легко, оскільки вони автоматично будуть визначатися контейнером. Ось приклад:
$container = new \Dice\Dice; // Якщо вам не потрібно впроваджувати нічого в свій клас // ви не повинні нічого визначати! Flight::registerContainerHandler(function($class, $params) use ($container) { return $container->create($class, $params); }); class MyCustomClass { public function parseThing() { return 'річ'; } } 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');
Flight підтримує маршрути та групи маршрутів для проміжного програмного забезпечення. Проміжне програмне забезпечення — це функція, яка виконується перед (або після) зворотного виклику маршруту. Це чудовий спосіб додати перевірки автентифікації API у вашому коді або підтвердити, що користувач має дозвіл на доступ до маршруту.
Ось базовий приклад:
// Якщо ви надасте лише анонімну функцію, вона буде виконана перед зворотним викликом маршруту. // немає "після" функцій проміжного програмного забезпечення, крім класів (див. нижче) Flight::route('/path', function() { echo ' Тут я!'; })->addMiddleware(function() { echo 'Проміжне програмне забезпечення першим!'; }); Flight::start(); // Це виведе "Проміжне програмне забезпечення першим! Тут я!"
Є кілька дуже важливих приміток про проміжне програмне забезпечення, про які вам слід знати, перш ніж їх використовувати:
Flight::redirect()
function($params) { ... }
public function before($params) {}
flight\Engine
__construct()
Проміжне програмне забезпечення також може бути зареєстроване як клас. Якщо вам потрібен функціонал "після", ви повинні використовувати клас.
class MyMiddleware { public function before($params) { echo 'Проміжне програмне забезпечення першим!'; } public function after($params) { echo 'Проміжне програмне забезпечення останнім!'; } } $MyMiddleware = new MyMiddleware(); Flight::route('/path', function() { echo ' Тут я! '; })->addMiddleware($MyMiddleware); // також ->addMiddleware([ $MyMiddleware, $MyMiddleware2 ]); Flight::start(); // Це виведе "Проміжне програмне забезпечення першим! Тут я! Проміжне програмне забезпечення останнім!"
Скажімо, у вас є проміжне програмне забезпечення для автентифікації, і ви хочете перенаправити користувача на сторінку входу, якщо він не автентифікований. У вас є кілька варіантів на вибір:
Ось простий приклад return false;:
class MyMiddleware { public function before($params) { if (isset($_SESSION['user']) === false) { return false; } // оскільки це правда, все продовжує йти далі } }
Ось приклад перенаправлення користувача на сторінку входу:
class MyMiddleware { public function before($params) { if (isset($_SESSION['user']) === false) { Flight::redirect('/login'); exit; } } }
Скажімо, вам потрібно викинути JSON-помилку, оскільки ви створюєте API. Ви можете зробити це ось так:
class MyMiddleware { public function before($params) { $authorization = Flight::request()->headers['Authorization']; if(empty($authorization)) { Flight::jsonHalt(['error' => 'Ви повинні бути увійшли, щоб отримати доступ до цієї сторінки.'], 403); // або Flight::json(['error' => 'Ви повинні бути увійшли, щоб отримати доступ до цієї сторінки.'], 403); exit; // або Flight::halt(403, json_encode(['error' => 'Ви повинні бути увійшли, щоб отримати доступ до цієї сторінки.']); } } }
Ви можете додати групу маршрутів, і тоді кожен маршрут у цій групі матиме таке ж проміжне програмне забезпечення. Це корисно, якщо ви хочете групувати кілька маршрутів за, наприклад, проміжним програмним забезпеченням Auth, щоб перевірити ключ API в заголовку.
// додано в кінець методу групи Flight::group('/api', function() { // Цей "порожній" виглядаючий маршрут насправді відповідатиме /api Flight::route('', function() { echo 'api'; }, false, 'api'); // Це відповідатиме /api/users Flight::route('/users', function() { echo 'users'; }, false, 'users'); // Це відповідатиме /api/users/1234 Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view'); }, [ new ApiAuthMiddleware() ]);
Якщо ви хочете застосувати глобальне проміжне програмне забезпечення до всіх ваших маршрутів, ви можете додати "порожню" групу:
// додано в кінець методу групи Flight::group('', function() { // Це все ще /users Flight::route('/users', function() { echo 'users'; }, false, 'users'); // А це все ще /users/1234 Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view'); }, [ new ApiAuthMiddleware() ]);
Flight дозволяє вам фільтрувати методи до і після їх виклику. Немає зазначених хуків, які потрібно запам'ятовувати. Ви можете фільтрувати будь-які з методів за замовчуванням фреймворку, а також будь-які користувацькі методи, які ви налаштували.
Функція фільтра виглядає так:
function (array &$params, string &$output): bool { // Код фільтра }
Використовуючи передані змінні, ви можете маніпулювати вхідними параметрами та/або виходом.
Ви можете запустити фільтр перед методом, зробивши:
Flight::before('start', function (array &$params, string &$output): bool { // Зробіть щось });
Ви можете запустити фільтр після методу, зробивши:
Flight::after('start', function (array &$params, string &$output): bool { // Зробіть щось });
Ви можете додати скільки завгодно фільтрів до будь-якого методу. Вони будуть викликані в порядку, в якому вони оголошені.
Ось приклад процесу фільтрації:
// Співвіднести користувацький метод Flight::map('hello', function (string $name) { return "Привіт, $name!"; }); // Додати фільтр перед Flight::before('hello', function (array &$params, string &$output): bool { // Маніпулюйте параметром $params[0] = 'Фред'; return true; }); // Додати фільтр після Flight::after('hello', function (array &$params, string &$output): bool { // Маніпулюйте виходом $output .= " Гарного вам дня!"; return true; }); // Викликати користувацький метод echo Flight::hello('Боб');
Це повинно відображати:
Привіт Фред! Гарного вам дня!
Якщо ви визначили кілька фільтрів, ви можете розірвати ланцюг, повернувши false в будь-якій з ваших функцій фільтра:
false
Flight::before('start', function (array &$params, string &$output): bool { echo 'один'; return true; }); Flight::before('start', function (array &$params, string &$output): bool { echo 'два'; // Це завершить ланцюг return false; }); // Це не буде викликано Flight::before('start', function (array &$params, string &$output): bool { echo 'три'; return true; });
Зверніть увагу, що основні методи, такі як map і register, не можна фільтрувати, оскільки їх викликають безпосередньо, а не динамічно.
map
register
Flight інкапсулює HTTP запит в один об'єкт, до якого можна доступитися, виконавши:
$request = Flight::request();
Коли ви працюєте з запитом в веб-додатку, зазвичай ви хочете отримати заголовок, або параметр $_GET чи $_POST, або можливо навіть сирий зміст запиту. Flight надає простий інтерфейс для всіх цих функцій.
$_GET
$_POST
Ось приклад отримання параметра рядка запиту:
Flight::route('/search', function(){ $keyword = Flight::request()->query['keyword']; echo "Ви шукаєте: $keyword"; // запит до бази даних або щось інше з $keyword });
Ось приклад можливої форми з методом POST:
Flight::route('POST /submit', function(){ $name = Flight::request()->data['name']; $email = Flight::request()->data['email']; echo "Ви надіслали: $name, $email"; // зберегти в базі даних або щось інше з $name та $email });
Об'єкт запиту надає такі властивості:
$_SERVER
HTTP_CLIENT_IP
HTTP_X_FORWARDED_FOR
HTTP_X_FORWARDED
HTTP_X_CLUSTER_CLIENT_IP
HTTP_FORWARDED_FOR
HTTP_FORWARDED
Ви можете доступитися до властивостей query, data, cookies та files як масивів або об'єктів.
query
data
cookies
files
Отже, щоб отримати параметр рядка запиту, ви можете зробити:
$id = Flight::request()->query['id'];
Або ви можете зробити:
$id = Flight::request()->query->id;
Щоб отримати сирий HTTP зміст запиту, наприклад, обробляючи запити PUT, ви можете зробити:
$body = Flight::request()->getBody();
Якщо ви надсилаєте запит з типом application/json і даними {"id": 123} це буде доступно з властивості data:
application/json
{"id": 123}
$id = Flight::request()->data->id;
Ви можете доступитися до масиву $_GET через властивість query:
Ви можете доступитися до масиву $_POST через властивість data:
$id = Flight::request()->data['id'];
$_COOKIE
Ви можете доступитися до масиву $_COOKIE через властивість cookies:
$myCookieValue = Flight::request()->cookies['myCookieName'];
Є доступна скорочена функція для доступу до масиву $_SERVER через метод getVar():
getVar()
$host = Flight::request()->getVar['HTTP_HOST'];
$_FILES
Ви можете доступитися до завантажених файлів через властивість files:
$uploadedFile = Flight::request()->files['myFile'];
Ви можете обробляти завантаження файлів, використовуючи фреймворк з деякими допоміжними методами. Це в основному зводиться до витягування даних файлу з запиту та переміщення їх у нове місце.
Flight::route('POST /upload', function(){ // Якщо у вас є поле введення <input type="file" name="myFile"> $uploadedFileData = Flight::request()->getUploadedFiles(); $uploadedFile = $uploadedFileData['myFile']; $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename()); });
Якщо ви завантажили кілька файлів, ви можете пройтися по ним:
Flight::route('POST /upload', function(){ // Якщо у вас є поле введення <input type="file" name="myFiles[]"> $uploadedFiles = Flight::request()->getUploadedFiles()['myFiles']; foreach ($uploadedFiles as $uploadedFile) { $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename()); } });
Примітка безпеки: Завжди перевіряйте та очищуйте введення користувача, особливо під час обробки завантажень файлів. Завжди перевіряйте тип розширень, які ви дозволите завантажувати, але також слід перевіряти "магічні байти" файлу, щоб впевнитися, що це дійсно той тип файлу, який користувач стверджує, що це. Існують статті та бібліотеки, які можуть допомогти з цим.
Ви можете доступитися до заголовків запиту, використовуючи методи getHeader() або getHeaders():
getHeader()
getHeaders()
// Можливо, вам потрібен заголовок Authorization $host = Flight::request()->getHeader('Authorization'); // або $host = Flight::request()->header('Authorization'); // Якщо вам потрібно забрати всі заголовки $headers = Flight::request()->getHeaders(); // або $headers = Flight::request()->headers();
Ви можете доступитися до сирого змісту запиту, використовуючи метод getBody():
getBody()
Ви можете доступитися до методу запиту, використовуючи властивість method або метод getMethod():
method
getMethod()
$method = Flight::request()->method; // насправді викликає getMethod() $method = Flight::request()->getMethod();
Примітка: Метод getMethod() спочатку отримує метод з $_SERVER['REQUEST_METHOD'], потім його можна переписати через $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'], якщо він існує, або $_REQUEST['_method'], якщо він існує.
$_SERVER['REQUEST_METHOD']
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']
$_REQUEST['_method']
Існує кілька допоміжних методів для збирання частин URL для зручності.
Ви можете доступитися до повного URL запиту, використовуючи метод getFullUrl():
getFullUrl()
$url = Flight::request()->getFullUrl(); // https://example.com/some/path?foo=bar
Ви можете доступитися до базового URL, використовуючи метод getBaseUrl():
getBaseUrl()
$url = Flight::request()->getBaseUrl(); // Зверніть увагу, без кінцевого слешу. // https://example.com
Ви можете передати URL до методу parseQuery(), щоб розпарсити рядок запиту в асоціативний масив:
parseQuery()
$query = Flight::request()->parseQuery('https://example.com/some/path?foo=bar'); // ['foo' => 'bar']
Flight розроблений для того, щоб бути простим у використанні та розумінні. Наступне є повним набором методів для фреймворку. Він складається з основних методів, які є звичайними статичними методами, та розширювальних методів, які є картованими методами, що можуть бути відфільтровані або перевизначені.
Ці методи є основними для фреймворку і не можуть бути перевизначені.
Flight::map(string $name, callable $callback, bool $pass_route = false) // Створює користувацький метод фреймворку. Flight::register(string $name, string $class, array $params = [], ?callable $callback = null) // Реєструє клас для методу фреймворку. Flight::unregister(string $name) // Знедоступлює клас для методу фреймворку. Flight::before(string $name, callable $callback) // Додає фільтр перед методом фреймворку. Flight::after(string $name, callable $callback) // Додає фільтр після методу фреймворку. Flight::path(string $path) // Додає шлях для автоматичного завантаження класів. Flight::get(string $key) // Отримує змінну, встановлену Flight::set(). Flight::set(string $key, mixed $value) // Встановлює змінну в рамках системи Flight. Flight::has(string $key) // Перевіряє, чи встановлено змінну. Flight::clear(array|string $key = []) // Очищає змінну. Flight::init() // Ініціалізує фреймворк до його стандартних налаштувань. Flight::app() // Отримує екземпляр об'єкта застосунку Flight::request() // Отримує екземпляр об'єкта запиту Flight::response() // Отримує екземпляр об'єкта відповіді Flight::router() // Отримує екземпляр об'єкта маршрутизатора Flight::view() // Отримує екземпляр об'єкта представлення
Flight::start() // Запускає фреймворк. Flight::stop() // Зупиняє фреймворк і надсилає відповідь. Flight::halt(int $code = 200, string $message = '') // Зупиняє фреймворк з допоміжним кодом статусу та повідомленням. Flight::route(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Відображає шаблон URL на колбек. Flight::post(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Відображає шаблон URL запиту POST на колбек. Flight::put(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Відображає шаблон URL запиту PUT на колбек. Flight::patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Відображає шаблон URL запиту PATCH на колбек. Flight::delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Відображає шаблон URL запиту DELETE на колбек. Flight::group(string $pattern, callable $callback) // Створює групування для URL, шаблон має бути рядком. Flight::getUrl(string $name, array $params = []) // Генерує URL на основі псевдоніму маршруту. Flight::redirect(string $url, int $code) // Перенаправляє на інший URL. Flight::download(string $filePath) // Завантажує файл. Flight::render(string $file, array $data, ?string $key = null) // Відображає файл шаблону. Flight::error(Throwable $error) // Надсилає HTTP-відповідь 500. Flight::notFound() // Надсилає HTTP-відповідь 404. Flight::etag(string $id, string $type = 'string') // Виконує кешування HTTP ETag. Flight::lastModified(int $time) // Виконує кешування HTTP для останнього модифікованого часу. Flight::json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Надсилає JSON-відповідь. Flight::jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Надсилає JSONP-відповідь. Flight::jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Надсилає JSON-відповідь і зупиняє фреймворк.
Будь-які користувацькі методи, додані за допомогою map та register, також можуть бути відфільтровані. Для прикладів, як картувати ці методи, дивіться посібник Розширення Flight.
Деякі програмісти рішуче проти використання фреймворків. Вони стверджують, що фреймворки є надмірними, повільними і важкими для навчання. Вони кажуть, що фреймворки є непотрібними і що ви можете написати кращий код без них. Звичайно, є деякі слушні зауваження щодо недоліків використання фреймворків. Однак також є багато переваг використання фреймворків.
Ось кілька причин, чому ви можете хотіти розглянути можливість використання фреймворка:
Flight — це мікро-фреймворк. Це означає, що він невеликий і легкий. Він не надає такої ж функціональності, як більші фреймворки, такі як Laravel або Symfony. Однак він забезпечує багато функціональності, яку ви потребуєте для створення веб-додатків. Його також легко навчитися і використовувати. Це робить його хорошим вибором для швидкого і легкого створення веб-додатків. Якщо ви новачок у фреймворках, Flight є чудовим початковим фреймворком для старту. Він допоможе вам дізнатися про переваги використання фреймворків, не перевантажуючи вас занадто великою складністю. Після того, як ви отримаєте деякий досвід з Flight, вам буде легше перейти на більш складні фреймворки, такі як Laravel або Symfony, однак Flight все ще може скласти успішну надійну програму.
Маршрутизація — це основа фреймворка Flight, але що це таке насправді? Маршрутизація — це процес взяття URL-адреси і зіставлення її з конкретною функцією у вашому коді. Це спосіб, яким ви можете змусити ваш веб-сайт виконувати різні дії в залежності від запитуваної URL-адреси. Наприклад, ви можете захотіти показати профіль користувача, коли вони відвідують /user/1234, але показати список всіх користувачів, коли вони відвідують /users. Це все робиться через маршрутизацію.
/user/1234
/users
Це може працювати приблизно так:
http://example.com/user/1234
Flight::route('/user/@id', [ 'UserController', 'viewUserProfile' ]);
viewUserProfile($id)
1234
$id
viewUserProfile()
Наявність належного централізованого маршрутизатора може значно спростити ваше життя! Це може бути важко зрозуміти на перший погляд. Ось кілька причин, чому:
user_view
id
/admin/user/1234
Я впевнений, що ви знайомі з методом "скрипт за скриптом" для створення веб-сайту. У вас може бути файл під назвою index.php, який містить безліч if операцій для перевірки URL-адреси, а потім виконання конкретної функції на основі URL-адреси. Це форма маршрутизації, але вона не дуже організована і може вийти з-під контролю швидко. Система маршрутизації Flight є набагато більш організованим і потужним способом обробки маршрутизації.
if
Це?
// /user/view_profile.php?id=1234 if ($_GET['id']) { $id = $_GET['id']; viewUserProfile($id); } // /user/edit_profile.php?id=1234 if ($_GET['id']) { $id = $_GET['id']; editUserProfile($id); } // і т.д...
Або це?
// index.php Flight::route('/user/@id', [ 'UserController', 'viewUserProfile' ]); Flight::route('/user/@id/edit', [ 'UserController', 'editUserProfile' ]); // У вашому app/controllers/UserController.php class UserController { public function viewUserProfile($id) { // зробити щось } public function editUserProfile($id) { // зробити щось } }
Сподіваюсь, ви вже почали бачити переваги використання централізованої системи маршрутизації. Це значно легше керувати та розуміти в довгостроковій перспективі!
Flight забезпечує простий і легкий спосіб обробки запитів і відповідей. Це основа того, що робить веб-фреймворк. Він приймає запит від браузера користувача, обробляє його, а потім надсилає відповідь. Це спосіб, яким ви можете створювати веб-додатки, які виконують такі дії, як показ профілю користувача, дозволяють користувачу входити в систему або дозволяють користувачу публікувати новий блог.
Запит — це те, що браузер користувача надсилає на ваш сервер, коли вони відвідують ваш веб-сайт. Цей запит містить інформацію про те, що користувач хоче зробити. Наприклад, він може містити інформацію про те, яку URL-адресу хоче відвідати користувач, які дані хоче надіслати користувач на ваш сервер, або який тип даних хоче отримати користувач від вашого сервера. Важливо знати, що запит є тільки для читання. Ви не можете змінити запит, але можете читати з нього.
Flight забезпечує простий спосіб доступу до інформації про запит. Ви можете отримати доступ до інформації про запит, використовуючи метод Flight::request(). Цей метод повертає об'єкт Request, який містить інформацію про запит. Ви можете використовувати цей об'єкт, щоб отримати інформацію про запит, наприклад, URL, метод або дані, які користувач надіслав на ваш сервер.
Flight::request()
Request
Відповідь — це те, що ваш сервер надсилає назад браузеру користувача, коли вони відвідують ваш веб-сайт. Ця відповідь містить інформацію про те, що ваш сервер хоче зробити. Наприклад, вона може містити інформацію про те, які дані ваш сервер хоче надіслати користувачу, які дані ваш сервер хоче отримати від користувача, або які дані ваш сервер хоче зберегти на комп'ютері користувача.
Flight надає простий спосіб надіслати відповідь браузеру користувача. Ви можете надіслати відповідь, використовуючи метод Flight::response(). Цей метод приймає об'єкт Response як аргумент і надсилає відповідь браузеру користувача. Ви можете використовувати цей об'єкт, щоб надіслати відповідь до браузера користувача, таку як HTML, JSON або файл. Flight допомагає вам автоматично генерувати деякі частини відповіді, щоб упростити процес, але в кінцевому підсумку ви маєте контроль над тим, що ви надсилаєте назад користувачу.
Flight::response()
Response
Flight допомагає генерувати частину заголовків відповіді для вас, але ви контролюєте більшість того, що надсилаєте назад користувачу. Іноді ви можете безпосередньо отримати доступ до об'єкта Response, але найчастіше ви будете використовувати екземпляр Flight для надсилання відповіді.
Flight
Flight використовує ob_start(), щоб буферизувати вихід. Це означає, що ви можете використовувати echo або print для надсилання відповіді користувачу, і Flight захопить це та надішле назад користувачу з відповідними заголовками.
echo
print
// Це надішле "Привіт, Світ!" у браузер користувача Flight::route('/', function() { echo "Привіт, Світ!"; }); // HTTP/1.1 200 OK // Content-Type: text/html // // Привіт, Світ!
Як альтернатива, ви можете викликати метод write(), щоб додати до тіла також.
write()
// Це надішле "Привіт, Світ!" у браузер користувача Flight::route('/', function() { // докладно, але іноді це необхідно Flight::response()->write("Привіт, Світ!"); // якщо ви хочете отримати тіло, яке ви встановили на цьому етапі // ви можете зробити це так $body = Flight::response()->getBody(); });
Ви можете встановити код статусу відповіді, використовуючи метод status:
status
Flight::route('/@id', function($id) { if($id == 123) { Flight::response()->status(200); echo "Привіт, Світ!"; } else { Flight::response()->status(403); echo "Заборонено"; } });
Якщо ви хочете отримати поточний код статусу, ви можете використовувати метод status без будь-яких аргументів:
Flight::response()->status(); // 200
Ви можете встановити тіло відповіді, використовуючи метод write, однак, якщо ви виконуєте echo або print, це буде захоплено і надіслано як тіло відповіді через буферизацію виходу.
write
Flight::route('/', function() { Flight::response()->write("Привіт, Світ!"); }); // те саме, що й Flight::route('/', function() { echo "Привіт, Світ!"; });
Якщо ви хочете очистити тіло відповіді, ви можете використовувати метод clearBody:
clearBody
Flight::route('/', function() { if($someCondition) { Flight::response()->write("Привіт, Світ!"); } else { Flight::response()->clearBody(); } });
Ви можете виконати зворотний виклик на тілі відповіді, використовуючи метод addResponseBodyCallback:
addResponseBodyCallback
Flight::route('/users', function() { $db = Flight::db(); $users = $db->fetchAll("SELECT * FROM users"); Flight::render('users_table', ['users' => $users]); }); // Це стисне всі відповіді для будь-якого маршруту Flight::response()->addResponseBodyCallback(function($body) { return gzencode($body, 9); });
Ви можете додати кілька зворотних викликів, і вони будуть виконані в порядку їх додавання. Оскільки це може приймати будь-який викликаємий, це може приймати масив класу [ $class, 'method' ], анонімну функцію $strReplace = function($body) { str_replace('hi', 'there', $body); };, або ім'я функції 'minify', якщо у вас є функція для мінімізації вашого HTML-коду, наприклад.
[ $class, 'method' ]
$strReplace = function($body) { str_replace('hi', 'there', $body); };
'minify'
Примітка: Зворотні виклики маршрутів не працюватимуть, якщо ви використовуєте опцію налаштування flight.v2.output_buffering.
Якщо ви хочете, щоб це застосовувалося тільки до конкретного маршруту, ви можете додати зворотний виклик безпосередньо в сам маршрут:
Flight::route('/users', function() { $db = Flight::db(); $users = $db->fetchAll("SELECT * FROM users"); Flight::render('users_table', ['users' => $users]); // Це стисне тільки відповідь для цього маршруту Flight::response()->addResponseBodyCallback(function($body) { return gzencode($body, 9); }); });
Ви також можете використовувати middleware, щоб застосувати зворотний виклик до всіх маршрутів через middleware:
// MinifyMiddleware.php class MinifyMiddleware { public function before() { // Застосуйте зворотний виклик тут до об'єкта response(). Flight::response()->addResponseBodyCallback(function($body) { return $this->minify($body); }); } protected function minify(string $body): string { // мінімізуйте тіло якимось чином return $body; } } // index.php Flight::group('/users', function() { Flight::route('', function() { /* ... */ }); Flight::route('/@id', function($id) { /* ... */ }); }, [ new MinifyMiddleware() ]);
Ви можете встановити заголовок, такий як тип вмісту відповіді, використовуючи метод header:
// Це надішле "Привіт, Світ!" у браузер користувача у незакодованому тексті Flight::route('/', function() { Flight::response()->header('Content-Type', 'text/plain'); // або Flight::response()->setHeader('Content-Type', 'text/plain'); echo "Привіт, Світ!"; });
Flight підтримує надсилання JSON і JSONP відповідей. Щоб надіслати JSON-відповідь, ви передаєте деякі дані для кодування в JSON:
Flight::json(['id' => 123]);
Ви також можете передати код статусу як другий аргумент:
Flight::json(['id' => 123], 201);
Ви також можете передати аргумент до останньої позиції для увімкнення красивого форматування:
Flight::json(['id' => 123], 200, true, 'utf-8', JSON_PRETTY_PRINT);
Якщо ви змінюєте параметри, передані в Flight::json(), і хочете спростити синтаксис, ви можете просто переназначити метод JSON:
Flight::json()
Flight::map('json', function($data, $code = 200, $options = 0) { Flight::_json($data, $code, true, 'utf-8', $options); } // І тепер його можна використовувати так Flight::json(['id' => 123], 200, JSON_PRETTY_PRINT);
Якщо ви хочете надіслати JSON-відповідь і зупинити виконання, ви можете використовувати метод jsonHalt. Це корисно для випадків, коли ви перевіряєте, можливо, якийсь вид авторизації, і якщо користувач не авторизований, ви можете надіслати JSON-відповідь негайно, очистити існуючий вміст тіла і зупинити виконання.
jsonHalt
Flight::route('/users', function() { $authorized = someAuthorizationCheck(); // Перевірте, чи користувач авторизований if($authorized === false) { Flight::jsonHalt(['error' => 'Неавторизований'], 401); } // Продовжте з рештою маршруту });
Перед v3.10.0, вам доводилося робити щось подібне:
Flight::route('/users', function() { $authorized = someAuthorizationCheck(); // Перевірте, чи користувач авторизований if($authorized === false) { Flight::halt(401, json_encode(['error' => 'Неавторизований'])); } // Продовжте з рештою маршруту });
Для запитів JSONP ви можете опціонально передати ім'я параметра запиту, який ви використовуєте для визначення вашої функції зворотного виклику:
Flight::jsonp(['id' => 123], 'q');
Отже, коли ви здійснюєте GET-запит з використанням ?q=my_func, ви повинні отримати вихід:
?q=my_func
my_func({"id":123});
Якщо ви не передасте ім'я параметра запиту, воно за замовчуванням буде jsonp.
jsonp
Ви можете перенаправити поточний запит, використовуючи метод redirect() і передавши нову URL-адресу:
Flight::redirect('/new/location');
За замовчуванням Flight надсилає код статусу HTTP 303 ("Перейти за іншим"). Ви можете додатково встановити кастомний код:
Flight::redirect('/new/location', 401);
Ви можете зупинити фреймворк у будь-який момент, викликавши метод halt:
halt
Flight::halt();
Ви також можете вказати необов'язковий код статусу HTTP і повідомлення:
HTTP
Flight::halt(200, 'Бувайте...');
Виклик halt скине будь-який вміст відповіді до цього моменту. Якщо ви хочете зупинити фреймворк і вивести поточну відповідь, використовуйте метод stop:
stop
Flight::stop();
Ви можете очистити тіло відповіді та заголовки, використовуючи метод clear(). Це очистить будь-які заголовки, призначені відповіді, очистить тіло відповіді та встановить код статусу на 200.
clear()
200
Flight::response()->clear();
Якщо ви хочете очистити тільки тіло відповіді, ви можете використовувати метод clearBody():
clearBody()
// Це все ще зберігатиме будь-які заголовки, встановлені на об'єкті response(). Flight::response()->clearBody();
Flight забезпечує вбудовану підтримку кешування на рівні HTTP. Якщо умови кешування виконуються, Flight поверне відповідь HTTP 304 Not Modified. Наступного разу, коли клієнт запросить той же ресурс, їх попросять використати свою локально кешовану версію.
304 Not Modified
Якщо ви хочете кешувати всю вашу відповідь, ви можете використовувати метод cache() і передати час для кешування.
cache()
// Це кешуватиме відповідь на 5 хвилин Flight::route('/news', function () { Flight::response()->cache(time() + 300); echo 'Цей вміст буде кешуватися.'; }); // Альтернативно, ви можете використовувати рядок, який ви передали б // до методу strtotime() Flight::route('/news', function () { Flight::response()->cache('+5 minutes'); echo 'Цей вміст буде кешуватися.'; });
Ви можете використовувати метод lastModified і передати UNIX-ташку, щоб встановити дату і час останньої модифікації сторінки. Клієнт продовжить використовувати свій кеш, поки значення останньої модифікації не зміниться.
lastModified
Flight::route('/news', function () { Flight::lastModified(1234567890); echo 'Цей вміст буде кешуватися.'; });
Кешування ETag схоже на Last-Modified, за винятком того, що ви можете вказати будь-який ідентифікатор, який ви бажаєте для ресурсу:
ETag
Last-Modified
Flight::route('/news', function () { Flight::etag('my-unique-id'); echo 'Цей вміст буде кешуватися.'; });
Пам'ятайте, що виклик будь-якого з методів lastModified або etag встановить і перевірить значення кешу. Якщо значення кешу однакове між запитами, Flight негайно надішле відповідь HTTP 304 і зупинить обробку.
etag
HTTP 304
Існує допоміжний метод для завантаження файлу. Ви можете використовувати метод download і передати шлях.
download
Flight::route('/download', function () { Flight::download('/path/to/file.txt'); });
Flight надає деякі базові функціональні можливості для шаблонізації за замовчуванням.
Якщо вам потрібні більш складні потреби в шаблонізації, подивіться приклади Smarty і Latte в розділі Custom Views.
Щоб відобразити шаблон перегляду, викликайте метод render з іменем файлу шаблону та необов'язковими даними шаблону:
render
Flight::render('hello.php', ['name' => 'Bob']);
Дані шаблону, які ви передаєте, автоматично вводяться в шаблон і можуть бути посиланнями, як локальні змінні. Файли шаблонів - це просто файли PHP. Якщо вміст файлу шаблону hello.php є:
hello.php
Hello, <?= $name ?>!
Вихідні дані будуть:
Hello, Bob!
Ви також можете вручну встановити змінні перегляду, використовуючи метод set:
Flight::view()->set('name', 'Bob');
Змінна name тепер доступна для всіх ваших переглядів. Тому ви просто можете зробити:
name
Flight::render('hello');
Зверніть увагу, що при вказуванні імені шаблону в методі render, ви можете опустити розширення .php.
.php
За замовчуванням Flight буде шукати директорію views для файлів шаблонів. Ви можете встановити альтернативний шлях для своїх шаблонів, задавши наступну конфігурацію:
views
Flight::set('flight.views.path', '/path/to/views');
Відомо, що веб-сайти мають єдиний шаблон макету з змінним вмістом. Щоб відобразити вміст, який буде використовуватися в макеті, ви можете передати необов'язковий параметр до методу render.
Flight::render('header', ['heading' => 'Hello'], 'headerContent'); Flight::render('body', ['body' => 'World'], 'bodyContent');
Ваш перегляд буде мати збережені змінні з іменами headerContent і bodyContent. Ви можете відобразити свій макет, виконавши:
headerContent
bodyContent
Flight::render('layout', ['title' => 'Home Page']);
Якщо файли шаблонів виглядають так:
header.php:
header.php
<h1><?= $heading ?></h1>
body.php:
body.php
<div><?= $body ?></div>
layout.php:
layout.php
<html> <head> <title><?= $title ?></title> </head> <body> <?= $headerContent ?> <?= $bodyContent ?> </body> </html>
<html> <head> <title>Home Page</title> </head> <body> <h1>Hello</h1> <div>World</div> </body> </html>
Flight дозволяє замінити дефолтний движок перегляду, просто зареєструвавши свій власний клас перегляду.
Ось як ви можете використовувати движок шаблонів Smarty для своїх переглядів:
// Завантажити бібліотеку Smarty require './Smarty/libs/Smarty.class.php'; // Зареєструвати Smarty як клас перегляду // Також передайте функцію зворотного виклику для налаштування Smarty при завантаженні Flight::register('view', Smarty::class, [], function (Smarty $smarty) { $smarty->setTemplateDir('./templates/'); $smarty->setCompileDir('./templates_c/'); $smarty->setConfigDir('./config/'); $smarty->setCacheDir('./cache/'); }); // Призначити дані шаблону Flight::view()->assign('name', 'Bob'); // Відобразити шаблон Flight::view()->display('hello.tpl');
Для повноти, вам також слід переоприділити дефолтний метод render Flight:
Flight::map('render', function(string $template, array $data): void { Flight::view()->assign($data); Flight::view()->display($template); });
Ось як ви можете використовувати движок шаблонів Latte для своїх переглядів:
// Зареєструвати Latte як клас перегляду // Також передайте функцію зворотного виклику для налаштування Latte при завантаженні Flight::register('view', Latte\Engine::class, [], function (Latte\Engine $latte) { // Тут Latte буде кешувати ваші шаблони для підвищення швидкості // Одна з цікавих особливостей Latte полягає в тому, що він автоматично оновлює ваш // кеш, коли ви вносите зміни до своїх шаблонів! $latte->setTempDirectory(__DIR__ . '/../cache/'); // Повідомте Latte, де буде коренева директорія для ваших переглядів. $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../views/')); }); // І підсумуйте це, щоб ви могли правильно використовувати Flight::render() Flight::map('render', function(string $template, array $data): void { // Це як $latte_engine->render($template, $data); echo Flight::view()->render($template, $data); });
Fat-Free (ласкаво відомий як F3) є потужним, але простим у використанні мікрофреймворком PHP, призначеним для допомоги у створенні динамічних і надійних веб-додатків - швидко!
Flight порівнюється з Fat-Free в багатьох аспектах і, мабуть, є найближчим родичем у термінах функціональності та простоти. Fat-Free має багато функцій, яких немає у Flight, але також має і багато функцій, які є у Flight. Fat-Free починає демонструвати свою старість і вже не є так популярним, як раніше.
Оновлення стають менш частими, а спільнота не така активна. Код досить простий, але іноді відсутність дисципліни в синтаксисі може ускладнити читання та розуміння. Він працює з PHP 8.3, але сам код все ще виглядає так, ніби живе у PHP 5.3.
GET
DB\SQL
active-record
Cache
beforeroute
afterroute
HIVE
Flight розроблений як розширювальний фреймворк. Фреймворк постачається з набором за замовчуванням методів та компонентів, але він дозволяє вам відображати свої власні методи, реєструвати свої власні класи або навіть переоприділяти існуючі класи та методи.
Якщо ви шукаєте DIC (Контейнер впровадження залежностей), досліджуйте Контейнер впровадження залежностей сторінку.
Щоб відобразити свій власний простий користувацький метод, використовуйте функцію map:
// Відобразіть свій метод Flight::map('hello', function (string $name) { echo "hello $name!"; }); // Викликайте свій користувацький метод Flight::hello('Bob');
Хоча можливе створення простих користувацьких методів, рекомендується просто створювати стандартні функції в PHP. Це має автозавершення в IDE та легше читається. Еквівалент наведенного вище коду буде:
function hello(string $name) { echo "hello $name!"; } hello('Bob');
Це використовується більше, коли вам потрібно передати змінні у ваш метод для отримання очікуваного значення. Використання методу register() як нижче більше підходить для передачі конфігурації а потім виклику вашого попередньо налаштованого класу.
register()
Щоб зареєструвати свій власний клас і налаштувати його, використовуйте функцію register:
// Зареєструйте свій клас Flight::register('user', User::class); // Отримайте екземпляр свого класу $user = Flight::user();
Метод реєстрації також дозволяє вам передавати параметри до конструктора вашого класу. Отже, коли ви завантажуєте свій користувацький клас, він буде попередньо ініціалізованим. Ви можете визначити параметри конструктора, передавши додатковий масив. Ось приклад завантаження підключення до бази даних:
// Зареєструйте клас з параметрами конструктора Flight::register('db', PDO::class, ['mysql:host=localhost;dbname=test', 'user', 'pass']); // Отримайте екземпляр свого класу // Це створить об'єкт з визначеними параметрами // // new PDO('mysql:host=localhost;dbname=test','user','pass'); // $db = Flight::db(); // і якщо вам це потрібно пізніше у вашому коді, ви просто викликаєте той же метод знову class SomeController { public function __construct() { $this->db = Flight::db(); } }
Якщо ви передаєте додатковий параметр зворотного виклику, він буде виконаний відразу після створення класу. Це дозволяє вам виконати будь-які процедури налаштування для вашого нового об'єкта. Функція зворотного виклику приймає один параметр, екземпляр нового об'єкта.
// Зворотний виклик буде переданий об'єкту, який був створений Flight::register( 'db', PDO::class, ['mysql:host=localhost;dbname=test', 'user', 'pass'], function (PDO $db) { $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } );
За замовчуванням, щоразу, коли ви завантажуєте свій клас, ви отримаєте спільний екземпляр. Щоб отримати новий екземпляр класу, просто передайте false як параметр:
// Спільний екземпляр класу $shared = Flight::db(); // Новий екземпляр класу $new = Flight::db(false);
Майте на увазі, що відображені методи мають перевагу над зареєстрованими класами. Якщо ви оголосите обидва з однаковим ім'ям, буде викликаний лише відображений метод.
Flight дозволяє вам переоприділити його стандартну функціональність відповідно до ваших потреб, не змінюючи жоден код. Ви можете переглянути всі методи, які можете переоприділити тут.
Наприклад, коли Flight не може співвіднести URL з маршрутом, він викликає метод notFound який надсилає загальний HTTP 404 відповідь. Ви можете переоприділити цю поведінку, використовуючи метод map:
HTTP 404
Flight::map('notFound', function() { // Відобразити власну 404 сторінку include 'errors/404.html'; });
Flight також дозволяє вам замінити основні компоненти фреймворку. Наприклад, ви можете замінити стандартний клас Router на свій власний власний клас:
// Зареєструйте свій власний клас Flight::register('router', MyRouter::class); // Коли Flight завантажує екземпляр Router, він завантажить ваш клас $myrouter = Flight::router();
Методи фреймворку, такі як map і register, однак не можуть бути переоприділені. Ви отримаєте помилку, якщо спробуєте це зробити.
Slim - це мікро-фреймворк PHP, який допомагає вам швидко писати прості, але потужні веб-додатки та API.
Багато з натхнення для деяких з функцій v3 Flight насправді прийшло від Slim. Групування маршрутів і виконання проміжного програмного забезпечення в конкретному порядку - це дві функції, які були натхнені Slim. Slim v3 з'явився, спрямований на простоту, але були змішані відгуки щодо v4.
Автозавантаження є концепцією в PHP, де ви вказуєте директорію або директорії для завантаження класів. Це набагато вигідніше, ніж використовувати require або include для завантаження класів. Це також є вимогою для використання пакетів Composer.
require
include
За замовчуванням будь-який клас Flight автоматично завантажується завдяки composer. Однак, якщо ви хочете автозавантажити власні класи, ви можете використовувати метод Flight::path(), щоб вказати директорію для завантаження класів.
Flight::path()
Припустимо, у нас є дерево директорій, як наведено нижче:
# Приклад шляху /home/user/project/my-flight-project/ ├── app │ ├── cache │ ├── config │ ├── controllers - містить контролери для цього проекту │ ├── translations │ ├── UTILS - містить класи лише для цього застосунку (це все в верхньому регістрі для прикладу далі) │ └── views └── public └── css └── js └── index.php
Ви, мабуть, помітили, що це та сама структура файлів, що і на цьому сайті документації.
Ви можете вказати кожну директорію для завантаження так:
/** * public/index.php */ // Додати шлях до автозавантажувача Flight::path(__DIR__.'/../app/controllers/'); Flight::path(__DIR__.'/../app/utils/'); /** * app/controllers/MyController.php */ // не потрібна неймспейсінг // Всіх автозавантажених класів рекомендується використовувати Pascal Case (кожне слово з великої літери, без пробілів) // Починаючи з 3.7.2, ви можете використовувати Pascal_Snake_Case для ваших імен класів, запустивши Loader::setV2ClassLoading(false); class MyController { public function index() { // зробіть щось } }
Якщо ви маєте неймспейси, це стає дуже простим для реалізації. Вам слід використовувати метод Flight::path(), щоб вказати кореневу директорію (не кореневу директорію документа чи папку public/) вашого застосунку.
public/
/** * public/index.php */ // Додати шлях до автозавантажувача Flight::path(__DIR__.'/../');
Тепер ваш контролер може виглядати так. Посмотріть на приклад нижче, але зверніть увагу на коментарі для важливої інформації.
/** * app/controllers/MyController.php */ // неймспейси є обов'язковими // неймспейси є такими ж, як структура директорій // неймспейси повинні відповідати такому ж регістру, як структура директорій // неймспейси та директорії не можуть містити жодних підкреслень (якщо не встановлено Loader::setV2ClassLoading(false)) namespace app\controllers; // Всіх автозавантажених класів рекомендується використовувати Pascal Case (кожне слово з великої літери, без пробілів) // Починаючи з 3.7.2, ви можете використовувати Pascal_Snake_Case для ваших імен класів, запустивши Loader::setV2ClassLoading(false); class MyController { public function index() { // зробіть щось } }
І якщо ви хочете автозавантажити клас у вашій директорії утиліт, ви будете робити в основному те ж саме:
/** * app/UTILS/ArrayHelperUtil.php */ // неймспейс повинен відповідати структурі директорії та регістру (зауважте, що директорія UTILS у верхньому регістрі // як у дереві файлів вище) namespace app\UTILS; class ArrayHelperUtil { public function changeArrayCase(array $array) { // зробіть щось } }
Починаючи з 3.7.2, ви можете використовувати Pascal_Snake_Case для ваших імен класів, запустивши Loader::setV2ClassLoading(false);. Це дозволить вам використовувати підкреслення в ваших іменах класів. Це не рекомендується, але це доступно для тих, хто це потребує.
Loader::setV2ClassLoading(false);
/** * public/index.php */ // Додати шлях до автозавантажувача Flight::path(__DIR__.'/../app/controllers/'); Flight::path(__DIR__.'/../app/utils/'); Loader::setV2ClassLoading(false); /** * app/controllers/My_Controller.php */ // не потрібна неймспейсінг class My_Controller { public function index() { // зробіть щось } }
Ця сторінка допоможе вам вирішити поширені проблеми, з якими ви можете зіткнутися при використанні Flight.
Якщо ви бачите помилку 404 Не знайдено (але клянетесь, що це дійсно там і це не помилка), це може бути проблемою з тим, що ви повертаєте значення у вашому маршруті замість того, щоб просто виводити його. Причина цього є навмисною, але може підкочуватися до деяких розробників.
Flight::route('/hello', function(){ // Це може викликати помилку 404 Не знайдено return 'Hello World'; }); // Що ви, напевно, хочете Flight::route('/hello', function(){ echo 'Hello World'; });
Причина цього полягає в особливому механізмі, вбудованому в маршрутизатор, який обробляє повернення виводу як одиночний для "перейти до наступного маршруту". Ви можете ознайомитися з поведінкою, задокументованою в розділі Маршрутизація.
Можливо, є кілька причин, чому це не відбувається. Нижче наведено кілька прикладів, але переконайтеся, що ви також переглянули розділ автозавантаження.
Найпоширенішою є те, що ім'я класу не відповідає імені файлу.
Якщо у вас є клас під назвою MyClass, то файл повинен називатися MyClass.php. Якщо у вас є клас під назвою MyClass, а файл називається myclass.php, тоді автозавантажувач не зможе його знайти.
MyClass
MyClass.php
myclass.php
Якщо ви використовуєте простори імен, то простір імен має відповідати структурі каталогу.
// код // якщо ваш MyController знаходиться в каталозі app/controllers і має простір імен // це не спрацює. Flight::route('/hello', 'MyController->hello'); // вам потрібно вибрати один з цих варіантів Flight::route('/hello', 'app\controllers\MyController->hello'); // або якщо у вас є оператор use на початку use app\controllers\MyController; Flight::route('/hello', [ MyController::class, 'hello' ]); // також можна записати Flight::route('/hello', MyController::class.'->hello'); // також... Flight::route('/hello', [ 'app\controllers\MyController', 'hello' ]);
path()
У скелетній програмі це визначено в файлі config.php, але для того, щоб ваші класи були знайдені, вам потрібно переконатися, що метод path() визначено (ймовірно, до кореня вашого каталогу) перед тим, як ви спробуєте його використовувати.
config.php
// Додайте шлях до автозавантажувача Flight::path(__DIR__.'/../');
Авторське право © 2024 @mikecao, @n0nag0n
2024
@mikecao, @n0nag0n
Цим надається дозвіл, безкоштовно, будь-якій особі, яка отримала копію цього програмного забезпечення та супутньої документації файлів (далі — “Програмне забезпечення”), користуватися Програмним забезпеченням без обмежень, включаючи без обмежень права на використання, копіювання, модифікацію, об’єднання, публікацію, розповсюдження, підліцензування та/або продаж копій Програмного забезпечення, а також дозволяти особам, яким Програмне забезпечення надано, робити це, за умов дотримання наступних умов:
Вищезазначене повідомлення про авторські права та це повідомлення про дозвіл повинні бути включені в усі копії або значні частини Програмного забезпечення.
ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ НАДАЄТЬСЯ “ЯК Є”, БЕЗ ГАРАНТІЙ БУДЬ-ЯКОГО РОДУ, ЯВНИХ АБО ПРИХОВАНИХ, ВКЛЮЧАЮЧИ, АЛЕ НЕ ОБМЕЖУЮЧИСЬ ГАРАНТІЯМИ КОМЕРЦІЙНОЇ РІЗНИЧКИ, ПРИДАТНОСТІ ДЛЯ ПЕВНОЇ МЕТИ ТА НЕПORУШЕННЯ. У ЖОДНОМУ ВИПАДКУ АВТОРИ АБО ВЛАСНИКИ АВТОРСЬКИХ ПРАВ НЕ НЕСУТЬ ВІДПОВІДАЛЬНОСТІ ЗА БУДЬ-ЯКІ ПРЕТЕНЗІЇ, ЗБИТКИ АБО ІНШІ ЗОБОВ'ЯЗАННЯ, ЧИ У ПРАВОВІЙ СПРАВІ, ДЕЛІКТІ АБО ІНШОМУ, ЩО ВИНИКЛО, ВИРІСШЕ З, АБО У ЗВ'ЯЗКУ З ПРОГРАМНИМ ЗАБЕЗПЕЧЕННЯМ АБО ВИКОРИСТАННЯМ АБО ІНШИМИ УГОДАМИ У ПРОГРАМНОМУ ЗАБЕЗПЕЧЕННІ.
Flight - це швидкий, простий, розширювальний фреймворк для PHP. Він досить універсальний і може бути використаний для створення будь-якого типу веб-додатків. Він спроектований з урахуванням простоти та написаний зрозумілою та зручною мовою.
Flight - чудовий фреймворк для початківців, які нові у PHP і хочуть навчитися будувати веб-додатки. Це також відмінний фреймворк для досвідчених розробників, які хочуть мати більше контролю над своїми веб-додатками. Він спроектований для легкого створення RESTful API, простого веб-додатка або складного веб-додатка.
<?php // якщо встановлено через composer require 'vendor/autoload.php'; // або якщо встановлено вручну через zip файл // require 'flight/Flight.php'; Flight::route('/', function() { echo 'привіт світ!'; }); Flight::route('/json', function() { Flight::json(['привіт' => 'світ']); }); Flight::start();
Досить просто, правда? Дізнайтеся більше про Flight у документації!
Існує приклад додатку, який може допомогти вам почати роботу з фреймворком Flight. Перейдіть до flightphp/skeleton для інструкцій про те, як почати! Ви також можете відвідати сторінку прикладів для натхнення щодо деяких речей, які ви можете зробити з Flight.
Ми в Matrix Чаті разом з нами за адресою #flight-php-framework:matrix.org.
Існує два способи, як ви можете внести свій внесок у Flight:
Flight вимагає PHP 7.4 або вище.
Примітка: PHP 7.4 підтримується, оскільки на момент написання (2024) PHP 7.4 є стандартною версією для деяких LTS дистрибутивів Linux. Примусове переходження на PHP >8 спричинило б багато незручностей для цих користувачів. Фреймворк також підтримує PHP >8.
Flight випущено під ліцензією MIT.
overclokk/cookie — це проста бібліотека для керування куки у вашому додатку.
Встановлення є простим за допомогою composer.
composer require overclokk/cookie
Використання таке ж просте, як реєстрація нового методу в класі Flight.
use Overclokk\Cookie\Cookie; /* * Встановіть у вашому bootstrap або public/index.php файлі */ Flight::register('cookie', Cookie::class); /** * ExampleController.php */ class ExampleController { public function login() { // Встановіть куки // ви захочете, щоб це було false, щоб отримати новий екземпляр // використовуйте наведену нижче коментар, якщо хочете автозаповнення /** @var \Overclokk\Cookie\Cookie $cookie */ $cookie = Flight::cookie(false); $cookie->set( 'stay_logged_in', // назва куки '1', // значення, яке ви хочете встановити 86400, // кількість секунд, протягом яких куки повинні існувати '/', // шлях, за яким куки будуть доступні 'example.com', // домен, за яким куки будуть доступні true, // куки будуть передаватися лише через безпечне HTTPS з'єднання true // куки будуть доступні лише через HTTP протокол ); // за бажанням, якщо ви хочете зберегти значення за замовчуванням // і мати швидкий спосіб встановити куки на тривалий час $cookie->forever('stay_logged_in', '1'); } public function home() { // Перевірте, чи маєте ви куки if (Flight::cookie()->has('stay_logged_in')) { // помістіть їх у область інформаційної панелі, наприклад. Flight::redirect('/dashboard'); } } }
defuse/php-encryption — це бібліотека, яку можна використовувати для шифрування та дешифрування даних. Запуск і налаштування досить прості, щоб почати шифрування та дешифрування даних. У них є чудовий посібник, який допомагає пояснити основи використання бібліотеки, а також важливі питання безпеки, пов’язані із шифруванням.
Встановлення просте за допомогою composer.
composer require defuse/php-encryption
Потім вам потрібно згенерувати ключ шифрування.
vendor/bin/generate-defuse-key
Це видасть ключ, який вам потрібно зберегти в безпеці. Ви можете зберегти ключ у вашому app/config/config.php файлі в масиві внизу файлу. Хоча це не ідеальне місце, але принаймні щось.
app/config/config.php
Тепер, коли у вас є бібліотека та ключ шифрування, ви можете почати шифрування та дешифрування даних.
use Defuse\Crypto\Crypto; use Defuse\Crypto\Key; /* * Встановіть у вашому bootstrap або public/index.php файлі */ // Метод шифрування Flight::map('encrypt', function($raw_data) { $encryption_key = /* $config['encryption_key'] або file_get_contents з того, де ви помістили ключ */; return Crypto::encrypt($raw_data, Key::loadFromAsciiSafeString($encryption_key)); }); // Метод дешифрування Flight::map('decrypt', function($encrypted_data) { $encryption_key = /* $config['encryption_key'] або file_get_contents з того, де ви помістили ключ */; try { $raw_data = Crypto::decrypt($encrypted_data, Key::loadFromAsciiSafeString($encryption_key)); } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) { // Атака! Або був завантажений неправильний ключ, або шифротекст було // змінено з моменту його створення — або пошкоджено в базі даних, або // навмисно змінено Евой, яка намагається здійснити атаку. // ... обробіть цей випадок таким чином, як це підходить для вашого застосунку ... } return $raw_data; }); Flight::route('/encrypt', function() { $encrypted_data = Flight::encrypt('Це секрет'); echo $encrypted_data; }); Flight::route('/decrypt', function() { $encrypted_data = '...'; // Отримати зашифровані дані звідкись $decrypted_data = Flight::decrypt($encrypted_data); echo $decrypted_data; });
Легка, проста та самостійна PHP клас кешування файлів
Переваги
Натисніть тут, щоб переглянути код.
Встановіть за допомогою composer:
composer require wruczek/php-file-cache
Використання досить просте.
use Wruczek\PhpFileCache\PhpFileCache; $app = Flight::app(); // Ви передаєте директорію, в якій буде зберігатися кеш, в конструктор $app->register('cache', PhpFileCache::class, [ __DIR__ . '/../cache/' ], function(PhpFileCache $cache) { // Це забезпечує, що кеш використовується лише в продуктивному режимі // ENVIRONMENT - це константа, яка встановлюється у вашому bootstrap файлі або в іншому місці вашого додатку $cache->setDevMode(ENVIRONMENT === 'development'); });
Тоді ви можете використовувати це у своєму коді так:
// Отримати екземпляр кешу $cache = Flight::cache(); $data = $cache->refreshIfExpired('simple-cache-test', function () { return date("H:i:s"); // повернути дані для кешування }, 10); // 10 секунд // або $data = $cache->retrieve('simple-cache-test'); if(empty($data)) { $data = date("H:i:s"); $cache->store('simple-cache-test', $data, 10); // 10 секунд }
Відвідайте https://github.com/Wruczek/PHP-File-Cache для повної документації і обов'язково перегляньте папку прикладів.
Це модуль дозволів, який можна використовувати у ваших проектах, якщо у вас є кілька ролей у вашому додатку, і кожна роль має трохи відмінну функціональність. Цей модуль дозволяє вам визначити дозволи для кожної ролі, а потім перевірити, чи має поточний користувач дозвіл на доступ до певної сторінки або виконання певної дії.
Клікніть тут, щоб перейти до репозиторію на GitHub.
Запустіть composer require flightphp/permissions, і ви на правильному шляху!
composer require flightphp/permissions
Спочатку вам потрібно налаштувати ваші дозволи, потім ви скажете вашому додатку, що означають ці дозволи. Врешті-решт, ви будете перевіряти ваші дозволи за допомогою $Permissions->has(), ->can(), або is(). has() і can() мають однакову функціональність, але називаються по-різному, щоб зробити ваш код читабельнішим.
$Permissions->has()
->can()
is()
has()
can()
Припустимо, що у вас є функція у вашому додатку, яка перевіряє, чи ввійшов користувач. Ви можете створити об'єкт дозволу таким чином:
// index.php require 'vendor/autoload.php'; // деякий код // потім, напевно, у вас є щось, що говорить вам, яка поточна роль особи // ймовірно, у вас є щось, де ви витягуєте поточну роль // з змінної сесії, яка це визначає // після того, як хтось увійде, інакше у них буде роль 'гостя' або 'публічна'. $current_role = 'admin'; // налаштування дозволів $permission = new \flight\Permission($current_role); $permission->defineRule('loggedIn', function($current_role) { return $current_role !== 'guest'; }); // Ви, напевно, захотите зберегти цей об'єкт у Flight десь Flight::set('permission', $permission);
Потім у контролері десь ви можете мати щось на зразок цього.
<?php // якийсь контролер class SomeController { public function someAction() { $permission = Flight::get('permission'); if ($permission->has('loggedIn')) { // зробити щось } else { // зробити щось інше } } }
Ви також можете використовувати це, щоб відстежувати, чи мають вони дозвіл робити щось у вашому додатку. Наприклад, якщо у вас є спосіб, яким користувачі можуть взаємодіяти з публікацією у вашому програмному забезпеченні, ви можете перевірити, чи мають вони дозвіл на виконання певних дій.
$current_role = 'admin'; // налаштування дозволів $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);
Потім у контролері десь...
class PostController { public function create() { $permission = Flight::get('permission'); if ($permission->can('post.create')) { // зробити щось } else { // зробити щось інше } } }
Ви можете впроваджувати залежності у замикання, яке визначає дозволи. Це корисно, якщо у вас є якийсь перемикач, id, або будь-яка інша точка даних, з якою ви хочете перевірити. Те ж саме стосується викликів типу Клас->Метод, за винятком того, що ви визначаєте аргументи в методі.
$Permission->defineRule('order', function(string $current_role, MyDependency $MyDependency = null) { // ... код }); // у вашому файлі контролера public function createOrder() { $MyDependency = Flight::myDependency(); $permission = Flight::get('permission'); if ($permission->can('order.create', $MyDependency)) { // зробити щось } else { // зробити щось інше } }
namespace MyApp; class Permissions { public function order(string $current_role, MyDependency $MyDependency = null) { // ... код } }
Ви також можете використовувати класи для визначення ваших дозволів. Це корисно, якщо у вас багато дозволів, і ви хочете зберегти ваш код чистим. Ви можете зробити щось на зразок цього:
<?php // код завантаження $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) { // Припускаємо, що ви налаштували це раніше /** @var \flight\database\PdoWrapper $db */ $db = Flight::db(); $allowed_permissions = [ 'read' ]; // всі можуть переглядати замовлення if($current_role === 'manager') { $allowed_permissions[] = 'create'; // менеджери можуть створювати замовлення } $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'; // якщо у користувача є спеціальний перемикач, вони можуть оновлювати замовлення } if($current_role === 'admin') { $allowed_permissions[] = 'delete'; // адміністратори можуть видаляти замовлення } return $allowed_permissions; } }
Завдяки цьому є також швидкий спосіб, який ви можете використовувати (який також може бути кешованим!!!), де ви просто говорите класу дозволів відобразити всі методи в класі в дозволи. Отже, якщо у вас є метод з назвою order() і метод з назвою company(), ці методи будуть автоматично відображені, так що ви зможете просто запустити $Permissions->has('order.read') або $Permissions->has('company.read'), і це спрацює. Визначити це дуже складно, тому залишайтеся зі мною тут. Вам просто потрібно зробити це:
order()
company()
$Permissions->has('order.read')
$Permissions->has('company.read')
Створіть клас дозволів, які ви хочете об'єднати разом.
class MyPermissions { public function order(string $current_role, int $order_id = 0): array { // код для визначення дозволів return $permissions_array; } public function company(string $current_role, int $company_id): array { // код для визначення дозволів return $permissions_array; } }
Потім зробіть дозволи видимими за допомогою цієї бібліотеки.
$Permissions = new \flight\Permission($current_role); $Permissions->defineRulesFromClassMethods(MyApp\Permissions::class); Flight::set('permissions', $Permissions);
Нарешті, викликайте дозвіл у вашій кодовій базі, щоб перевірити, чи дозволено користувачу виконати даний дозвіл.
class SomeController { public function createOrder() { if(Flight::get('permissions')->can('order.create') === false) { die('Ви не можете створити замовлення. Вибачте!'); } } }
Щоб увімкнути кешування, ознайомтеся з простим wruczak/phpfilecache бібліотекою. Приклад увімкнення цього наведено нижче.
// цей $app може бути частиною вашого коду, або // ви можете просто передати null, і це // витягне з Flight::app() у конструкторі $app = Flight::app(); // Поки що він приймає це як кеш файлів. Інші можна легко // додати в майбутньому. $Cache = new Wruczek\PhpFileCache\PhpFileCache; $Permissions = new \flight\Permission($current_role, $app, $Cache); $Permissions->defineRulesFromClassMethods(MyApp\Permissions::class, 3600); // 3600 - це скільки секунд кешувати це. Залиште це, щоб не використовувати кешування
І вперед!
Flight постачається з допоміжним класом для PDO. Це дозволяє вам легко запитувати вашу базу даних з усією підготовкою/виконанням/fetchAll() заморочкою. Це значно спрощує, як ви можете запитувати вашу базу даних. Кожен рядок результату повертається як клас Colletion Flight, який дозволяє вам отримувати доступ до ваших даних через синтаксис масиву або синтаксис об'єкта.
// Зареєструйте клас допомоги 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 ] ]);
Цей об'єкт розширює PDO, тому всі звичайні методи PDO доступні. Наступні методи додані, щоб спростити запити до бази даних:
runQuery(string $sql, array $params = []): PDOStatement
Використовуйте це для ВСТАВКИ, ОНОВЛЕННЯ або якщо ви плануєте використовувати SELECT в циклі while
$db = Flight::db(); $statement = $db->runQuery("SELECT * FROM table WHERE something = ?", [ $something ]); while($row = $statement->fetch()) { // ... } // Або запис до бази даних $db->runQuery("INSERT INTO table (name) VALUES (?)", [ $name ]); $db->runQuery("UPDATE table SET name = ? WHERE id = ?", [ $name, $id ]);
fetchField(string $sql, array $params = []): mixed
Отримує перше поле з запиту
$db = Flight::db(); $count = $db->fetchField("SELECT COUNT(*) FROM table WHERE something = ?", [ $something ]);
fetchRow(string $sql, array $params = []): array
Отримує один рядок з запиту
$db = Flight::db(); $row = $db->fetchRow("SELECT id, name FROM table WHERE id = ?", [ $id ]); echo $row['name']; // або echo $row->name;
fetchAll(string $sql, array $params = []): array
Отримує всі рядки з запиту
$db = Flight::db(); $rows = $db->fetchAll("SELECT id, name FROM table WHERE something = ?", [ $something ]); foreach($rows as $row) { echo $row['name']; // або echo $row->name; }
IN()
Це також має корисну обгортку для операторів IN(). Ви можете просто передати один знак питання як заповнювач для IN() а потім масив значень. Ось приклад того, як це може виглядати:
$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 ]);
// Приклад маршруту і як ви б використовували цю обгортку Flight::route('/users', function () { // Отримати всіх користувачів $users = Flight::db()->fetchAll('SELECT * FROM users'); // Потік всіх користувачів $statement = Flight::db()->runQuery('SELECT * FROM users'); while ($user = $statement->fetch()) { echo $user['name']; // або echo $user->name; } // Отримати одного користувача $user = Flight::db()->fetchRow('SELECT * FROM users WHERE id = ?', [123]); // Отримати одне значення $count = Flight::db()->fetchField('SELECT COUNT(*) FROM users'); // Спеціальний синтаксис IN() для допомоги (обов'язково, щоб IN було великими літерами) $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [[1,2,3,4,5]]); // ви також можете зробити так $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [ '1,2,3,4,5']); // Вставити нового користувача Flight::db()->runQuery("INSERT INTO users (name, email) VALUES (?, ?)", ['Bob', 'bob@example.com']); $insert_id = Flight::db()->lastInsertId(); // Оновити користувача Flight::db()->runQuery("UPDATE users SET name = ? WHERE id = ?", ['Bob', 123]); // Видалити користувача Flight::db()->runQuery("DELETE FROM users WHERE id = ?", [123]); // Отримати кількість змінених рядків $statement = Flight::db()->runQuery("UPDATE users SET name = ? WHERE name = ?", ['Bob', 'Sally']); $affected_rows = $statement->rowCount(); });
PHP Менеджер Сесій (нема блокувань, flash, сегмент, шифрування сесій). Використовує PHP open_ssl для необов’язкового шифрування/дешифрування даних сесії. Підтримує файли, MySQL, Redis та Memcached.
Встановіть за допомогою composer.
composer require ghostff/session
Вам не потрібно передавати нічого, щоб використовувати налаштування за замовчуванням з вашою сесією. Ви можете прочитати про більше налаштувань у Github Readme.
use Ghostff\Session\Session; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('session', Session::class); // одна річ, яку потрібно пам’ятати, це те, що ви повинні зафіксувати свою сесію при завантаженні кожної сторінки // або вам потрібно буде виконати auto_commit у вашій конфігурації.
Ось простий приклад того, як ви могли б це використовувати.
Flight::route('POST /login', function() { $session = Flight::session(); // виконайте вашу логіку входу тут // перевірте пароль тощо. // якщо вхід успішний $session->set('is_logged_in', true); $session->set('user', $user); // кожного разу, коли ви записуєте у сесію, ви повинні зафіксувати її навмисно. $session->commit(); }); // Ця перевірка могла б бути в логіці обмеженої сторінки або обернута з middleware. Flight::route('/some-restricted-page', function() { $session = Flight::session(); if(!$session->get('is_logged_in')) { Flight::redirect('/login'); } // виконайте вашу логіку обмеженої сторінки тут }); // версія middleware Flight::route('/some-restricted-page', function() { // звичайна логіка сторінки })->addMiddleware(function() { $session = Flight::session(); if(!$session->get('is_logged_in')) { Flight::redirect('/login'); } });
Ось більш складний приклад того, як ви могли б це використовувати.
use Ghostff\Session\Session; require 'vendor/autoload.php'; $app = Flight::app(); // задайте власний шлях до вашого файлу конфігурації сесій і дайте йому випадковий рядок для ідентифікатора сесії $app->register('session', Session::class, [ 'path/to/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) { // або ви можете вручну перезаписати параметри конфігурації $session->updateConfiguration([ // якщо ви хочете зберігати дані своєї сесії в базі даних (добре, якщо ви хочете щось на кшталт "вийти з усіх пристроїв") Session::CONFIG_DRIVER => Ghostff\Session\Drivers\MySql::class, Session::CONFIG_ENCRYPT_DATA => true, Session::CONFIG_SALT_KEY => hash('sha256', 'my-super-S3CR3T-salt'), // будь ласка, змініть це на щось інше Session::CONFIG_AUTO_COMMIT => true, // робіть це лише якщо це потрібно і/або важко зафіксувати() вашу сесію. // додатково ви могли б зробити Flight::after('start', function() { Flight::session()->commit(); }); Session::CONFIG_MYSQL_DS => [ 'driver' => 'mysql', # Драйвер бази даних для PDO dns eg(mysql:host=...;dbname=...) 'host' => '127.0.0.1', # Хост бази даних 'db_name' => 'my_app_database', # Назва бази даних 'db_table' => 'sessions', # Таблиця бази даних 'db_user' => 'root', # Ім’я користувача бази даних 'db_pass' => '', # Пароль бази даних 'persistent_conn'=> false, # Уникайте накладних витрат на установку нового з’єднання щоразу, коли скрипт потребує зв’язку з базою даних, що призводить до швидшого веб-застосунку. ЗНАЙДІТЬ ЗВОРОТНІСТЬ САМОСТІЙНО ] ]); } );
Ви встановлюєте свої дані сесії, але вони не зберігаються між запитами? Ви могли забути зафіксувати свої дані сесії. Ви можете зробити це, викликавши $session->commit(), після того як ви встановили свої дані сесії.
$session->commit()
Flight::route('POST /login', function() { $session = Flight::session(); // виконайте вашу логіку входу тут // перевірте пароль тощо. // якщо вхід успішний $session->set('is_logged_in', true); $session->set('user', $user); // кожного разу, коли ви записуєте у сесію, ви повинні зафіксувати її навмисно. $session->commit(); });
Інший спосіб вирішення цієї проблеми - це коли ви налаштовуєте свою службу сесій, ви повинні встановити auto_commit на true у вашій конфігурації. Це автоматично зафіксує ваші дані сесії після кожного запиту.
auto_commit
$app->register('session', Session::class, [ 'path/to/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) { $session->updateConfiguration([ Session::CONFIG_AUTO_COMMIT => true, ]); } );
Додатково ви могли б зробити Flight::after('start', function() { Flight::session()->commit(); });, щоб зафіксувати свої дані сесії після кожного запиту.
Flight::after('start', function() { Flight::session()->commit(); });
Відвідайте Github Readme для повної документації. Параметри конфігурації добре задокументовані у файлі default_config.php. Код простий для розуміння, якщо ви хочете переглянути цей пакет самостійно.
Розгін - це CLI-додаток, який допомагає вам керувати вашими застосунками Flight. Він може генерувати контролери, відображати всі маршрути та багато іншого. Він базується на відмінній бібліотеці adhocore/php-cli.
composer require flightphp/runway
Перший раз, коли ви запустите Розгін, він проведе вас через процес налаштування і створить файл конфігурації .runway.json у корені вашого проєкту. Цей файл міститиме необхідні конфігурації для коректної роботи Розгону.
.runway.json
Розгін має кілька команд, які ви можете використовувати для керування вашим застосунком Flight. Є два простих способи використовувати Розгін.
php runway [command]
vendor/bin/runway [command]
Для будь-якої команди ви можете передати прапор --help, щоб отримати більше інформації про те, як використовувати команду.
--help
php runway routes --help
Ось кілька прикладів:
На основі конфігурації у вашому файлі .runway.json, за замовчуванням буде згенеровано контролер у каталозі app/controllers/.
app/controllers/
php runway make:controller MyController
На основі конфігурації у вашому файлі .runway.json, за замовчуванням буде згенеровано контролер у каталозі app/records/.
app/records/
php runway make:record users
Якщо, наприклад, у вас є таблиця users з наступною схемою: id, name, email, created_at, updated_at, буде створено файл подібний до наступного у файлі app/records/UserRecord.php:
users
email
created_at
updated_at
app/records/UserRecord.php
<?php declare(strict_types=1); namespace app\records; /** * Клас ActiveRecord для таблиці користувачів. * @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 * // ви також можете додати зв'язки тут, як тільки визначите їх у масиві $relations * @property CompanyRecord $company Приклад зв'язку */ class UserRecord extends \flight\ActiveRecord { /** * @var array $relations Встановити зв'язки для моделі * https://docs.flightphp.com/awesome-plugins/active-record#relationships */ protected array $relations = []; /** * Конструктор * @param mixed $databaseConnection З'єднання з базою даних */ public function __construct($databaseConnection) { parent::__construct($databaseConnection, 'users'); } }
Це відобразить всі маршрути, які наразі зареєстровані в Flight.
php runway routes
Якщо ви хочете переглянути лише конкретні маршрути, ви можете передати прапор для фільтрації маршрутів.
# Відображати лише маршрути GET php runway routes --get # Відображати лише маршрути POST php runway routes --post # тощо.
Якщо ви або створюєте пакет для Flight, або хочете додати свої власні команди у свій проєкт, ви можете це зробити, створивши каталог src/commands/, flight/commands/, app/commands/, або commands/ для вашого проєкту/пакету.
src/commands/
flight/commands/
app/commands/
commands/
Щоб створити команду, вам просто потрібно розширити клас AbstractBaseCommand і реалізувати, принаймні, методи __construct та execute.
AbstractBaseCommand
__construct
execute
<?php declare(strict_types=1); namespace flight\commands; class ExampleCommand extends AbstractBaseCommand { /** * Конструктор * * @param array<string,mixed> $config JSON конфігурація з .runway-config.json */ public function __construct(array $config) { parent::__construct('make:example', 'Створити приклад для документації', $config); $this->argument('<funny-gif>', 'Назва смішного гіфу'); } /** * Виконує функцію * * @return void */ public function execute(string $controller) { $io = $this->app()->io(); $io->info('Створення прикладу...'); // Зробіть щось тут $io->ok('Приклад створено!'); } }
Дивіться adhocore/php-cli Документацію для отримання додаткової інформації про те, як створити свої власні команди у вашому застосунку Flight!
Це набір розширень, щоб зробити роботу з Flight трохи більш насиченою.
$_SESSION
Це панель
І кожна панель показує дуже корисну інформацію про вашу програму!
Запустіть composer require flightphp/tracy-extensions --dev і ви на правильному шляху!
composer require flightphp/tracy-extensions --dev
Є дуже небагато конфігурацій, які вам потрібно зробити, щоб це запрацювало. Вам потрібно ініціювати відладчик Tracy перед використанням цього https://tracy.nette.org/en/guide:
<?php use Tracy\Debugger; use flight\debug\tracy\TracyExtensionLoader; // код завантаження require __DIR__ . '/vendor/autoload.php'; Debugger::enable(); // Можливо, вам потрібно вказати ваше середовище з Debugger::enable(Debugger::DEVELOPMENT) // якщо ви використовуєте з'єднання з базою даних у вашій програмі, // необхідний обгортка PDO, щоб використовувати ТІЛЬКИ В РОЗРОБЦІ (не в продукції, будь ласка!) // Він має ті ж параметри, що й звичайне з'єднання PDO $pdo = new PdoQueryCapture('sqlite:test.db', 'user', 'pass'); // або, якщо ви прикріпите це до фреймворку Flight Flight::register('db', PdoQueryCapture::class, ['sqlite:test.db', 'user', 'pass']); // тепер щоразу, коли ви виконуєте запит, він буде реєструвати час, запит та параметри // Це з'єднує всі точки if(Debugger::$showBar === true) { // Це повинно бути false або Tracy не зможе відобразити :( Flight::set('flight.content_length', false); new TracyExtensionLoader(Flight::app()); } // більше коду Flight::start();
Якщо у вас є власний обробник сесій (такий як ghostff/session), ви можете передати будь-який масив даних сесії до Tracy, і вона автоматично виведе його для вас. Ви передаєте його з ключем session_data у другому параметрі конструктора TracyExtensionLoader.
session_data
TracyExtensionLoader
use Ghostff\Session\Session; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('session', Session::class); if(Debugger::$showBar === true) { // Це повинно бути false або Tracy не зможе відобразити :( Flight::set('flight.content_length', false); new TracyExtensionLoader(Flight::app(), [ 'session_data' => Flight::session()->getAll() ]); } // маршрути та інші речі... Flight::start();
Якщо у вас є Latte, встановлений у вашому проекті, ви можете використовувати панель Latte для аналізу ваших шаблонів. Ви можете передати екземпляр Latte до конструктора TracyExtensionLoader з ключем latte у другому параметрі.
latte
use Latte\Engine; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('latte', Engine::class, [], function($latte) { $latte->setTempDirectory(__DIR__ . '/temp'); // це те місце, де ви додаєте панель Latte до Tracy $latte->addExtension(new Latte\Bridges\Tracy\TracyExtension); }); if(Debugger::$showBar === true) { // Це повинно бути false або Tracy не зможе відобразити :( Flight::set('flight.content_length', false); new TracyExtensionLoader(Flight::app()); }
Tracy — це чудовий обробник помилок, який можна використовувати з Flight. Він має кілька панелей, які можуть допомогти вам налагодити вашу програму. Також його дуже легко розширити та додати свої панелі. Команда Flight створила кілька панелей спеціально для проектів Flight за допомогою плагіна flightphp/tracy-extensions.
Встановіть з Composer. І вам насправді захочеться встановити це без версії для розробників, оскільки Tracy постачається з компонентом обробки помилок для виробництва.
composer require tracy/tracy
Є кілька основних параметрів конфігурації, щоб почати. Ви можете прочитати більше про них у Документації Tracy.
require 'vendor/autoload.php'; use Tracy\Debugger; // Увімкніть Tracy Debugger::enable(); // Debugger::enable(Debugger::DEVELOPMENT) // іноді вам потрібно бути явним (також Debugger::PRODUCTION) // Debugger::enable('23.75.345.200'); // ви також можете надати масив IP-адрес // Тут будуть записані помилки та виключення. Переконайтеся, що цей каталог існує і має право на запис. Debugger::$logDirectory = __DIR__ . '/../log/'; Debugger::$strictMode = true; // показувати всі помилки // Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // всі помилки, крім застарілих повідомлень if (Debugger::$showBar) { $app->set('flight.content_length', false); // якщо панель Debugger видима, то довжину вмісту не можна встановити Flight // Це специфічно для розширення Tracy для Flight, якщо ви це включили // інакше прокоментуйте це. new TracyExtensionLoader($app); }
Коли ви налагоджуєте свій код, є кілька дуже корисних функцій для виводу даних для вас.
bdump($var)
dumpe($var)
Активний запис - це відображення об'єкта бази даних на PHP об'єкт. Простими словами, якщо у вас є таблиця користувачів у вашій базі даних, ви можете "перекласти" рядок у цій таблиці на клас User і об'єкт $user у ваше кодове базі. Дивіться основний приклад.
User
$user
Натисніть тут, щоб перейти до репозиторію на GitHub.
Припустимо, у вас є наступна таблиця:
CREATE TABLE users ( id INTEGER PRIMARY KEY, name TEXT, password TEXT );
Тепер ви можете створити новий клас, щоб представляти цю таблицю:
/** * Клас ActiveRecord зазвичай є в однині * * Рекомендується додавати властивості таблиці як коментарі тут * * @property int $id * @property string $name * @property string $password */ class User extends flight\ActiveRecord { public function __construct($database_connection) { // ви можете налаштувати його таким чином parent::__construct($database_connection, 'users'); // або таким чином parent::__construct($database_connection, null, [ 'table' => 'users']); } }
Тепер спостерігайте за магією!
// для sqlite $database_connection = new PDO('sqlite:test.db'); // це просто для прикладу, ви, напевно, використовуєте реальне з’єднання з базою даних // для mysql $database_connection = new PDO('mysql:host=localhost;dbname=test_db&charset=utf8bm4', 'username', 'password'); // або mysqli $database_connection = new mysqli('localhost', 'username', 'password', 'test_db'); // або mysqli з не об'єктним створенням $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(); // або $user->save(); echo $user->id; // 1 $user->name = 'Joseph Mamma'; $user->password = password_hash('some cool password again!!!'); $user->insert(); // не можна використовувати $user->save() тут, інакше це буде вважатися оновленням! echo $user->id; // 2
І це було так просто, щоб додати нового користувача! Тепер, коли в базі даних є рядок користувача, як витягти його?
$user->find(1); // знайти id = 1 у базі даних і повернути його. echo $user->name; // 'Bobby Tables'
А що, якщо ви хочете знайти всіх користувачів?
$users = $user->findAll();
А що стосується певної умови?
$users = $user->like('name', '%mamma%')->findAll();
Бачите, як це весело? Давайте встановимо його та почнемо!
Просто встановіть за допомогою Composer
composer require flightphp/active-record
Це можна використовувати як незалежну бібліотеку або з PHP фреймворком Flight. Повністю на ваш розсуд.
Просто переконайтеся, що ви передаєте з'єднання PDO до конструктора.
$pdo_connection = new PDO('sqlite:test.db'); // це просто для прикладу, ви, напевно, використовуєте реальне з’єднання з базою даних $User = new User($pdo_connection);
Не хочете завжди налаштовувати з'єднання з базою даних у конструкторі? Дивіться Управління з'єднанням з базою даних для інших ідей!
Якщо ви використовуєте PHP фреймворк Flight, ви можете зареєструвати клас ActiveRecord як сервіс, але вам насправді не потрібно цього робити.
Flight::register('user', 'User', [ $pdo_connection ]); // тоді ви можете використовувати це так у контролері, функції тощо. Flight::user()->find(1);
runway
runway - це CLI інструмент для Flight, який має спеціальну команду для цієї бібліотеки.
# Використання php runway make:record database_table_name [class_name] # Приклад php runway make:record users
Це створить новий клас у каталозі app/records/ як UserRecord.php з наступним вмістом:
UserRecord.php
<?php declare(strict_types=1); namespace app\records; /** * Клас ActiveRecord для таблиці користувачів. * @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 Встановіть зв'язки для моделі * https://docs.flightphp.com/awesome-plugins/active-record#relationships */ protected array $relations = [ // 'relation_name' => [ self::HAS_MANY, 'RelatedClass', 'foreign_key' ], ]; /** * Конструктор * @param mixed $databaseConnection З’єднання з базою даних */ public function __construct($databaseConnection) { parent::__construct($databaseConnection, 'users'); } }
find($id = null) : boolean|ActiveRecord
Знайти один запис і присвоїти його поточному об'єкту. Якщо ви передаєте $id якесь значення, то вона виконає пошук по первинному ключу з цим значенням. Якщо нічого не передано, вона просто знайде перший запис у таблиці.
Додатково ви можете передати йому інші допоміжні методи для запиту до вашої таблиці.
// знайти запис з деякими умовами заздалегідь $user->notNull('password')->orderBy('id DESC')->find(); // знайти запис за певним id $id = 123; $user->find($id);
findAll(): array<int,ActiveRecord>
Знаходить усі записи в таблиці, яку ви вкажете.
$user->findAll();
isHydrated(): boolean
Повертає true, якщо поточний запис був гідратизований (отриманий з бази даних).
$user->find(1); // якщо запис знайдений з даними... $user->isHydrated(); // true
insert(): boolean|ActiveRecord
Вставляє поточний запис у базу даних.
$user = new User($pdo_connection); $user->name = 'demo'; $user->password = md5('demo'); $user->insert();
Якщо у вас є текстовий первинний ключ (такий як UUID), ви можете встановити значення первинного ключа перед вставкою одним із двох способів.
$user = new User($pdo_connection, [ 'primaryKey' => 'uuid' ]); $user->uuid = 'some-uuid'; $user->name = 'demo'; $user->password = md5('demo'); $user->insert(); // або $user->save();
або ви можете мати первинний ключ, автоматично згенерований для вас через події.
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users', [ 'primaryKey' => 'uuid' ]); // ви також можете встановити первинний ключ таким чином замість масиву вище. $this->primaryKey = 'uuid'; } protected function beforeInsert(self $self) { $self->uuid = uniqid(); // або як вам потрібно згенерувати ваші унікальні ідентифікатори } }
Якщо ви не встановите первинний ключ перед вставкою, він буде встановлено на rowid, і база даних згенерує його для вас, але він не буде зберігатися, оскільки це поле може не існувати у вашій таблиці. Ось чому рекомендується використовувати цю подію, щоб автоматично обробляти це за вас.
rowid
update(): boolean|ActiveRecord
Оновлює поточний запис у базі даних.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); $user->email = 'test@example.com'; $user->update();
save(): boolean|ActiveRecord
Вставляє або оновлює поточний запис у базі даних. Якщо запис має id, він оновиться, інакше буде вставлено.
$user = new User($pdo_connection); $user->name = 'demo'; $user->password = md5('demo'); $user->save();
Примітка: Якщо у вас є зв'язки, визначені в класі, вони також будуть рекурсивно зберігатися, якщо вони були визначені, створені та мають брудні дані для оновлення. (v0.4.0 і вище)
delete(): boolean
Видаляє поточний запис з бази даних.
$user->gt('id', 0)->orderBy('id desc')->find(); $user->delete();
Ви також можете видалити кілька записів, виконуючи пошук заздалегідь.
$user->like('name', 'Bob%')->delete();
dirty(array $dirty = []): ActiveRecord
Брудні дані відносяться до даних, які були змінені в запису.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); // на даний момент нічого не є "брудним". $user->email = 'test@example.com'; // тепер електронна пошта вважається "брудною", оскільки була змінена. $user->update(); // тепер немає даних, які є брудними, оскільки вони були оновлені та збережені в базі даних $user->password = password_hash()'newpassword'); // тепер це брудно $user->dirty(); // не передаючи нічого, ви очистите всі брудні записи. $user->update(); // нічого не буде оновлено, оскільки нічого не було захоплено як брудне. $user->dirty([ 'name' => 'something', 'password' => password_hash('a different password') ]); $user->update(); // і ім'я, і пароль оновлені.
copyFrom(array $data): ActiveRecord
Це псевдоним для методу dirty(). Це трохи ясніше, що ви робите.
dirty()
$user->copyFrom([ 'name' => 'something', 'password' => password_hash('a different password') ]); $user->update(); // і ім'я, і пароль оновлені.
isDirty(): boolean
Повертає true, якщо поточний запис був змінений.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); $user->email = 'test@email.com'; $user->isDirty(); // true
reset(bool $include_query_data = true): ActiveRecord
Скидає поточний запис до початкового стану. Це дійсно добре використовувати в поведінках на кшталт циклу. Якщо ви передаєте true, вона також скине дані запиту, які використовувалися для знаходження поточного об’єкта (за замовчуванням).
$users = $user->greaterThan('id', 0)->orderBy('id desc')->find(); $user_company = new UserCompany($pdo_connection); foreach($users as $user) { $user_company->reset(); // почати з чистого листа $user_company->user_id = $user->id; $user_company->company_id = $some_company_id; $user_company->insert(); }
getBuiltSql(): string
Після виконання методу find(), findAll(), insert(), update() або save() ви можете отримати SQL, який був побудований, і використовувати його для налагодження.
find()
findAll()
insert()
update()
save()
select(string $field1 [, string $field2 ... ])
Ви можете вибрати лише деякі стовпці в таблиці, якщо хочете (це більш ефективно на дійсно широких таблицях з багатьма стовпцями)
$user->select('id', 'name')->find();
from(string $table)
Ви технічно можете вибрати й іншу таблицю! Чому б і ні?!
$user->select('id', 'name')->from('user')->find();
join(string $table_name, string $join_condition)
Ви навіть можете здійснити з'єднання з іншою таблицею в базі даних.
$user->join('contacts', 'contacts.user_id = users.id')->find();
where(string $where_conditions)
Ви можете встановити деякі користувацькі умови where (ви не можете встановлювати параметри в цій умові where)
$user->where('id=1 AND name="demo"')->find();
Примітка безпеки - Ви могли б подумати зробити щось на кшталт $user->where("id = '{$id}' AND name = '{$name}'")->find();. Будь ласка, НЕ РОБІТЬ ЦЬОГО!!! Це піддається так званим атакам SQL Injection. Є багато статей в Інтернеті, будь ласка, Google "sql injection attacks php", і ви знайдете багато статей на цю тему. Правильний спосіб впоратися з цим за допомогою цієї бібліотеки - замість цього методу where() ви повинні зробити щось на кшталт $user->eq('id', $id)->eq('name', $name)->find();. Якщо ви абсолютно повинні це зробити, бібліотека PDO має $pdo->quote($var), щоб екранувати це для вас. Тільки після використання quote() ви можете використовувати це в операторі where().
$user->where("id = '{$id}' AND name = '{$name}'")->find();
where()
$user->eq('id', $id)->eq('name', $name)->find();
$pdo->quote($var)
quote()
group(string $group_by_statement)/groupBy(string $group_by_statement)
Групуйте результати за певною умовою.
$user->select('COUNT(*) as count')->groupBy('name')->findAll();
order(string $order_by_statement)/orderBy(string $order_by_statement)
Сортуйте повернуті запити певним чином.
$user->orderBy('name DESC')->find();
limit(string $limit)/limit(int $offset, int $limit)
Обмежте кількість повернених записів. Якщо передано друге ціле число, він буде зсувом, обмеженням, як у SQL.
$user->orderby('name DESC')->limit(0, 10)->findAll();
equal(string $field, mixed $value) / eq(string $field, mixed $value)
Де field = $value
field = $value
$user->eq('id', 1)->find();
notEqual(string $field, mixed $value) / ne(string $field, mixed $value)
Де field <> $value
field <> $value
$user->ne('id', 1)->find();
isNull(string $field)
Де field IS NULL
field IS NULL
$user->isNull('id')->find();
isNotNull(string $field) / notNull(string $field)
Де field IS NOT NULL
field IS NOT NULL
$user->isNotNull('id')->find();
greaterThan(string $field, mixed $value) / gt(string $field, mixed $value)
Де field > $value
field > $value
$user->gt('id', 1)->find();
lessThan(string $field, mixed $value) / lt(string $field, mixed $value)
Де field < $value
field < $value
$user->lt('id', 1)->find();
greaterThanOrEqual(string $field, mixed $value) / ge(string $field, mixed $value) / gte(string $field, mixed $value)
Де field >= $value
field >= $value
$user->ge('id', 1)->find();
lessThanOrEqual(string $field, mixed $value) / le(string $field, mixed $value) / lte(string $field, mixed $value)
Де field <= $value
field <= $value
$user->le('id', 1)->find();
like(string $field, mixed $value) / notLike(string $field, mixed $value)
Де field LIKE $value або field NOT LIKE $value
field LIKE $value
field NOT LIKE $value
$user->like('name', 'de')->find();
in(string $field, array $values) / notIn(string $field, array $values)
Де field IN($value) або field NOT IN($value)
field IN($value)
field NOT IN($value)
$user->in('id', [1, 2])->find();
between(string $field, array $values)
Де field BETWEEN $value AND $value1
field BETWEEN $value AND $value1
$user->between('id', [1, 2])->find();
Ви можете встановити кілька видів зв’язків, використовуючи цю бібліотеку. Ви можете встановити один->багато та один->один зв'язки між таблицями. Це вимагає деякого додаткового налаштування в класі заздалегідь.
Встановлення масиву $relations не є важким, але вгадувати правильний синтаксис може бути заплутаним.
$relations
protected array $relations = [ // ви можете називати ключ будь-яким бажаним. Назва ActiveRecord, напевно, підходить. Напр. user, contact, client 'user' => [ // обов'язково // self::HAS_MANY, self::HAS_ONE, self::BELONGS_TO self::HAS_ONE, // це тип зв'язку // обов'язково 'Some_Class', // це "інший" клас ActiveRecord, на який буде посилатися // обов'язково // залежно від типу зв'язку // self::HAS_ONE = зовнішній ключ, що посилається на з’єднання // self::HAS_MANY = зовнішній ключ, що посилається на з’єднання // self::BELONGS_TO = локальний ключ, що посилається на з’єднання 'local_or_foreign_key', // просто для довідки, це також тільки з'єднує з первинним ключем "іншої" моделі // необов'язково [ 'eq' => [ 'client_id', 5 ], 'select' => 'COUNT(*) as count', 'limit' 5 ], // додаткові умови, які ви хочете під час з'єднання зі зв'язком // $record->eq('client_id', 5)->select('COUNT(*) as count')->limit(5)) // необов'язково 'back_reference_name' // це якщо ви хочете посилатися на цю зв'язок назад до себе Наприклад: $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'); } }
Тепер у нас є налаштовані посилання, тому ми можемо використовувати їх дуже легко!
$user = new User($pdo_connection); // знайти найновішого користувача. $user->notNull('id')->orderBy('id desc')->find(); // отримати контакти, використовуючи зв'язок: foreach($user->contacts as $contact) { echo $contact->id; } // або можемо піти іншим шляхом. $contact = new Contact(); // знайти один контакт $contact->find(); // отримати користувача, використовуючи зв'язок: echo $contact->user->name; // це ім'я користувача
Досить круто, так?
Іноді вам може знадобитися прикріпити щось унікальне до вашого ActiveRecord, наприклад, спеціальне обчислення, яке може бути легше просто прикріпити до об’єкта, який потім буде передано, наприклад, шаблону.
setCustomData(string $field, mixed $value)
Ви прикріпляєте користувальницькі дані за допомогою методу setCustomData().
setCustomData()
$user->setCustomData('page_view_count', $page_view_count);
А потім ви просто посилаєтеся на це як на звичайну властивість об'єкта.
echo $user->page_view_count;
Ще одна надзвичайно крута функція цієї бібліотеки - це події. Події спрацьовують у певний час на основі певних методів, які ви викликаєте. Вони дуже корисні для автоматичного налаштування даних для вас.
onConstruct(ActiveRecord $ActiveRecord, array &config)
Це дійсно корисно, якщо вам потрібно встановити з'єднання за замовчуванням або щось подібне.
// index.php або bootstrap.php Flight::register('db', 'PDO', [ 'sqlite:test.db' ]); // // // // User.php class User extends flight\ActiveRecord { protected function onConstruct(self $self, array &$config) { // не забудьте про & посилання // ви могли б зробити це, щоб автоматично встановити з'єднання $config['connection'] = Flight::db(); // або так $self->transformAndPersistConnection(Flight::db()); // Ви також можете встановити назву таблиці таким чином. $config['table'] = 'users'; } }
beforeFind(ActiveRecord $ActiveRecord)
Це, мабуть, буде корисно лише за умови, що вам потрібно змінити запит щоразу.
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users'); } protected function beforeFind(self $self) { // завжди виконую id >= 0, якщо це ваше $self->gte('id', 0); } }
afterFind(ActiveRecord $ActiveRecord)
Це, мабуть, більш корисно, якщо вам щоразу потрібно виконувати якусь логіку щоразу, коли цей запис отримується. Вам потрібно дещо розшифрувати? Вам потрібно виконати запит на підрахунок щоразу (неефективно, але в будь-якому разі)?
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users'); } protected function afterFind(self $self) { // розшифрування чогось $self->secret = yourDecryptFunction($self->secret, $some_key); // можливо, збереження чогось спеціального, як запит??? $self->setCustomData('view_count', $self->select('COUNT(*) count')->from('user_views')->eq('user_id', $self->id)['count']; } }
beforeFindAll(ActiveRecord $ActiveRecord)
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users'); } protected function beforeFindAll(self $self) { // завжди виконую id >= 0, якщо це ваше $self->gte('id', 0); } }
afterFindAll(array<int,ActiveRecord> $results)
Подібно до afterFind(), але ви можете зробити це з усіма записами!
afterFind()
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users'); } protected function afterFindAll(array $results) { foreach($results as $self) { // зробіть щось класне, як в afterFind() } } }
beforeInsert(ActiveRecord $ActiveRecord)
Дуже корисно, якщо вам потрібно встановити деякі значення за замовчуванням щоразу.
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users'); } protected function beforeInsert(self $self) { // задайте добрі значення за замовчуванням if(!$self->created_date) { $self->created_date = gmdate('Y-m-d'); } if(!$self->password) { $self->password = password_hash((string) microtime(true)); } } }
afterInsert(ActiveRecord $ActiveRecord)
Можливо, у вас є випадок зміни даних після їх вставки?
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users'); } protected function afterInsert(self $self) { // ви робите своє Flight::cache()->set('most_recent_insert_id', $self->id); // або що-небудь.... } }
beforeUpdate(ActiveRecord $ActiveRecord)
Дуже корисно, якщо вам потрібно встановити деякі значення за замовчуванням щоразу при оновленні.
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users'); } protected function beforeUpdate(self $self) { // задайте добрі значення за замовчуванням if(!$self->updated_date) { $self->updated_date = gmdate('Y-m-d'); } } }
afterUpdate(ActiveRecord $ActiveRecord)
Можливо, у вас є випадок зміни даних після оновлення?
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users'); } protected function afterUpdate(self $self) { // ви робите своє Flight::cache()->set('most_recently_updated_user_id', $self->id); // або що-небудь.... } }
beforeSave(ActiveRecord $ActiveRecord)/afterSave(ActiveRecord $ActiveRecord)
Це корисно, якщо ви хочете, щоб події відбувалися як під час вставок, так і під час оновлень. Я заощаджу вам довге пояснення, але я впевнений, що ви можете здогадатися, що це так.
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)
Не знаю, що ви хочете робити тут, але я не суджу! Дій!
class User extends flight\ActiveRecord { public function __construct($database_connection) { parent::__construct($database_connection, 'users'); } protected function beforeDelete(self $self) { echo 'Він був відважним солдатом... :cry-face:'; } }
Коли ви використовуєте цю бібліотеку, ви можете налаштувати з'єднання з базою даних кількома різними способами. Ви можете налаштувати з'єднання в конструкторі, ви можете налаштувати його через змінну конфігурації $config['connection'], або ви можете налаштувати його через setDatabaseConnection() (v0.4.1).
$config['connection']
setDatabaseConnection()
$pdo_connection = new PDO('sqlite:test.db'); // наприклад $user = new User($pdo_connection); // або $user = new User(null, [ 'connection' => $pdo_connection ]); // або $user = new User(); $user->setDatabaseConnection($pdo_connection);
Якщо ви хочете уникнути необхідності встановлювати $database_connection щоразу, коли викликаєте активний запис, є способи уникнути цього!
$database_connection
// index.php або bootstrap.php // Встановіть це як зареєстрований клас у 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); } } // І тепер не потрібно аргументів! $user = new User();
Примітка: Якщо ви плануєте одиничне тестування, робити це таким чином може бути складно для одиничного тестування, але взагалі, оскільки ви можете впровадити своє з'єднання за допомогою setDatabaseConnection() або $config['connection'], це не надто погано.
Якщо вам потрібно оновити з'єднання з базою даних, наприклад, якщо ви запускаєте тривалу CLI програму і потрібно оновити з'єднання час від часу, ви можете перенастроїти з'єднання за допомогою $your_record->setDatabaseConnection($pdo_connection).
$your_record->setDatabaseConnection($pdo_connection)
Будь ласка, зробіть це. :D
Коли ви будете робити внески, обов'язково запустіть composer test-coverage, щоб підтримувати 100% покриття тестами (це не справжнє покриття одиничних тестів, швидше інтеграційне тестування).
composer test-coverage
Також не забудьте запустити composer beautify і composer phpcs, щоб виправити всі помилки синтаксису.
composer beautify
composer phpcs
MIT
Latte — це повнофункціональний шаблонний引擎, який дуже простий у використанні і виглядає ближче до синтаксису PHP, ніж Twig або Smarty. Його також дуже легко розширити та додати власні фільтри та функції.
composer require latte/latte
Існує кілька основних конфігураційних параметрів для початку роботи. Ви можете дізнатися про них більше в Latte Documentation.
use Latte\Engine as LatteEngine; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('latte', LatteEngine::class, [], function(LatteEngine $latte) use ($app) { // Тут Latte буде кешувати ваші шаблони, щоб прискорити процес // Однією з чудових особливостей Latte є те, що він автоматично оновлює ваш // кеш, коли ви вносите зміни у ваші шаблони! $latte->setTempDirectory(__DIR__ . '/../cache/'); // Скажіть Latte, де буде коренева директорія для ваших шаблонів. // $app->get('flight.views.path') встановлюється у файлі config.php // Ви також могли б просто зробити щось на кшталт `__DIR__ . '/../views/'` $latte->setLoader(new \Latte\Loaders\FileLoader($app->get('flight.views.path'))); });
Ось простий приклад файлу макету. Це файл, який буде використано для обгортання всіх інших ваших шаблонів.
<!-- app/views/layout.latte --> <!doctype html> <html lang="en"> <head> <title>{$title ? $title . ' - '}Мій додаток</title> <link rel="stylesheet" href="style.css"> </head> <body> <header> <nav> <!-- ваші елементи навігації тут --> </nav> </header> <div id="content"> <!-- Тут і є ця магія --> {block content}{/block} </div> <div id="footer"> © Авторські права </div> </body> </html>
А тепер у нас є ваш файл, який буде відображатися всередині цього блоку контенту:
<!-- app/views/home.latte --> <!-- Це говорить Latte, що цей файл "всередині" файлу layout.latte --> {extends layout.latte} <!-- Це контент, який буде відображатися всередині макету в блоці контенту --> {block content} <h1>Головна сторінка</h1> <p>Ласкаво просимо до мого додатку!</p> {/block}
Отже, коли ви будете відображати це у вашій функції або контролері, ви можете зробити щось на кшталт цього:
// простий маршрут Flight::route('/', function () { Flight::latte()->render('home.latte', [ 'title' => 'Головна сторінка' ]); }); // або якщо ви використовуєте контролер Flight::route('/', [HomeController::class, 'index']); // HomeController.php class HomeController { public function index() { Flight::latte()->render('home.latte', [ 'title' => 'Головна сторінка' ]); } }
Дивіться Latte Documentation для отримання додаткової інформації про те, як максимально використовувати Latte!
Flight є надзвичайно розширювальним. Є кілька плагінів, які можна використовувати для додавання функціональності до вашого застосунку Flight. Деякі офіційно підтримуються командою Flight, а інші є мікро/легкими бібліотеками, щоб допомогти вам почати.
Аутентифікація та авторизація є критично важливими для будь-якого застосунку, який вимагає контролю над тим, хто може мати доступ до чого.
Кешування є чудовим способом прискорити ваш застосунок. Є кілька бібліотек кешування, які можна використовувати з Flight.
CLI-застосунки є чудовим способом взаємодії з вашим застосунком. Ви можете використовувати їх для генерування контролерів, відображення всіх маршрутів тощо.
Cookies є чудовим способом зберігати невеликі шматки даних на стороні клієнта. їх можна використовувати для зберігання вподобань користувача, налаштувань застосунків тощо.
Налагодження є критично важливим, коли ви розробляєте у своєму локальному середовищі. Є кілька плагінів, які можуть підвищити ваш досвід налагодження.
Бази даних є основою більшості застосунків. Це те, як ви зберігаєте та отримуєте дані. Деякі бібліотеки бази даних просто є обгортками для написання запитів, а деякі є повністю функціональними ORM.
Шифрування є критично важливим для будь-якого застосунку, який зберігає чутливі дані. Шифрування та дешифрування даних не є надто складним, але правильне зберігання ключа шифрування може бути складним. Найважливіше – ніколи не зберігати ваш ключ шифрування в публічному каталозі або не комітити його до вашого репозиторію коду.
Сесії не є дійсно корисними для API, але для створення веб-застосунку сесії можуть бути критично важливими для підтримки стану та інформації про вхід.
Шаблонізація є основою будь-якого веб-застосунку з UI. Є кілька шаблонних рушіїв, які можна використовувати з Flight.
Є плагін, який ви хотіли б поділитися? Надішліть запит на злиття, щоб додати його до списку!
Ми намагалися з'ясувати, що можемо про різні типи медіа в інтернеті, пов'язані з Flight. Дивіться нижче різні ресурси, які ви можете використовувати, щоб дізнатися більше про Flight.
У вас є два варіанти, щоб почати з Flight:
Хоча ці проекти офіційно не спонсоруються командою Flight, вони можуть дати вам ідеї щодо структурування ваших власних проектів, створених за допомогою Flight!
Якщо у вас є проект, яким ви хочете поділитися, будь ласка, надішліть запит на злиття, щоб додати його до цього списку!
Переконайтесь, що у вас на системі встановлено PHP. Якщо ні, натисніть тут для інструкцій щодо його встановлення.
Якщо ви використовуєте Composer, ви можете виконати наступну команду:
composer require flightphp/core
АБО ви можете завантажити файли безпосередньо та витягти їх у свій веб-директорію.
Це, безумовно, найпростіший спосіб запустити свій проект. Ви можете використовувати вбудований сервер, щоб запустити своє застосування та навіть використовувати SQLite для бази даних (якщо sqlite3 встановлено на вашій системі) і не вимагати багато чого! Просто виконайте наступну команду після встановлення PHP:
php -S localhost:8000
Потім відкрийте свій браузер і перейдіть на http://localhost:8000.
http://localhost:8000
Якщо ви хочете зробити корінь документа вашого проекту в іншому каталозі (Наприклад: ваш проект ~/myproject, але корінь документа ~/myproject/public/), ви можете виконати наступну команду, як тільки ви в директорії ~/myproject:
~/myproject
~/myproject/public/
php -S localhost:8000 -t public/
Переконайтесь, що Apache вже встановлено на вашій системі. Якщо ні, знайдіть у Google, як встановити Apache на вашій системі.
Для Apache, відредагуйте свій файл .htaccess наступним чином:
.htaccess
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L]
Примітка: Якщо вам потрібно використовувати flight в підкаталозі, додайте рядок RewriteBase /subdir/ відразу після RewriteEngine On. Примітка: Якщо ви хочете захистити всі серверні файли, такі як db чи env файл. Помістіть це у свій файл .htaccess:
Примітка: Якщо вам потрібно використовувати flight в підкаталозі, додайте рядок RewriteBase /subdir/ відразу після RewriteEngine On.
RewriteBase /subdir/
RewriteEngine On
Примітка: Якщо ви хочете захистити всі серверні файли, такі як db чи env файл. Помістіть це у свій файл .htaccess:
RewriteEngine On RewriteRule ^(.*)$ index.php
Переконайтесь, що Nginx вже встановлено на вашій системі. Якщо ні, знайдіть у Google, як встановити Nginx на вашу систему.
Для Nginx, додайте наступне до вашої декларації сервера:
server { location / { try_files $uri $uri/ /index.php; } }
<?php // Якщо ви використовуєте Composer, підключіть автозавантажувач. require 'vendor/autoload.php'; // якщо ви не використовуєте Composer, підключіть фреймворк безпосередньо // require 'flight/Flight.php'; // Потім визначте маршрут і призначте функцію для обробки запиту. Flight::route('/', function () { echo 'hello world!'; }); // Нарешті, запустіть фреймворк. Flight::start();
Якщо у вас вже встановлено php на вашій системі, сміливо пропустіть ці інструкції та перейдіть до розділу завантаження
php
Звичайно! Ось інструкції для встановлення PHP на macOS, Windows 10/11, Ubuntu та Rocky Linux. Я також включу деталі про те, як встановити різні версії PHP.
Встановіть Homebrew (якщо ще не встановлено):
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Встановіть PHP:
brew install php
brew tap shivammathur/php brew install shivammathur/php/php@8.1
Перемикання між версіями PHP:
brew unlink php brew link --overwrite --force php@8.1
php -v
Завантажте PHP:
Розпакуйте PHP:
C:\php
Додайте PHP до системної PATH:
Налаштуйте PHP:
php.ini-development
php.ini
extension_dir
Перевірте установку PHP:
Повторіть вищезазначені кроки для кожної версії, розміщуючи кожну в окремій директорії (наприклад, C:\php7, C:\php8).
C:\php7
C:\php8
Перемикання між версіями шляхом коригування системної змінної PATH, щоб вказати на директорію бажаної версії.
Оновіть списки пакетів:
sudo apt update
sudo apt install php
sudo apt install php8.1
Встановлення додаткових модулів (за бажанням):
sudo apt install php8.1-mysql
update-alternatives
sudo update-alternatives --set php /usr/bin/php8.1
Перевірте встановлену версію:
Увімкніть репозиторій EPEL:
sudo dnf install epel-release
Встановіть репозиторій Remi:
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm sudo dnf module reset php
sudo dnf install php
sudo dnf module install php:remi-7.4
dnf
sudo dnf module reset php sudo dnf module enable php:remi-8.0 sudo dnf install php