Відповіді
Огляд
Flight допомагає генерувати частину заголовків відповіді для вас, але ви маєте більший контроль над тим, що ви надсилаєте назад користувачеві. Більшість часу ви звертатиметесь безпосередньо до об'єкта response(), але Flight має деякі допоміжні методи для встановлення деяких заголовків відповіді для вас.
Розуміння
Після того, як користувач надсилає свій запит до вашого додатка, вам потрібно генерувати правильну відповідь для них. Вони надіслали вам інформацію, таку як мова, яку вони віддають перевагу, чи можуть вони обробляти певні типи стиснення, їхній агент користувача тощо, і після обробки всього настав час надіслати їм назад правильну відповідь. Це може бути встановлення заголовків, вивід тіла HTML або JSON для них або перенаправлення їх на сторінку.
Основне використання
Надсилання тіла відповіді
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();
});JSON
Flight надає підтримку для надсилання JSON та JSONP відповідей. Щоб надіслати JSON відповідь, ви передаєте деякі дані для кодування JSON:
Flight::route('/@companyId/users', function(int $companyId) {
    // якось витягніть своїх користувачів з бази даних, наприклад
    $users = Flight::db()->fetchAll("SELECT id, first_name, last_name FROM users WHERE company_id = ?", [ $companyId ]);
    Flight::json($users);
});
// [{"id":1,"first_name":"Bob","last_name":"Jones"}, /* more users */ ]Примітка: За замовчуванням 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);Зміна порядку аргументів JSON
Flight::json() є дуже застарілим методом, але мета Flight — підтримувати зворотну сумісність для проєктів. Насправді це дуже просто, якщо ви хочете переробити порядок аргументів для використання простішого синтаксису, ви можете просто переналаштувати метод JSON як будь-який інший метод Flight:
Flight::map('json', function($data, $code = 200, $options = 0) {
    // тепер вам не потрібно `true, 'utf-8'` при використанні методу json()!
    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 = someAuthorizationCheck();
    // Перевірте, чи авторизований користувач
    if($authorized === false) {
        Flight::jsonHalt(['error' => 'Unauthorized'], 401);
        // немає exit; потрібно тут.
    }
    // Продовжуйте з рештою маршруту
});До v3.10.0 ви б мусили зробити щось на кшталт цього:
Flight::route('/users', function() {
    $authorized = someAuthorizationCheck();
    // Перевірте, чи авторизований користувач
    if($authorized === false) {
        Flight::halt(401, json_encode(['error' => 'Unauthorized']));
    }
    // Продовжуйте з рештою маршруту
});Очищення тіла відповіді
Якщо ви хочете очистити тіло відповіді, ви можете використовувати метод clearBody:
Flight::route('/', function() {
    if($someCondition) {
        Flight::response()->write("Hello, World!");
    } else {
        Flight::response()->clearBody();
    }
});Випадок використання вище, ймовірно, не є поширеним, однак він міг би бути більш поширеним, якщо це використовувалося в middleware.
Виконання зворотного виклику на тілі відповіді
Ви можете виконати зворотний виклик на тілі відповіді, використовуючи метод addResponseBodyCallback:
Flight::route('/users', function() {
    $db = Flight::db();
    $users = $db->fetchAll("SELECT * FROM users");
    Flight::render('users_table', ['users' => $users]);
});
// Це gzip-увиме всі відповіді для будь-якого маршруту
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]);
    // Це gzip-увиме тільки відповідь для цього маршруту
    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() ]);Коди статусу
Ви можете встановити код статусу відповіді, використовуючи метод status:
Flight::route('/@id', function($id) {
    if($id == 123) {
        Flight::response()->status(200);
        echo "Hello, World!";
    } else {
        Flight::response()->status(403);
        echo "Forbidden";
    }
});Якщо ви хочете отримати поточний код статусу, ви можете використовувати метод status без будь-яких аргументів:
Flight::response()->status(); // 200Встановлення заголовка відповіді
Ви можете встановити заголовок, такий як тип вмісту відповіді, використовуючи метод header:
// Це надішле "Hello, World!" до браузера користувача як звичайний текст
Flight::route('/', function() {
    Flight::response()->header('Content-Type', 'text/plain');
    // або
    Flight::response()->setHeader('Content-Type', 'text/plain');
    echo "Hello, World!";
});Перенаправлення
Ви можете перенаправити поточний запит, використовуючи метод redirect() і передаючи новий URL:
Flight::route('/login', function() {
    $username = Flight::request()->data->username;
    $password = Flight::request()->data->password;
    $passwordConfirm = Flight::request()->data->password_confirm;
    if($password !== $passwordConfirm) {
        Flight::redirect('/new/location');
        return; // це необхідно, щоб функціональність нижче не виконувалася
    }
    // додайте нового користувача...
    Flight::db()->runQuery("INSERT INTO users ....");
    Flight::redirect('/admin/dashboard');
});Примітка: За замовчуванням Flight надсилає HTTP 303 ("See Other") код статусу. Ви можете опціонально встановити власний код:
Flight::redirect('/new/location', 301); // постійнийЗупинка виконання маршруту
Ви можете зупинити фреймворк і негайно вийти в будь-якій точці, викликаючи метод halt:
Flight::halt();Ви також можете вказати опціональний HTTP код статусу та повідомлення:
Flight::halt(200, 'Be right back...');Виклик halt відкине будь-який вміст відповіді до цієї точки та зупинить все виконання. Якщо ви хочете зупинити фреймворк і вивести поточну відповідь, використовуйте метод stop:
Flight::stop($httpStatusCode = null);Примітка:
Flight::stop()має деяку дивну поведінку, таку як вивід відповіді, але продовження виконання вашого скрипту, що може не бути тим, чого ви хочете. Ви можете використовуватиexitабоreturnпісля викликуFlight::stop()для запобігання подальшому виконанню, але загалом рекомендується використовуватиFlight::halt().
Це збереже ключ і значення заголовка в об'єкті відповіді. Наприкінці циклу життя запиту він побудує заголовки та надішле відповідь.
Розширене використання
Надсилання заголовка негайно
Можуть бути випадки, коли вам потрібно зробити щось власне з заголовком, і вам потрібно надіслати заголовок на тій самій лінії коду, з якою ви працюєте. Якщо ви встановлюєте потоковий маршрут, це те, що вам знадобиться. Це досягається через response()->setRealHeader().
Flight::route('/', function() {
    Flight::response()->setRealHeader('Content-Type: text/plain');
    echo 'Streaming response...';
    sleep(5);
    echo 'Done!';
})->stream();JSONP
Для JSONP запитів ви можете опціонально передати назву параметра запиту, який ви використовуєте для визначення вашої функції зворотного виклику:
Flight::jsonp(['id' => 123], 'q');Отже, коли робиться GET запит за допомогою ?q=my_func, ви повинні отримати вивід:
my_func({"id":123});Якщо ви не передасте назву параметра запиту, він за замовчуванням буде jsonp.
Примітка: Якщо ви все ще використовуєте JSONP запити в 2025 році та пізніше, приєднуйтеся до чату та розкажіть нам чому! Нам подобається чути хороші історії битв/жахів!
Очищення даних відповіді
Ви можете очистити тіло відповіді та заголовки, використовуючи метод clear(). Це очистить будь-які заголовки, призначені для відповіді, очистить тіло відповіді та встановить код статусу на 200.
Flight::response()->clear();Очищення тільки тіла відповіді
Якщо ви хочете очистити тільки тіло відповіді, ви можете використовувати метод clearBody():
// Це все ще збереже будь-які заголовки, встановлені на об'єкті response().
// Це все ще збереже будь-які заголовки, встановлені на об'єкті response().
Flight::response()->clearBody();Кешування HTTP
Flight надає вбудовану підтримку для кешування на рівні HTTP. Якщо умова кешування виконана, Flight поверне HTTP відповідь 304 Not Modified. Наступного разу, коли клієнт запитує той самий ресурс, йому буде запропоновано використовувати локально кешовану версію.
Кешування на рівні маршруту
Якщо ви хочете кешувати всю вашу відповідь, ви можете використовувати метод cache() і передати час для кешування.
// Це кешуватиме відповідь на 5 хвилин
Flight::route('/news', function () {
  Flight::response()->cache(time() + 300);
  echo 'This content will be cached.';
});
// Альтернативно, ви можете використовувати рядок, який ви б передали
// методу strtotime()
Flight::route('/news', function () {
  Flight::response()->cache('+5 minutes');
  echo 'This content will be cached.';
});Last-Modified
Ви можете використовувати метод lastModified і передати UNIX мітку часу для встановлення дати та часу, коли сторінка була востаннє змінена. Клієнт продовжуватиме використовувати свій кеш, доки значення останньої модифікації не зміниться.
Flight::route('/news', function () {
  Flight::lastModified(1234567890);
  echo 'This content will be cached.';
});ETag
Кешування ETag подібне до Last-Modified, за винятком того, що ви можете вказати будь-який ідентифікатор, який ви хочете для ресурсу:
Flight::route('/news', function () {
  Flight::etag('my-unique-id');
  echo 'This content will be cached.';
});Пам'ятайте, що виклик як lastModified, так і etag обидва встановлять і перевірять значення кешу. Якщо значення кешу однакове між запитами, Flight негайно надішле відповідь HTTP 304 і зупинить обробку.
Завантаження файлу
v3.12.0
Є допоміжний метод для потокової передачі файлу кінцевому користувачеві. Ви можете використовувати метод download і передати шлях.
Flight::route('/download', function () {
  Flight::download('/path/to/file.txt');
  // Починаючи з v3.17.1 ви можете вказати власну назву файлу для завантаження
  Flight::download('/path/to/file.txt', 'custom_name.txt');
});Дивіться також
- Маршрутизація - Як зіставляти маршрути з контролерами та рендерити перегляди.
 - Запити - Розуміння, як обробляти вхідні запити.
 - Middleware - Використання middleware з маршрутами для автентифікації, логування тощо.
 - Чому фреймворк? - Розуміння переваг використання фреймворку, як Flight.
 - Розширення - Як розширювати Flight власною функціональністю.
 
Вирішення проблем
- Якщо у вас проблеми з перенаправленнями, які не працюють, переконайтеся, що ви додаєте 
return;до методу. stop()іhalt()— не те саме.halt()зупинить виконання негайно, тоді якstop()дозволить виконанню продовжуватися.
Журнал змін
- v3.17.1 - Додано 
$fileNameдо методуdownloadFile(). - v3.12.0 - Додано допоміжний метод downloadFile.
 - v3.10.0 - Додано 
jsonHalt. - v1.0 - Початковий реліз.