Learn
Досліджуйте Flight
Flight - це швидкий, простий, розширювальний фреймворк для PHP. Він досить універсальний і може використовуватися для створення будь-якого виду веб-додатку. Він створений з урахуванням простоти та написаний так, що його легко зрозуміти і використовувати.
Важливі Концепції Фреймворку
Чому Фреймворк?
Ось коротка стаття про те, чому ви повинні використовувати фреймворк. Було б хорошою ідеєю зрозуміти переваги використання фреймворку перед тим, як почати його використовувати.
Крім того, відмінний урок був створений @lubiana. Хоча він не вдається у великі деталі щодо Flight зокрема, цей посібник допоможе вам зрозуміти деякі з основних концепцій навколо фреймворку і чому вони корисні. Ви можете знайти урок тут.
Flight у порівнянні з іншими фреймворками
Якщо ви мігруєте з іншого фреймворку, такого як Laravel, Slim, Fat-Free або Symfony до Flight, ця сторінка допоможе вам зрозуміти відмінності між ними.
Основні Теми
Автозавантаження
Досліджуйте, як автозавантажувати власні класи у вашому додатку.
Маршрутизація
Досліджуйте, як керувати маршрутами для вашого веб-додатку. Це також включає групування маршрутів, параметри маршруту та проміжне програмне забезпечення.
Проміжне Програмне Забезпечення
Досліджуйте, як використовувати проміжне програмне забезпечення для фільтрації запитів та відповідей у вашому додатку.
Запити
Досліджуйте, як обробляти запити та відповіді у вашому додатку.
Відповіді
Досліджуйте, як надсилати відповіді вашим користувачам.
Події
Досліджуйте, як використовувати систему подій для додавання користувацьких подій у вашому додатку.
HTML Шаблони
Досліджуйте, як використовувати вбудований рушій представлень для рендерингу ваших HTML шаблонів.
Безпека
Досліджуйте, як захистити ваш додаток від поширених загроз безпеки.
Конфігурація
Досліджуйте, як налаштувати фреймворк для вашого додатку.
Розширення Flight
Досліджуйте, як розширити фреймворк, додаючи власні методи і класи.
Події та Фільтрація
Досліджуйте, як використовувати систему подій для додавання хуків до ваших методів і внутрішніх методів фреймворку.
Контейнер Впровадження Залежностей
Досліджуйте, як використовувати контейнери впровадження залежностей (DIC) для управління залежностями вашого додатку.
API Фреймворку
Досліджуйте основні методи фреймворку.
Міграція до v3
Зворотна сумісність на більшості зберігалася, але є деякі зміни, про які вам слід знати при міграції з v2 до v3.
Виправлення Помилок
Є деякі поширені проблеми, з якими ви можете зіткнутися при використанні Flight. Ця сторінка допоможе вам усунути ці проблеми.
Learn/flight_vs_laravel
Flight проти Laravel
Що таке Laravel?
Laravel — це повнофункціональний фреймворк, який має всі можливості та чудову екосистему, орієнтовану на розробників, але з витратами на продуктивність і складність. Метою Laravel є забезпечити розробників найвищим рівнем продуктивності та спростити виконання звичних завдань. Laravel є відмінним вибором для розробників, які прагнуть створити повнофункціональну web-додаток для підприємств. Це має певні компроміси, зокрема щодо продуктивності та складності. Вивчити основи Laravel може бути легко, але досягти майстерності у фреймворку може знадобитися певний час.
Також є багато модулів Laravel, і розробники часто відчувають, що єдиний спосіб вирішити проблеми — це використання цих модулів, тоді як насправді ви могли б просто використовувати іншу бібліотеку або написати свій власний код.
Переваги в порівнянні з Flight
- Laravel має велику екосистему розробників і модулів, які можна використовувати для вирішення звичних проблем.
- Laravel має повнофункціональний ORM, який можна використовувати для роботи з вашою базою даних.
- Laravel має неймовірну кількість документації та уроків, які можна використовувати для вивчення фреймворка.
- Laravel має вбудовану систему автентифікації, яку можна використовувати для забезпечення безпеки вашого застосунку.
- Laravel має подкасти, конференції, зустрічі, відео та інші ресурси, які можна використовувати для вивчення фреймворка.
- Laravel орієнтований на досвідченого розробника, який прагне створити повнофункціональну web-додаток для підприємств.
Недоліки в порівнянні з Flight
- Laravel має значно більше подій під капотом, ніж Flight. Це призводить до драматичних витрат на продуктивність. Див. TechEmpower benchmarks для отримання додаткової інформації.
- Flight орієнтований на розробника, який прагне створити легкий, швидкий та зручний у використанні web-додаток.
- Flight орієнтований на простоту і зручність використання.
- Однією з основних характеристик Flight є те, що він намагається підтримувати зворотну сумісність. Laravel викликає багато розчарувань між основними версіями.
- Flight призначений для розробників, які вперше вирушають у світ фреймворків.
- Flight не має залежностей, тоді як Laravel має неприязно велику кількість залежностей
- Flight також може виконувати додатки на рівні підприємств, але не має такої ж кількості шаблонного коду, як Laravel. Він також вимагатиме більше дисципліни з боку розробника, щоб підтримувати порядок і добре структурувати.
- Flight надає розробнику більше контролю над додатком, тоді як у Laravel є безліч магії за кулісами, що може викликати розчарування.
Learn/migrating_to_v3
Міграція на v3
Зворотна сумісність в основному зберігається, але є деякі зміни, про які вам слід знати при міграції з v2 на v3.
Поведінка буферизації виходу (3.5.0)
Буферизація виходу — це процес, при якому вихід, згенерований 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>';
});
Увімкнення поведінки рендерингу v2
Ви все ще можете зберегти свій старий код у тому вигляді, в якому він є, без переписування, щоб заставити його працювати з v3? Так,
можете! Ви можете увімкнути поведінку рендерингу v2, встановивши параметр конфігурації flight.v2.output_buffering
в true
.
Це дозволить вам продовжити використовувати стару поведінку рендерингу, але рекомендується виправити це на майбутнє.
У v4 фреймворка це буде видалено.
// index.php
require 'vendor/autoload.php';
Flight::set('flight.v2.output_buffering', true);
Flight::before('start', function(){
// Тепер це буде просто добре
echo '<html><head><title>Моя Сторінка</title></head><body>';
});
// більше коду
Зміни в Диспетчері (3.7.0)
Якщо ви безпосередньо викликали статичні методи для Dispatcher
, такі як Dispatcher::invokeMethod()
, Dispatcher::execute()
, і т.д.,
вам потрібно буде оновити свій код, щоб не викликати ці методи безпосередньо. Dispatcher
був перетворений на об'єктно-орієнтований,
щоб контейнери впровадження залежностей могли використовуватися простіше. Якщо вам потрібно викликати метод, подібно до того, як це
робив Dispatcher, ви можете вручну використовувати щось на кшталт $result = $class->$method(...$params);
або call_user_func_array()
замість цього.
Зміни halt()
stop()
redirect()
та error()
(3.10.0)
За замовчуванням поведінка до 3.10.0 полягала в очищенні як заголовків, так і тіла відповіді. Це було змінено на очищення лише тіла відповіді.
Якщо вам потрібно очистити також заголовки, ви можете використовувати Flight::response()->clear()
.
Learn/configuration
Налаштування
Ви можете налаштувати певні поведінки Flight, встановлюючи значення конфігурації
через метод set
.
Flight::set('flight.log_errors', true);
Доступні налаштування конфігурації
Нижче наведено список усіх доступних налаштувань конфігурації:
- flight.base_url
?string
- Переозначте базову URL запиту. (за замовчуванням: null) - flight.case_sensitive
bool
- Чутливе до регістру співвідношення для URL. (за замовчуванням: false) - flight.handle_errors
bool
- Дозволити Flight обробляти всі помилки внутрішньо. (за замовчуванням: true) - flight.log_errors
bool
- Записувати помилки у файл журналу помилок веб-сервера. (за замовчуванням: false) - flight.views.path
string
- Директорія, що містить файли шаблонів для перегляду. (за замовчуванням: ./views) - flight.views.extension
string
- Розширення файлу шаблону для перегляду. (за замовчуванням: .php) - flight.content_length
bool
- Встановити заголовокContent-Length
. (за замовчуванням: true) - flight.v2.output_buffering
bool
- Використовувати застаріле буферизацію виводу. Див. міграцію на v3. (за замовчуванням: false)
Налаштування завантажувача
Також є ще одне налаштування конфігурації для завантажувача. Це дозволить вам
автозавантажувати класи з _
в імені класу.
// Увімкнення завантаження класів з підкресленнями
// За замовчуванням: 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::set('flight.log_errors', true);
Обробка помилок
Помилки та виключення
Всі помилки та виключення перехоплюються Flight і передаються в метод error
.
За замовчуванням поведінка полягає в тому, щоб надіслати загальний HTTP 500 Internal Server Error
відповідь з деякою інформацією про помилку.
Ви можете переозначити цю поведінку для своїх потреб:
Flight::map('error', function (Throwable $error) {
// Обробка помилки
echo $error->getTraceAsString();
});
За замовчуванням помилки не записуються в веб-сервер. Ви можете активувати це, змінивши конфігурацію:
Flight::set('flight.log_errors', true);
Не знайдено
Коли URL не можна знайти, Flight викликає метод notFound
. За замовчуванням
поведінка полягає в тому, щоб надіслати відповідь HTTP 404 Not Found
з простим повідомленням.
Ви можете переозначити цю поведінку для своїх потреб:
Flight::map('notFound', function () {
// Обробка не знайдено
});
Learn/security
Безпека
Безпека є важливою справою, коли мова йде про веб-додатки. Ви хочете переконатися, що ваш додаток є безпечним, а дані ваших користувачів - в безпеці. Flight надає ряд функцій, щоб допомогти вам захистити ваші веб-додатки.
Заголовки
HTTP заголовки - один з найбільш простих способів захистити ваші веб-додатки. Ви можете використовувати заголовки, щоб запобігти кліковій атаці, XSS та іншим атакам. Існує кілька способів, якими ви можете додати ці заголовки до вашого додатку.
Два чудових веб-сайти для перевірки безпеки ваших заголовків - це securityheaders.com та observatory.mozilla.org.
Додати вручну
Ви можете вручну додати ці заголовки, використовуючи метод 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 sniffing
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
.
Додати як фільтр
Ви також можете додати їх у фільтрі/хуку, як у наступному прикладі:
// Додати заголовки у фільтрі
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)
Підробка міжсайтових запитів (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>
Використання Latte
Ви також можете налаштувати власну функцію для виводу токену 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.
<form method="post">
{csrf()}
<!-- інші поля форми -->
</form>
Просто і зрозуміло, так?
Перевірка токену CSRF
Ви можете перевірити токен 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)
Міжсайтове скриптування (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-ін'єкція - це тип атаки, коли зловмисний користувач може впровадити SQL-код у вашу базу даних. Це може бути використано для
викрадення інформації з вашої бази даних або виконання дій на вашій базі даних. Знову ви повинні ніколи не довіряти
виходу ваших користувачів! Завжди вважайте, що вони намагаються заподіяти шкоду. Ви можете використовувати підготовлені запити у ваших
об'єктах PDO
, щоб запобігти SQL-ін'єкції.
// Припустимо, ви зареєстрували 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
Обмін ресурсами між різними джерелами (CORS) - це механізм, який дозволяє багатьом ресурсам (наприклад, шрифтам, JavaScript тощо) на веб-сторінці бути
запитуваними з іншого домену, відмінного від домену, з якого ресурс походить. Flight не має вбудованого функціоналу, але це можна легко
обробити з допомогою хуку, який виконується перед викликом методу 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();
// Це потрібно виконати перед тим, як запуститься start.
Flight::before('start', [ $CorsUtil, 'setupCors' ]);
Обробка помилок
Сховати чутливі деталі помилок у продакшені, щоб уникнути витоку інформації зловмисникам.
// У вашому bootstrap.php або index.php
// у flightphp/skeleton це в app/config/config.php
$environment = ENVIRONMENT;
if ($environment === 'production') {
ini_set('display_errors', 0); // Вимкнути відображення помилок
ini_set('log_errors', 1); // Логувати помилки натомість
ini_set('error_log', '/path/to/error.log');
}
// У ваших маршрутах або контролерах
// Використовуйте Flight::halt() для контрольованих відповідей на помилки
Flight::halt(403, 'Доступ заборонено');
Санітаризація вводу
Ніколи не довіряйте вводу користувачів. Санітаризуйте його перед обробкою, щоб запобігти проникненню шкідливих даних.
// Припустимо запит $_POST з $_POST['input'] та $_POST['email']
// Санітаризація строкового вводу
$clean_input = filter_var(Flight::request()->data->input, FILTER_SANITIZE_STRING);
// Санітаризація електронної пошти
$clean_email = filter_var(Flight::request()->data->email, FILTER_SANITIZE_EMAIL);
Хешування паролів
Зберігайте паролі у безпеці та перевіряйте їх безпечно, використовуючи вбудовані функції PHP.
$password = Flight::request()->data->password;
// Хешуйте пароль при зберіганні (наприклад, під час реєстрації)
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
// Перевірте пароль (наприклад, під час входу)
if (password_verify($password, $stored_hash)) {
// Пароль співпадає
}
Обмеження швидкості
Захистіть від атак типу brute force, обмежуючи темп запитів за допомогою кешу.
// Припустимо, що у вас встановлено та зареєстровано flightphp/cache
// Використовуючи flightphp/cache в проміжному програмному забезпеченні
Flight::before('start', function() {
$cache = Flight::cache();
$ip = Flight::request()->ip;
$key = "rate_limit_{$ip}";
$attempts = (int) $cache->retrieve($key);
if ($attempts >= 10) {
Flight::halt(429, 'Забагато запитів');
}
$cache->set($key, $attempts + 1, 60); // Скинути через 60 секунд
});
Висновок
Безпека є важливою справою, і важливо переконатися, що ваші веб-додатки безпечні. Flight надає ряд функцій, щоб допомогти вам захистити ваші веб-додатки, але важливо завжди залишатися пильним і переконатися, що ви робите все можливе, щоб захистити дані своїх користувачів. Завжди вважайте найгірше і ніколи не довіряйте вводу ваших користувачів. Завжди екранізуйте вихід і використовуйте підготовлені запити, щоб запобігти SQL ін'єкції. Завжди використовуйте проміжне програмне забезпечення, щоб захистити свої маршрути від атак CSRF та CORS. Якщо ви виконаєте всі ці дії, ви будете на шляху до створення безпечних веб-додатків.
Learn/routing
Маршрутизація
Примітка: Хочете дізнатися більше про маршрутизацію? Перегляньте сторінку "чому фреймворк?" для більш детального пояснення.
Основна маршрутизація у Flight здійснюється шляхом зіставлення шаблону URL з функцією зворотного виклику або масивом класу та методу.
Flight::route('/', function(){
echo 'hello world!';
});
Маршрути зіставляються в порядку, в якому вони визначені. Перший маршрут, який співпадає з запитом, буде викликаний.
Функції зворотного виклику
Функція зворотного виклику може бути будь-яким об'єктом, який можна викликати. Тож ви можете використовувати звичайну функцію:
function hello() {
echo 'hello world!';
}
Flight::route('/', 'hello');
Класи
Ви також можете використовувати статичний метод класу:
class Greeting {
public static function hello() {
echo 'hello world!';
}
}
Flight::route('/', [ 'Greeting','hello' ]);
Або спочатку створивши об'єкт, а потім викликавши метод:
// Greeting.php
class Greeting
{
public function __construct() {
$this->name = 'John Doe';
}
public function hello() {
echo "Hello, {$this->name}!";
}
}
// index.php
$greeting = new Greeting();
Flight::route('/', [ $greeting, 'hello' ]);
// Ви також можете зробити це без попереднього створення об'єкта
// Примітка: жодних аргументів не буде впроваджено в конструктор
Flight::route('/', [ 'Greeting', 'hello' ]);
// Крім того, ви можете використовувати цей коротший синтаксис
Flight::route('/', 'Greeting->hello');
// або
Flight::route('/', Greeting::class.'->hello');
Впровадження залежностей через DIC (Контейнер впровадження залежностей)
Якщо ви хочете використовувати впровадження залежностей через контейнер (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 "Hello, world! My name is {$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 'hello world!';
});
// 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 "hello, $name ($id)!";
});
Ви також можете включити регулярні вирази з вашими іменованими параметрами, використовуючи роздільник :
:
Flight::route('/@name/@id:[0-9]{3}', function (string $name, string $id) {
// Це буде відповідати /bob/123
// Але не буде відповідати /bob/12345
});
Примітка: Співпадіння груп регекс
()
з позиційними параметрами не підтримується. :'(
Важлива застереження
Хоча у наведеному прикладі здається, що @name
безпосередньо пов'язаний зі змінною $name
, це не так. Порядок параметрів у функції зворотного виклику визначає, що їй передається. Тож якщо ви зміните порядок параметрів у функції зворотного виклику, змінні також будуть змінені. Ось приклад:
Flight::route('/@name/@id', function (string $id, string $name) {
echo "hello, $name ($id)!";
});
І якщо ви перейдете за наступною URL: /bob/123
, вивід буде hello, 123 (bob)!
.
Будь ласка, будьте обережні, коли ви налаштовуєте свої маршрути та функції зворотного виклику.
Необов'язкові параметри
Ви можете вказати іменовані параметри, які є необов'язковими для співпадіння, обертаючи сегменти в дужки.
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
.
Вайлдкарди
Співпадіння здійснюється лише на окремих сегментах URL. Якщо вам потрібно співпадати з кількома сегментами, ви можете використовувати вайлдкард *
.
Flight::route('/blog/*', function () {
// Це буде відповідати /blog/2000/02/01
});
Щоб направити всі запити до одного зворотного виклику, ви можете зробити так:
Flight::route('*', function () {
// Зробіть щось
});
Передача
Ви можете передати виконання наступному співпадаючому маршруту, повернувши true
з вашої функції зворотного виклику.
Flight::route('/user/@name', function (string $name) {
// Перевірте деяку умову
if ($name !== "Bob") {
// Продовжити до наступного маршруту
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
, як у
наведеному прикладі.
Псевдоніми маршруту також працюють у групах:
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
:
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
наступним чином:
$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
});
});
Ресурсна маршрутизація
Ви можете створити набір маршрутів для ресурсу, використовуючи метод resource
. Це створить
набір маршрутів для ресурсу, що дотримується RESTful конвенцій.
Щоб створити ресурс, виконайте наступні дії:
Flight::resource('/users', UsersController::class);
І те, що відбудеться за лаштунками, це створить наступні маршрути:
[
'index' => 'GET ',
'create' => 'GET /create',
'store' => 'POST ',
'show' => 'GET /@id',
'edit' => 'GET /@id/edit',
'update' => 'PUT /@id',
'destroy' => 'DELETE /@id'
]
А ваш контролер виглядатиме так:
class UsersController
{
public function index(): void
{
}
public function show(string $id): void
{
}
public function create(): void
{
}
public function store(): void
{
}
public function edit(string $id): void
{
}
public function update(string $id): void
{
}
public function destroy(string $id): void
{
}
}
Примітка: Ви можете переглянути нові додані маршрути з
runway
, запустившиphp runway routes
.
Налаштування маршрутів ресурсів
Існує кілька варіантів для налаштування маршрутів ресурсів.
Псевдонім бази
Ви можете налаштувати aliasBase
. За замовчуванням псевдонім - це остання частина вказаного URL.
Наприклад, /users/
призведе до aliasBase
як users
. Коли ці маршрути створюються,
псевдоніми є users.index
, users.create
тощо. Якщо ви хочете змінити псевдонім, задайте aliasBase
на бажане значення.
Flight::resource('/users', UsersController::class, [ 'aliasBase' => 'user' ]);
Тільки і Винятки
Ви також можете вказати, які маршрути ви хочете створити, використовуючи параметри only
та except
.
Flight::resource('/users', UsersController::class, [ 'only' => [ 'index', 'show' ] ]);
Flight::resource('/users', UsersController::class, [ 'except' => [ 'create', 'store', 'edit', 'update', 'destroy' ] ]);
Це в основному варіанти білого списку та чорного списку, щоб ви могли вказати, які маршрути ви хочете створити.
Програмне забезпечення
Ви також можете вказати програмне забезпечення, яке запускається на кожному з маршрутів, створених за допомогою методу resource
.
Flight::resource('/users', UsersController::class, [ 'middleware' => [ MyAuthMiddleware::class ] ]);
Стрімінг
Тепер ви можете стрімити відповіді клієнту, використовуючи метод streamWithHeaders()
.
Це корисно для відправки великих файлів, довготривалих процесів або генерації великих відповідей.
Стрімінг маршруту обробляється трохи інакше, ніж звичайний маршрут.
Примітка: Відповіді стрімінгу доступні тільки якщо ви маєте
flight.v2.output_buffering
встановлений на false.
Стрім з ручними заголовками
Ви можете стрімити відповідь клієнту, використовуючи метод stream()
на маршруті. Якщо ви
так робите, ви повинні налаштувати всі методи вручну перед тим, як вивести що-небудь клієнту.
Це робиться за допомогою функції header()
php або методу 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
]);
Learn/flight_vs_symfony
Flight vs Symfony
Що таке Symfony?
Symfony — це набір повторно використовуваних компонентів PHP і PHP фреймворк для веб-проектів.
Стандартна основа, на якій побудовані найкращі PHP додатки. Виберіть будь-який з 50 автономних компонентів, доступних для ваших власних додатків.
Прискорте створення та підтримку ваших PHP веб-додатків. Припиніть повторювані завдання кодування і насолоджуйтесь можливістю контролювати свій код.
Плюси в порівнянні з Flight
- Symfony має великий екосистему розробників і модулів, які можна використовувати для вирішення поширених проблем.
- Symfony має повнофункціональний ORM (Doctrine), який можна використовувати для взаємодії з вашою базою даних.
- Symfony має велику кількість документації та навчальних посібників, які можна використовувати для вивчення фреймворку.
- Symfony має подкасти, конференції, зустрічі, відео та інші ресурси, які можна використовувати для вивчення фреймворку.
- Symfony орієнтований на досвідченого розробника, який прагне створити повнофункціональний, корпоративний веб-додаток.
Мінуси в порівнянні з Flight
- Symfony має набагато більше в роботі під капотом, ніж Flight. Це має драматичну ціну з точки зору продуктивності. Дивіться TechEmpower benchmarks для отримання додаткової інформації.
- Flight орієнтований на розробника, який прагне створити легкий, швидкий і простий у використанні веб-додаток.
- Flight спрямований на простоту і зручність використання.
- Одна з основних функцій Flight полягає в тому, що вона намагається підтримувати зворотну сумісність.
- Flight не має залежностей, тоді як Symfony має безліч залежностей.
- Flight призначений для розробників, які вперше намагаються впровадити фреймворки.
- Flight також може виконувати корпоративні додатки, але у нього немає стільки ж прикладів і навчальних посібників, як у Symfony. Це також вимагатиме більше дисципліни з боку розробника для підтримки організованості та структурованості.
- Flight надає розробнику більше контролю над додатком, тоді як Symfony може непомітно включати деяку магію за лаштунками.
Learn/flight_vs_another_framework
Порівняння Flight з іншим фреймворком
Якщо ви мігруєте з іншого фреймворка, такого як Laravel, Slim, Fat-Free або Symfony до Flight, ця сторінка допоможе вам зрозуміти відмінності між цими двома.
Laravel
Laravel — це повнофункціональний фреймворк, який має всі принади та дивовижну екосистему, орієнтовану на розробників, але вартість цього — продуктивність і складність.
Дивіться порівняння між Laravel і Flight.
Slim
Slim — це мікрофреймворк, схожий на Flight. Він розроблений для того, щоб бути легким і простим у використанні, але може бути трохи складнішим, ніж Flight.
Дивіться порівняння між Slim і Flight.
Fat-Free
Fat-Free — це повноцінний фреймворк у набагато меншому пакеті. Хоча в ньому є всі інструменти в ящику, він має архітектуру даних, яка може ускладнити деякі проекти більше, ніж потрібно.
Дивіться порівняння між Fat-Free і Flight.
Symfony
Symfony — це модульний фреймворк корпоративного рівня, який розроблений для того, щоб бути гнучким і масштабованим. Для менших проектів або нових розробників Symfony може бути трохи приголомшуючим.
Дивіться порівняння між Symfony і Flight.
Learn/dependency_injection_container
Контейнер для впровадження залежностей
Вступ
Контейнер для впровадження залежностей (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 стає в нагоді.
Ось той же приклад, використовуючи 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 є те, що модульне тестування стає значно легшим. Ви можете створити змодельований об'єкт і передати його своєму класу. Це величезна перевага, коли ви пишете тести для свого застосунку!
PSR-11
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
Ви також можете створити власний обробник 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');
Learn/middleware
Middleware маршрути
Flight підтримує маршрути та групи маршрутів для проміжного програмного забезпечення. Проміжне програмне забезпечення — це функція, яка виконується перед (або після) зворотного виклику маршруту. Це чудовий спосіб додати перевірки автентифікації API у вашому коді або підтвердити, що користувач має дозвіл на доступ до маршруту.
Основне проміжне програмне забезпечення
Ось базовий приклад:
// Якщо ви надасте лише анонімну функцію, вона буде виконана перед зворотним викликом маршруту.
// немає "після" функцій проміжного програмного забезпечення, крім класів (див. нижче)
Flight::route('/path', function() { echo ' Тут я!'; })->addMiddleware(function() {
echo 'Проміжне програмне забезпечення першим!';
});
Flight::start();
// Це виведе "Проміжне програмне забезпечення першим! Тут я!"
Є кілька дуже важливих приміток про проміжне програмне забезпечення, про які вам слід знати, перш ніж їх використовувати:
- Функції проміжного програмного забезпечення виконуються в порядку їх додавання до маршруту. Виконання подібне до того, як Slim Framework обробляє це.
- Спочатку виконуються функції "перед", а потім "після" в зворотному порядку.
- Якщо ваша функція проміжного програмного забезпечення повертає false, все виконання зупиняється, і виникає помилка 403 Заборонено. Вам, напевно, захочеться обробити це більш елегантно за допомогою
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();
// Це виведе "Проміжне програмне забезпечення першим! Тут я! Проміжне програмне забезпечення останнім!"
Обробка помилок проміжного програмного забезпечення
Скажімо, у вас є проміжне програмне забезпечення для автентифікації, і ви хочете перенаправити користувача на сторінку входу, якщо він не автентифікований. У вас є кілька варіантів на вибір:
- Ви можете повернути false з функції проміжного програмного забезпечення, і Flight автоматично поверне помилку 403 Заборонено, але без кастомізації.
- Ви можете перенаправити користувача на сторінку входу за допомогою
Flight::redirect()
. - Ви можете створити власну помилку в межах проміжного програмного забезпечення та зупинити виконання маршруту.
Основний приклад
Ось простий приклад 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() ]);
Learn/filtering
Фільтрація
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
в будь-якій з ваших функцій фільтра:
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
, не можна фільтрувати, оскільки їх
викликають безпосередньо, а не динамічно.
Learn/requests
Запити
Flight інкапсулює HTTP запит в один об'єкт, до якого можна доступитися, виконавши:
$request = Flight::request();
Типові випадки використання
Коли ви працюєте з запитом в веб-додатку, зазвичай ви
хочете отримати заголовок, або параметр $_GET
чи $_POST
, або можливо
навіть сирий зміст запиту. Flight надає простий інтерфейс для всіх цих функцій.
Ось приклад отримання параметра рядка запиту:
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
});
Властивості об'єкта запиту
Об'єкт запиту надає такі властивості:
- body - Сирий HTTP зміст запиту
- url - Запитувана URL
- base - Батьківський підкаталог URL
- method - Метод запиту (GET, POST, PUT, DELETE)
- referrer - URL реферера
- ip - IP адреса клієнта
- ajax - Чи є запит AJAX запитом
- scheme - Протокол сервера (http, https)
- user_agent - Інформація про браузер
- type - Тип вмісту
- length - Довжина вмісту
- query - Параметри рядка запиту
- data - Пост дані або JSON дані
- cookies - Дані кукі
- files - Завантажені файли
- secure - Чи є з'єднання безпечним
- accept - HTTP параметри прийому
- proxy_ip - Проксі IP адреса клієнта. Оглядає масив
$_SERVER
на наявністьHTTP_CLIENT_IP
,HTTP_X_FORWARDED_FOR
,HTTP_X_FORWARDED
,HTTP_X_CLUSTER_CLIENT_IP
,HTTP_FORWARDED_FOR
,HTTP_FORWARDED
у цьому порядку. - host - Назва хоста запиту
Ви можете доступитися до властивостей query
, data
, cookies
та files
як масивів або об'єктів.
Отже, щоб отримати параметр рядка запиту, ви можете зробити:
$id = Flight::request()->query['id'];
Або ви можете зробити:
$id = Flight::request()->query->id;
Сирий зміст запиту
Щоб отримати сирий HTTP зміст запиту, наприклад, обробляючи запити PUT, ви можете зробити:
$body = Flight::request()->getBody();
JSON Вхідні дані
Якщо ви надсилаєте запит з типом application/json
і даними {"id": 123}
це буде доступно з властивості data
:
$id = Flight::request()->data->id;
$_GET
Ви можете доступитися до масиву $_GET
через властивість query
:
$id = Flight::request()->query['id'];
$_POST
Ви можете доступитися до масиву $_POST
через властивість data
:
$id = Flight::request()->data['id'];
$_COOKIE
Ви можете доступитися до масиву $_COOKIE
через властивість cookies
:
$myCookieValue = Flight::request()->cookies['myCookieName'];
$_SERVER
Є доступна скорочена функція для доступу до масиву $_SERVER
через метод getVar()
:
$host = Flight::request()->getVar['HTTP_HOST'];
Доступ до завантажених файлів через $_FILES
Ви можете доступитися до завантажених файлів через властивість files
:
$uploadedFile = Flight::request()->files['myFile'];
Обробка завантажень файлів (v3.12.0)
Ви можете обробляти завантаження файлів, використовуючи фреймворк з деякими допоміжними методами. Це в основному зводиться до витягування даних файлу з запиту та переміщення їх у нове місце.
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()
:
// Можливо, вам потрібен заголовок Authorization
$host = Flight::request()->getHeader('Authorization');
// або
$host = Flight::request()->header('Authorization');
// Якщо вам потрібно забрати всі заголовки
$headers = Flight::request()->getHeaders();
// або
$headers = Flight::request()->headers();
Зміст запиту
Ви можете доступитися до сирого змісту запиту, використовуючи метод getBody()
:
$body = Flight::request()->getBody();
Метод запиту
Ви можете доступитися до методу запиту, використовуючи властивість method
або метод getMethod()
:
$method = Flight::request()->method; // насправді викликає getMethod()
$method = Flight::request()->getMethod();
Примітка: Метод getMethod()
спочатку отримує метод з $_SERVER['REQUEST_METHOD']
, потім його можна переписати
через $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']
, якщо він існує, або $_REQUEST['_method']
, якщо він існує.
URL запитів
Існує кілька допоміжних методів для збирання частин URL для зручності.
Повний URL
Ви можете доступитися до повного URL запиту, використовуючи метод getFullUrl()
:
$url = Flight::request()->getFullUrl();
// https://example.com/some/path?foo=bar
Базовий URL
Ви можете доступитися до базового URL, використовуючи метод getBaseUrl()
:
$url = Flight::request()->getBaseUrl();
// Зверніть увагу, без кінцевого слешу.
// https://example.com
Парсинг запитів
Ви можете передати URL до методу parseQuery()
, щоб розпарсити рядок запиту в асоціативний масив:
$query = Flight::request()->parseQuery('https://example.com/some/path?foo=bar');
// ['foo' => 'bar']
Learn/api
Методи API фреймворку
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') // Виконує ETag HTTP кешування.
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 і зупиняє фреймворк.
Flight::onEvent(string $event, callable $callback) // Реєструє слухача подій.
Flight::triggerEvent(string $event, ...$args) // Запускає подію.
Будь-які кастомні методи, додані за допомогою map
та register
, також можуть бути відфільтровані. Для прикладів того, як відобразити ці методи, дивіться посібник Розширення Flight.
Learn/why_frameworks
Чому фреймворк?
Деякі програмісти рішуче проти використання фреймворків. Вони стверджують, що фреймворки є надмірними, повільними і важкими для навчання. Вони кажуть, що фреймворки є непотрібними і що ви можете написати кращий код без них. Звичайно, є деякі слушні зауваження щодо недоліків використання фреймворків. Однак також є багато переваг використання фреймворків.
Причини використання фреймворка
Ось кілька причин, чому ви можете хотіти розглянути можливість використання фреймворка:
- Швидка розробка: Фреймворки забезпечують багато функціональності прямо з коробки. Це означає, що ви можете швидше створювати веб-додатки. Вам не потрібно писати так багато коду, оскільки фреймворк забезпечує багато функціональності, яку ви потребуєте.
- Послідовність: Фреймворки забезпечують послідовний спосіб виконання завдань. Це полегшує розуміння того, як працює код, і спрощує іншим розробникам розуміння вашого коду. Якщо ви маєте все по порядку, ви можете втратити послідовність між скриптами, особливо якщо працюєте в команді з розробниками.
- Безпека: Фреймворки надають функції безпеки, які допомагають захистити ваші веб-додатки від загальних загроз безпеки. Це означає, що вам не потрібно так сильно хвилюватися про безпеку, оскільки фреймворк піклується про багато з цього.
- Спільнота: У фреймворків є великі спільноти розробників, які роблять внески у фреймворк. Це означає, що ви можете отримувати допомогу від інших розробників, коли у вас є запитання або проблеми. Це також означає, що існує багато ресурсів для навчання роботи з фреймворком.
- Кращі практики: Фреймворки створені за допомогою кращих практик. Це означає, що ви можете навчитися від фреймворка і використовувати ті ж самі кращі практики у своєму коді. Це може допомогти вам стати кращим програмістом. Іноді ви не знаєте, що ви не знаєте, і це може зашкодити вам у кінці.
- Розширюваність: Фреймворки розроблені для розширення. Це означає, що ви можете додавати свою функціональність у фреймворк. Це дозволяє вам створювати веб-додатки, які відповідають вашим специфічним потребам.
Flight — це мікро-фреймворк. Це означає, що він невеликий і легкий. Він не надає такої ж функціональності, як більші фреймворки, такі як Laravel або Symfony. Однак він забезпечує багато функціональності, яку ви потребуєте для створення веб-додатків. Його також легко навчитися і використовувати. Це робить його хорошим вибором для швидкого і легкого створення веб-додатків. Якщо ви новачок у фреймворках, Flight є чудовим початковим фреймворком для старту. Він допоможе вам дізнатися про переваги використання фреймворків, не перевантажуючи вас занадто великою складністю. Після того, як ви отримаєте деякий досвід з Flight, вам буде легше перейти на більш складні фреймворки, такі як Laravel або Symfony, однак Flight все ще може скласти успішну надійну програму.
Що таке маршрутизація?
Маршрутизація — це основа фреймворка Flight, але що це таке насправді? Маршрутизація — це процес взяття URL-адреси і зіставлення її з конкретною функцією у вашому коді.
Це спосіб, яким ви можете змусити ваш веб-сайт виконувати різні дії в залежності від запитуваної URL-адреси. Наприклад, ви можете захотіти показати профіль користувача, коли вони
відвідують /user/1234
, але показати список всіх користувачів, коли вони відвідують /users
. Це все робиться через маршрутизацію.
Це може працювати приблизно так:
- Користувач переходить у ваш браузер і вводить
http://example.com/user/1234
. - Сервер отримує запит і дивиться на URL-адресу та передає його вашому коду додатку Flight.
- Скажімо, у вашому коді Flight ви маєте щось на зразок
Flight::route('/user/@id', [ 'UserController', 'viewUserProfile' ]);
. Ваш код додатку Flight дивиться на URL-адресу і бачить, що вона відповідає маршруту, який ви визначили, а потім виконує код, який ви визначили для цього маршруту. - Маршрутизатор Flight запуститься і викличе метод
viewUserProfile($id)
у класіUserController
, передаючи1234
як аргумент$id
у методі. - Код у вашому методі
viewUserProfile()
потім виконається і зробить те, що ви йому сказали. Ви можете закодувати виведення HTML для сторінки профілю користувача, або, якщо це RESTful API, ви можете закодувати виведення JSON-відповіді з інформацією про користувача. - Flight упаковує це красиво, генерує заголовки відповіді і відправляє їх назад у браузер користувача.
- Користувач заповнюється радістю та обіймає себе!
І чому це важливо?
Наявність належного централізованого маршрутизатора може значно спростити ваше життя! Це може бути важко зрозуміти на перший погляд. Ось кілька причин, чому:
- Централізована маршрутизація: Ви можете зберігати всі свої маршрути в одному місці. Це полегшує перегляд маршрутів, які у вас є, та того, що вони роблять. Це також полегшує внесення змін, якщо це буде потрібно.
- Параметри маршруту: Ви можете використовувати параметри маршруту, щоб передавати дані своїм методам маршруту. Це чудовий спосіб зберегти чистоту та організованість вашого коду.
- Групи маршрутів: Ви можете групувати маршрути разом. Це чудово для організації вашого коду та застосування проміжного програмного забезпечення до групи маршрутів.
- Псевдоніми маршрутів: Ви можете призначити псевдонім маршруту, щоб URL-адреса могла динамічно генеруватись пізніше у вашому коді (наприклад, як шаблон). Наприклад: замість того, щоб хардкодити
/user/1234
у вашому коді, ви можете натомість посилатись на псевдонімuser_view
і передаватиid
як параметр. Це робить його чудовим, якщо ви вирішите змінити його на/admin/user/1234
пізніше. Вам не потрібно буде змінювати всі ваші зашкарублені URL-адреси, а тільки URL, що прикріплений до маршруту. - Проміжне програмне забезпечення маршруту: Ви можете додати проміжне програмне забезпечення до ваших маршрутів. Проміжне програмне забезпечення надзвичайно потужне, додаючи специфічні поведінки до вашого додатку, такі як підтвердження, що певний користувач має доступ до маршруту або групи маршрутів.
Я впевнений, що ви знайомі з методом "скрипт за скриптом" для створення веб-сайту. У вас може бути файл під назвою index.php
, який містить безліч if
операцій для перевірки URL-адреси, а потім виконання конкретної функції на основі URL-адреси. Це форма маршрутизації, але вона не дуже організована і може
вийти з-під контролю швидко. Система маршрутизації Flight є набагато більш організованим і потужним способом обробки маршрутизації.
Це?
// /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 надає простий спосіб надіслати відповідь браузеру користувача. Ви можете надіслати відповідь, використовуючи метод Flight::response()
. Цей метод
приймає об'єкт Response
як аргумент і надсилає відповідь браузеру користувача. Ви можете використовувати цей об'єкт, щоб надіслати відповідь
до браузера користувача, таку як HTML, JSON або файл. Flight допомагає вам автоматично генерувати деякі частини відповіді, щоб упростити процес, але в кінцевому підсумку ви маєте
контроль над тим, що ви надсилаєте назад користувачу.
Learn/responses
Відповіді
Flight допомагає генерувати частину заголовків відповіді для вас, але ви контролюєте більшу частину того, що ви повертаєте користувачу. Іноді ви можете безпосередньо отримати доступ до об'єкта Response
, але зазвичай ви будете використовувати екземпляр Flight
, щоб надіслати відповідь.
Відправка базової відповіді
Flight використовує ob_start() для буферизації виходу. Це означає, що ви можете використовувати echo
або print
, щоб надіслати відповідь користувачу, а Flight захопить її і надішле назад користувачу з відповідними заголовками.
// Це надішле "Hello, World!" до браузера користувача
Flight::route('/', function() {
echo "Hello, World!";
});
// HTTP/1.1 200 OK
// Content-Type: text/html
//
// Hello, World!
Як альтернатива, ви можете викликати метод write()
, щоб додати до тіла також.
// Це надішле "Hello, World!" до браузера користувача
Flight::route('/', function() {
// докладно, але робить свою справу, коли вам це потрібно
Flight::response()->write("Hello, World!");
// якщо ви хочете отримати тіло, яке ви встановили на цей момент
// ви можете зробити це так
$body = Flight::response()->getBody();
});
Коди статусу
Ви можете встановити код статусу відповіді, використовуючи метод status
:
Flight::route('/@id', function($id) {
if($id == 123) {
Flight::response()->status(200);
echo "Hello, World!";
} else {
Flight::response()->status(403);
echo "Заборонено";
}
});
Якщо ви хочете отримати поточний код статусу, ви можете використовувати метод status
без аргументів:
Flight::response()->status(); // 200
Встановлення тіла відповіді
Ви можете встановити тіло відповіді, використовуючи метод write
, однак, якщо ви щось echo або print,
воно буде захоплено і надіслано як тіло відповіді через буферизацію виходу.
Flight::route('/', function() {
Flight::response()->write("Hello, World!");
});
// те ж саме, що
Flight::route('/', function() {
echo "Hello, World!";
});
Очиснення тіла відповіді
Якщо ви хочете очистити тіло відповіді, ви можете використовувати метод clearBody
:
Flight::route('/', function() {
if($someCondition) {
Flight::response()->write("Hello, World!");
} else {
Flight::response()->clearBody();
}
});
Виконання колбеку на тілі відповіді
Ви можете виконати колбек на тілі відповіді, використовуючи метод 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, наприклад.
Примітка: Колбеки маршрутів не працюватимуть, якщо ви використовуєте параметр конфігурації 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, щоб застосувати колбек до всіх маршрутів через 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
:
// Це надішле "Hello, World!" до браузера користувача у простому тексті
Flight::route('/', function() {
Flight::response()->header('Content-Type', 'text/plain');
// або
Flight::response()->setHeader('Content-Type', 'text/plain');
echo "Hello, World!";
});
JSON
Flight надає підтримку для надсилання JSON та JSONP відповідей. Щоб надіслати JSON відповідь, ви передаєте деякі дані для JSON кодування:
Flight::json(['id' => 123]);
Примітка: За замовчуванням Flight надішле заголовок
Content-Type: application/json
з відповіддю. Він також використовуватиме константиJSON_THROW_ON_ERROR
іJSON_UNESCAPED_SLASHES
під час кодування JSON.
JSON з кодом статусу
Ви також можете передати код статусу як другий аргумент:
Flight::json(['id' => 123], 201);
JSON з гарною розміткою
Ви також можете передати аргумент до останньої позиції, щоб увімкнути гарну розмітку:
Flight::json(['id' => 123], 200, true, 'utf-8', JSON_PRETTY_PRINT);
Якщо ви змінюєте параметри, передані в 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 і зупинка виконання (v3.10.0)
Якщо ви хочете надіслати JSON відповідь і зупинити виконання, ви можете використовувати метод jsonHalt
. Це корисно для випадків, коли ви перевіряєте авторизацію, і якщо
користувач не авторизований, ви можете миттєво надіслати JSON відповідь, очистити вміст тіла і зупинити виконання.
Flight::route('/users', function() {
$authorized = деякаПеревіркаАвторизації();
// Перевірте, чи користувач авторизований
if($authorized === false) {
Flight::jsonHalt(['error' => 'Неавторизований'], 401);
}
// Продовжте з рештою маршруту
});
До версії v3.10.0 вам потрібно було зробити щось подібне:
Flight::route('/users', function() {
$authorized = деякаПеревіркаАвторизації();
// Перевірте, чи користувач авторизований
if($authorized === false) {
Flight::halt(401, json_encode(['error' => 'Неавторизований']));
}
// Продовжте з рештою маршруту
});
JSONP
Для запитів JSONP ви можете необов'язково передати параметр запиту, який ви використовуєте, щоб визначити вашу функцію колбеку:
Flight::jsonp(['id' => 123], 'q');
Отже, коли ви здійснюєте GET запит, використовуючи ?q=my_func
, ви повинні отримати вихід:
my_func({"id":123});
Якщо ви не передасте параметр запиту, він за замовчуванням буде jsonp
.
Перенаправлення на іншу URL-адресу
Ви можете перенаправити поточний запит, використовуючи метод redirect()
і передаючи
нову URL-адресу:
Flight::redirect('/new/location');
За замовчуванням Flight надсилає HTTP код статусу 303 ("See Other"). Ви можете необов'язково встановити кастомний код:
Flight::redirect('/new/location', 401);
Зупинка
Ви можете зупинити фреймворк в будь-який момент, викликавши метод halt
:
Flight::halt();
Ви також можете вказати необов'язковий HTTP
код статусу і повідомлення:
Flight::halt(200, 'Давайте повернемося...');
Виклик halt
знищить будь-який контент відповіді до цього моменту. Якщо ви хочете зупинити
фреймворк і вивести поточну відповідь, використовуйте метод stop
:
Flight::stop();
Очищення даних відповіді
Ви можете очистити тіло відповіді та заголовки, використовуючи метод clear()
. Це очистить
будь-які заголовки, призначені відповіді, очистить тіло відповіді і встановить код статусу 200
.
Flight::response()->clear();
Очищення тіла відповіді тільки
Якщо ви хочете очистити лише тіло відповіді, ви можете використовувати метод clearBody()
:
// Це все ще зберігатиме будь-які заголовки, встановлені на об'єкті response().
Flight::response()->clearBody();
HTTP кешування
Flight надає вбудовану підтримку для кешування на рівні HTTP. Якщо умова кешування
виконана, Flight поверне HTTP 304 Not Modified
відповідь. Наступного разу, коли
клієнт запитає той же ресурс, йому буде запропоновано використовувати їх локально
закешовану версію.
Кешування на рівні маршруту
Якщо ви хочете кешувати вашу всю відповідь, ви можете використовувати метод 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-мітку часу, щоб встановити дату
і час, коли сторінка востаннє була змінена. Клієнт продовжуватиме використовувати свій кеш, поки
значення останнього змінення не зміниться.
Flight::route('/news', function () {
Flight::lastModified(1234567890);
echo 'Цей контент буде кешовано.';
});
ETag
Кешування ETag
подібне до Last-Modified
, за винятком того, що ви можете вказати будь-який ідентифікатор, який
ви хочете для ресурсу:
Flight::route('/news', function () {
Flight::etag('my-unique-id');
echo 'Цей контент буде кешовано.';
});
Пам'ятайте, що виклик або lastModified
, або etag
і обидва встановлять і перевірять
значення кешу. Якщо значення кешу однакове між запитами, Flight негайно
надішле відповідь HTTP 304
і зупинить обробку.
Завантаження файлу (v3.12.0)
Існує допоміжний метод для завантаження файлу. Ви можете використовувати метод download
і передати шлях.
Flight::route('/download', function () {
Flight::download('/path/to/file.txt');
});
Learn/events
Система подій у Flight PHP (v3.15.0+)
Flight PHP вводить легку та інтуїтивно зрозумілу систему подій, яка дозволяє вам реєструвати та активувати власні події у вашій програмі. З додаванням Flight::onEvent()
та Flight::triggerEvent()
, ви тепер можете підключатися до ключових моментів життєвого циклу вашого додатку або визначати свої власні події, щоб зробити ваш код більш модульним та розширювальним. Ці методи є частиною відображуваних методів Flight, що означає, що ви можете перевизначити їх поведінку відповідно до ваших потреб.
Цей посібник охоплює все, що вам потрібно знати, щоб почати працювати з подіями, включаючи чому вони цінні, як їх використовувати та практичні приклади, щоб допомогти новачкам зрозуміти їхню силу.
Чому варто використовувати події?
Події дозволяють вам розділити різні частини вашого додатку так, щоб вони не залежали занадто сильно один від одного. Це розділення — часто називане декуплінгом — робить ваш код легшим для оновлення, розширення чи налагодження. Замість того, щоб писати все в одному великому шматку, ви можете розділити вашу логіку на менші, незалежні частини, які реагують на конкретні дії (події).
Уявіть, що ви розробляєте додаток для блогу:
- Коли користувач залишає коментар, ви можливо захочете:
- Зберегти коментар у базі даних.
- Відправити електронний лист власнику блогу.
- Залоги приводу для безпеки.
Без подій, ви б змусили все це в одну функцію. З подіями, ви можете розділити це: одна частина зберігає коментар, інша активує подію на кшталт 'comment.posted'
, а окремі слухачі обробляють електронну пошту та логування. Це зберігає ваш код чистішим та дозволяє вам додавати або видаляти функції (як-от сповіщення) без втручання в основну логіку.
Загальні застосування
- Логування: Записуйте дії, такі як входи або помилки, не заважаючи вашому основному коду.
- Сповіщення: Відправляйте електронні листи або сповіщення, коли щось відбувається.
- Оновлення: Оновлюйте кеш або сповіщайте інші системи про зміни.
Реєстрація слухачів подій
Щоб прослухати подію, використовуйте Flight::onEvent()
. Цей метод дозволяє вам визначити, що повинно відбутися, коли подія виникає.
Синтаксис
Flight::onEvent(string $event, callable $callback): void
$event
: Назва вашої події (наприклад,'user.login'
).$callback
: Функція, яка виконується, коли подія активується.
Як це працює
Ви "підписуєтеся" на подію, кажучи Flight, що робити, коли це відбувається. Колбек може приймати аргументи, передані з тригера події.
Система подій Flight є синхронною, що означає, що кожен слухач подій виконується в послідовності, один за одним. Коли ви активуєте подію, всі зареєстровані слухачі для цієї події будуть виконані до завершення, перш ніж ваш код продовжиться. Це важливо розуміти, оскільки це відрізняється від асинхронних систем подій, де слухачі можуть виконуватись паралельно або в пізніший час.
Простий приклад
Flight::onEvent('user.login', function ($username) {
echo "Ласкаво просимо назад, $username!";
});
Тут, коли активується подія 'user.login'
, вона привітає користувача за іменем.
Ключові моменти
- Ви можете додати кілька слухачів до однієї й тієї ж події — вони виконуватимуться в порядку, в якому ви їх зареєстрували.
- Колбек може бути функцією, анонімною функцією або методом класу.
Активація подій
Щоб зробити подію активною, використовуйте Flight::triggerEvent()
. Це говорить Flight виконати всіх слухачів, зареєстрованих для цієї події, передаючи будь-які дані, які ви надаєте.
Синтаксис
Flight::triggerEvent(string $event, ...$args): void
$event
: Назва події, яку ви активуєте (має відповідати зареєстрованій події)....$args
: Опціональні аргументи для відправки слухачам (може бути будь-яка кількість аргументів).
Простий приклад
$username = 'alice';
Flight::triggerEvent('user.login', $username);
Це активує подію 'user.login'
і передає 'alice'
слухачу, якого ми визначили раніше, який виведе: Ласкаво просимо назад, alice!
.
Ключові моменти
- Якщо не зареєстровано слухачів, нічого не відбувається — ваш додаток не буде ламатися.
- Використовуйте оператор поширення (
...
), щоб гнучко передавати кілька аргументів.
Реєстрація слухачів подій
...
Зупинка подальших слухачів:
Якщо слухач повертає false
, жоден з наступних слухачів для цієї події не буде виконано. Це дозволяє вам зупинити ланцюг подій на основі конкретних умов. Пам'ятайте, що порядок слухачів має значення, оскільки перший, хто повертає false
, зупинить решту від виконання.
Приклад:
Flight::onEvent('user.login', function ($username) {
if (isBanned($username)) {
logoutUser($username);
return false; // Зупиняє наступні слухачі
}
});
Flight::onEvent('user.login', function ($username) {
sendWelcomeEmail($username); // цей ніколи не буде надіслано
});
Перевизначення методів подій
Flight::onEvent()
та Flight::triggerEvent()
доступні для розширення, що означає, що ви можете переозначити, як вони працюють. Це чудово підходить для просунутих користувачів, які хочуть налаштувати систему подій, наприклад, додати логування або змінити, як події передаються.
Приклад: Налаштування onEvent
Flight::map('onEvent', function (string $event, callable $callback) {
// Логувати кожну реєстрацію події
error_log("Додано новий слухач події для: $event");
// Викликати стандартну поведінку (припускаючи внутрішню систему подій)
Flight::_onEvent($event, $callback);
});
Тепер кожного разу, коли ви реєструєте подію, вона записується перед продовженням.
Чому перевизначати?
- Додати налагодження або моніторинг.
- Обмежити події в певних середовищах (наприклад, вимкнути у тестуванні).
- Інтегруватися з іншою бібліотекою подій.
Де розмістити ваші події
Як новачок, ви можете запитати: де мені реєструвати всі ці події в моєму додатку? Простота Flight означає, що немає суворих правил — ви можете помістити їх туди, де це має сенс для вашого проекту. Проте, збереження їх в організованому вигляді допоможе вам підтримувати ваш код в міру зростання вашого додатку. Ось кілька практичних варіантів і найкращих практик, адаптованих до легкості Flight:
Варіант 1: У вашому основному index.php
Для невеликих додатків або швидких прототипів ви можете зареєструвати події прямо у вашому файлі index.php
, поряд з вашими маршрутами. Це утримує все в одному місці, що є прийнятним, коли простота є вашим пріоритетом.
require 'vendor/autoload.php';
// Реєстрація подій
Flight::onEvent('user.login', function ($username) {
error_log("$username увійшов о " . date('Y-m-d H:i:s'));
});
// Визначення маршрутів
Flight::route('/login', function () {
$username = 'bob';
Flight::triggerEvent('user.login', $username);
echo "Увійшов!";
});
Flight::start();
- Плюси: Просто, немає додаткових файлів, відмінно для невеликих проектів.
- Мінуси: Може стати неохайно, коли ваш додаток зростає з більшими подіями та маршрутами.
Варіант 2: Окремий файл events.php
Для трохи більших додатків розгляньте можливість перенесення реєстрацій подій у спеціалізований файл, такий як app/config/events.php
. Включіть цей файл у ваш index.php
перед вашими маршрутами. Це імітує те, як маршрути часто організовані в app/config/routes.php
у проектах Flight.
// app/config/events.php
Flight::onEvent('user.login', function ($username) {
error_log("$username увійшов о " . date('Y-m-d H:i:s'));
});
Flight::onEvent('user.registered', function ($email, $name) {
echo "Електронний лист надіслано на $email: Ласкаво просимо, $name!";
});
// index.php
require 'vendor/autoload.php';
require 'app/config/events.php';
Flight::route('/login', function () {
$username = 'bob';
Flight::triggerEvent('user.login', $username);
echo "Увійшов!";
});
Flight::start();
- Плюси: Зберігає
index.php
зосередженим на маршрутизації, логічно організовує події, легко знаходити та редагувати. - Мінуси: Додає трохи структури, що може відчуватися надмірно для дуже малих додатків.
Варіант 3: Поруч з місцем, де їх активують
Ще один підхід - реєструвати події ближче до місця, де їх активують, наприклад, всередині контролера або визначення маршруту. Це добре працює, якщо подія специфічна для однієї частини вашого додатку.
Flight::route('/signup', function () {
// Реєструвати подію тут
Flight::onEvent('user.registered', function ($email) {
echo "Сповіщення надіслано на $email!";
});
$email = 'jane@example.com';
Flight::triggerEvent('user.registered', $email);
echo "Зареєстровано!";
});
- Плюси: Зберігає пов’язаний код разом, добре для ізольованих функцій.
- Мінуси: Розкидає реєстрації подій, ускладнюючи перегляд усіх подій одночасно; ризик дублікатів реєстрацій, якщо не бути уважним.
Найкраща практика для Flight
- Починайте з простоти: Для крихітних додатків розмістіть події в
index.php
. Це швидко і відповідає мінімалізму Flight. - Розвивайтеся розумно: Коли ваш додаток розширюється (наприклад, більше 5-10 подій), використовуйте файл
app/config/events.php
. Це природний крок уперед, як організація маршрутів, і утримує ваш код охайним без надмірного ускладнення. - Уникайте надмірної інженерії: Не створюйте повноцінний "клас менеджера подій" або каталог, якщо ваш додаток не став величезним — Flight процвітає завдяки простоті, тому зберігайте його легким.
Порада: Групуйте за метою
У events.php
, групуйте пов’язані події (наприклад, всі події, пов’язані з користувачами, разом) з коментарями для чіткості:
// app/config/events.php
// Події користувачів
Flight::onEvent('user.login', function ($username) {
error_log("$username увійшов");
});
Flight::onEvent('user.registered', function ($email) {
echo "Ласкаво просимо до $email!";
});
// Події сторінок
Flight::onEvent('page.updated', function ($pageId) {
unset($_SESSION['pages'][$pageId]);
});
Ця структура добре масштабується і залишається зрозумілою для новачків.
Приклади для новачків
Давайте пройдемося через кілька реальних сценаріїв, щоб показати, як працюють події і чому вони корисні.
Приклад 1: Логування входу користувача
// Крок 1: Реєстрація слухача
Flight::onEvent('user.login', function ($username) {
$time = date('Y-m-d H:i:s');
error_log("$username увійшов о $time");
});
// Крок 2: Активуйте це у вашому додатку
Flight::route('/login', function () {
$username = 'bob'; // Уявімо, що це приходить з форми
Flight::triggerEvent('user.login', $username);
echo "Привіт, $username!";
});
Чому це корисно: Код входу не повинен знати про логування — він просто активує подію. Ви можете пізніше додати більше слухачів (наприклад, відправити вітальний лист) без зміни маршруту.
Приклад 2: Сповіщення про нових користувачів
// Слухач для нових реєстрацій
Flight::onEvent('user.registered', function ($email, $name) {
// Імітувати відправлення електронного листа
echo "Електронний лист надіслано на $email: Ласкаво просимо, $name!";
});
// Активуйте це, коли хтось реєструється
Flight::route('/signup', function () {
$email = 'jane@example.com';
$name = 'Jane';
Flight::triggerEvent('user.registered', $email, $name);
echo "Дякуємо за реєстрацію!";
});
Чому це корисно: Логіка реєстрації зосереджена на створенні користувача, тоді як подія обробляє сповіщення. Ви могли б додати більше слухачів (наприклад, залогувати реєстрацію) пізніше.
Приклад 3: Очистка кешу
// Слухач для очищення кешу
Flight::onEvent('page.updated', function ($pageId) {
unset($_SESSION['pages'][$pageId]); // Очистити кеш сесії, якщо це доречно
echo "Кеш очищено для сторінки $pageId.";
});
// Активуйте це, коли сторінка редагується
Flight::route('/edit-page/(@id)', function ($pageId) {
// Уявімо, що ми оновили сторінку
Flight::triggerEvent('page.updated', $pageId);
echo "Сторінка $pageId оновлена.";
});
Чому це корисно: Код редагування не повинен піклуватися про кешування — він просто сигналізує про оновлення. Інші частини програми можуть реагувати на це за потребою.
Найкращі практики
- Чітко називайте події: Використовуйте специфічні назви, такі як
'user.login'
або'page.updated'
, щоб було очевидно, що вони роблять. - Зберігайте слухачів простими: Не ставте повільні або складні завдання в слухачах — зберігайте ваш додаток швидким.
- Тестуйте ваші події: Активуйте їх вручну, щоб переконатися, що слухачі працюють, як очікується.
- Використовуйте події з розумом: Вони чудово підходять для декуплінгу, але надто багато може ускладнити ваш код — використовуйте їх, коли це має сенс.
Система подій у Flight PHP, з Flight::onEvent()
та Flight::triggerEvent()
, дає вам простий, але потужний спосіб створювати гнучкі додатки. Дозволяючи різним частинам вашого додатку спілкуватися одне з одним через події, ви можете зберігати ваш код організованим, повторно використаним і легким для розширення. Чи ви логіруєте дії, надсилаєте сповіщення чи управляєте оновленнями, події допомагають вам робити це без заплутування вашої логіки. Більше того, з можливістю перевизначення цих методів, ви отримуєте свободу налаштувати систему під ваші потреби. Почніть з маленької події і спостерігайте, як вона трансформує структуру вашого додатку!
Вбудовані події
Flight PHP поставляється з кількома вбудованими подіями, які ви можете використовувати для підключення до життєвого циклу фреймворку. Ці події активуються в певні моменти в циклі запит/відповідь, дозволяючи вам виконувати власну логіку, коли відбуваються певні дії.
Список вбудованих подій
flight.request.received
: Активується, коли запит отримано, розпарсено та оброблено.flight.route.middleware.before
: Активується, після того як виконано попереднє проміжне програмне забезпечення.flight.route.middleware.after
: Активується, після того як виконано післяпроміжне програмне забезпечення.flight.route.executed
: Активується після виконання та обробки маршруту.flight.response.sent
: Активується після того, як відповідь надіслана клієнту.
Learn/templates
HTML Views та Шаблони
Flight надає деяку базову функціональність шаблонізації за замовчуванням.
Flight дозволяє вам замінити базовий механізм перегляду просто зареєструвавши свій клас представлення. Прокрутіть вниз, щоб побачити приклади використання Smarty, Latte, Blade та інших!
Вбудований механізм перегляду
Щоб відобразити шаблон представлення, викликайте метод render
з ім'ям
файлу шаблону та необов'язковими даними шаблону:
Flight::render('hello.php', ['name' => 'Bob']);
Дані шаблону, які ви передаєте, автоматично інжектуються у шаблон і можуть
бути доступні як локальна змінна. Шаблони — це просто PHP файли. Якщо
вміст файлу шаблону hello.php
є:
Hello, <?= $name ?>!
Вихід буде:
Hello, Bob!
Ви також можете вручну встановити змінні представлення, використовуючи метод set:
Flight::view()->set('name', 'Bob');
Змінна name
тепер доступна у всіх ваших представленнях. Тому ви можете просто зробити:
Flight::render('hello');
Зверніть увагу, що при вказуванні імені шаблону в методі render ви можете
не вказувати розширення .php
.
За замовчуванням Flight буде шукати каталог views
для файлів шаблонів. Ви можете
вказати альтернативний шлях для ваших шаблонів, задавши наступну конфігурацію:
Flight::set('flight.views.path', '/path/to/views');
Макети
Зазвичай веб-сайти мають один шаблон макета з мінливим
вмістом. Щоб відобразити вміст, який слід використовувати в макеті, ви можете передати необов'язковий
параметр до методу render
.
Flight::render('header', ['heading' => 'Hello'], 'headerContent');
Flight::render('body', ['body' => 'World'], 'bodyContent');
Ваше представлення тепер матиме збережені змінні, звані headerContent
та bodyContent
.
Ви можете відобразити свій макет, зробивши:
Flight::render('layout', ['title' => 'Home Page']);
Якщо файли шаблонів виглядають ось так:
header.php
:
<h1><?= $heading ?></h1>
body.php
:
<div><?= $body ?></div>
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>
Smarty
Ось як ви можете використовувати шаблонний механізм 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 як клас представлення
// Також передайте функцію зворотного виклику для налаштування 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);
});
Blade
Ось як ви можете використовувати шаблонний механізм Blade для своїх представлень:
Спочатку вам потрібно встановити бібліотеку BladeOne за допомогою Composer:
composer require eftec/bladeone
Тоді ви можете налаштувати BladeOne як клас представлення в Flight:
<?php
// Завантажте бібліотеку BladeOne
use eftec\bladeone\BladeOne;
// Зареєструйте BladeOne як клас представлення
// Також передайте функцію зворотного виклику для налаштування BladeOne при завантаженні
Flight::register('view', BladeOne::class, [], function (BladeOne $blade) {
$views = __DIR__ . '/../views';
$cache = __DIR__ . '/../cache';
$blade->setPath($views);
$blade->setCompiledPath($cache);
});
// Призначте дані шаблону
Flight::view()->share('name', 'Bob');
// Відобразіть шаблон
echo Flight::view()->run('hello', []);
Для повноти ви також повинні переозначити стандартний метод render Flight:
<?php
Flight::map('render', function(string $template, array $data): void {
echo Flight::view()->run($template, $data);
});
У цьому прикладі файл шаблону hello.blade.php може виглядати ось так:
<?php
Hello, {{ $name }}!
Вихід буде:
Hello, Bob!
Дотримуючись цих кроків, ви можете інтегрувати механізм шаблонів Blade з Flight і використовувати його для візуалізації ваших представлень.
Learn/flight_vs_fat_free
Flight vs Fat-Free
Що таке Fat-Free?
Fat-Free (ласкаво відомий як F3) є потужним, але простим у використанні мікрофреймворком PHP, призначеним для допомоги у створенні динамічних і надійних веб-додатків - швидко!
Flight порівнюється з Fat-Free в багатьох аспектах і, мабуть, є найближчим родичем у термінах функціональності та простоти. Fat-Free має багато функцій, яких немає у Flight, але також має і багато функцій, які є у Flight. Fat-Free починає демонструвати свою старість і вже не є так популярним, як раніше.
Оновлення стають менш частими, а спільнота не така активна. Код досить простий, але іноді відсутність дисципліни в синтаксисі може ускладнити читання та розуміння. Він працює з PHP 8.3, але сам код все ще виглядає так, ніби живе у PHP 5.3.
Плюси у порівнянні з Flight
- Fat-Free має кілька більше зірок на GitHub, ніж Flight.
- Fat-Free має деяку пристойну документацію, але в деяких областях їй не вистачає ясності.
- Fat-Free має деякі рідкісні ресурси, такі як уроки на YouTube та онлайн-статті, які можна використовувати для вивчення фреймворку.
- Fat-Free має декілька корисних плагінів, що вбудовані, які іноді можуть бути корисними.
- Fat-Free має вбудований ORM під назвою Mapper, який можна використовувати для взаємодії з вашою базою даних. Flight має active-record.
- Fat-Free має вбудовані Сесії, кешування та локалізацію. Flight вимагає використовувати сторонні бібліотеки, але це охоплено у документації.
- Fat-Free має невелику групу плагінів, створених спільнотою, які можна використовувати для розширення фреймворку. Flight має деякі з них, описані на сторінках документації та прикладів.
- Fat-Free, як і Flight, не має залежностей.
- Fat-Free, як і Flight, спрямований на надання розробнику контролю над своїм додатком та простого досвіду розробника.
- Fat-Free підтримує зворотну сумісність, подібно до Flight (частково тому, що оновлення стають менш частими).
- Fat-Free, як і Flight, призначений для розробників, які вперше потрапляють у світ фреймворків.
- Fat-Free має вбудований шаблонний движок, який є більш потужним, ніж шаблонний движок Flight. Flight рекомендує Latte для досягнення цієї мети.
- Fat-Free має унікальну команду типу CLI "route", де ви можете створювати CLI додатки безпосередньо у Fat-Free і обробляти це, як звичайний запит
GET
. Flight досягає цього за допомогою runway.
Мінуси у порівнянні з Flight
- Fat-Free має певні тести реалізації і навіть має свій власний тест клас, який є дуже базовим. Проте, він не 100% модульно протестований, як Flight.
- Вам доведеться використовувати пошукову систему, таку як Google, щоб фактично знайти сайт документації.
- Flight має темний режим на своєму сайті документації. (падіння мікрофона)
- Fat-Free має кілька модулів, які, на жаль, не підтримуються.
- Flight має простий PdoWrapper, який є трохи простішим, ніж вбудований
DB\SQL
клас Fat-Free. - Flight має плагін для управління правами доступу, який можна використовувати для забезпечення безпеки вашого додатку. Slim вимагає використовувати сторонню бібліотеку.
- Flight має ORM під назвою active-record, який виглядає більше як ORM, ніж Mapper Fat-Free.
Додаткова перевага
active-record
полягає в тому, що ви можете визначати відносини між записами для автоматичних злиттів, тоді як Mapper Fat-Free вимагає від вас створення SQL.views. - Дивіться на це, Fat-Free не має кореневого простору назв. Flight має простір назв у всьому коді, щоб не стикатися з вашим власним кодом.
клас
Cache
є найбільшим порушником у цьому. - Fat-Free не має проміжного програмного забезпечення. Замість цього є хуки
beforeroute
іafterroute
, які можна використовувати для фільтрації запитів і відповідей у контролерах. - Fat-Free не може групувати маршрути.
- Fat-Free має обробник контейнера ін'єкції залежностей, але документація надзвичайно обмежена з приводу того, як його використовувати.
- Налагодження може бути трохи складним, оскільки в основному все зберігається в тому, що називається
HIVE
Learn/extending
Розширення
Flight розроблений як розширювальний фреймворк. Фреймворк постачається з набором за замовчуванням методів та компонентів, але дозволяє вам відображати свої власні методи, реєструвати свої власні класи або навіть перевизначати існуючі класи та методи.
Якщо ви шукаєте DIC (Контейнер впровадження залежностей), перейдіть на Сторінка контейнера впровадження залежностей.
Відображення методів
Щоб відобразити свій власний простий кастомний метод, використовуйте функцію map
:
// Відобразіть свій метод
Flight::map('hello', function (string $name) {
echo "привіт $name!";
});
// Викличте свій кастомний метод
Flight::hello('Боб');
Хоча можливо створити прості кастомні методи, рекомендується просто створювати стандартні функції в PHP. Це має автозаповнення в IDE і легше читається. Еквівалентом наведеного вище коду буде:
function hello(string $name) {
echo "привіт $name!";
}
hello('Боб');
Це використовується більше, коли вам потрібно передати змінні у ваш метод, щоб отримати очікуване
значення. Використання методу 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. Ось приклад, що використовує бібліотеку Monolog:
// index.php або bootstrap.php
// Зареєструйте логгер з Flight
Flight::register('log', Monolog\Logger::class, [ 'name' ], function(Monolog\Logger $log) {
$log->pushHandler(new Monolog\Handler\StreamHandler('path/to/your.log', Monolog\Logger::WARNING));
});
Тепер, коли він зареєстрований, ви можете використовувати його у вашій програмі:
// У вашому контролері або маршруті
Flight::log()->warning('Це повідомлення про попередження');
Це запише повідомлення у файл журналу, який ви вказали. Що якщо ви хочете зафіксувати щось, коли відбувається помилка? Ви можете використовувати метод error
:
// У вашому контролері або маршруті
Flight::map('error', function(Throwable $ex) {
Flight::log()->error($ex->getMessage());
// Відобразіть свою кастомну сторінку помилки
include 'errors/500.html';
});
Ви також можете створити базову систему APM (Моніторинг продуктивності додатка), використовуючи методи before
та after
:
// У вашому файлі старту
Flight::before('start', function() {
Flight::set('start_time', microtime(true));
});
Flight::after('start', function() {
$end = microtime(true);
$start = Flight::get('start_time');
Flight::log()->info('Запит '.Flight::request()->url.' тривав ' . round($end - $start, 4) . ' секунд');
// Ви також можете додати свої заголовки запиту або відповіді
// щоб зафіксувати їх (будьте обережні, бо це буде
// багато даних, якщо у вас багато запитів)
Flight::log()->info('Заголовки запиту: ' . json_encode(Flight::request()->headers));
Flight::log()->info('Заголовки відповіді: ' . json_encode(Flight::response()->headers));
});
Перевизначення методів фреймворку
Flight дозволяє вам перевизначати свою стандартну функціональність відповідно до ваших потреб, не вносячи зміни в код. Ви можете переглянути всі методи, які можете перевизначити тут.
Наприклад, коли Flight не може співвіднести URL з маршрутом, він викликає метод notFound
,
який надсилає загальний HTTP 404
відповідь. Ви можете перевизначити цю поведінку
за допомогою методу map
:
Flight::map('notFound', function() {
// Відобразіть кастомну 404 сторінку
include 'errors/404.html';
});
Flight також дозволяє вам замінити основні компоненти фреймворку. Наприклад, ви можете замінити стандартний клас Router своїм кастомним класом:
// Зареєструйте свій кастомний клас
Flight::register('router', MyRouter::class);
// Коли Flight завантажує екземпляр Router, він завантажить ваш клас
$myrouter = Flight::router();
Методи фреймворку, такі як map
та register
, однак не можуть бути перевизначені. Ви отримаєте помилку, якщо спробуєте це зробити.
Learn/flight_vs_slim
Flight vs Slim
Що таке Slim?
Slim - це мікро-фреймворк PHP, який допомагає вам швидко писати прості, але потужні веб-додатки та API.
Багато з натхнення для деяких з функцій v3 Flight насправді прийшло від Slim. Групування маршрутів і виконання проміжного програмного забезпечення в конкретному порядку - це дві функції, які були натхнені Slim. Slim v3 з'явився, спрямований на простоту, але були змішані відгуки щодо v4.
Переваги у порівнянні з Flight
- У Slim є більша спільнота розробників, які в свою чергу створюють зручні модулі, щоб допомогти вам не винаходити велосипед заново.
- Slim дотримується багатьох інтерфейсів і стандартів, які є поширеними у спільноті PHP, що підвищує взаємозв'язок.
- Slim має прийнятну документацію та навчальні матеріали, які можна використовувати для вивчення фреймворку (навіть не порівняти з Laravel або Symfony).
- Slim має різноманітні ресурси, такі як навчальні відео на YouTube та онлайн-статті, які можна використовувати для вивчення фреймворку.
- Slim дозволяє вам використовувати будь-які компоненти, які ви хочете, для обробки основних функцій маршрутизації, оскільки він відповідає стандарту PSR-7.
Недоліки у порівнянні з Flight
- Дивно, але Slim не такий швидкий, як ви могли б подумати для мікро-фреймворку. Дивіться TechEmpower benchmarks для отримання додаткової інформації.
- Flight орієнтований на розробника, який хоче створити легкий, швидкий і простий у використанні веб-додаток.
- У Flight немає залежностей, тоді як Slim має кілька залежностей, які ви повинні встановити.
- Flight орієнтований на простоту та зручність використання.
- Одна з основних функцій Flight полягає в тому, що він робить все можливе, щоб зберегти зворотну сумісність. Зміна з Slim v3 до v4 була руйнівною зміною.
- Flight призначений для розробників, які вперше пробують себе у світі фреймворків.
- Flight також може реалізовувати додатки на корпоративному рівні, але в нього не так багато прикладів і навчальних матеріалів, як у Slim. Це також вимагатиме більшу дисципліну з боку розробника, щоб зберігати все організованим і добре структурованим.
- Flight дає розробнику більше контролю над додатком, тоді як Slim може ввести в дію деяку магію за лаштунками.
- Flight має простий PdoWrapper, який можна використовувати для взаємодії з вашою базою даних. Slim вимагає використовувати сторонню бібліотеку.
- Flight має плагін для управління доступом, який можна використовувати для захисту вашого додатка. Slim вимагає використовувати сторонню бібліотеку.
- Flight має ORM під назвою active-record, який можна використовувати для взаємодії з вашою базою даних. Slim вимагає використовувати сторонню бібліотеку.
- Flight має CLI-додаток під назвою runway, який можна використовувати для запуску вашого додатка з командного рядка. У Slim цього немає.
Learn/autoloading
Автозавантаження
Автозавантаження є концепцією в PHP, де ви вказуєте директорію або директорії для завантаження класів. Це набагато вигідніше, ніж використовувати require
або include
для завантаження класів. Це також є вимогою для використання пакетів Composer.
За замовчуванням будь-який клас Flight
автоматично завантажується завдяки composer. Однак, якщо ви хочете автозавантажити власні класи, ви можете використовувати метод 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/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);
.
Це дозволить вам використовувати підкреслення в ваших іменах класів.
Це не рекомендується, але це доступно для тих, хто це потребує.
/**
* 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() {
// зробіть щось
}
}
Learn/troubleshooting
Виправлення несправностей
Ця сторінка допоможе вам вирішити поширені проблеми, з якими ви можете зіткнутися при використанні Flight.
Поширені проблеми
404 Не знайдено або несподівана поведінка маршруту
Якщо ви бачите помилку 404 Не знайдено (але клянетесь, що це дійсно там і це не помилка), це може бути проблемою з тим, що ви повертаєте значення у вашому маршруті замість того, щоб просто виводити його. Причина цього є навмисною, але може підкочуватися до деяких розробників.
Flight::route('/hello', function(){
// Це може викликати помилку 404 Не знайдено
return 'Hello World';
});
// Що ви, напевно, хочете
Flight::route('/hello', function(){
echo 'Hello World';
});
Причина цього полягає в особливому механізмі, вбудованому в маршрутизатор, який обробляє повернення виводу як одиночний для "перейти до наступного маршруту". Ви можете ознайомитися з поведінкою, задокументованою в розділі Маршрутизація.
Клас не знайдено (автозавантаження не працює)
Можливо, є кілька причин, чому це не відбувається. Нижче наведено кілька прикладів, але переконайтеся, що ви також переглянули розділ автозавантаження.
Неправильне ім'я файлу
Найпоширенішою є те, що ім'я класу не відповідає імені файлу.
Якщо у вас є клас під назвою MyClass
, то файл повинен називатися MyClass.php
. Якщо у вас є клас під назвою MyClass
, а файл називається 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()
визначено (ймовірно, до кореня вашого каталогу) перед тим, як ви спробуєте його використовувати.
// Додайте шлях до автозавантажувача
Flight::path(__DIR__.'/../');
Guides/blog
Будівництво простого блогу з Flight PHP
Цей посібник проведе вас через створення базового блогу з використанням фреймворку Flight PHP. Ви налаштуєте проект, визначите маршрути, керуватимете дописами з JSON та відображатимете їх за допомогою движка шаблонів Latte, демонструючи простоту та гнучкість Flight. Наприкінці у вас буде функціональний блог з головною сторінкою, індивідуальними сторінками дописів та формою створення.
Потреби
- PHP 7.4+: Встановлений на вашій системі.
- Composer: Для управління залежностями.
- Текстовий редактор: Будь-який редактор, як-от VS Code або PHPStorm.
- Базові знання PHP та веб-розробки.
Крок 1: Налаштування вашого проекту
Почніть зі створення нового каталогу проекту та встановлення Flight через Composer.
-
Створіть каталог:
mkdir flight-blog cd flight-blog
-
Встановіть Flight:
composer require flightphp/core
-
Створіть публічний каталог: Flight використовує єдину точку входу (
index.php
). Створіть папкуpublic/
для цього:mkdir public
-
Основний
index.php
: Створітьpublic/index.php
з простою маршрутом "hello world":<?php require '../vendor/autoload.php'; Flight::route('/', function () { echo 'Привіт, Flight!'; }); Flight::start();
-
Запустіть вбудований сервер: Перевірте вашу установку за допомогою розробницького сервера PHP:
php -S localhost:8000 -t public/
Відвідайте
http://localhost:8000
, щоб побачити "Привіт, Flight!".
Крок 2: Організуйте структуру вашого проекту
Для чистого налаштування структуруйте ваш проект ось так:
flight-blog/
├── app/
│ ├── config/
│ └── views/
├── data/
├── public/
│ └── index.php
├── vendor/
└── composer.json
app/config/
: Файли конфігурації (наприклад, події, маршрути).app/views/
: Шаблони для відображення сторінок.data/
: JSON-файл для зберігання дописів блогу.public/
: Веб-корінь зindex.php
.
Крок 3: Встановіть та налаштуйте Latte
Latte - це легкий движок шаблонів, який добре інтегрується з Flight.
-
Встановіть Latte:
composer require latte/latte
-
Налаштуйте Latte в Flight: Оновіть
public/index.php
, щоб зареєструвати Latte як двигун відображення:<?php require '../vendor/autoload.php'; use Latte\Engine; Flight::register('view', Engine::class, [], function ($latte) { $latte->setTempDirectory(__DIR__ . '/../cache/'); $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../app/views/')); }); Flight::route('/', function () { Flight::view()->render('home.latte', ['title' => 'Мій блог']); }); Flight::start();
-
Створіть шаблон макету: У
app/views/layout.latte
:<!DOCTYPE html> <html> <head> <title>{$title}</title> </head> <body> <header> <h1>Мій блог</h1> <nav> <a href="/">Головна</a> | <a href="/create">Створити допис</a> </nav> </header> <main> {block content}{/block} </main> <footer> <p>© {date('Y')} Блог Flight</p> </footer> </body> </html>
-
Створіть домашній шаблон: У
app/views/home.latte
:{extends 'layout.latte'} {block content} <h2>{$title}</h2> <ul> {foreach $posts as $post} <li><a href="/post/{$post['slug']}">{$post['title']}</a></li> {/foreach} </ul> {/block}
Перезапустіть сервер, якщо ви вийшли з нього, та відвідайте
http://localhost:8000
, щоб побачити відображену сторінку. -
Створіть файл даних:
Використовуйте JSON-файл, щоб імітувати базу даних для спрощення.
У
data/posts.json
:[ { "slug": "first-post", "title": "Мій перший допис", "content": "Це мій перший допис у блозі з Flight PHP!" } ]
Крок 4: Визначте маршрути
Розділіть ваші маршрути на файл конфігурації для кращої організації.
-
Створіть
routes.php
: Уapp/config/routes.php
:<?php Flight::route('/', function () { Flight::view()->render('home.latte', ['title' => 'Мій блог']); }); Flight::route('/post/@slug', function ($slug) { Flight::view()->render('post.latte', ['title' => 'Допис: ' . $slug, 'slug' => $slug]); }); Flight::route('GET /create', function () { Flight::view()->render('create.latte', ['title' => 'Створити допис']); });
-
Оновіть
index.php
: Додайте файл маршрутів:<?php require '../vendor/autoload.php'; use Latte\Engine; Flight::register('view', Engine::class, [], function ($latte) { $latte->setTempDirectory(__DIR__ . '/../cache/'); $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../app/views/')); }); require '../app/config/routes.php'; Flight::start();
Крок 5: Зберігайте та отримуйте дописи блогу
Додайте методи для завантаження і збереження дописів.
-
Додайте методи дописів: У
index.php
додайте метод для завантаження дописів:Flight::map('posts', function () { $file = __DIR__ . '/../data/posts.json'; return json_decode(file_get_contents($file), true); });
-
Оновіть маршрути: Змініть
app/config/routes.php
, щоб використовувати дописи:<?php Flight::route('/', function () { $posts = Flight::posts(); Flight::view()->render('home.latte', [ 'title' => 'Мій блог', 'posts' => $posts ]); }); Flight::route('/post/@slug', function ($slug) { $posts = Flight::posts(); $post = array_filter($posts, fn($p) => $p['slug'] === $slug); $post = reset($post) ?: null; if (!$post) { Flight::notFound(); return; } Flight::view()->render('post.latte', [ 'title' => $post['title'], 'post' => $post ]); }); Flight::route('GET /create', function () { Flight::view()->render('create.latte', ['title' => 'Створити допис']); });
Крок 6: Створіть шаблони
Оновіть ваші шаблони, щоб відображати дописи.
-
Сторінка допису (
app/views/post.latte
):{extends 'layout.latte'} {block content} <h2>{$post['title']}</h2> <div class="post-content"> <p>{$post['content']}</p> </div> {/block}
Крок 7: Додайте створення дописів
Обробіть подання форми для додавання нових дописів.
-
Створіть форму (
app/views/create.latte
):{extends 'layout.latte'} {block content} <h2>{$title}</h2> <form method="POST" action="/create"> <div class="form-group"> <label for="title">Назва:</label> <input type="text" name="title" id="title" required> </div> <div class="form-group"> <label for="content">Зміст:</label> <textarea name="content" id="content" required></textarea> </div> <button type="submit">Зберегти допис</button> </form> {/block}
-
Додайте POST-маршрут: У
app/config/routes.php
:Flight::route('POST /create', function () { $request = Flight::request(); $title = $request->data['title']; $content = $request->data['content']; $slug = strtolower(str_replace(' ', '-', $title)); $posts = Flight::posts(); $posts[] = ['slug' => $slug, 'title' => $title, 'content' => $content]; file_put_contents(__DIR__ . '/../../data/posts.json', json_encode($posts, JSON_PRETTY_PRINT)); Flight::redirect('/'); });
-
Перевірте це:
- Відвідайте
http://localhost:8000/create
. - Надішліть новий допис (наприклад, "Другий допис" з деяким змістом).
- Перевірте головну сторінку, щоб побачити його в списку.
- Відвідайте
Крок 8: Поліпшіть обробку помилок
Перевизначте метод notFound
для покращеного досвіду 404.
У index.php
:
Flight::map('notFound', function () {
Flight::view()->render('404.latte', ['title' => 'Сторінка не знайдена']);
});
Створіть app/views/404.latte
:
{extends 'layout.latte'}
{block content}
<h2>404 - {$title}</h2>
<p>Вибачте, така сторінка не існує!</p>
{/block}
Наступні кроки
- Додайте стилі: Використовуйте CSS у ваших шаблонах для кращого вигляду.
- База даних: Замість
posts.json
використовуйте базу даних, наприклад, SQLite за допомогоюPdoWrapper
. - Валідність: Додайте перевірки на наявність дублікатів слугів або порожніх полів.
- Проміжне програмне забезпечення: Реалізуйте автентифікацію для створення дописів.
Висновок
Ви побудували простий блог з Flight PHP! Цей посібник демонструє основні функції, такі як маршрутизація, шаблонізація з Latte та обробка подань форм, зберігаючи все легким. Досліджуйте документацію Flight для вивчення більш розвинених функцій, щоб підвищити ваш блог!
License
Ліцензія MIT (MIT)
Авторське право © 2024
@mikecao, @n0nag0n
Цим надається дозвіл, безкоштовно, будь-якій особі, яка отримала копію цього програмного забезпечення та супутньої документації файлів (далі — “Програмне забезпечення”), користуватися Програмним забезпеченням без обмежень, включаючи без обмежень права на використання, копіювання, модифікацію, об’єднання, публікацію, розповсюдження, підліцензування та/або продаж копій Програмного забезпечення, а також дозволяти особам, яким Програмне забезпечення надано, робити це, за умов дотримання наступних умов:
Вищезазначене повідомлення про авторські права та це повідомлення про дозвіл повинні бути включені в усі копії або значні частини Програмного забезпечення.
ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ НАДАЄТЬСЯ “ЯК Є”, БЕЗ ГАРАНТІЙ БУДЬ-ЯКОГО РОДУ, ЯВНИХ АБО ПРИХОВАНИХ, ВКЛЮЧАЮЧИ, АЛЕ НЕ ОБМЕЖУЮЧИСЬ ГАРАНТІЯМИ КОМЕРЦІЙНОЇ РІЗНИЧКИ, ПРИДАТНОСТІ ДЛЯ ПЕВНОЇ МЕТИ ТА НЕПORУШЕННЯ. У ЖОДНОМУ ВИПАДКУ АВТОРИ АБО ВЛАСНИКИ АВТОРСЬКИХ ПРАВ НЕ НЕСУТЬ ВІДПОВІДАЛЬНОСТІ ЗА БУДЬ-ЯКІ ПРЕТЕНЗІЇ, ЗБИТКИ АБО ІНШІ ЗОБОВ'ЯЗАННЯ, ЧИ У ПРАВОВІЙ СПРАВІ, ДЕЛІКТІ АБО ІНШОМУ, ЩО ВИНИКЛО, ВИРІСШЕ З, АБО У ЗВ'ЯЗКУ З ПРОГРАМНИМ ЗАБЕЗПЕЧЕННЯМ АБО ВИКОРИСТАННЯМ АБО ІНШИМИ УГОДАМИ У ПРОГРАМНОМУ ЗАБЕЗПЕЧЕННІ.
About
Що таке Flight?
Flight – це швидкий, простий, розширювальний фреймворк для PHP. Він досить універсальний і може бути використаний для створення будь-якого виду веб-додатків. Він побудований з урахуванням простоти і написаний так, щоб його було легко зрозуміти та використовувати.
Flight – це чудовий фреймворк для початківців, які нові у PHP і хочуть навчитися створювати веб-додатки. Це також чудовий фреймворк для досвідчених розробників, які хочуть мати більше контролю над своїми веб-додатками. Він спроектований для легкого створення RESTful API, простого веб-додатка або складного веб-додатка.
Швидкий старт
Перш ніж його встановити, використовуючи Composer
composer require flightphp/core
або ви можете завантажити zip-архів репозиторію тут. Тоді у вас буде базовий файл index.php
, схожий на наступний:
<?php
// якщо встановлено за допомогою composer
require 'vendor/autoload.php';
// або якщо встановлено вручну за допомогою zip-файлу
// require 'flight/Flight.php';
Flight::route('/', function() {
echo 'привіт, світ!';
});
Flight::route('/json', function() {
Flight::json(['привіт' => 'світ']);
});
Flight::start();
Ось і все! У вас є базовий додаток Flight. Тепер ви можете запустити цей файл за допомогою php -S localhost:8000
і відвідати http://localhost:8000
у вашому браузері, щоб побачити результат.
Чи швидкий він?
Так! Flight швидкий. Він є одним з найбільш швидких фреймворків PHP. Ви можете побачити всі бенчмарки на TechEmpower
Дивіться бенчмарк нижче з деякими іншими популярними фреймворками PHP.
Фреймворк | Plaintext Reqs/sec | JSON Reqs/sec |
---|---|---|
Flight | 190,421 | 182,491 |
Yii | 145,749 | 131,434 |
Fat-Free | 139,238 | 133,952 |
Slim | 89,588 | 87,348 |
Phalcon | 95,911 | 87,675 |
Symfony | 65,053 | 63,237 |
Lumen | 40,572 | 39,700 |
Laravel | 26,657 | 26,901 |
CodeIgniter | 20,628 | 19,901 |
Скелет/Шаблон додатка
Існує приклад додатка, який може допомогти вам почати працювати з фреймворком Flight. Перейдіть на flightphp/skeleton для отримання інструкцій, як почати! Ви також можете відвідати сторінку прикладів для натхнення щодо деяких речей, які ви можете зробити з Flight.
Спільнота
Ми в Matrix Chat
І в Discord
Участь
Є два способи, якими ви можете внести свій внесок у Flight:
- Ви можете внести свій внесок у основний фреймворк, відвідавши основний репозиторій.
- Ви можете внести свій внесок у документацію. Цей веб-сайт документації розміщено на Github. Якщо ви помітите помилку або хочете вдосконалити щось, не соромтеся виправити це та надіслати запит на злиття! Ми намагаємося стежити за речами, але оновлення та переклади мов бажані.
Вимоги
Flight вимагає PHP 7.4 або новішої версії.
Примітка: PHP 7.4 підтримується, оскільки на момент написання (2024) PHP 7.4 є версією за замовчуванням для деяких LTS-дистрибутивів Linux. Примусове переходження на PHP >8 викликало б багато труднощів для цих користувачів. Фреймворк також підтримує PHP >8.
Ліцензія
Flight випущений під ліцензією MIT.
Awesome-plugins/php_cookie
Cookies
overclokk/cookie — це проста бібліотека для керування куки у вашому додатку.
Installation
Встановлення є простим за допомогою composer.
composer require overclokk/cookie
Usage
Використання таке ж просте, як реєстрація нового методу в класі 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');
}
}
}
Awesome-plugins/php_encryption
PHP Шифрування
defuse/php-encryption — це бібліотека, яку можна використовувати для шифрування та дешифрування даних. Запуск і налаштування досить прості, щоб почати шифрування та дешифрування даних. У них є чудовий посібник, який допомагає пояснити основи використання бібліотеки, а також важливі питання безпеки, пов’язані із шифруванням.
Встановлення
Встановлення просте за допомогою composer.
composer require defuse/php-encryption
Налаштування
Потім вам потрібно згенерувати ключ шифрування.
vendor/bin/generate-defuse-key
Це видасть ключ, який вам потрібно зберегти в безпеці. Ви можете зберегти ключ у вашому 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;
});
Awesome-plugins/php_file_cache
flightphp/cache
Легка, проста та автономна клас кешування PHP в файлі
Переваги
- Легка, автономна та проста
- Увесь код в одному файлі - без марних драйверів.
- Безпечна - кожен згенерований кеш-файл має php заголовок з die, що робить прямий доступ неможливим, навіть якщо хтось знає шлях, а ваш сервер не налаштований належним чином
- Добре задокументована та протестована
- Коректно обробляє конкуренцію через flock
- Підтримує PHP 7.4+
- Безкоштовна за ліцензією MIT
Цей сайт документації використовує цю бібліотеку для кешування кожної зі сторінок!
Натисніть тут, щоб переглянути код.
Встановлення
Встановіть через composer:
composer require flightphp/cache
Використання
Використання досить просте. Це зберігає кеш-файл в каталозі кешу.
use flight\Cache;
$app = Flight::app();
// Ви передаєте каталог, в якому буде зберігатися кеш, у конструктор
$app->register('cache', Cache::class, [ __DIR__ . '/../cache/' ], function(Cache $cache) {
// Це забезпечує використання кешу лише в режимі виробництва
// ENVIRONMENT - це константа, яка встановлюється у вашому файлі завантаження або в іншому місці вашого додатку
$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/flightphp/cache, щоб отримати повну документацію, і обов'язково подивіться на папку прикладів.
Awesome-plugins/permissions
FlightPHP/Permissions
Це модуль дозволів, який можна використовувати у ваших проектах, якщо у вас є кілька ролей у вашому додатку, і кожна роль має трохи відмінну функціональність. Цей модуль дозволяє вам визначити дозволи для кожної ролі, а потім перевірити, чи має поточний користувач дозвіл на доступ до певної сторінки або виконання певної дії.
Клікніть тут, щоб перейти до репозиторію на GitHub.
Встановлення
Запустіть composer require flightphp/permissions
, і ви на правильному шляху!
Використання
Спочатку вам потрібно налаштувати ваші дозволи, потім ви скажете вашому додатку, що означають ці дозволи. Врешті-решт, ви будете перевіряти ваші дозволи за допомогою $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')
, і це спрацює. Визначити це дуже складно, тому залишайтеся зі мною тут. Вам просто потрібно зробити це:
Створіть клас дозволів, які ви хочете об'єднати разом.
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 - це скільки секунд кешувати це. Залиште це, щоб не використовувати кешування
І вперед!
Awesome-plugins/simple_job_queue
Проста черга завдань
Проста черга завдань - це бібліотека, яка може використовуватися для асинхронної обробки завдань. Її можна використовувати з beanstalkd, MySQL/MariaDB, SQLite і PostgreSQL.
Встановлення
composer require n0nag0n/simple-job-queue
Використання
Щоб це працювало, вам потрібен спосіб додати завдання до черги та спосіб обробляти завдання (робітник). Нижче наведені приклади того, як додати завдання до черги та як обробити завдання.
Додавання до Flight
Додавання цього до Flight є простим і здійснюється за допомогою методу register()
. Нижче наведено приклад того, як додати це до Flight.
<?php
require 'vendor/autoload.php';
// Змініть ['mysql'] на ['beanstalkd'], якщо ви хочете використовувати beanstalkd
Flight::register('queue', n0nag0n\Job_Queue::class, ['mysql'], function($Job_Queue) {
// якщо у вас вже є з'єднання PDO в Flight::db();
$Job_Queue->addQueueConnection(Flight::db());
// або якщо ви використовуєте beanstalkd/Pheanstalk
$pheanstalk = Pheanstalk\Pheanstalk::create('127.0.0.1');
$Job_Queue->addQueueConnection($pheanstalk);
});
Додавання нового завдання
Коли ви додаєте завдання, вам потрібно вказати конвеєр (чергу). Це можна порівняти з каналом у RabbitMQ або трубою в beanstalkd.
<?php
Flight::queue()->selectPipeline('send_important_emails');
Flight::queue()->addJob(json_encode([ 'something' => 'that', 'ends' => 'up', 'a' => 'string' ]));
Запуск робітника
Ось приклад файлу про те, як запустити робітника.
<?php
require 'vendor/autoload.php';
$Job_Queue = new n0nag0n\Job_Queue('mysql');
// З'єднання PDO
$PDO = new PDO('mysql:dbname=testdb;host=127.0.0.1', 'user', 'pass');
$Job_Queue->addQueueConnection($PDO);
// або якщо ви використовуєте beanstalkd/Pheanstalk
$pheanstalk = Pheanstalk\Pheanstalk::create('127.0.0.1');
$Job_Queue->addQueueConnection($pheanstalk);
$Job_Queue->watchPipeline('send_important_emails');
while(true) {
$job = $Job_Queue->getNextJobAndReserve();
// налаштуйте так, як вам краще спати вночі (тільки для черг бази даних, beanstalkd не потребує цієї умови)
if(empty($job)) {
usleep(500000);
continue;
}
echo "Обробка {$job['id']}\n";
$payload = json_decode($job['payload'], true);
try {
$result = doSomethingThatDoesSomething($payload);
if($result === true) {
$Job_Queue->deleteJob($job);
} else {
// це забирає його з готової черги та ставить його в іншу чергу, яку можна буде забрати та "вибити" пізніше.
$Job_Queue->buryJob($job);
}
} catch(Exception $e) {
$Job_Queue->buryJob($job);
}
}
Обробка тривалих процесів із Supervisord
Supervisord - це система контролю процесів, яка забезпечує безперервну роботу ваших робочих процесів. Ось більш детальний посібник із налаштування його з вашим робітником Simple Job Queue:
Встановлення Supervisord
# На Ubuntu/Debian
sudo apt-get install supervisor
# На CentOS/RHEL
sudo yum install supervisor
# На macOS з Homebrew
brew install supervisor
Створення скрипта робітника
Спочатку збережіть код вашого робітника в окремому файлі PHP:
<?php
require 'vendor/autoload.php';
$Job_Queue = new n0nag0n\Job_Queue('mysql');
// З'єднання PDO
$PDO = new PDO('mysql:dbname=your_database;host=127.0.0.1', 'username', 'password');
$Job_Queue->addQueueConnection($PDO);
// Встановіть конвеєр для моніторингу
$Job_Queue->watchPipeline('send_important_emails');
// Лог початку робітника
echo date('Y-m-d H:i:s') . " - Робітник запущений\n";
while(true) {
$job = $Job_Queue->getNextJobAndReserve();
if(empty($job)) {
usleep(500000); // Спати 0,5 секунди
continue;
}
echo date('Y-m-d H:i:s') . " - Обробка завдання {$job['id']}\n";
$payload = json_decode($job['payload'], true);
try {
$result = doSomethingThatDoesSomething($payload);
if($result === true) {
$Job_Queue->deleteJob($job);
echo date('Y-m-d H:i:s') . " - Завдання {$job['id']} успішно завершено\n";
} else {
$Job_Queue->buryJob($job);
echo date('Y-m-d H:i:s') . " - Завдання {$job['id']} не вдалося, закопано\n";
}
} catch(Exception $e) {
$Job_Queue->buryJob($job);
echo date('Y-m-d H:i:s') . " - Виключення при обробці завдання {$job['id']}: {$e->getMessage()}\n";
}
}
Налаштування Supervisord
Створіть файл конфігурації для вашого робітника:
[program:email_worker]
command=php /path/to/worker.php
directory=/path/to/project
autostart=true
autorestart=true
startretries=3
stderr_logfile=/var/log/simple_job_queue_err.log
stdout_logfile=/var/log/simple_job_queue.log
user=www-data
numprocs=2
process_name=%(program_name)s_%(process_num)02d
Основні параметри конфігурації:
command
: Команда для запуску вашого робітникаdirectory
: Робоча папка для робітникаautostart
: Автоматичний запуск при запуску supervisordautorestart
: Автоматичний перезапуск, якщо процес завершуєтьсяstartretries
: Кількість спроб перезапустити, якщо це не вдаєтьсяstderr_logfile
/stdout_logfile
: Місцезнаходження файлів журналуuser
: Системний користувач для запуску процесуnumprocs
: Кількість екземплярів робітника для запускуprocess_name
: Формат іменування для кількох процесів робітників
Управління робітниками за допомогою Supervisorctl
Після створення або модифікації конфігурації:
# Перезавантаження конфігурації супервайзера
sudo supervisorctl reread
sudo supervisorctl update
# Управління конкретними процесами робітників
sudo supervisorctl start email_worker:*
sudo supervisorctl stop email_worker:*
sudo supervisorctl restart email_worker:*
sudo supervisorctl status email_worker:*
Запуск кількох конвеєрів
Для кількох конвеєрів створіть окремі файли робітників і конфігурації:
[program:email_worker]
command=php /path/to/email_worker.php
# ... інші конфігурації ...
[program:notification_worker]
command=php /path/to/notification_worker.php
# ... інші конфігурації ...
Моніторинг та журнали
Перевірте журнали, щоб контролювати активність робітника:
# Перегляд журналів
sudo tail -f /var/log/simple_job_queue.log
# Перевірка статусу
sudo supervisorctl status
Ця настройка забезпечує неперервну роботу ваших робочих процесів, навіть після аварій, перезавантажень сервера або інших проблем, що робить вашу систему черги надійною для виробничих середовищ.
Awesome-plugins/ghost_session
Ghostff/Session
Менеджер сесій PHP (без блокування, флеш, сегмент, шифрування сесій). Використовує PHP open_ssl для необов'язкового шифрування/дешифрування даних сесії. Підтримує File, 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();
});
// Ця перевірка може бути в обмеженій логіці сторінки або обгорнута в посередника.
Flight::route('/some-restricted-page', function() {
$session = Flight::session();
if(!$session->get('is_logged_in')) {
Flight::redirect('/login');
}
// виконайте свою логіку обмеженої сторінки тут
});
// версія посередника
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()
, після того як ви налаштували свої дані сесії.
Flight::route('POST /login', function() {
$session = Flight::session();
// виконайте свою логіку входу тут
// перевірте пароль тощо.
// якщо вхід успішний
$session->set('is_logged_in', true);
$session->set('user', $user);
// щоразу, коли ви записуєте в сесію, ви повинні зафіксувати це навмисно.
$session->commit();
});
Інший спосіб обійти це, коли ви налаштовуєте свою службу сесії, вам потрібно встановити auto_commit
на true
у вашій конфігурації. Це автоматично зафіксує ваші дані сесії після кожного запиту.
$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(); });
, щоб зафіксувати ваші дані сесії після кожного запиту.
Документація
Відвідайте Github Readme для повної документації. Параметри конфігурації добре задокументовані у файлі default_config.php. Код легко зрозуміти, якщо ви хочете ознайомитися з цим пакетом самостійно.
Awesome-plugins/pdo_wrapper
PdoWrapper PDO Helper Class
Flight постачається з допоміжним класом для PDO. Це дозволяє вам легко запитувати вашу базу даних з усією підготовкою/виконанням/fetchAll() заморочкою. Це значно спрощує, як ви можете запитувати вашу базу даних. Кожен рядок результату повертається як клас Colletion Flight, який дозволяє вам отримувати доступ до ваших даних через синтаксис масиву або синтаксис об'єкта.
Реєстрація класу допомоги PDO
// Зареєструйте клас допомоги 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();
});
Awesome-plugins/migrations
Міграції
Міграція для вашого проєкту – це відстеження всіх змін бази даних, пов’язаних з вашим проєктом. byjg/php-migration – це справді корисна основна бібліотека, яка допоможе вам розпочати.
Встановлення
PHP Бібліотека
Якщо ви хочете використовувати тільки PHP бібліотеку у вашому проєкті:
composer require "byjg/migration"
Інтерфейс командного рядка
Інтерфейс командного рядка є самостійним і не вимагає, щоб ви встановлювали його разом із вашим проєктом.
Ви можете встановити його глобально і створити символічне посилання
composer require "byjg/migration-cli"
Будь ласка, відвідайте byjg/migration-cli, щоб отримати більше інформації про Migration CLI.
Підтримувані бази даних
База даних | Драйвер | Строка з’єднання |
---|---|---|
Sqlite | pdo_sqlite | sqlite:///path/to/file |
MySql/MariaDb | pdo_mysql | mysql://username:password@hostname:port/database |
Postgres | pdo_pgsql | pgsql://username:password@hostname:port/database |
Sql Server | pdo_dblib, pdo_sysbase Linux | dblib://username:password@hostname:port/database |
Sql Server | pdo_sqlsrv Windows | sqlsrv://username:password@hostname:port/database |
Як це працює?
Міграція бази даних використовує ЧИСТИЙ SQL для управління версіонуванням бази даних. Щоб це працювало, вам потрібно:
- Створити SQL скрипти
- Керувати за допомогою командного рядка або API.
SQL Скрипти
Скрипти поділені на три набори скриптів:
- БАЗОВИЙ скрипт містить УСІ sql команди для створення нової бази даних;
- UP скрипти містять усі sql команди міграції для "підняття" версії бази даних;
- DOWN скрипти містять усі sql команди міграції для "зниження" або повернення версії бази даних;
Директорія зі скриптами виглядає так:
<root dir>
|
+-- base.sql
|
+-- /migrations
|
+-- /up
|
+-- 00001.sql
+-- 00002.sql
+-- /down
|
+-- 00000.sql
+-- 00001.sql
- "base.sql" – це базовий скрипт
- Папка "up" містить скрипти для підняття версії. Наприклад: 00002.sql – це скрипт для переходу бази даних з версії '1' на '2'.
- Папка "down" містить скрипти для зниження версії. Наприклад: 00001.sql – це скрипт для повернення бази даних з версії '2' на '1'. Папка "down" є необов'язковою.
Багаторазове середовище розробки
Якщо ви працюєте з кількома розробниками та кількома гілками, важко визначити, яке наступне число.
У цьому випадку ви можете додати суфікс "-dev" після номера версії.
Погляньте на сценарій:
- Розробник 1 створює гілку, а найновіша версія, наприклад, 42.
- Розробник 2 одночасно створює гілку і має те саме число версії бази даних.
У обох випадках розробники створять файл під назвою 43-dev.sql. Обидва розробники зможуть мігрувати UP і DOWN без проблем, а ваша локальна версія буде 43.
Але розробник 1 об'єднав свої зміни і створив фінальну версію 43.sql (git mv 43-dev.sql 43.sql
). Якщо розробник 2 оновить вашу локальну гілку, він отримає файл 43.sql (від розробника 1) і ваш файл 43-dev.sql.
Якщо він спробує мігрувати UP або DOWN, скрипт міграції повідомить про помилку і сповістить його про те, що існує ДВІ версії 43. У такому випадку розробник 2 повинен оновити свій файл на 44-dev.sql і продовжити працювати, поки не об’єднає свої зміни і не створить фінальну версію.
Використання PHP API та інтеграція його у ваші проєкти
Основне використання:
- Створити з'єднання з об'єктом ConnectionManagement. Для отримання додаткової інформації див. компонент "byjg/anydataset"
- Створити об'єкт Migration з цим з’єднанням та папкою, в якій знаходяться sql скрипти.
- Використати відповідну команду для "скидання", "підняття" або "зниження" скриптів міграцій.
Дивіться приклад:
<?php
// Створіть URI з'єднання
// Дивіться більше: https://github.com/byjg/anydataset#connection-based-on-uri
$connectionUri = new \ByJG\Util\Uri('mysql://migrateuser:migratepwd@localhost/migratedatabase');
// Зареєструйте базу даних або бази даних, які можуть обробляти цей URI:
\ByJG\DbMigration\Migration::registerDatabase(\ByJG\DbMigration\Database\MySqlDatabase::class);
// Створіть екземпляр Migration
$migration = new \ByJG\DbMigration\Migration($connectionUri, '.');
// Додайте функцію зворотного виклику для отримання інформації про виконання
$migration->addCallbackProgress(function ($action, $currentVersion, $fileInfo) {
echo "$action, $currentVersion, ${fileInfo['description']}\n";
});
// Відновіть базу даних за допомогою скрипта "base.sql"
// і виконайте УСІ існуючі скрипти, щоб підняти версію бази даних до останньої
$migration->reset();
// Виконайте УСІ існуючі скрипти для підняття чи зниження версії бази даних
// з поточної версії до номера $version;
// Якщо номер версії не вказано, мігруйте до останньої версії бази даних
$migration->update($version = null);
Об'єкт Migration контролює версію бази даних.
Створення контролю версій у вашому проєкті
<?php
// Зареєструйте базу даних або бази даних, які можуть обробляти цей URI:
\ByJG\DbMigration\Migration::registerDatabase(\ByJG\DbMigration\Database\MySqlDatabase::class);
// Створіть екземпляр Migration
$migration = new \ByJG\DbMigration\Migration($connectionUri, '.');
// Ця команда створить таблицю версій у вашій базі даних
$migration->createVersion();
Отримання поточної версії
<?php
$migration->getCurrentVersion();
Додати зворотний виклик для контролю прогресу
<?php
$migration->addCallbackProgress(function ($command, $version, $fileInfo) {
echo "Виконання команди: $command на версії $version - ${fileInfo['description']}, ${fileInfo['exists']}, ${fileInfo['file']}, ${fileInfo['checksum']}\n";
});
Отримання екземпляра драйвера бази даних
<?php
$migration->getDbDriver();
Щоб використовувати це, будь ласка, відвідайте: https://github.com/byjg/anydataset-db
Уникнення часткової міграції (не доступно для MySQL)
Часткова міграція – це коли скрипт міграції переривається посеред процесу через помилку або ручну переривання.
Таблиця міграції буде мати статус partial up
або partial down
, і її потрібно буде виправити вручну, перш ніж можна буде мігрувати знову.
Щоб уникнути цієї ситуації, ви можете вказати, що міграція буде виконуватись у транзакційному контексті. Якщо скрипт міграції не вдасться, транзакція буде скасована, а таблиця міграції буде позначена як complete
, і версія буде одразу попередньою версією до скрипта, який спричинив помилку.
Щоб увімкнути цю функцію, вам потрібно викликати метод withTransactionEnabled
, передавши true
як параметр:
<?php
$migration->withTransactionEnabled(true);
ПРИМІТКА: Ця функція недоступна для MySQL, оскільки він не підтримує DDL команди всередині транзакції. Якщо ви використовуєте цей метод з MySQL, Migration проігнорує його тихо. Більше інформації: https://dev.mysql.com/doc/refman/8.0/en/cannot-roll-back.html
Поради щодо написання SQL міграцій для Postgres
При створенні тригерів і SQL-функцій
-- DO
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
-- Перевірте, що ім'я працівника та зарплата вказані
IF NEW.empname IS NULL THEN
RAISE EXCEPTION 'empname не може бути null'; -- не має значення, якщо ці коментарі пусті
END IF; --
IF NEW.salary IS NULL THEN
RAISE EXCEPTION '% не може мати null зарплату', NEW.empname; --
END IF; --
-- Хто працює на нас, коли вони повинні це оплачувати?
IF NEW.salary < 0 THEN
RAISE EXCEPTION '% не може мати негативну зарплату', NEW.empname; --
END IF; --
-- Запам'ятайте, хто змінив платіж від коли
NEW.last_date := current_timestamp; --
NEW.last_user := current_user; --
RETURN NEW; --
END; --
$emp_stamp$ LANGUAGE plpgsql;
-- DON'T
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
-- Перевірте, що ім'я працівника та зарплата вказані
IF NEW.empname IS NULL THEN
RAISE EXCEPTION 'empname не може бути null';
END IF;
IF NEW.salary IS NULL THEN
RAISE EXCEPTION '% не може мати null зарплату', NEW.empname;
END IF;
-- Хто працює на нас, коли вони повинні це оплачувати?
IF NEW.salary < 0 THEN
RAISE EXCEPTION '% не може мати негативну зарплату', NEW.empname;
END IF;
-- Запам'ятайте, хто змінив платіж від коли
NEW.last_date := current_timestamp;
NEW.last_user := current_user;
RETURN NEW;
END;
$emp_stamp$ LANGUAGE plpgsql;
Оскільки абстрактний рівень бази даних PDO
не може виконувати партії SQL заявок, коли byjg/migration
читає файл міграції, він повинен розділити весь вміст SQL файлу на частини за крапками з коми та виконати заяви одну за одною. Однак є один вид заяви, який може містити кілька крапок з коми між його тілом: функції.
Щоб мати можливість правильно парсити функції, byjg/migration
2.1.0 почав розділяти файли міграцій за послідовністю semicolon + EOL
замість лише за крапкою з комою. Таким чином, якщо ви додасте пустий коментар після кожної внутрішньої крапки з комою у визначенні функції, byjg/migration
зможе їх правильно розпізнати.
На жаль, якщо ви забудете додати будь-який з цих коментарів, бібліотека розділить заяву CREATE FUNCTION
на кілька частин, і міграція завершиться невдачею.
Уникнення символа двокрапки (:
)
-- DO
CREATE TABLE bookings (
booking_id UUID PRIMARY KEY,
booked_at TIMESTAMPTZ NOT NULL CHECK (CAST(booked_at AS DATE) <= check_in),
check_in DATE NOT NULL
);
-- DON'T
CREATE TABLE bookings (
booking_id UUID PRIMARY KEY,
booked_at TIMESTAMPTZ NOT NULL CHECK (booked_at::DATE <= check_in),
check_in DATE NOT NULL
);
Оскільки PDO
використовує символ двокрапки для префікса названих параметрів у підготовлених запитах, його використання призведе до помилки в інших контекстах.
Наприклад, заяви PostgreSQL можуть використовувати ::
для приведення значень між типами. З іншого боку, PDO
прочитає це як недійсний названий параметр в недійсному контексті і завершить спробу його виконання з помилкою.
Єдиний спосіб виправити цю невідповідність – це уникати двокрапок взагалі (у цьому випадку PostgreSQL також має альтернативний синтаксис: CAST(value AS type)
).
Використовуйте SQL редактор
Нарешті, написання ручних SQL міграцій може бути виснажливим, але це набагато простіше, якщо ви використовуєте редактор, здатний розуміти синтаксис SQL, надавати автозаповнення, досліджувати вашу поточну схему бази даних та/або автоматично форматувати ваш код.
Обробка різних міграцій всередині однієї схеми
Якщо вам потрібно створити різні скрипти міграцій та версії в одній схемі, це можливо, але надто ризиковано, і я не рекомендую цього зовсім.
Для цього вам потрібно створити різні "таблиці міграцій", передаючи параметр конструктору.
<?php
$migration = new \ByJG\DbMigration\Migration("db:/uri", "/path", true, "NEW_MIGRATION_TABLE_NAME");
З міркувань безпеки ця функція недоступна з командного рядка, але ви можете використовувати змінну середовища MIGRATION_VERSION
, щоб зберегти ім'я.
Ми справді рекомендуємо не використовувати цю функцію. Рекомендація – одна міграція для однієї схеми.
Запуск юніт-тестів
Основні юніт-тести можна запускати за допомогою:
vendor/bin/phpunit
Запуск тестів бази даних
Запуск інтеграційних тестів вимагає, щоб бази даних були запущені. Ми надали базовий docker-compose.yml
, який ви можете використовувати для запуску баз даних для тестування.
Запуск баз даних
docker-compose up -d postgres mysql mssql
Запуск тестів
vendor/bin/phpunit
vendor/bin/phpunit tests/SqliteDatabase*
vendor/bin/phpunit tests/MysqlDatabase*
vendor/bin/phpunit tests/PostgresDatabase*
vendor/bin/phpunit tests/SqlServerDblibDatabase*
vendor/bin/phpunit tests/SqlServerSqlsrvDatabase*
Опціонально, ви можете встановити хост і пароль, які використовуються юніт-тестами
export MYSQL_TEST_HOST=localhost # за замовчуванням localhost
export MYSQL_PASSWORD=newpassword # використовуйте '.' якщо хочете мати порожній пароль
export PSQL_TEST_HOST=localhost # за замовчуванням localhost
export PSQL_PASSWORD=newpassword # використовуйте '.' якщо хочете мати порожній пароль
export MSSQL_TEST_HOST=localhost # за замовчуванням localhost
export MSSQL_PASSWORD=Pa55word
export SQLITE_TEST_HOST=/tmp/test.db # за замовчуванням /tmp/test.db
Awesome-plugins/session
FlightPHP Сесія - Легкий обробник сесій на основі файлів
Це легкий плагін для обробки сесій на основі файлів для Flight PHP Framework. Він надає просте, але потужне рішення для управління сесіями, з такими функціями, як неблокуючі читання сесій, необов'язкова шифрування, функціональність автозбереження та режим тестування для розробки. Дані сесії зберігаються у файлах, що робить його ідеальним для додатків, які не потребують бази даних.
Якщо ви хочете використовувати базу даних, ознайомтеся з плагіном ghostff/session, який має багато з цих самих функцій, але з бекендом бази даних.
Відвідайте репозиторій Github для повного вихідного коду та деталей.
Встановлення
Встановіть плагін через Composer:
composer require flightphp/session
Основне використання
Ось простий приклад того, як використовувати плагін flightphp/session
у вашому додатку Flight:
require 'vendor/autoload.php';
use flight\Session;
$app = Flight::app();
// Зареєструйте сервіс сесій
$app->register('session', Session::class);
// Приклад маршруту з використанням сесії
Flight::route('/login', function() {
$session = Flight::session();
$session->set('user_id', 123);
$session->set('username', 'johndoe');
$session->set('is_admin', false);
echo $session->get('username'); // Виводить: johndoe
echo $session->get('preferences', 'default_theme'); // Виводить: default_theme
if ($session->get('user_id')) {
Flight::json(['message' => 'Користувач увійшов в систему!', 'user_id' => $session->get('user_id')]);
}
});
Flight::route('/logout', function() {
$session = Flight::session();
$session->clear(); // Очистити всі дані сесії
Flight::json(['message' => 'Вихід виконано успішно']);
});
Flight::start();
Ключові моменти
- Неблокуючий: Використовує
read_and_close
для початку сесії за замовчуванням, запобігаючи проблемам з блокуванням сесій. - Автозбереження: Увімкнено за замовчуванням, тому зміни зберігаються автоматично при завершенні роботи, якщо не вимкнено.
- Зберігання файлів: Сесії зберігаються в системній папці для тимчасових файлів за замовчуванням у
/flight_sessions
.
Налаштування
Ви можете налаштувати обробник сесій, передаючи масив параметрів при реєстрації:
$app->register('session', Session::class, [
'save_path' => '/custom/path/to/sessions', // Директорія для файлів сесій
'encryption_key' => 'a-secure-32-byte-key-here', // Увімкнути шифрування (рекомендовано 32 байти для AES-256-CBC)
'auto_commit' => false, // Вимкнути автозбереження для ручного контролю
'start_session' => true, // Автоматично розпочати сесію (за замовчуванням: так)
'test_mode' => false // Увімкнути тестовий режим для розробки
]);
Параметри конфігурації
Параметр | Опис | Значення за замовчуванням |
---|---|---|
save_path |
Директорія, де зберігаються файли сесій | sys_get_temp_dir() . '/flight_sessions' |
encryption_key |
Ключ для шифрування AES-256-CBC (необов'язковий) | null (без шифрування) |
auto_commit |
Авто-збереження даних сесії при завершенні роботи | true |
start_session |
Автоматично розпочати сесію | true |
test_mode |
Запустити в тестовому режимі, не впливаючи на PHP сесії | false |
test_session_id |
Користувацький ID сесії для тестового режиму (необов'язковий) | Генерується випадково, якщо не задано |
Розширене використання
Ручне збереження
Якщо ви вимкнули автозбереження, вам потрібно вручну зафіксувати зміни:
$app->register('session', Session::class, ['auto_commit' => false]);
Flight::route('/update', function() {
$session = Flight::session();
$session->set('key', 'value');
$session->commit(); // Явно зберегти зміни
});
Безпека сесії з шифруванням
Увімкніть шифрування для чутливих даних:
$app->register('session', Session::class, [
'encryption_key' => 'your-32-byte-secret-key-here'
]);
Flight::route('/secure', function() {
$session = Flight::session();
$session->set('credit_card', '4111-1111-1111-1111'); // Автоматично зашифровано
echo $session->get('credit_card'); // Дешифровано під час отримання
});
Регенація сесії
Регеніруйте ID сесії для безпеки (наприклад, після входу в систему):
Flight::route('/post-login', function() {
$session = Flight::session();
$session->regenerate(); // Новий ID, зберегти дані
// АБО
$session->regenerate(true); // Новий ID, вилучити старі дані
});
Приклад Middleware
Захистіть маршрути за допомогою аутентифікації на основі сесій:
Flight::route('/admin', function() {
Flight::json(['message' => 'Ласкаво просимо до панелі адміністрування']);
})->addMiddleware(function() {
$session = Flight::session();
if (!$session->get('is_admin')) {
Flight::halt(403, 'Доступ заборонено');
}
});
Це лише простий приклад того, як використовувати це в middleware. Для більш детального прикладу див. документацію middleware.
Методи
Клас Session
надає ці методи:
set(string $key, $value)
: Зберігає значення в сесії.get(string $key, $default = null)
: Отримує значення з необов'язковим значенням за замовчуванням, якщо ключ не існує.delete(string $key)
: Видаляє певний ключ із сесії.clear()
: Видаляє всі дані сесії.commit()
: Зберігає поточні дані сесії у файловій системі.id()
: Повертає поточний ID сесії.regenerate(bool $deleteOld = false)
: Регенірує ID сесії, при потребі видаляючи старі дані.
Усі методи, крім get()
і id()
, повертають екземпляр Session
для ланцюгового виклику.
Чому варто використовувати цей плагін?
- Легкий: Без зовнішніх залежностей — лише файли.
- Неблокуючий: Уникає блокування сесій з
read_and_close
за замовчуванням. - Безпечно: Підтримує шифрування AES-256-CBC для чутливих даних.
- Гнучкий: Опції автозбереження, тестовий режим і ручний контроль.
- Flight-Native: Побудований спеціально для фреймворку Flight.
Технічні деталі
- Формат зберігання: Файли сесій мають префікс
sess_
і зберігаються в сконфігурованійsave_path
. Зашифровані дані використовують префіксE
, текстові —P
. - Шифрування: Використовує AES-256-CBC з випадковим IV для кожного запису сесії, коли надано
encryption_key
. - Сміттєзвалище: Реалізує
SessionHandlerInterface::gc()
PHP для очищення термінових сесій.
Консультування
Внесення змін віталося! Форкніть репозиторій, внесіть свої зміни та надішліть запит на злиття. Повідомляйте про помилки або пропонуйте функції через трекер проблем Github.
Ліцензія
Цей плагін ліцензований під ліцензією MIT. Дивіться репозиторій Github для деталей.
Awesome-plugins/runway
Розгін
Розгін - це CLI-додаток, який допомагає вам керувати вашими застосунками Flight. Він може генерувати контролери, відображати всі маршрути та багато іншого. Він базується на відмінній бібліотеці adhocore/php-cli.
Натисніть тут, щоб переглянути код.
Встановлення
Встановіть за допомогою composer.
composer require flightphp/runway
Основна конфігурація
Перший раз, коли ви запустите Розгін, він проведе вас через процес налаштування і створить файл конфігурації .runway.json
у корені вашого проєкту. Цей файл міститиме необхідні конфігурації для коректної роботи Розгону.
Використання
Розгін має кілька команд, які ви можете використовувати для керування вашим застосунком Flight. Є два простих способи використовувати Розгін.
- Якщо ви використовуєте скелетний проєкт, ви можете запустити
php runway [command]
з кореня вашого проєкту. - Якщо ви використовуєте Розгін як пакет, встановлений через composer, ви можете запустити
vendor/bin/runway [command]
з кореня вашого проєкту.
Для будь-якої команди ви можете передати прапор --help
, щоб отримати більше інформації про те, як використовувати команду.
php runway routes --help
Ось кілька прикладів:
Генерація контролера
На основі конфігурації у вашому файлі .runway.json
, за замовчуванням буде згенеровано контролер у каталозі app/controllers/
.
php runway make:controller MyController
Генерація моделі Active Record
На основі конфігурації у вашому файлі .runway.json
, за замовчуванням буде згенеровано контролер у каталозі app/records/
.
php runway make:record users
Якщо, наприклад, у вас є таблиця users
з наступною схемою: id
, name
, 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/
для вашого проєкту/пакету.
Щоб створити команду, вам просто потрібно розширити клас 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!
Awesome-plugins/tracy_extensions
Tracy Flight Panel Extensions
Це набір розширень, щоб зробити роботу з Flight трохи більш насиченою.
- Flight - Аналізувати всі змінні Flight.
- Database - Аналізувати всі запити, що виконалися на сторінці (якщо ви правильно ініціювали з'єднання з базою даних)
- Request - Аналізувати всі змінні
$_SERVER
та перевіряти всі глобальні дані ($_GET
,$_POST
,$_FILES
) - Session - Аналізувати всі змінні
$_SESSION
, якщо сесії активно використовуються.
Це панель
І кожна панель показує дуже корисну інформацію про вашу програму!
Натисніть тут, щоб переглянути код.
Installation
Запустіть composer require flightphp/tracy-extensions --dev
і ви на правильному шляху!
Configuration
Є дуже небагато конфігурацій, які вам потрібно зробити, щоб це запрацювало. Вам потрібно ініціювати відладчик 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
.
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 для аналізу ваших шаблонів. Ви можете передати екземпляр Latte до конструктора TracyExtensionLoader
з ключем 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());
}
Awesome-plugins/tracy
Tracy
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)
- Це відобразить змінну в панелі Tracy в окремій секції.dumpe($var)
- Це відобразить змінну, а потім відразу зупинить виконання.
Awesome-plugins/active_record
Flight Active Record
Активний запис - це відображення сутності бази даних на об'єкт PHP. Простими словами, якщо у вас є таблиця користувачів у вашій базі даних, ви можете "перекласти" рядок у цій таблиці в клас 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 Framework Flight. Цілком на ваш розсуд.
Окремо
Просто переконайтеся, що передали з'єднання PDO в конструктор.
$pdo_connection = new PDO('sqlite:test.db'); // це лише для прикладу, ви, ймовірно, будете використовувати реальне з'єднання з базою даних
$User = new User($pdo_connection);
Не хочете завжди встановлювати з'єднання з базою даних у конструкторі? Дивіться Управління з'єднаннями з базою даних для інших ідей!
Зареєструвати як метод у Flight
Якщо ви використовуєте PHP Framework 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
з наступним вмістом:
<?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');
}
}
CRUD функції
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
(v0.4.0)
Повертає 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' ]);
// ви можете також встановити primaryKey таким чином замість масиву вище.
$this->primaryKey = 'uuid';
}
protected function beforeInsert(self $self) {
$self->uuid = uniqid(); // або як вам потрібно генерувати ваші унікальні id
}
}
Якщо ви не встановите первинний ключ перед вставкою, він буде встановлений на 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'; // тепер email вважається "брудним", оскільки він змінився.
$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
(v0.4.0)
Це псевдонім для методу dirty()
. Це трохи ясніше, що ви робите.
$user->copyFrom([ 'name' => 'something', 'password' => password_hash('a different password') ]);
$user->update(); // і ім'я, і пароль оновлюються.
isDirty(): boolean
(v0.4.0)
Повертає 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
(v0.4.1)
Після того, як ви запустите find()
, findAll()
, insert()
, update()
, або save()
метод, ви можете отримати SQL, який був побудований, і використовувати його для налагодження.
Методи SQL Запитів
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-ін'єкцій. Є багато статей в Інтернеті, будь ласка, Google "sql injection attacks php", і ви знайдете багато статей на цю тему. Правильний спосіб обробити це з цією бібліотекою - замість цього методу where()
, ви повинні зробити щось на зразок $user->eq('id', $id)->eq('name', $name)->find();
Якщо вам дійсно потрібно це зробити, бібліотека PDO
має $pdo->quote($var)
, щоб екранізувати його для вас. Тільки після того, як ви використовуєте quote()
, ви можете використовувати це в операторі where()
.
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)
Обмежте кількість повернених записів. Якщо задано другий int, він буде зсувати, обмежуючи так, як у SQL.
$user->orderby('name DESC')->limit(0, 10)->findAll();
Умови WHERE
equal(string $field, mixed $value) / eq(string $field, mixed $value)
Де field = $value
$user->eq('id', 1)->find();
notEqual(string $field, mixed $value) / ne(string $field, mixed $value)
Де field <> $value
$user->ne('id', 1)->find();
isNull(string $field)
Де field IS NULL
$user->isNull('id')->find();
isNotNull(string $field) / notNull(string $field)
Де field IS NOT NULL
$user->isNotNull('id')->find();
greaterThan(string $field, mixed $value) / gt(string $field, mixed $value)
Де field > $value
$user->gt('id', 1)->find();
lessThan(string $field, mixed $value) / lt(string $field, mixed $value)
Де field < $value
$user->lt('id', 1)->find();
greaterThanOrEqual(string $field, mixed $value) / ge(string $field, mixed $value) / gte(string $field, mixed $value)
Де field >= $value
$user->ge('id', 1)->find();
lessThanOrEqual(string $field, mixed $value) / le(string $field, mixed $value) / lte(string $field, mixed $value)
Де field <= $value
$user->le('id', 1)->find();
like(string $field, mixed $value) / notLike(string $field, mixed $value)
Де field LIKE $value
або 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)
$user->in('id', [1, 2])->find();
between(string $field, array $values)
Де field BETWEEN $value AND $value1
$user->between('id', [1, 2])->find();
Умови OR
Можливо обернути ваші умови в оператор OR. Це здійснюється або за допомогою методів startWrap()
та endWrap()
, або заповнюючи третій параметр умови після поля та значення.
// Метод 1
$user->eq('id', 1)->startWrap()->eq('name', 'demo')->or()->eq('name', 'test')->endWrap('OR')->find();
// Це буде оцінено як `id = 1 AND (name = 'demo' OR name = 'test')`
// Метод 2
$user->eq('id', 1)->eq('name', 'demo', 'OR')->find();
// Це буде оцінено як `id = 1 OR name = 'demo'`
Взаємовідносини
Ви можете налаштувати декілька видів взаємовідносин, використовуючи цю бібліотеку. Ви можете налаштувати один->багато та один->один взаємовідносини між таблицями. Це потребує незначної додаткової підготовки у класі заздалегідь.
Налаштування масиву $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()
.
$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()
, але ви можете зробити це для усіх записів!
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).
$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
щоразу, коли ви викликаєте активний запис, існують варіанти!
// 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)
.
Внески
Будь ласка, робіть це. :D
Налаштування
Коли ви будете брати участь, переконайтеся, що ви запустили composer test-coverage
, щоб підтримувати 100% покриття тестами (це не 100% покриття юніт-тестами, а скоріше інтеграційне тестування).
Також переконайтеся, що ви запустили composer beautify
та composer phpcs
, щоб виправити будь-які помилки синтаксису.
Ліцензія
MIT
Awesome-plugins/latte
Latte
Latte — це повнофункціональний шаблонний引擎, який дуже простий у використанні і виглядає ближче до синтаксису PHP, ніж Twig або Smarty. Його також дуже легко розширити та додати власні фільтри та функції.
Встановлення
Встановіть за допомогою composer.
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!
Awesome-plugins/awesome_plugins
Чудові плагіни
Flight надзвичайно розширюваний. Існує кілька плагінів, які можна використовувати для додавання функціональності до вашого додатку Flight. Деякі з них офіційно підтримуються командою Flight, а інші є мікро/легкими бібліотеками, які допоможуть вам розпочати.
Документація API
Документація API має вирішальне значення для будь-якого API. Вона допомагає розробникам зрозуміти, як взаємодіяти з вашим API та чого очікувати у відповідь. Є кілька інструментів, доступних для генерації документації API для ваших проєктів Flight.
- FlightPHP OpenAPI Generator - Пост у блозі, написаний Даніелем Шрайбером про те, як використовувати специфікацію OpenAPI з FlightPHP для побудови вашого API, використовуючи підхід API в першу чергу.
- SwaggerUI - Swagger UI - це чудовий інструмент для генерації документації API для ваших проєктів Flight. Його дуже легко використовувати, і його можна налаштувати відповідно до ваших потреб. Це бібліотека PHP, яка допомагає генерувати документацію Swagger.
Аутентифікація/Авторизація
Аутентифікація та авторизація є критично важливими для будь-якої програми, яка вимагає контролю за тим, хто може отримувати доступ до чого.
- офіційний flightphp/permissions - Офіційна бібліотека дозволів Flight. Ця бібліотека є простим способом додавання дозволів на рівні користувача та програми до вашого застосунку.
Кешування
Кешування - це чудовий спосіб пришвидшити вашу програму. Існує кілька бібліотек кешування, які можна використовувати з Flight.
- офіційний flightphp/cache - Легка, проста і незалежна клас для кешування на PHP.
CLI
CLI-додатки - це чудовий спосіб взаємодіяти з вашим додатком. Ви можете використовувати їх для генерації контролерів, відображення всіх маршрутів тощо.
- офіційний flightphp/runway - Runway - це CLI-додаток, який допомагає вам управляти вашими додатками Flight.
Cookies
Cookies - це чудовий спосіб зберігати невелику кількість даних на стороні клієнта. Їх можна використовувати для зберігання налаштувань користувача, налаштувань програми тощо.
- overclokk/cookie - PHP Cookie - це бібліотека PHP, яка надає простий та ефективний спосіб керування cookie.
Налагодження
Налагодження має вирішальне значення, коли ви розробляєте у своєму локальному середовищі. Є кілька плагінів, які можуть покращити ваш досвід налагодження.
- tracy/tracy - Це повнофункціональний обробник помилок, який можна використовувати з Flight. Він має кілька панелей, які можуть допомогти вам налагодити ваш додаток. Його також дуже легко розширити і додати свої панелі.
- flightphp/tracy-extensions - Використовується разом з обробником помилок Tracy, цей плагін додає кілька додаткових панелей для допомоги в налагодженні конкретно для проєктів Flight.
Бази даних
Бази даних є основою більшості додатків. Ось як ви зберігаєте та отримуєте дані. Деякі бібліотеки бази даних є просто обгортками для написання запитів, а інші є повнофункціональними ORM.
- офіційний flightphp/core PdoWrapper - Офіційна обгортка Flight PDO, яка є частиною ядра. Це проста обгортка, яка допомагає спростити процес написання запитів та їх виконання. Це не є ORM.
- офіційний flightphp/active-record - Офіційний ActiveRecord ORM/Mapper Flight. Чудова маленька бібліотека для легкого отримання та зберігання даних у вашій базі даних.
- byjg/php-migration - Плагін для відстеження всіх змін бази даних для вашого проєкту.
Шифрування
Шифрування має критичне значення для будь-якої програми, яка зберігає чутливі дані. Шифрування та дешифрування даних не є надто складним, але правильне зберігання ключа шифрування може бути важким. Найважливіше - ніколи не зберігайте свій ключ шифрування у публічному каталозі або не комітуйте його в своєму кодовому репозиторії.
- defuse/php-encryption - Це бібліотека, яку можна використовувати для шифрування та дешифрування даних. Розпочати та запустити досить просто, щоб почати шифрування та дешифрування даних.
Черга завдань
Черги завдань дуже корисні для асинхронної обробки завдань. Це може бути відправка електронних листів, обробка зображень або що завгодно, що не потрібно виконувати в реальному часі.
- n0nag0n/simple-job-queue - Simple Job Queue - це бібліотека, яку можна використовувати для обробки завдань асинхронно. Її можна використовувати з beanstalkd, MySQL/MariaDB, SQLite і PostgreSQL.
Сесія
Сесії не є дуже корисними для API, але для створення веб-додатку сесії можуть бути критично важливими для підтримання стану та інформації для входу.
- офіційний flightphp/session - Офіційна бібліотека сесій Flight. Це проста бібліотека сесій, яку можна використовувати для зберігання та отримання даних сесії. Вона використовує вбудовану обробку сесій PHP.
- Ghostff/Session - Менеджер сесій PHP (не блокуючий, спалах, сегмент, шифрування сесій). Використовує PHP open_ssl для необов'язкового шифрування/дешифрування даних сесії.
Шаблонізація
Шаблонізація є основою будь-якого веб-додатку з інтерфейсом. Існує кілька движків шаблонізації, які можна використовувати з Flight.
- застарілий flightphp/core View - Це дуже базовий движок шаблонізації, який є частиною ядра. Його не рекомендується використовувати, якщо у вашому проєкті більше ніж кілька сторінок.
- latte/latte - Latte - це повнофункціональний движок шаблонізації, який дуже легко використовувати і відчуває себе ближче до синтаксису PHP, ніж Twig або Smarty. Його також дуже легко розширити і додати свої фільтри та функції.
Участь
Є плагін, яким ви хочете поділитися? Надішліть запит на злиття, щоб додати його до списку!
Media
Медіа
Ми намагалися знайти все, що можемо, про різні види медіа в Інтернеті навколо Flight. Дивіться нижче різні ресурси, які ви можете використовувати, щоб дізнатися більше про Flight.
Статті та огляди
- Визначення, генерація та реалізація: підхід API-First з OpenAPI Generator та FlightPHP від Данила Шрайбера (2025)
- Найкращі мікрофреймворки PHP для 2024 року від n0nag0n (2024)
- Створення RESTful API з фреймворком Flight від n0nag0n (2024)
- Створення простого блогу з Flight ЧАСТИНА 2 від n0nag0n (2024)
- Створення простого блогу з Flight ЧАСТИНА 1 від n0nag0n (2024)
- 🚀 Створіть простий CRUD API на PHP з фреймворком Flight від soheil-khaledabadi (2024)
- Створення веб-додатку на PHP з мікрофреймворком Flight від Артур К. Кодекс (2023)
- Найкращі фреймворки PHP для веб-розробки у 2024 році від Равікіран А. С. (2023)
- Топ-12 фреймворків PHP: всебічний посібник на 2023 рік від marketing kbk (2023)
- 5 фреймворків PHP, про які ви (напевно) ніколи не чули від n0nag0n (2022)
- 12 найкращих фреймворків PHP для веб-розробників у 2023 році від Анни Монус (2022)
- Найкращі мікрофреймворки PHP на хмарному сервері від Шахзеб Ахмед (2021)
- Фреймворк PHP: Топ-15 потужних для вашої веб-розробки від AHT Tech (2020)
- Легке PHP-маршрутизація з FlightPHP від Лукаса Консейсао (2019)
- Спробування нового фреймворку PHP (Flight) від Леона (2017)
- Налаштування FlightPHP для роботи з Backbonejs від Тимоті Токкі (2015)
Відео та навчальні посібники
- Створіть REST API для IoT приладів за допомогою PHP та FlightPHP - ESP32 API від IoT Craft Hub (2024)
- Просте вступне відео про фреймворк PHP Flight від n0nag0n (2024)
- Встановіть код заголовка HTTP у Flightphp (3 рішення!!) від Роела Ван де Пара (2024)
- Навчальний курс фреймворка Flight PHP. Дуже простий API проект! від n0nag0n (2022)
- Веб-додаток CRUD з PHP, MySQL та Bootstrap за допомогою Flight від Devlopteca - Оскар Ух (2021)
- DevOps та SysAdmins: правило переписування Lighttpd для мікрофреймворку PHP Flight від Роела Ван де Пара (2021)
- Навчальний курс REST API Flight PHP #ЧАСТИНА2 ВСТАВИТИ ТАБЛИЦЮ Інфо #Код (Тагалог) від Info Singkat Official (2020)
- Навчальний курс REST API Flight PHP #ЧАСТИНА1 Інфо #Код (Тагалог) від Info Singkat Official (2020)
- Як створити JSON REST API в PHP - Частина 2 від Codewife (2018)
- Як створити JSON REST API в PHP - Частина 1 від Codewife (2018)
- Тестування мікрофреймворків PHP - Flight PHP, Lumen, Slim 3 і Laravel від Codemarket (2016)
- Навчальний курс 1 Flight PHP - Інсталяція від absagg (2014)
- Навчальний курс 2 Flight PHP - Маршрут частина 1 від absagg (2014)
Examples
Потрібен швидкий старт?
У вас є два варіанти, щоб почати новий проект на Flight:
- Повний скелетний проект: Більш розгорнутий приклад з контролерами та видами.
- Однофайловий скелетний проект: Один файл, який включає все необхідне для запуску вашого додатку в одному простому файлі.
Приклади, надані спільнотою:
- flightravel: FlightPHP з директоріями Laravel, з PHP засобами + GH Actions
- fleact - Стартовий набір для FlightPHP з інтеграцією ReactJS.
- flastro - Стартовий набір для FlightPHP з інтеграцією Astro.
- velt - Velt - це швидкий та простий шаблон для Svelte з бекендом FlightPHP.
Потрібна трохи натхнення?
Хоча ці проекти офіційно не спонсоруються командою Flight, вони можуть дати вам ідеї про те, як структуризувати власні проекти, побудовані на Flight!
- Decay - Flight v3 з HTMX та SleekDB про зомбі! (Демо)
- Приклад блогу на Flight - Flight v3 з Middleware, контролерами, Active Record та Latte.
- Flight CRUD RESTful API - Простий проект CRUD API, що використовує фреймворк Flight, який забезпечує базову структуру для нових користувачів, щоб швидко налаштувати PHP-додаток з операціями CRUD та підключенням до бази даних. Проект демонструє, як використовувати Flight для розробки RESTful API, що робить його ідеальним навчальним засобом для початківців та корисним стартовим набором для більш досвідчених розробників.
- Система управління школою Flight - Flight v3
- Paste Bin з коментарями - Flight v3
- Базовий скелетний додаток
- Приклад Вікі
- Застосунок PHP-фреймворку IT-Innovator
- LittleEducationalCMS (іспанською)
- API жовтих сторінок Італії
- Універсальна система управління контентом (з....дуже малою документацією)
- Маленький php фреймворк на основі Flight та medoo.
- Приклад MVC-додатку
Хочете поділитися власним прикладом?
Якщо у вас є проект, яким ви хочете поділитися, будь ласка, подайте запит на злиття, щоб додати його до цього списку!
Install/install
Встановлення
Завантажте файли
Переконайтесь, що у вас на системі встановлено PHP. Якщо ні, натисніть тут для інструкцій щодо його встановлення.
Якщо ви використовуєте Composer, ви можете виконати наступну команду:
composer require flightphp/core
АБО ви можете завантажити файли безпосередньо та витягти їх у свій веб-директорію.
Налаштуйте свій веб-сервер
Вбудований сервер розробки PHP
Це, безумовно, найпростіший спосіб запустити свій проект. Ви можете використовувати вбудований сервер, щоб запустити своє застосування та навіть використовувати SQLite для бази даних (якщо sqlite3 встановлено на вашій системі) і не вимагати багато чого! Просто виконайте наступну команду після встановлення PHP:
php -S localhost:8000
Потім відкрийте свій браузер і перейдіть на http://localhost:8000
.
Якщо ви хочете зробити корінь документа вашого проекту в іншому каталозі (Наприклад: ваш проект ~/myproject
, але корінь документа ~/myproject/public/
), ви можете виконати наступну команду, як тільки ви в директорії ~/myproject
:
php -S localhost:8000 -t public/
Потім відкрийте свій браузер і перейдіть на http://localhost:8000
.
Apache
Переконайтесь, що Apache вже встановлено на вашій системі. Якщо ні, знайдіть у Google, як встановити Apache на вашій системі.
Для Apache, відредагуйте свій файл .htaccess
наступним чином:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
Примітка: Якщо вам потрібно використовувати flight в підкаталозі, додайте рядок
RewriteBase /subdir/
відразу післяRewriteEngine On
.Примітка: Якщо ви хочете захистити всі серверні файли, такі як db чи env файл. Помістіть це у свій файл
.htaccess
:
RewriteEngine On
RewriteRule ^(.*)$ index.php
Nginx
Переконайтесь, що Nginx вже встановлено на вашій системі. Якщо ні, знайдіть у Google, як встановити Nginx на вашу систему.
Для Nginx, додайте наступне до вашої декларації сервера:
server {
location / {
try_files $uri $uri/ /index.php;
}
}
Створіть свій файл 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.
macOS
Встановлення PHP за допомогою Homebrew
-
Встановіть Homebrew (якщо ще не встановлено):
- Відкрийте Terminal і виконайте:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- Відкрийте Terminal і виконайте:
-
Встановіть PHP:
- Встановіть останню версію:
brew install php
- Щоб встановити конкретну версію, наприклад, PHP 8.1:
brew tap shivammathur/php brew install shivammathur/php/php@8.1
- Встановіть останню версію:
-
Перемикання між версіями PHP:
- Відключіть поточну версію та підключіть бажану версію:
brew unlink php brew link --overwrite --force php@8.1
- Перевірте встановлену версію:
php -v
- Відключіть поточну версію та підключіть бажану версію:
Windows 10/11
Встановлення PHP вручну
-
Завантажте PHP:
- Відвідайте PHP для Windows і завантажте останню або конкретну версію (наприклад, 7.4, 8.0) у вигляді zip-файлу без підтримки потоків.
-
Розпакуйте PHP:
- Розпакуйте завантажений zip-файл до
C:\php
.
- Розпакуйте завантажений zip-файл до
-
Додайте PHP до системної PATH:
- Перейдіть до Системні властивості > Змінні середовища.
- У розділі Системні змінні знайдіть Path і натисніть Редагувати.
- Додайте шлях
C:\php
(або куди ви розпакували PHP). - Натисніть ОК, щоб закрити всі вікна.
-
Налаштуйте PHP:
- Скопіюйте
php.ini-development
уphp.ini
. - Відредагуйте
php.ini
, щоб налаштувати PHP за потреби (наприклад, налаштуванняextension_dir
, увімкнення розширень).
- Скопіюйте
-
Перевірте установку PHP:
- Відкрийте командний рядок і виконайте:
php -v
- Відкрийте командний рядок і виконайте:
Встановлення кількох версій PHP
-
Повторіть вищезазначені кроки для кожної версії, розміщуючи кожну в окремій директорії (наприклад,
C:\php7
,C:\php8
). -
Перемикання між версіями шляхом коригування системної змінної PATH, щоб вказати на директорію бажаної версії.
Ubuntu (20.04, 22.04 тощо)
Встановлення PHP за допомогою apt
-
Оновіть списки пакетів:
- Відкрийте Terminal і виконайте:
sudo apt update
- Відкрийте Terminal і виконайте:
-
Встановіть PHP:
- Встановіть останню версію PHP:
sudo apt install php
- Щоб встановити конкретну версію, наприклад, PHP 8.1:
sudo apt install php8.1
- Встановіть останню версію PHP:
-
Встановлення додаткових модулів (за бажанням):
- Наприклад, щоб встановити підтримку MySQL:
sudo apt install php8.1-mysql
- Наприклад, щоб встановити підтримку MySQL:
-
Перемикання між версіями PHP:
- Використовуйте
update-alternatives
:sudo update-alternatives --set php /usr/bin/php8.1
- Використовуйте
-
Перевірте встановлену версію:
- Виконайте:
php -v
- Виконайте:
Rocky Linux
Встановлення PHP за допомогою yum/dnf
-
Увімкніть репозиторій EPEL:
- Відкрийте Terminal і виконайте:
sudo dnf install epel-release
- Відкрийте Terminal і виконайте:
-
Встановіть репозиторій Remi:
- Виконайте:
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm sudo dnf module reset php
- Виконайте:
-
Встановіть PHP:
- Щоб встановити версію за замовчуванням:
sudo dnf install php
- Щоб встановити конкретну версію, наприклад, PHP 7.4:
sudo dnf module install php:remi-7.4
- Щоб встановити версію за замовчуванням:
-
Перемикання між версіями PHP:
- Використовуйте команду модуля
dnf
:sudo dnf module reset php sudo dnf module enable php:remi-8.0 sudo dnf install php
- Використовуйте команду модуля
-
Перевірте встановлену версію:
- Виконайте:
php -v
- Виконайте:
Загальні нотатки
- Для середовищ розробки важливо налаштувати параметри PHP відповідно до вимог вашого проекту.
- При перемиканні версій PHP переконайтесь, що всі необхідні розширення PHP встановлено для конкретної версії, яку ви плануєте використовувати.
- Перезапустіть свій веб-сервер (Apache, Nginx тощо) після перемикання версій PHP або оновлення конфігурацій для застосування змін.
Guides
Посібники
Flight PHP створений, щоб бути простим, але потужним, а наші посібники допоможуть вам крок за кроком створити реальні додатки. Ці практичні навчальні посібники проведуть вас через повноцінні проекти, щоб продемонструвати, як Flight може бути використаний ефективно.
Офіційні посібники
Створення блогу
Дізнайтеся, як створити функціональний блог-додаток за допомогою Flight PHP. Цей посібник проводить вас через:
- Налаштування структури проекту
- Робота з шаблонами, використовуючи Latte
- Реалізація маршрутів для постів
- Зберігання та відновлення даних
- Обробка подань форм
- Основна обробка помилок
Цей навчальний посібник ідеально підходить для початківців, які хочуть побачити, як усі елементи складаються разом у реальному додатку.
Неофіційні посібники
Хоча ці посібники не підтримуються офіційно командою Flight, вони є цінними ресурсами, створеними спільнотою. Вони охоплюють різні теми та сценарії використання, надаючи додаткові відомості про використання Flight PHP.
Створення RESTful API за допомогою Flight Framework
Цей посібник проводить вас через створення RESTful API, використовуючи фреймворк Flight PHP. Він охоплює основи налаштування API, визначення маршрутів і повернення JSON-відповідей.
Створення простого блогу
Цей посібник проводить вас через створення базового блогу, використовуючи фреймворк Flight PHP. Він насправді має 2 частини: одна охоплює основи, а інша – більш складні теми та вдосконалення для готового до виробництва блогу.
- Створення простого блогу з Flight - Частина 1 - Початок роботи з простим блогом.
- Створення простого блогу з Flight - Частина 2 - Удосконалення блогу для виробництва.
Створення Pokémon API в PHP: Посібник для початківців
Цей веселий посібник проводить вас через створення простого Pokémon API за допомогою Flight PHP. Він охоплює основи налаштування API, визначення маршрутів і повернення JSON-відповідей.
Участь
Є ідея для посібника? Знайшли помилку? Ми вітаємо внески! Наші посібники підтримуються в репозиторії документації FlightPHP.
Якщо ви створили щось цікаве з Flight і хочете поділитися цим як посібником, будь ласка, надішліть запит на злиття. Обмін знаннями допомагає спільноті Flight зростати.
Шукаєте документацію API?
Якщо ви шукаєте конкретну інформацію про основні функції та методи Flight, зверніть увагу на розділ "Learn" у нашій документації.