Learn

Pelajari Tentang Flight

Flight adalah framework PHP yang cepat, sederhana, dan dapat diperluas. Ini cukup serbaguna dan dapat digunakan untuk membangun berbagai jenis aplikasi web. Ini dibangun dengan kesederhanaan dalam pikiran dan ditulis dengan cara yang mudah dipahami dan digunakan.

Konsep Penting dalam Framework

Mengapa Menggunakan Framework?

Berikut adalah artikel singkat tentang mengapa Anda harus menggunakan framework. Ini adalah ide yang baik untuk memahami manfaat menggunakan framework sebelum Anda mulai menggunakannya.

Selain itu, tutorial yang sangat baik telah dibuat oleh @lubiana. Meskipun tidak membahas secara mendalam tentang Flight secara spesifik, petunjuk ini akan membantu Anda memahami beberapa konsep utama seputar framework dan mengapa mereka bermanfaat untuk digunakan. Anda dapat menemukan tutorial tersebut di sini.

Flight Dibandingkan dengan Framework Lain

Jika Anda bermigrasi dari framework lain seperti Laravel, Slim, Fat-Free, atau Symfony ke Flight, halaman ini akan membantu Anda memahami perbedaan antara keduanya.

Topik Inti

Autoloading

Pelajari cara meng-autoload kelas Anda sendiri dalam aplikasi Anda.

Routing

Pelajari cara mengelola rute untuk aplikasi web Anda. Ini juga termasuk pengelompokan rute, parameter rute, dan middleware.

Middleware

Pelajari cara menggunakan middleware untuk memfilter permintaan dan respon dalam aplikasi Anda.

Requests

Pelajari cara menangani permintaan dan respon dalam aplikasi Anda.

Responses

Pelajari cara mengirim respon kepada pengguna Anda.

HTML Templates

Pelajari cara menggunakan mesin tampilan bawaan untuk merender template HTML Anda.

Keamanan

Pelajari cara mengamankan aplikasi Anda dari ancaman keamanan yang umum.

Konfigurasi

Pelajari cara mengonfigurasi framework untuk aplikasi Anda.

Memperluas Flight

Pelajari cara memperluas framework dengan menambahkan metode dan kelas Anda sendiri.

Event dan Penyaringan

Pelajari cara menggunakan sistem event untuk menambahkan hook ke metode Anda dan metode internal framework.

Kontainer Injeksi Ketergantungan

Pelajari cara menggunakan kontainer injeksi ketergantungan (DIC) untuk mengelola ketergantungan aplikasi Anda.

API Framework

Pelajari tentang metode inti dari framework.

Migrasi ke v3

Kompatibilitas mundur sebagian besar telah dipertahankan, tetapi ada beberapa perubahan yang harus Anda ketahui saat bermigrasi dari v2 ke v3.

Memecahkan Masalah

Ada beberapa masalah umum yang mungkin Anda temui saat menggunakan Flight. Halaman ini akan membantu Anda memecahkan masalah tersebut.

Learn/flight_vs_laravel

Flight vs Laravel

Apa itu Laravel?

Laravel adalah framework yang memiliki fitur lengkap yang dilengkapi dengan segala hal menarik dan ekosistem yang berfokus pada pengembang, tetapi dengan biaya dalam hal kinerja dan kompleksitas. Tujuan Laravel adalah agar pengembang memiliki tingkat produktivitas tertinggi dan untuk memudahkan tugas-tugas umum. Laravel adalah pilihan yang baik bagi pengembang yang mencari untuk membangun aplikasi web berfitur lengkap untuk perusahaan. Itu datang dengan beberapa pertukaran, terutama dalam hal kinerja dan kompleksitas. Mempelajari dasar-dasar Laravel bisa jadi mudah, tetapi menguasai framework ini bisa memakan waktu.

Ada juga banyak modul Laravel sehingga pengembang sering merasa bahwa satu-satunya cara untuk menyelesaikan masalah adalah melalui modul-modul ini, padahal sebenarnya Anda bisa saja menggunakan perpustakaan lain atau menulis kode Anda sendiri.

Kelebihan dibandingkan Flight

Kekurangan dibandingkan Flight

Learn/migrating_to_v3

Migrasi ke v3

Kompatibilitas ke belakang sebagian besar telah dipertahankan, tetapi ada beberapa perubahan yang harus Anda perhatikan saat migrasi dari v2 ke v3.

Perilaku Buffering Output (3.5.0)

Buffering output adalah proses di mana output yang dihasilkan oleh skrip PHP disimpan dalam buffer (internal di PHP) sebelum dikirim ke klien. Ini memungkinkan Anda untuk memodifikasi output sebelum dikirim ke klien.

Dalam aplikasi MVC, Controller adalah "pengelola" dan mengatur apa yang dilakukan tampilan. Memiliki output yang dihasilkan di luar controller (atau dalam kasus Flight kadang-kadang fungsi anonim) merusak pola MVC. Perubahan ini bertujuan untuk lebih selaras dengan pola MVC dan untuk membuat framework lebih dapat diprediksi dan lebih mudah digunakan.

Di v2, buffering output ditangani sedemikian rupa sehingga tidak secara konsisten menutup buffer output sendiri dan ini membuat unit testing dan streaming menjadi lebih sulit. Untuk sebagian besar pengguna, perubahan ini mungkin tidak benar-benar memengaruhi Anda. Namun jika Anda mencetak konten di luar callable dan controller (misalnya dalam hook), Anda kemungkinan akan menghadapi masalah. Mencetak konten dalam hook, dan sebelum framework benar-benar mengeksekusi mungkin berfungsi di masa lalu, tetapi tidak akan berfungsi ke depan.

Di mana Anda mungkin mengalami masalah

// index.php
require 'vendor/autoload.php';

// hanya contoh
define('START_TIME', microtime(true));

function hello() {
    echo 'Hello World';
}

Flight::map('hello', 'hello');
Flight::after('hello', function(){
    // ini sebenarnya baik-baik saja
    echo '<p>Frasa Hello World ini dibawakan kepada Anda oleh huruf "H"</p>';
});

Flight::before('start', function(){
    // hal-hal seperti ini akan menyebabkan kesalahan
    echo '<html><head><title>Halaman Saya</title></head><body>';
});

Flight::route('/', function(){
    // ini sebenarnya baik-baik saja
    echo 'Hello World';

    // Ini juga seharusnya baik-baik saja
    Flight::hello();
});

Flight::after('start', function(){
    // ini akan menyebabkan kesalahan
    echo '<div>Halaman Anda dimuat dalam '.(microtime(true) - START_TIME).' detik</div></body></html>';
});

Mengaktifkan Perilaku Rendering v2

Apakah Anda masih bisa menjaga kode lama Anda seperti semula tanpa melakukan penulisan ulang untuk membuatnya berfungsi dengan v3? Ya, Anda bisa! Anda dapat mengaktifkan perilaku rendering v2 dengan mengatur opsi konfigurasi flight.v2.output_buffering menjadi true. Ini akan memungkinkan Anda untuk terus menggunakan perilaku rendering lama, tetapi disarankan untuk memperbaikinya ke depan. Di v4 dari framework, ini akan dihapus.

// index.php
require 'vendor/autoload.php';

Flight::set('flight.v2.output_buffering', true);

Flight::before('start', function(){
    // Sekarang ini akan baik-baik saja
    echo '<html><head><title>Halaman Saya</title></head><body>';
});

// lebih banyak kode 

Perubahan Dispatcher (3.7.0)

Jika Anda langsung memanggil metode statis untuk Dispatcher seperti Dispatcher::invokeMethod(), Dispatcher::execute(), dll. Anda perlu memperbarui kode Anda agar tidak langsung memanggil metode ini. Dispatcher telah diubah menjadi lebih berorientasi objek sehingga Container Penyuntikan Ketergantungan dapat digunakan dengan cara yang lebih mudah. Jika Anda perlu memanggil metode mirip seperti yang dilakukan Dispatcher, Anda dapat menggunakan sesuatu seperti $result = $class->$method(...$params); atau call_user_func_array() sebagai gantinya.

Perubahan halt() stop() redirect() dan error() (3.10.0)

Perilaku default sebelum 3.10.0 adalah untuk menghapus baik header maupun body respons. Ini diubah hanya untuk menghapus body respons. Jika Anda perlu menghapus header juga, Anda bisa menggunakan Flight::response()->clear().

Learn/configuration

Konfigurasi

Anda dapat menyesuaikan perilaku tertentu dari Flight dengan menetapkan nilai konfigurasi melalui metode set.

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

Pengaturan Konfigurasi Tersedia

Berikut adalah daftar semua pengaturan konfigurasi yang tersedia:

Konfigurasi Loader

Selain itu, ada pengaturan konfigurasi lain untuk loader. Ini akan memungkinkan Anda untuk memuat kelas secara otomatis dengan _ dalam nama kelas.

// Aktifkan pemuatan kelas dengan garis bawah
// Defaultnya adalah true
Loader::$v2ClassLoading = false;

Variabel

Flight memungkinkan Anda untuk menyimpan variabel sehingga dapat digunakan di mana saja dalam aplikasi Anda.

// Simpan variabel Anda
Flight::set('id', 123);

// Di tempat lain dalam aplikasi Anda
$id = Flight::get('id');

Untuk melihat apakah sebuah variabel telah disetel, Anda dapat melakukan:

if (Flight::has('id')) {
  // Lakukan sesuatu
}

Anda dapat menghapus variabel dengan melakukan:

// Menghapus variabel id
Flight::clear('id');

// Menghapus semua variabel
Flight::clear();

Flight juga menggunakan variabel untuk tujuan konfigurasi.

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

Penanganan Kesalahan

Kesalahan dan Pengecualian

Semua kesalahan dan pengecualian ditangkap oleh Flight dan diteruskan ke metode error. Perilaku default adalah mengirimkan respons HTTP 500 Internal Server Error dengan beberapa informasi kesalahan.

Anda dapat mengganti perilaku ini sesuai kebutuhan Anda:

Flight::map('error', function (Throwable $error) {
  // Tangani kesalahan
  echo $error->getTraceAsString();
});

Secara default kesalahan tidak dicatat ke server web. Anda dapat mengaktifkan ini dengan mengubah konfigurasi:

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

Tidak Ditemukan

Ketika sebuah URL tidak dapat ditemukan, Flight memanggil metode notFound. Perilaku default adalah mengirimkan respons HTTP 404 Not Found dengan pesan sederhana.

Anda dapat mengganti perilaku ini sesuai kebutuhan Anda:

Flight::map('notFound', function () {
  // Tangani tidak ditemukan
});

Learn/security

Keamanan

Keamanan adalah hal yang sangat penting ketika datang ke aplikasi web. Anda ingin memastikan bahwa aplikasi Anda aman dan bahwa data pengguna Anda berada dalam keadaan aman. Flight menyediakan sejumlah fitur untuk membantu Anda mengamankan aplikasi web Anda.

Header

Header HTTP adalah salah satu cara termudah untuk mengamankan aplikasi web Anda. Anda dapat menggunakan header untuk mencegah clickjacking, XSS, dan serangan lainnya. Ada beberapa cara yang dapat Anda lakukan untuk menambahkan header ini ke aplikasi Anda.

Dua situs web hebat untuk memeriksa keamanan header Anda adalah securityheaders.com dan observatory.mozilla.org.

Tambahkan Secara Manual

Anda dapat menambahkan header ini secara manual dengan menggunakan metode header pada objek Flight\Response.

// Setel header X-Frame-Options untuk mencegah clickjacking
Flight::response()->header('X-Frame-Options', 'SAMEORIGIN');

// Setel header Content-Security-Policy untuk mencegah XSS
// Catatan: header ini dapat menjadi sangat kompleks, jadi Anda ingin
// berkonsultasi dengan contoh di internet untuk aplikasi Anda
Flight::response()->header("Content-Security-Policy", "default-src 'self'");

// Setel header X-XSS-Protection untuk mencegah XSS
Flight::response()->header('X-XSS-Protection', '1; mode=block');

// Setel header X-Content-Type-Options untuk mencegah MIME sniffing
Flight::response()->header('X-Content-Type-Options', 'nosniff');

// Setel header Referrer-Policy untuk mengontrol seberapa banyak informasi referrer yang dikirim
Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade');

// Setel header Strict-Transport-Security untuk memaksa HTTPS
Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');

// Setel header Permissions-Policy untuk mengontrol fitur dan API mana yang dapat digunakan
Flight::response()->header('Permissions-Policy', 'geolocation=()');

Header ini dapat ditambahkan di bagian atas file bootstrap.php atau index.php Anda.

Tambahkan sebagai Filter

Anda juga dapat menambahkannya dalam filter/hook seperti berikut:

// Tambahkan header dalam filter
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=()');
});

Tambahkan sebagai Middleware

Anda juga dapat menambahkannya sebagai kelas middleware. Ini adalah cara yang baik untuk menjaga kode Anda tetap bersih dan terorganisir.

// 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 atau di mana pun Anda memiliki rute Anda
// FYI, grup string kosong ini bertindak sebagai middleware global untuk
// semua rute. Tentu saja, Anda bisa melakukan hal yang sama dan hanya menambahkan
// ini hanya pada rute tertentu.
Flight::group('', function(Router $router) {
    $router->get('/users', [ 'UserController', 'getUsers' ]);
    // lebih banyak rute
}, [ new SecurityHeadersMiddleware() ]);

Cross Site Request Forgery (CSRF)

Cross Site Request Forgery (CSRF) adalah jenis serangan di mana situs web jahat dapat membuat browser pengguna mengirim permintaan ke situs web Anda. Ini dapat digunakan untuk melakukan tindakan di situs web Anda tanpa sepengetahuan pengguna. Flight tidak menyediakan mekanisme perlindungan CSRF bawaan, tetapi Anda dapat dengan mudah mengimplementasikan sendiri dengan menggunakan middleware.

Pengaturan

Pertama, Anda perlu menghasilkan token CSRF dan menyimpannya di sesi pengguna. Anda kemudian dapat menggunakan token ini di formulir Anda dan memeriksa saat formulir dikirimkan.

// Hasilkan token CSRF dan simpan di sesi pengguna
// (mengasumsikan Anda telah membuat objek sesi dan melampirkannya ke Flight)
// lihat dokumentasi sesi untuk informasi lebih lanjut
Flight::register('session', \Ghostff\Session\Session::class);

// Anda hanya perlu menghasilkan satu token per sesi (agar berfungsi 
// di beberapa tab dan permintaan untuk pengguna yang sama)
if(Flight::session()->get('csrf_token') === null) {
    Flight::session()->set('csrf_token', bin2hex(random_bytes(32)) );
}
<!-- Gunakan token CSRF di formulir Anda -->
<form method="post">
    <input type="hidden" name="csrf_token" value="<?= Flight::session()->get('csrf_token') ?>">
    <!-- field formulir lainnya -->
</form>

Menggunakan Latte

Anda juga dapat mengatur fungsi khusus untuk menampilkan token CSRF di template Latte Anda.

// Atur fungsi khusus untuk menampilkan token CSRF
// Catatan: Tampilan telah dikonfigurasi dengan Latte sebagai mesin tampilan
Flight::view()->addFunction('csrf', function() {
    $csrfToken = Flight::session()->get('csrf_token');
    return new \Latte\Runtime\Html('<input type="hidden" name="csrf_token" value="' . $csrfToken . '">');
});

Dan sekarang di template Latte Anda, Anda dapat menggunakan fungsi csrf() untuk menampilkan token CSRF.

<form method="post">
    {csrf()}
    <!-- field formulir lainnya -->
</form>

Singkat dan sederhana, bukan?

Periksa Token CSRF

Anda dapat memeriksa token CSRF menggunakan filter acara:

// Middleware ini memeriksa apakah permintaan adalah permintaan POST dan jika ya, memeriksa apakah token CSRF valid
Flight::before('start', function() {
    if(Flight::request()->method == 'POST') {

        // ambil token csrf dari nilai formulir
        $token = Flight::request()->data->csrf_token;
        if($token !== Flight::session()->get('csrf_token')) {
            Flight::halt(403, 'Token CSRF tidak valid');
            // atau untuk respon JSON
            Flight::jsonHalt(['error' => 'Token CSRF tidak valid'], 403);
        }
    }
});

Atau Anda dapat menggunakan kelas middleware:

// app/middleware/CsrfMiddleware.php

namespace app\middleware;

class CsrfMiddleware
{
    public function before(array $params): void
    {
        if(Flight::request()->method == 'POST') {
            $token = Flight::request()->data->csrf_token;
            if($token !== Flight::session()->get('csrf_token')) {
                Flight::halt(403, 'Token CSRF tidak valid');
            }
        }
    }
}

// index.php atau di mana pun Anda memiliki rute
Flight::group('', function(Router $router) {
    $router->get('/users', [ 'UserController', 'getUsers' ]);
    // lebih banyak rute
}, [ new CsrfMiddleware() ]);

Cross Site Scripting (XSS)

Cross Site Scripting (XSS) adalah jenis serangan di mana situs web jahat dapat menyisipkan kode ke situs web Anda. Sebagian besar peluang ini muncul dari nilai formulir yang akan diisi oleh pengguna akhir Anda. Anda tidak boleh pernah mempercayai output dari pengguna Anda! Selalu anggap semua dari mereka adalah pengacau terbaik di dunia. Mereka dapat menyisipkan JavaScript atau HTML berbahaya ke dalam halaman Anda. Kode ini dapat digunakan untuk mencuri informasi dari pengguna Anda atau melakukan tindakan di situs web Anda. Menggunakan kelas tampilan Flight, Anda dapat dengan mudah melarikan output untuk mencegah serangan XSS.

// Mari kita anggap pengguna cukup cerdas dan mencoba menggunakan ini sebagai nama mereka
$name = '<script>alert("XSS")</script>';

// Ini akan melarikan output
Flight::view()->set('name', $name);
// Ini akan menghasilkan: &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

// Jika Anda menggunakan sesuatu seperti Latte yang terdaftar sebagai kelas tampilan Anda, itu juga akan secara otomatis melarikan ini.
Flight::view()->render('template', ['name' => $name]);

SQL Injection

SQL Injection adalah jenis serangan di mana pengguna jahat dapat menyisipkan kode SQL ke dalam database Anda. Ini dapat digunakan untuk mencuri informasi dari database Anda atau melakukan tindakan di database Anda. Sekali lagi, Anda tidak boleh mempercayai input dari pengguna Anda! Selalu anggap mereka mencari darah. Anda dapat menggunakan pernyataan yang dipersiapkan dalam objek PDO Anda untuk mencegah injeksi SQL.

// Mengasumsikan Anda memiliki Flight::db() terdaftar sebagai objek PDO Anda
$statement = Flight::db()->prepare('SELECT * FROM users WHERE username = :username');
$statement->execute([':username' => $username]);
$users = $statement->fetchAll();

// Jika Anda menggunakan kelas PdoWrapper, ini dapat dengan mudah dilakukan dalam satu baris
$users = Flight::db()->fetchAll('SELECT * FROM users WHERE username = :username', [ 'username' => $username ]);

// Anda dapat melakukan hal yang sama dengan objek PDO dengan placeholder ?
$statement = Flight::db()->fetchAll('SELECT * FROM users WHERE username = ?', [ $username ]);

// Hanya janjikan Anda tidak akan PERNAH melakukan sesuatu seperti ini...
$users = Flight::db()->fetchAll("SELECT * FROM users WHERE username = '{$username}' LIMIT 5");
// karena bagaimana jika $username = "' OR 1=1; -- "; 
// Setelah kueri dibangun, sepertinya ini
// SELECT * FROM users WHERE username = '' OR 1=1; -- LIMIT 5
// Sepertinya aneh, tetapi itu adalah kueri yang valid yang akan berhasil. Faktanya,
// ini adalah serangan injeksi SQL yang sangat umum yang akan mengembalikan semua pengguna.

CORS

Cross-Origin Resource Sharing (CORS) adalah mekanisme yang memungkinkan banyak sumber daya (misalnya, font, JavaScript, dll.) pada halaman web untuk diminta dari domain lain di luar domain dari mana sumber daya itu berasal. Flight tidak memiliki fungsi bawaan, tetapi ini dapat dengan mudah ditangani dengan hook yang dijalankan sebelum metode Flight::start() dipanggil.

// 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
    {
        // sesuaikan host yang diizinkan di sini.
        $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 atau di mana pun Anda memiliki rute
$CorsUtil = new CorsUtil();

// Ini perlu dijalankan sebelum mulai berjalan.
Flight::before('start', [ $CorsUtil, 'setupCors' ]);

Kesimpulan

Keamanan adalah hal yang sangat penting dan penting untuk memastikan aplikasi web Anda aman. Flight menyediakan sejumlah fitur untuk membantu Anda mengamankan aplikasi web Anda, tetapi penting untuk selalu waspada dan memastikan Anda melakukan semua yang Anda bisa untuk menjaga data pengguna Anda aman. Selalu anggap yang terburuk dan jangan pernah mempercayai input dari pengguna Anda. Selalu melarikan output dan gunakan pernyataan yang dipersiapkan untuk mencegah injeksi SQL. Selalu gunakan middleware untuk melindungi rute Anda dari serangan CSRF dan CORS. Jika Anda melakukan semua hal ini, Anda akan berada di jalur yang baik untuk membangun aplikasi web yang aman.

Learn/routing

Routing

Catatan: Ingin memahami lebih lanjut tentang routing? Periksa halaman "mengapa sebuah framework?" untuk penjelasan yang lebih mendalam.

Routing dasar di Flight dilakukan dengan mencocokkan pola URL dengan fungsi callback atau sebuah array dari sebuah kelas dan metode.

Flight::route('/', function(){
    echo 'hello world!';
});

Rute dicocokkan dalam urutan mereka didefinisikan. Rute pertama yang mencocokkan permintaan akan dipanggil.

Callback/Fungsi

Callback dapat berupa objek apa pun yang dapat dipanggil. Jadi Anda dapat menggunakan fungsi biasa:

function hello() {
    echo 'hello world!';
}

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

Kelas

Anda juga dapat menggunakan metode statis dari sebuah kelas:

class Greeting {
    public static function hello() {
        echo 'hello world!';
    }
}

Flight::route('/', [ 'Greeting','hello' ]);

Atau dengan membuat objek terlebih dahulu dan kemudian memanggil metode:


// 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' ]);
// Anda juga dapat melakukan ini tanpa membuat objek terlebih dahulu
// Catatan: Tidak ada argumen yang akan disuntikkan ke konstruktor
Flight::route('/', [ 'Greeting', 'hello' ]);
// Selain itu, Anda dapat menggunakan sintaks lebih pendek ini
Flight::route('/', 'Greeting->hello');
// atau
Flight::route('/', Greeting::class.'->hello');

Dependency Injection melalui DIC (Dependency Injection Container)

Jika Anda ingin menggunakan dependency injection melalui sebuah container (PSR-11, PHP-DI, Dice, dll), satu-satunya jenis rute yang tersedia adalah langsung membuat objek sendiri dan menggunakan container untuk membuat objek Anda atau Anda dapat menggunakan string untuk mendefinisikan kelas dan metode yang akan dipanggil. Anda dapat pergi ke halaman Dependency Injection untuk informasi lebih lanjut.

Berikut adalah contoh cepat:


use flight\database\PdoWrapper;

// Greeting.php
class Greeting
{
    protected PdoWrapper $pdoWrapper;
    public function __construct(PdoWrapper $pdoWrapper) {
        $this->pdoWrapper = $pdoWrapper;
    }

    public function hello(int $id) {
        // lakukan sesuatu dengan $this->pdoWrapper
        $name = $this->pdoWrapper->fetchField("SELECT name FROM users WHERE id = ?", [ $id ]);
        echo "Hello, world! Nama saya adalah {$name}!";
    }
}

// index.php

// Siapkan container dengan parameter apa pun yang Anda butuhkan
// Lihat halaman Dependency Injection untuk informasi lebih lanjut tentang PSR-11
$dice = new \Dice\Dice();

// Jangan lupa untuk menetapkan kembali variabel dengan '$dice = '!!!!!
$dice = $dice->addRule('flight\database\PdoWrapper', [
    'shared' => true,
    'constructParams' => [ 
        'mysql:host=localhost;dbname=test', 
        'root',
        'password'
    ]
]);

// Daftarkan pengendali container
Flight::registerContainerHandler(function($class, $params) use ($dice) {
    return $dice->create($class, $params);
});

// Rute seperti biasa
Flight::route('/hello/@id', [ 'Greeting', 'hello' ]);
// atau
Flight::route('/hello/@id', 'Greeting->hello');
// atau
Flight::route('/hello/@id', 'Greeting::hello');

Flight::start();

Metode Routing

Secara default, pola rute dicocokkan dengan semua metode permintaan. Anda dapat merespons metode tertentu dengan menempatkan pengenal sebelum URL.

Flight::route('GET /', function () {
  echo 'Saya menerima permintaan GET.';
});

Flight::route('POST /', function () {
  echo 'Saya menerima permintaan POST.';
});

// Anda tidak dapat menggunakan Flight::get() untuk rute karena itu adalah metode 
//    untuk mendapatkan variabel, tidak membuat rute.
// Flight::post('/', function() { /* kode */ });
// Flight::patch('/', function() { /* kode */ });
// Flight::put('/', function() { /* kode */ });
// Flight::delete('/', function() { /* kode */ });

Anda juga dapat memetakan beberapa metode ke satu callback dengan menggunakan pemisah |:

Flight::route('GET|POST /', function () {
  echo 'Saya menerima baik permintaan GET atau POST.';
});

Selain itu, Anda dapat mengambil objek Router yang memiliki beberapa metode pembantu untuk Anda gunakan:


$router = Flight::router();

// memetakan semua metode
$router->map('/', function() {
    echo 'hello world!';
});

// permintaan GET
$router->get('/users', function() {
    echo 'users';
});
// $router->post();
// $router->put();
// $router->delete();
// $router->patch();

Ekspresi Reguler

Anda dapat menggunakan ekspresi reguler dalam rute Anda:

Flight::route('/user/[0-9]+', function () {
  // Ini akan mencocokkan /user/1234
});

Meskipun metode ini tersedia, disarankan untuk menggunakan parameter bernama, atau parameter bernama dengan ekspresi reguler, karena lebih mudah dibaca dan lebih mudah untuk dipelihara.

Parameter Bernama

Anda dapat menentukan parameter bernama dalam rute Anda yang akan diteruskan ke fungsi callback Anda. Ini lebih untuk keterbacaan rute daripada yang lain . Silakan lihat bagian di bawah tentang caveat penting.

Flight::route('/@name/@id', function (string $name, string $id) {
  echo "hello, $name ($id)!";
});

Anda juga dapat menyertakan ekspresi reguler dengan parameter bernama Anda menggunakan pemisah ::

Flight::route('/@name/@id:[0-9]{3}', function (string $name, string $id) {
  // Ini akan mencocokkan /bob/123
  // Tetapi tidak akan mencocokkan /bob/12345
});

Catatan: Mencocokkan grup regex () dengan parameter posisi tidak didukung. :'(

Caveat Penting

Meskipun dalam contoh di atas, tampaknya @name terikat langsung pada variabel $name, itu tidak. Urutan parameter dalam fungsi callback yang menentukan apa yang diteruskan ke dalamnya. Jadi jika Anda membalik urutan parameter dalam fungsi callback, variabel juga akan dibalik. Berikut adalah contohnya:

Flight::route('/@name/@id', function (string $id, string $name) {
  echo "hello, $name ($id)!";
});

Dan jika Anda mengunjungi URL berikut: /bob/123, hasilnya akan menjadi hello, 123 (bob)!. Silakan berhati-hati saat Anda menetapkan rute dan fungsi callback Anda.

Parameter Opsional

Anda dapat menentukan parameter bernama yang bersifat opsional untuk pencocokan dengan membungkus segmen dalam tanda kurung.

Flight::route(
  '/blog(/@year(/@month(/@day)))',
  function(?string $year, ?string $month, ?string $day) {
    // Ini akan mencocokkan URL berikut:
    // /blog/2012/12/10
    // /blog/2012/12
    // /blog/2012
    // /blog
  }
);

Parameter opsional yang tidak dicocokkan akan diteruskan sebagai NULL.

Wildcards

Pencocokan hanya dilakukan pada segmen URL individu. Jika Anda ingin mencocokkan beberapa segmen Anda dapat menggunakan wildcard *.

Flight::route('/blog/*', function () {
  // Ini akan mencocokkan /blog/2000/02/01
});

Untuk merutekan semua permintaan ke satu callback, Anda dapat melakukan:

Flight::route('*', function () {
  // Lakukan sesuatu
});

Menyampaikan

Anda dapat meneruskan eksekusi ke rute berikutnya yang cocok dengan mengembalikan true dari fungsi callback Anda.

Flight::route('/user/@name', function (string $name) {
  // Periksa beberapa kondisi
  if ($name !== "Bob") {
    // Lanjutkan ke rute berikutnya
    return true;
  }
});

Flight::route('/user/*', function () {
  // Ini akan dipanggil
});

Aliasing Rute

Anda dapat menetapkan alias ke sebuah rute, sehingga URL dapat dibuat secara dinamis dilanjutkan dalam kode Anda (seperti template misalnya).

Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');

// nanti dalam kode di suatu tempat
Flight::getUrl('user_view', [ 'id' => 5 ]); // akan mengembalikan '/users/5'

Ini sangat membantu jika URL Anda kebetulan berubah. Dalam contoh di atas, katakanlah bahwa pengguna dipindahkan ke /admin/users/@id alih-alih. Dengan aliasing di tempat, Anda tidak perlu mengubah di mana pun Anda merujuk alias karena alias sekarang akan mengembalikan /admin/users/5 seperti dalam contoh di atas.

Aliasing rute masih berfungsi dalam grup juga:

Flight::group('/users', function() {
    Flight::route('/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');
});

// nanti dalam kode di suatu tempat
Flight::getUrl('user_view', [ 'id' => 5 ]); // akan mengembalikan '/users/5'

Informasi Rute

Jika Anda ingin memeriksa informasi rute yang cocok, Anda dapat meminta objek rute untuk diteruskan ke fungsi callback Anda dengan meneruskan true sebagai parameter ketiga di metode rute. Objek rute akan selalu menjadi parameter terakhir yang diteruskan ke fungsi callback Anda.

Flight::route('/', function(\flight\net\Route $route) {
  // Array metode HTTP yang dicocokkan
  $route->methods;

  // Array parameter bernama
  $route->params;

  // Ekspresi reguler yang cocok
  $route->regex;

  // Berisi konten dari setiap '*' yang digunakan dalam pola URL
  $route->splat;

  // Menunjukkan jalur url....jika Anda benar-benar membutuhkannya
  $route->pattern;

  // Menunjukkan middleware apa yang ditugaskan untuk ini
  $route->middleware;

  // Menunjukkan alias yang ditugaskan untuk rute ini
  $route->alias;
}, true);

Pengelompokan Rute

Mungkin ada waktu ketika Anda ingin mengelompokkan rute-rute terkait bersama (seperti /api/v1). Anda dapat melakukan ini dengan menggunakan metode group:

Flight::group('/api/v1', function () {
  Flight::route('/users', function () {
    // Mencocokkan /api/v1/users
  });

  Flight::route('/posts', function () {
    // Mencocokkan /api/v1/posts
  });
});

Anda bahkan dapat menelurkan grup dari grup:

Flight::group('/api', function () {
  Flight::group('/v1', function () {
    // Flight::get() mendapatkan variabel, itu tidak menetapkan rute! Lihat konteks objek di bawah
    Flight::route('GET /users', function () {
      // Mencocokkan GET /api/v1/users
    });

    Flight::post('/posts', function () {
      // Mencocokkan POST /api/v1/posts
    });

    Flight::put('/posts/1', function () {
      // Mencocokkan PUT /api/v1/posts
    });
  });
  Flight::group('/v2', function () {

    // Flight::get() mendapatkan variabel, itu tidak menetapkan rute! Lihat konteks objek di bawah
    Flight::route('GET /users', function () {
      // Mencocokkan GET /api/v2/users
    });
  });
});

Pengelompokan dengan Konteks Objek

Anda masih dapat menggunakan pengelompokan rute dengan objek Engine dengan cara berikut:

$app = new \flight\Engine();
$app->group('/api/v1', function (Router $router) {

  // gunakan variabel $router
  $router->get('/users', function () {
    // Mencocokkan GET /api/v1/users
  });

  $router->post('/posts', function () {
    // Mencocokkan POST /api/v1/posts
  });
});

Resource Routing

Anda dapat membuat serangkaian rute untuk sebuah sumber daya menggunakan metode resource. Ini akan membuat serangkaian rute untuk sumber daya yang mengikuti konvensi RESTful.

Untuk membuat sumber daya, lakukan hal berikut:

Flight::resource('/users', UsersController::class);

Dan yang akan terjadi di latar belakang adalah ini akan membuat rute berikut:

[
      'index' => 'GET ',
      'create' => 'GET /create',
      'store' => 'POST ',
      'show' => 'GET /@id',
      'edit' => 'GET /@id/edit',
      'update' => 'PUT /@id',
      'destroy' => 'DELETE /@id'
]

Dan controller Anda akan terlihat seperti ini:

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
    {
    }
}

Catatan: Anda dapat melihat rute yang baru ditambahkan dengan runway dengan menjalankan php runway routes.

Menyesuaikan Rute Sumber Daya

Ada beberapa opsi untuk mengonfigurasi rute sumber daya.

Alias Basis

Anda dapat mengonfigurasi aliasBase. Secara default, alias adalah bagian terakhir dari URL yang ditentukan. Misalnya /users/ akan menghasilkan aliasBase menjadi users. Ketika rute ini dibuat, alias adalah users.index, users.create, dst. Jika Anda ingin mengubah alias, atur aliasBase ke nilai yang Anda inginkan.

Flight::resource('/users', UsersController::class, [ 'aliasBase' => 'user' ]);

Hanya dan Kecuali

Anda juga dapat menentukan rute mana yang ingin Anda buat dengan menggunakan opsi only dan except.

Flight::resource('/users', UsersController::class, [ 'only' => [ 'index', 'show' ] ]);
Flight::resource('/users', UsersController::class, [ 'except' => [ 'create', 'store', 'edit', 'update', 'destroy' ] ]);

Ini pada dasarnya adalah opsi daftar putih dan daftar hitam sehingga Anda dapat menentukan rute mana yang ingin Anda buat.

Middleware

Anda juga dapat menentukan middleware yang akan dijalankan di setiap rute yang dibuat oleh metode resource.

Flight::resource('/users', UsersController::class, [ 'middleware' => [ MyAuthMiddleware::class ] ]);

Streaming

Anda sekarang dapat melakukan streaming respons ke klien menggunakan metode streamWithHeaders(). Ini berguna untuk mengirim file besar, proses yang memakan waktu lama, atau menghasilkan respons besar. Streaming rute ditangani sedikit berbeda dari rute biasa.

Catatan: Streaming respons hanya tersedia jika Anda memiliki flight.v2.output_buffering disetel ke false.

Stream dengan Header Manual

Anda dapat melakukan streaming respons ke klien dengan menggunakan metode stream() pada sebuah rute. Jika Anda melakukan ini, Anda harus menetapkan semua metode secara manual sebelum Anda mengeluarkan apapun kepada klien. Ini dilakukan dengan fungsi header() php atau metode Flight::response()->setRealHeader().

Flight::route('/@filename', function($filename) {

    // jelas Anda akan menyaring jalur dan lain-lain.
    $fileNameSafe = basename($filename);

    // Jika Anda memiliki header tambahan untuk diatur di sini setelah rute dieksekusi
    // Anda harus mendefinisikannya sebelum ada yang di-echo keluar.
    // Mereka semua harus merupakan panggilan mentah ke fungsi header() 
    // atau panggilan ke Flight::response()->setRealHeader()
    header('Content-Disposition: attachment; filename="'.$fileNameSafe.'"');
    // atau
    Flight::response()->setRealHeader('Content-Disposition', 'attachment; filename="'.$fileNameSafe.'"');

    $fileData = file_get_contents('/some/path/to/files/'.$fileNameSafe);

    // Penanganan kesalahan dan lain-lain
    if(empty($fileData)) {
        Flight::halt(404, 'File tidak ditemukan');
    }

    // set panjang konten secara manual jika Anda suka
    header('Content-Length: '.filesize($filename));

    // Streaming data ke klien
    echo $fileData;

// Ini adalah baris ajaib di sini
})->stream();

Stream dengan Header

Anda juga dapat menggunakan metode streamWithHeaders() untuk mengatur header sebelum Anda mulai streaming.

Flight::route('/stream-users', function() {

    // Anda dapat menambahkan header tambahan apa pun yang Anda inginkan di sini
    // Anda hanya harus menggunakan header() atau Flight::response()->setRealHeader()

    // namun cara Anda menarik data Anda, hanya sebagai contoh...
    $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 ',';
        }

        // Ini diperlukan untuk mengirim data ke klien
        ob_flush();
    }
    echo '}';

// Ini adalah bagaimana Anda mengatur header sebelum Anda mulai streaming.
})->streamWithHeaders([
    'Content-Type' => 'application/json',
    'Content-Disposition' => 'attachment; filename="users.json"',
    // kode status opsional, default ke 200
    'status' => 200
]);

Learn/flight_vs_symfony

Flight vs Symfony

Apa itu Symfony?

Symfony adalah sekumpulan komponen PHP yang dapat digunakan kembali dan framework PHP untuk proyek web.

Landasan standar di mana aplikasi PHP terbaik dibangun. Pilih salah satu dari 50 komponen mandiri yang tersedia untuk aplikasi Anda sendiri.

Percepat pembuatan dan pemeliharaan aplikasi web PHP Anda. Akhiri tugas pengkodean yang repetitif dan nikmati kekuatan mengendalikan kode Anda.

Kelebihan dibandingkan Flight

Kekurangan dibandingkan Flight

Learn/flight_vs_another_framework

Membandingkan Flight dengan Framework Lain

Jika Anda bermigrasi dari framework lain seperti Laravel, Slim, Fat-Free, atau Symfony ke Flight, halaman ini akan membantu Anda memahami perbedaan antara keduanya.

Laravel

Laravel adalah framework yang penuh fitur yang memiliki segala fasilitas dan ekosistem yang menakjubkan yang berfokus pada pengembang, tetapi dengan biaya dalam kinerja dan kompleksitas.

Lihat perbandingan antara Laravel dan Flight.

Slim

Slim adalah micro-framework yang mirip dengan Flight. Ini dirancang agar ringan dan mudah digunakan, tetapi bisa sedikit lebih kompleks daripada Flight.

Lihat perbandingan antara Slim dan Flight.

Fat-Free

Fat-Free adalah framework full-stack dalam paket yang jauh lebih kecil. Meskipun memiliki semua alat dalam kotak perkakas, ia memiliki arsitektur data yang dapat membuat beberapa proyek menjadi lebih kompleks daripada yang seharusnya.

Lihat perbandingan antara Fat-Free dan Flight.

Symfony

Symfony adalah framework modular tingkat perusahaan yang dirancang untuk fleksibel dan skalabel. Untuk proyek yang lebih kecil atau pengembang yang lebih baru, Symfony bisa sedikit membingungkan.

Lihat perbandingan antara Symfony dan Flight.

Learn/dependency_injection_container

Kontainer Penyuntikan Ketergantungan

Pengenalan

Kontainer Penyuntikan Ketergantungan (DIC) adalah alat yang kuat yang memungkinkan Anda untuk mengelola ketergantungan aplikasi Anda. Ini adalah konsep kunci dalam kerangka PHP modern dan digunakan untuk mengelola instansiasi dan konfigurasi objek. Beberapa contoh pustaka DIC adalah: Dice, Pimple, PHP-DI, dan league/container.

DIC adalah cara mewah untuk mengatakan bahwa ia memungkinkan Anda untuk membuat dan mengelola kelas Anda di lokasi terpusat. Ini berguna ketika Anda perlu mengoper objek yang sama ke beberapa kelas (seperti pengontrol Anda). Contoh sederhana mungkin membantu ini menjadi lebih jelas.

Contoh Dasar

Cara lama dalam melakukan sesuatu mungkin terlihat seperti ini:


require 'vendor/autoload.php';

// kelas untuk mengelola pengguna dari database
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();

Anda dapat melihat dari kode di atas bahwa kami membuat objek PDO baru dan mengoperasikan ke kelas UserController kami. Ini baik untuk aplikasi kecil, tetapi seiring pertumbuhan aplikasi Anda, Anda akan menemukan bahwa Anda membuat objek PDO yang sama di beberapa tempat. Inilah saatnya DIC berguna.

Berikut adalah contoh yang sama menggunakan DIC (menggunakan Dice):


require 'vendor/autoload.php';

// kelas yang sama seperti di atas. Tidak ada yang berubah
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());
    }
}

// buat kontainer baru
$container = new \Dice\Dice;
// jangan lupa untuk menetapkannya kembali ke dirinya sendiri seperti di bawah ini!
$container = $container->addRule('PDO', [
    // dibagikan berarti objek yang sama akan dikembalikan setiap kali
    'shared' => true,
    'constructParams' => ['mysql:host=localhost;dbname=test', 'user', 'pass' ]
]);

// Ini mendaftarkan penangan kontainer sehingga Flight tahu untuk menggunakannya.
Flight::registerContainerHandler(function($class, $params) use ($container) {
    return $container->create($class, $params);
});

// sekarang kita bisa menggunakan kontainer untuk membuat UserController kita
Flight::route('/user/@id', [ 'UserController', 'view' ]);
// atau alternatifnya, Anda dapat mendefinisikan rute seperti ini
Flight::route('/user/@id', 'UserController->view');
// atau
Flight::route('/user/@id', 'UserController::view');

Flight::start();

Saya yakin Anda mungkin berpikir bahwa banyak kode tambahan ditambahkan ke contoh ini. Keajaiban datang ketika Anda memiliki pengontrol lain yang membutuhkan objek PDO.


// Jika semua pengontrol Anda memiliki konstruktor yang membutuhkan objek PDO
// masing-masing rute di bawah ini akan secara otomatis menginjeksikannya!!!
Flight::route('/company/@id', 'CompanyController->view');
Flight::route('/organization/@id', 'OrganizationController->view');
Flight::route('/category/@id', 'CategoryController->view');
Flight::route('/settings', 'SettingsController->view');

Bonus tambahan dari memanfaatkan DIC adalah bahwa pengujian unit menjadi jauh lebih mudah. Anda dapat membuat objek tiruan dan mengoperasikannya ke kelas Anda. Ini adalah manfaat besar ketika Anda menulis tes untuk aplikasi Anda!

PSR-11

Flight juga dapat menggunakan kontainer yang sesuai dengan PSR-11. Ini berarti Anda dapat menggunakan kontainer apa pun yang mengimplementasikan antarmuka PSR-11. Berikut adalah contoh menggunakan kontainer PSR-11 dari League:


require 'vendor/autoload.php';

// kelas UserController yang sama seperti di atas

$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();

Ini mungkin sedikit lebih panjang daripada contoh Dice sebelumnya, tetapi tetap menyelesaikan pekerjaan dengan keuntungan yang sama!

Penangan DIC Kustom

Anda juga dapat membuat penangan DIC Anda sendiri. Ini berguna jika Anda memiliki kontainer kustom yang ingin Anda gunakan yang bukan PSR-11 (Dice). Lihat contoh dasar untuk cara melakukannya.

Selain itu, ada beberapa default yang berguna yang akan membuat hidup Anda lebih mudah saat menggunakan Flight.

Instance Engine

Jika Anda menggunakan instance Engine di pengontrol/middleware Anda, inilah cara Anda mengkonfigurasinya:


// Di suatu tempat di file bootstrap Anda
$engine = Flight::app();

$container = new \Dice\Dice;
$container = $container->addRule('*', [
    'substitutions' => [
        // Ini adalah tempat Anda mengoper instance
        Engine::class => $engine
    ]
]);

$engine->registerContainerHandler(function($class, $params) use ($container) {
    return $container->create($class, $params);
});

// Sekarang Anda dapat menggunakan instance Engine di pengontrol/middleware Anda

class MyController {
    public function __construct(Engine $app) {
        $this->app = $app;
    }

    public function index() {
        $this->app->render('index');
    }
}

Menambahkan Kelas Lain

Jika Anda memiliki kelas lain yang ingin Anda tambahkan ke kontainer, dengan Dice sangat mudah karena mereka akan secara otomatis diselesaikan oleh kontainer. Berikut adalah contohnya:


$container = new \Dice\Dice;
// Jika Anda tidak perlu menyuntikkan apa pun ke dalam kelas Anda
// Anda tidak perlu mendefinisikan apa pun!
Flight::registerContainerHandler(function($class, $params) use ($container) {
    return $container->create($class, $params);
});

class MyCustomClass {
    public function parseThing() {
        return 'thing';
    }
}

class UserController {

    protected MyCustomClass $MyCustomClass;

    public function __construct(MyCustomClass $MyCustomClass) {
        $this->MyCustomClass = $MyCustomClass;
    }

    public function index() {
        echo $this->MyCustomClass->parseThing();
    }
}

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

Learn/middleware

Middleware Rute

Flight mendukung middleware rute dan group rute. Middleware adalah fungsi yang dijalankan sebelum (atau setelah) callback rute. Ini adalah cara yang bagus untuk menambahkan pemeriksaan otentikasi API dalam kode Anda, atau untuk memvalidasi bahwa pengguna memiliki izin untuk mengakses rute tersebut.

Middleware Dasar

Berikut adalah contoh dasar:

// Jika Anda hanya menyediakan fungsi anonim, itu akan dieksekusi sebelum callback rute. 
// tidak ada fungsi middleware "setelah" kecuali untuk kelas (lihat di bawah)
Flight::route('/path', function() { echo ' Di sini saya!'; })->addMiddleware(function() {
    echo 'Middleware pertama!';
});

Flight::start();

// Ini akan menghasilkan "Middleware pertama! Di sini saya!"

Ada beberapa catatan yang sangat penting tentang middleware yang harus Anda ketahui sebelum menggunakannya:

Kelas Middleware

Middleware dapat terdaftar sebagai kelas juga. Jika Anda perlu fungsi "setelah", Anda harus menggunakan kelas.

class MyMiddleware {
    public function before($params) {
        echo 'Middleware pertama!';
    }

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

$MyMiddleware = new MyMiddleware();
Flight::route('/path', function() { echo ' Di sini saya! '; })->addMiddleware($MyMiddleware); // juga ->addMiddleware([ $MyMiddleware, $MyMiddleware2 ]);

Flight::start();

// Ini akan menampilkan "Middleware pertama! Di sini saya! Middleware terakhir!"

Menangani Kesalahan Middleware

Misalkan Anda memiliki middleware otentikasi dan Anda ingin mengalihkan pengguna ke halaman login jika mereka tidak terautentikasi. Anda memiliki beberapa opsi di tangan Anda:

  1. Anda dapat mengembalikan false dari fungsi middleware dan Flight akan secara otomatis mengembalikan kesalahan 403 Forbidden, tetapi tidak ada kustomisasi.
  2. Anda dapat mengalihkan pengguna ke halaman login menggunakan Flight::redirect().
  3. Anda dapat membuat kesalahan kustom dalam middleware dan menghentikan eksekusi rute.

Contoh Dasar

Ini adalah contoh sederhana return false;:

class MyMiddleware {
    public function before($params) {
        if (isset($_SESSION['user']) === false) {
            return false;
        }

        // karena ini benar, semuanya akan terus berjalan
    }
}

Contoh Redirect

Ini adalah contoh mengalihkan pengguna ke halaman login:

class MyMiddleware {
    public function before($params) {
        if (isset($_SESSION['user']) === false) {
            Flight::redirect('/login');
            exit;
        }
    }
}

Contoh Kesalahan Kustom

Misalkan Anda perlu membuang kesalahan JSON karena Anda sedang membangun API. Anda dapat melakukannya seperti ini:

class MyMiddleware {
    public function before($params) {
        $authorization = Flight::request()->headers['Authorization'];
        if(empty($authorization)) {
            Flight::jsonHalt(['error' => 'Anda harus masuk untuk mengakses halaman ini.'], 403);
            // atau
            Flight::json(['error' => 'Anda harus masuk untuk mengakses halaman ini.'], 403);
            exit;
            // atau
            Flight::halt(403, json_encode(['error' => 'Anda harus masuk untuk mengakses halaman ini.']));
        }
    }
}

Pengelompokan Middleware

Anda dapat menambahkan grup rute, dan kemudian setiap rute dalam grup itu akan memiliki middleware yang sama juga. Ini berguna jika Anda perlu mengelompokkan sejumlah rute dengan misalnya middleware Auth untuk memeriksa kunci API di header.


// ditambahkan di akhir metode grup
Flight::group('/api', function() {

    // Rute yang "kosong" ini sebenarnya akan mencocokkan /api
    Flight::route('', function() { echo 'api'; }, false, 'api');
    // Ini akan mencocokkan /api/users
    Flight::route('/users', function() { echo 'users'; }, false, 'users');
    // Ini akan mencocokkan /api/users/1234
    Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');
}, [ new ApiAuthMiddleware() ]);

Jika Anda ingin menerapkan middleware global ke semua rute Anda, Anda dapat menambahkan grup "kosong":


// ditambahkan di akhir metode grup
Flight::group('', function() {

    // Ini masih /users
    Flight::route('/users', function() { echo 'users'; }, false, 'users');
    // Dan ini masih /users/1234
    Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');
}, [ new ApiAuthMiddleware() ]);

Learn/filtering

Penyaringan

Flight memungkinkan Anda untuk menyaring metode sebelum dan setelah mereka dipanggil. Tidak ada hook yang telah ditentukan sebelumnya yang perlu Anda ingat. Anda dapat menyaring salah satu dari metode kerangka kerja default serta metode kustom apa pun yang telah Anda peta.

Fungsi filter terlihat seperti ini:

function (array &$params, string &$output): bool {
  // Kode penyaring
}

Dengan menggunakan variabel yang diteruskan, Anda dapat memanipulasi parameter input dan/atau output.

Anda dapat menjalankan filter sebelum sebuah metode dengan melakukan:

Flight::before('start', function (array &$params, string &$output): bool {
  // Lakukan sesuatu
});

Anda dapat menjalankan filter setelah sebuah metode dengan melakukan:

Flight::after('start', function (array &$params, string &$output): bool {
  // Lakukan sesuatu
});

Anda dapat menambahkan sebanyak mungkin filter yang Anda inginkan ke metode mana pun. Mereka akan dipanggil dalam urutan di mana mereka dideklarasikan.

Berikut adalah contoh proses penyaringan:

// Peta metode kustom
Flight::map('hello', function (string $name) {
  return "Halo, $name!";
});

// Tambahkan filter sebelum
Flight::before('hello', function (array &$params, string &$output): bool {
  // Manipulasi parameter
  $params[0] = 'Fred';
  return true;
});

// Tambahkan filter setelah
Flight::after('hello', function (array &$params, string &$output): bool {
  // Manipulasi output
  $output .= " Semoga harimu menyenangkan!";
  return true;
});

// Panggil metode kustom
echo Flight::hello('Bob');

Ini seharusnya menampilkan:

Halo Fred! Semoga harimu menyenangkan!

Jika Anda telah mendefinisikan beberapa filter, Anda dapat memutus rantai dengan mengembalikan false di salah satu fungsi filter Anda:

Flight::before('start', function (array &$params, string &$output): bool {
  echo 'satu';
  return true;
});

Flight::before('start', function (array &$params, string &$output): bool {
  echo 'dua';

  // Ini akan mengakhiri rantai
  return false;
});

// Ini tidak akan dipanggil
Flight::before('start', function (array &$params, string &$output): bool {
  echo 'tiga';
  return true;
});

Catatan, metode inti seperti map dan register tidak dapat disaring karena mereka dipanggil secara langsung dan tidak dipanggil secara dinamis.

Learn/requests

Permintaan

Flight mengenkapsulasi permintaan HTTP ke dalam satu objek, yang dapat diakses dengan melakukan:

$request = Flight::request();

Kasus Penggunaan Umum

Ketika Anda sedang bekerja dengan permintaan di aplikasi web, biasanya Anda ingin mengambil header, atau parameter $_GET atau $_POST, atau mungkin bahkan body permintaan mentah. Flight menyediakan antarmuka sederhana untuk melakukan semua hal ini.

Berikut adalah contoh mengambil parameter string kueri:

Flight::route('/search', function(){
    $keyword = Flight::request()->query['keyword'];
    echo "Anda sedang mencari: $keyword";
    // kueri database atau sesuatu lainnya dengan $keyword
});

Berikut adalah contoh dari mungkin sebuah formulir dengan metode POST:

Flight::route('POST /submit', function(){
    $name = Flight::request()->data['name'];
    $email = Flight::request()->data['email'];
    echo "Anda mengirim: $name, $email";
    // simpan ke dalam database atau sesuatu lainnya dengan $name dan $email
});

Properti Objek Permintaan

Objek permintaan menyediakan properti berikut:

Anda dapat mengakses properti query, data, cookies, dan files sebagai array atau objek.

Jadi, untuk mendapatkan parameter string kueri, Anda dapat melakukan:

$id = Flight::request()->query['id'];

Atau Anda dapat melakukan:

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

Body Permintaan RAW

Untuk mendapatkan body permintaan HTTP mentah, misalnya saat menangani permintaan PUT, Anda dapat melakukan:

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

Input JSON

Jika Anda mengirimkan permintaan dengan tipe application/json dan data {"id": 123} itu akan tersedia dari properti data:

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

$_GET

Anda dapat mengakses array $_GET melalui properti query:

$id = Flight::request()->query['id'];

$_POST

Anda dapat mengakses array $_POST melalui properti data:

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

$_COOKIE

Anda dapat mengakses array $_COOKIE melalui properti cookies:

$myCookieValue = Flight::request()->cookies['myCookieName'];

$_SERVER

Ada pintasan yang tersedia untuk mengakses array $_SERVER melalui metode getVar():


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

Mengakses File yang Diunggah melalui $_FILES

Anda dapat mengakses file yang diunggah melalui properti files:

$uploadedFile = Flight::request()->files['myFile'];

Memproses Unggahan File (v3.12.0)

Anda dapat memproses unggahan file menggunakan framework dengan beberapa metode pembantu. Secara dasar, ini menyangkut mengambil data file dari permintaan, dan memindahkannya ke lokasi baru.

Flight::route('POST /upload', function(){
    // Jika Anda memiliki field input seperti <input type="file" name="myFile">
    $uploadedFileData = Flight::request()->getUploadedFiles();
    $uploadedFile = $uploadedFileData['myFile'];
    $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename());
});

Jika Anda memiliki beberapa file yang diunggah, Anda dapat melakukan pengulangan melalui mereka:

Flight::route('POST /upload', function(){
    // Jika Anda memiliki field input seperti <input type="file" name="myFiles[]">
    $uploadedFiles = Flight::request()->getUploadedFiles()['myFiles'];
    foreach ($uploadedFiles as $uploadedFile) {
        $uploadedFile->moveTo('/path/to/uploads/' . $uploadedFile->getClientFilename());
    }
});

Catatan Keamanan: Selalu validasi dan bersihkan input pengguna, terutama saat menangani unggahan file. Selalu validasi tipe ekstensi yang akan Anda izinkan untuk diunggah, tetapi Anda juga harus memvalidasi "magic bytes" dari file untuk memastikan file tersebut sebenarnya adalah tipe file yang diklaim pengguna. Terdapat artikel dan perpustakaan yang tersedia untuk membantu dengan ini.

Header Permintaan

Anda dapat mengakses header permintaan menggunakan metode getHeader() atau getHeaders():


// Mungkin Anda membutuhkan header Authorization
$host = Flight::request()->getHeader('Authorization');
// atau
$host = Flight::request()->header('Authorization');

// Jika Anda perlu mengambil semua header
$headers = Flight::request()->getHeaders();
// atau
$headers = Flight::request()->headers();

Body Permintaan

Anda dapat mengakses body permintaan mentah menggunakan metode getBody():

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

Metode Permintaan

Anda dapat mengakses metode permintaan menggunakan properti method atau metode getMethod():

$method = Flight::request()->method; // sebenarnya memanggil getMethod()
$method = Flight::request()->getMethod();

Catatan: Metode getMethod() pertama-tama menarik metode dari $_SERVER['REQUEST_METHOD'], kemudian bisa ditimpa oleh $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] jika ada atau $_REQUEST['_method'] jika ada.

URL Permintaan

Terdapat beberapa metode pembantu untuk menyusun bagian dari URL demi kenyamanan Anda.

URL Lengkap

Anda dapat mengakses URL permintaan penuh menggunakan metode getFullUrl():

$url = Flight::request()->getFullUrl();
// https://example.com/some/path?foo=bar

URL Dasar

Anda dapat mengakses URL dasar menggunakan metode getBaseUrl():

$url = Flight::request()->getBaseUrl();
// Perhatikan, tidak ada garis miring di akhir.
// https://example.com

Penguraian Kueri

Anda dapat mengoper URL ke metode parseQuery() untuk menguraikan string kueri menjadi array asosiatif:

$query = Flight::request()->parseQuery('https://example.com/some/path?foo=bar');
// ['foo' => 'bar']

Learn/api

Metode API Framework

Flight dirancang agar mudah digunakan dan dipahami. Berikut adalah kumpulan lengkap metode untuk framework. Ini terdiri dari metode inti, yang merupakan metode statis biasa, dan metode yang dapat diperluas, yang merupakan metode yang dipetakan yang dapat difilter atau di-override.

Metode Inti

Metode ini adalah inti dari framework dan tidak dapat di-override.

Flight::map(string $name, callable $callback, bool $pass_route = false) // Membuat metode framework kustom.
Flight::register(string $name, string $class, array $params = [], ?callable $callback = null) // Mendaftar kelas ke metode framework.
Flight::unregister(string $name) // Mencopot pendaftaran kelas dari metode framework.
Flight::before(string $name, callable $callback) // Menambahkan filter sebelum metode framework.
Flight::after(string $name, callable $callback) // Menambahkan filter setelah metode framework.
Flight::path(string $path) // Menambahkan jalur untuk mengautoload kelas.
Flight::get(string $key) // Mendapatkan variabel yang ditetapkan oleh Flight::set().
Flight::set(string $key, mixed $value) // Mengatur variabel dalam mesin Flight.
Flight::has(string $key) // Memeriksa apakah variabel telah diatur.
Flight::clear(array|string $key = []) // Menghapus variabel.
Flight::init() // Menginisialisasi framework ke pengaturan default.
Flight::app() // Mendapatkan instance objek aplikasi.
Flight::request() // Mendapatkan instance objek permintaan.
Flight::response() // Mendapatkan instance objek respons.
Flight::router() // Mendapatkan instance objek router.
Flight::view() // Mendapatkan instance objek tampilan.

Metode yang Dapat Diperluas

Flight::start() // Memulai framework.
Flight::stop() // Menghentikan framework dan mengirimkan respons.
Flight::halt(int $code = 200, string $message = '') // Menghentikan framework dengan kode status dan pesan opsional.
Flight::route(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Memetakan pola URL ke callback.
Flight::post(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Memetakan pola URL permintaan POST ke callback.
Flight::put(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Memetakan pola URL permintaan PUT ke callback.
Flight::patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Memetakan pola URL permintaan PATCH ke callback.
Flight::delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') // Memetakan pola URL permintaan DELETE ke callback.
Flight::group(string $pattern, callable $callback) // Membuat pengelompokan untuk URL, pola harus berupa string.
Flight::getUrl(string $name, array $params = []) // Menghasilkan URL berdasarkan alias rute.
Flight::redirect(string $url, int $code) // Mengarahkan ke URL lain.
Flight::download(string $filePath) // Mengunduh file.
Flight::render(string $file, array $data, ?string $key = null) // Membangun file template.
Flight::error(Throwable $error) // Mengirimkan respons HTTP 500.
Flight::notFound() // Mengirimkan respons HTTP 404.
Flight::etag(string $id, string $type = 'string') // Melakukan caching HTTP ETag.
Flight::lastModified(int $time) // Melakukan caching HTTP modifikasi terakhir.
Flight::json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Mengirimkan respons JSON.
Flight::jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Mengirimkan respons JSONP.
Flight::jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Mengirimkan respons JSON dan menghentikan framework.

Metode kustom yang ditambahkan dengan map dan register juga dapat difilter. Untuk contoh tentang cara memetakan metode ini, lihat panduan Memperluas Flight.

Learn/why_frameworks

Mengapa Kerangka?

Beberapa pemrogram sangat menentang penggunaan kerangka. Mereka berpendapat bahwa kerangka itu berlebihan, lambat, dan sulit dipelajari. Mereka mengatakan bahwa kerangka tidak diperlukan dan bahwa Anda dapat menulis kode yang lebih baik tanpa mereka. Tentu ada beberapa poin yang valid mengenai kekurangan menggunakan kerangka. Namun, ada juga banyak keuntungan dalam menggunakan kerangka.

Alasan untuk Menggunakan Kerangka

Berikut adalah beberapa alasan mengapa Anda mungkin ingin mempertimbangkan untuk menggunakan kerangka:

Flight adalah micro-framework. Ini berarti bahwa ia kecil dan ringan. Ia tidak menyediakan sebanyak fungsionalitas seperti kerangka besar seperti Laravel atau Symfony. Namun, ia menyediakan banyak fungsionalitas yang Anda butuhkan untuk membangun aplikasi web. Ini juga mudah dipelajari dan digunakan. Ini membuatnya menjadi pilihan yang baik untuk membangun aplikasi web dengan cepat dan mudah. Jika Anda baru mengenal kerangka, Flight adalah kerangka pemula yang hebat untuk mulai digunakan. Ini akan membantu Anda belajar tentang keuntungan menggunakan kerangka tanpa membebani Anda dengan terlalu banyak kompleksitas. Setelah Anda memiliki beberapa pengalaman dengan Flight, akan lebih mudah untuk beralih ke kerangka yang lebih kompleks seperti Laravel atau Symfony, namun Flight masih dapat membuat aplikasi yang berhasil dan tangguh.

Apa itu Routing?

Routing adalah inti dari kerangka Flight, tetapi apa itu sebenarnya? Routing adalah proses mengambil URL dan mencocokkannya dengan fungsi tertentu di kode Anda. Inilah cara Anda dapat membuat situs web Anda melakukan hal-hal yang berbeda berdasarkan URL yang diminta. Misalnya, Anda mungkin ingin menampilkan profil pengguna ketika mereka mengunjungi /user/1234, tetapi menampilkan daftar semua pengguna ketika mereka mengunjungi /users. Semua ini dilakukan melalui routing.

Ini mungkin bekerja seperti ini:

Dan Mengapa Ini Penting?

Memiliki router terpusat yang baik sebenarnya dapat membuat hidup Anda jauh lebih mudah! Ini mungkin sulit dilihat pada awalnya. Berikut adalah beberapa alasan mengapa:

Saya yakin Anda sudah familiar dengan cara skrip demi skrip untuk membuat situs web. Anda mungkin memiliki file bernama index.php yang memiliki banyak pernyataan if untuk memeriksa URL dan kemudian menjalankan fungsi tertentu berdasarkan URL tersebut. Ini adalah bentuk routing, tetapi tidak sangat teratur dan dapat menjadi tidak terkendali dengan cepat. Sistem routing Flight adalah cara yang jauh lebih teratur dan kuat untuk menangani routing.

Ini?


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

// dll...

Atau ini?


// index.php
Flight::route('/user/@id', [ 'UserController', 'viewUserProfile' ]);
Flight::route('/user/@id/edit', [ 'UserController', 'editUserProfile' ]);

// Mungkin di dalam app/controllers/UserController.php Anda
class UserController {
    public function viewUserProfile($id) {
        // lakukan sesuatu
    }

    public function editUserProfile($id) {
        // lakukan sesuatu
    }
}

Semoga Anda mulai melihat manfaat menggunakan sistem routing terpusat. Ini jauh lebih mudah untuk dikelola dan dipahami dalam jangka panjang!

Permintaan dan Respons

Flight menyediakan cara yang sederhana dan mudah untuk menangani permintaan dan respons. Ini adalah inti dari apa yang dilakukan kerangka web. Ini menerima permintaan dari peramban pengguna, memprosesnya, dan kemudian mengirim kembali respons. Ini adalah cara Anda dapat membangun aplikasi web yang melakukan hal-hal seperti menampilkan profil pengguna, memungkinkan pengguna masuk, atau memungkinkan pengguna membuat posting blog baru.

Permintaan

Permintaan adalah apa yang dikirim peramban pengguna ke server Anda ketika mereka mengunjungi situs web Anda. Permintaan ini mengandung informasi tentang apa yang ingin dilakukan pengguna. Misalnya, mungkin berisi informasi tentang URL apa yang ingin dikunjungi pengguna, data apa yang ingin dikirim pengguna ke server Anda, atau jenis data apa yang ingin diterima pengguna dari server Anda. Penting untuk diketahui bahwa permintaan bersifat read-only. Anda tidak dapat mengubah permintaan, tetapi Anda dapat membacanya.

Flight menyediakan cara yang sederhana untuk mengakses informasi tentang permintaan tersebut. Anda dapat mengakses informasi tentang permintaan menggunakan metode Flight::request() . Metode ini mengembalikan objek Request yang berisi informasi tentang permintaan. Anda dapat menggunakan objek ini untuk mengakses informasi tentang permintaan, seperti URL, metode, atau data yang dikirim pengguna ke server Anda.

Respons

Respons adalah apa yang dikirim server Anda kembali ke peramban pengguna ketika mereka mengunjungi situs web Anda. Respons ini berisi informasi tentang apa yang ingin dilakukan server Anda. Misalnya, mungkin berisi informasi tentang jenis data apa yang ingin dikirim server Anda kepada pengguna, jenis data apa yang ingin diterima server Anda dari pengguna, atau jenis data apa yang ingin disimpan server Anda di komputer pengguna.

Flight menyediakan cara yang sederhana untuk mengirim respons ke peramban pengguna. Anda dapat mengirim respons menggunakan metode Flight::response(). Metode ini mengambil objek Response sebagai argumen dan mengirimkan respons ke peramban pengguna. Anda dapat menggunakan objek ini untuk mengirim respons kepada peramban pengguna, seperti HTML, JSON, atau file. Flight membantu Anda secara otomatis menghasilkan beberapa bagian dari respons untuk mempermudah, tetapi pada akhirnya Anda memiliki kendali atas apa yang Anda kirim kembali kepada pengguna.

Learn/responses

Respons

Flight membantu menghasilkan sebagian dari header respons untuk Anda, tetapi Anda memegang sebagian besar kontrol atas apa yang Anda kirim kembali kepada pengguna. Terkadang Anda dapat mengakses objek Response secara langsung, tetapi sebagian besar waktu Anda akan menggunakan instance Flight untuk mengirim respons.

Mengirim Respons Dasar

Flight menggunakan ob_start() untuk menampung keluaran. Ini berarti Anda dapat menggunakan echo atau print untuk mengirim respons kepada pengguna dan Flight akan menangkapnya dan mengirimkannya kembali kepada pengguna dengan header yang sesuai.


// Ini akan mengirim "Hello, World!" ke browser pengguna
Flight::route('/', function() {
    echo "Hello, World!";
});

// HTTP/1.1 200 OK
// Content-Type: text/html
//
// Hello, World!

Sebagai alternatif, Anda dapat memanggil metode write() untuk menambahkan ke tubuh juga.


// Ini akan mengirim "Hello, World!" ke browser pengguna
Flight::route('/', function() {
    // verbose, tetapi kadang-kadang menyelesaikan pekerjaan ketika Anda membutuhkannya
    Flight::response()->write("Hello, World!");

    // jika Anda ingin mengambil tubuh yang telah Anda atur pada titik ini
    // Anda dapat melakukannya seperti ini
    $body = Flight::response()->getBody();
});

Kode Status

Anda dapat mengatur kode status dari respons dengan menggunakan metode status:

Flight::route('/@id', function($id) {
    if($id == 123) {
        Flight::response()->status(200);
        echo "Hello, World!";
    } else {
        Flight::response()->status(403);
        echo "Forbidden";
    }
});

Jika Anda ingin mendapatkan kode status saat ini, Anda dapat menggunakan metode status tanpa argumen:

Flight::response()->status(); // 200

Mengatur Tubuh Respons

Anda dapat mengatur tubuh respons dengan menggunakan metode write, namun, jika Anda menggunakan echo atau print apa pun, itu akan ditangkap dan dikirim sebagai tubuh respons melalui output buffering.

Flight::route('/', function() {
    Flight::response()->write("Hello, World!");
});

// sama dengan

Flight::route('/', function() {
    echo "Hello, World!";
});

Menghapus Tubuh Respons

Jika Anda ingin menghapus tubuh respons, Anda dapat menggunakan metode clearBody:

Flight::route('/', function() {
    if($someCondition) {
        Flight::response()->write("Hello, World!");
    } else {
        Flight::response()->clearBody();
    }
});

Menjalankan Callback pada Tubuh Respons

Anda dapat menjalankan callback pada tubuh respons dengan menggunakan metode addResponseBodyCallback:

Flight::route('/users', function() {
    $db = Flight::db();
    $users = $db->fetchAll("SELECT * FROM users");
    Flight::render('users_table', ['users' => $users]);
});

// Ini akan gzip semua respons untuk rute mana pun
Flight::response()->addResponseBodyCallback(function($body) {
    return gzencode($body, 9);
});

Anda dapat menambahkan beberapa callback dan mereka akan dijalankan dalam urutan di mana mereka ditambahkan. Karena ini dapat menerima callable, ini dapat menerima array kelas [ $class, 'method' ], penutupan $strReplace = function($body) { str_replace('hi', 'there', $body); };, atau nama fungsi 'minify' jika Anda memiliki fungsi untuk meminimalkan kode html Anda misalnya.

Catatan: Callback rute tidak akan berfungsi jika Anda menggunakan opsi konfigurasi flight.v2.output_buffering.

Callback Rute Khusus

Jika Anda ingin ini hanya berlaku untuk rute tertentu, Anda dapat menambahkan callback di dalam rute itu sendiri:

Flight::route('/users', function() {
    $db = Flight::db();
    $users = $db->fetchAll("SELECT * FROM users");
    Flight::render('users_table', ['users' => $users]);

    // Ini akan gzip hanya respons untuk rute ini
    Flight::response()->addResponseBodyCallback(function($body) {
        return gzencode($body, 9);
    });
});

Opsi Middleware

Anda juga dapat menggunakan middleware untuk menerapkan callback ke semua rute melalui middleware:

// MinifyMiddleware.php
class MinifyMiddleware {
    public function before() {
        // Terapkan callback di sini pada objek response().
        Flight::response()->addResponseBodyCallback(function($body) {
            return $this->minify($body);
        });
    }

    protected function minify(string $body): string {
        // meminimalkan tubuh dengan cara tertentu
        return $body;
    }
}

// index.php
Flight::group('/users', function() {
    Flight::route('', function() { /* ... */ });
    Flight::route('/@id', function($id) { /* ... */ });
}, [ new MinifyMiddleware() ]);

Mengatur Header Respons

Anda dapat mengatur header seperti tipe konten dari respons dengan menggunakan metode header:


// Ini akan mengirim "Hello, World!" ke browser pengguna dalam teks biasa
Flight::route('/', function() {
    Flight::response()->header('Content-Type', 'text/plain');
    // atau
    Flight::response()->setHeader('Content-Type', 'text/plain');
    echo "Hello, World!";
});

JSON

Flight menyediakan dukungan untuk mengirim respons JSON dan JSONP. Untuk mengirim respons JSON Anda mengirimkan beberapa data untuk di-JSON encode:

Flight::json(['id' => 123]);

JSON dengan Kode Status

Anda juga dapat mengirimkan kode status sebagai argumen kedua:

Flight::json(['id' => 123], 201);

JSON dengan Pretty Print

Anda juga dapat mengirimkan argumen ke posisi terakhir untuk mengaktifkan pretty printing:

Flight::json(['id' => 123], 200, true, 'utf-8', JSON_PRETTY_PRINT);

Jika Anda mengubah opsi yang diteruskan ke Flight::json() dan ingin sintaks yang lebih sederhana, Anda dapat hanya memetakan kembali metode JSON:

Flight::map('json', function($data, $code = 200, $options = 0) {
    Flight::_json($data, $code, true, 'utf-8', $options);
}

// Dan sekarang itu dapat digunakan seperti ini
Flight::json(['id' => 123], 200, JSON_PRETTY_PRINT);

JSON dan Berhenti Eksekusi (v3.10.0)

Jika Anda ingin mengirim respons JSON dan menghentikan eksekusi, Anda dapat menggunakan metode jsonHalt. Ini berguna untuk kasus di mana Anda memeriksa mungkin beberapa jenis otorisasi dan jika pengguna tidak berwenang, Anda dapat segera mengirim respons JSON, menghapus konten tubuh yang ada dan menghentikan eksekusi.

Flight::route('/users', function() {
    $authorized = someAuthorizationCheck();
    // Periksa apakah pengguna berwenang
    if($authorized === false) {
        Flight::jsonHalt(['error' => 'Unauthorized'], 401);
    }

    // Lanjutkan dengan sisa rute
});

Sebelum v3.10.0, Anda harus melakukan sesuatu seperti ini:

Flight::route('/users', function() {
    $authorized = someAuthorizationCheck();
    // Periksa apakah pengguna berwenang
    if($authorized === false) {
        Flight::halt(401, json_encode(['error' => 'Unauthorized']));
    }

    // Lanjutkan dengan sisa rute
});

JSONP

Untuk permintaan JSONP, Anda dapat secara opsional meneruskan nama parameter kueri yang Anda gunakan untuk mendefinisikan fungsi callback Anda:

Flight::jsonp(['id' => 123], 'q');

Jadi, ketika melakukan permintaan GET menggunakan ?q=my_func, Anda harus menerima keluaran:

my_func({"id":123});

Jika Anda tidak meneruskan nama parameter kueri, itu akan default ke jsonp.

Mengalihkan ke URL Lain

Anda dapat mengalihkan permintaan saat ini dengan menggunakan metode redirect() dan meneruskan URL baru:

Flight::redirect('/new/location');

Secara default, Flight mengirimkan kode status HTTP 303 ("Lihat Lain"). Anda dapat secara opsional mengatur kode khusus:

Flight::redirect('/new/location', 401);

Menghentikan

Anda dapat menghentikan kerangka kerja di mana saja dengan memanggil metode halt:

Flight::halt();

Anda juga dapat menentukan kode status HTTP dan pesan yang opsional:

Flight::halt(200, 'Be right back...');

Memanggil halt akan membuang konten respons apa pun hingga saat itu. Jika Anda ingin menghentikan kerangka kerja dan mengeluarkan respons saat ini, gunakan metode stop:

Flight::stop();

Menghapus Data Respons

Anda dapat menghapus tubuh respons dan header dengan menggunakan metode clear(). Ini akan menghapus header apa pun yang ditetapkan ke respons, menghapus tubuh respons, dan mengatur kode status ke 200.

Flight::response()->clear();

Menghapus Tubuh Respons Saja

Jika Anda hanya ingin menghapus tubuh respons, Anda dapat menggunakan metode clearBody():

// Ini akan tetap menjaga header yang telah ditetapkan pada objek response().
Flight::response()->clearBody();

Cache HTTP

Flight menyediakan dukungan bawaan untuk caching tingkat HTTP. Jika kondisi caching terpenuhi, Flight akan mengembalikan respons HTTP 304 Not Modified. Lain kali klien meminta sumber daya yang sama, mereka akan diminta untuk menggunakan versi cached lokal mereka.

Caching Tingkat Rute

Jika Anda ingin menyimpan seluruh respons, Anda dapat menggunakan metode cache() dan meneruskan waktu untuk caching.


// Ini akan menyimpan respons selama 5 menit
Flight::route('/news', function () {
  Flight::response()->cache(time() + 300);
  echo 'Konten ini akan disimpan.';
});

// Sebagai alternatif, Anda dapat menggunakan string yang akan Anda kirimkan
// ke metode strtotime()
Flight::route('/news', function () {
  Flight::response()->cache('+5 minutes');
  echo 'Konten ini akan disimpan.';
});

Last-Modified

Anda dapat menggunakan metode lastModified dan meneruskan timestamp UNIX untuk mengatur tanggal dan waktu halaman terakhir dimodifikasi. Klien akan terus menggunakan cache mereka hingga nilai terakhir dimodifikasi berubah.

Flight::route('/news', function () {
  Flight::lastModified(1234567890);
  echo 'Konten ini akan disimpan.';
});

ETag

Caching ETag mirip dengan Last-Modified, kecuali Anda dapat menentukan id apa pun yang Anda inginkan untuk sumber daya:

Flight::route('/news', function () {
  Flight::etag('my-unique-id');
  echo 'Konten ini akan disimpan.';
});

Ingatlah bahwa memanggil baik lastModified atau etag akan menetapkan dan memeriksa nilai cache. Jika nilai cache sama antara permintaan, Flight akan segera mengirim respons HTTP 304 dan menghentikan pemrosesan.

Mengunduh File (v3.12.0)

Ada metode bantuan untuk mengunduh file. Anda dapat menggunakan metode download dan meneruskan jalur.

Flight::route('/download', function () {
  Flight::download('/path/to/file.txt');
});

Learn/templates

Tampilan dan Template HTML

Flight menyediakan beberapa fungsionalitas templating dasar secara default.

Jika Anda memerlukan kebutuhan templating yang lebih kompleks, lihat contoh Smarty dan Latte di bagian Tampilan Kustom.

Mesin Tampilan Default

Untuk menampilkan template tampilan, panggil metode render dengan nama file template dan data template opsional:

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

Data template yang Anda masukkan akan secara otomatis disuntikkan ke dalam template dan dapat diacu seperti variabel lokal. File template hanyalah file PHP. Jika isi file template hello.php adalah:

Hello, <?= $name ?>!

Outputnya akan menjadi:

Hello, Bob!

Anda juga dapat secara manual mengatur variabel tampilan dengan menggunakan metode set:

Flight::view()->set('name', 'Bob');

Variabel name sekarang tersedia di semua tampilan Anda. Jadi Anda cukup melakukan:

Flight::render('hello');

Perhatikan bahwa saat menentukan nama template dalam metode render, Anda dapat mengabaikan ekstensi .php.

Secara default, Flight akan mencari direktori views untuk file template. Anda dapat mengatur jalur alternatif untuk template Anda dengan menyetel konfigurasi berikut:

Flight::set('flight.views.path', '/path/to/views');

Layout

Umum bagi situs web untuk memiliki satu file template layout dengan konten yang berganti-ganti. Untuk merender konten yang akan digunakan dalam layout, Anda dapat memberikan parameter opsional pada metode render.

Flight::render('header', ['heading' => 'Hello'], 'headerContent');
Flight::render('body', ['body' => 'World'], 'bodyContent');

Tampilan Anda kemudian akan memiliki variabel yang disimpan bernama headerContent dan bodyContent. Anda kemudian dapat merender layout Anda dengan melakukan:

Flight::render('layout', ['title' => 'Halaman Utama']);

Jika file template terlihat seperti ini:

header.php:

<h1><?= $heading ?></h1>

body.php:

<div><?= $body ?></div>

layout.php:

<html>
  <head>
    <title><?= $title ?></title>
  </head>
  <body>
    <?= $headerContent ?>
    <?= $bodyContent ?>
  </body>
</html>

Outputnya akan menjadi:

<html>
  <head>
    <title>Halaman Utama</title>
  </head>
  <body>
    <h1>Hello</h1>
    <div>World</div>
  </body>
</html>

Mesin Tampilan Kustom

Flight memungkinkan Anda untuk mengganti mesin tampilan default hanya dengan mendaftarkan kelas tampilan Anda sendiri.

Smarty

Inilah cara Anda menggunakan mesin template Smarty untuk tampilan Anda:

// Memuat pustaka Smarty
require './Smarty/libs/Smarty.class.php';

// Mendaftarkan Smarty sebagai kelas tampilan
// Juga berikan fungsi callback untuk mengonfigurasi Smarty saat dimuat
Flight::register('view', Smarty::class, [], function (Smarty $smarty) {
  $smarty->setTemplateDir('./templates/');
  $smarty->setCompileDir('./templates_c/');
  $smarty->setConfigDir('./config/');
  $smarty->setCacheDir('./cache/');
});

// Menetapkan data template
Flight::view()->assign('name', 'Bob');

// Menampilkan template
Flight::view()->display('hello.tpl');

Untuk kelengkapan, Anda juga harus menimpa metode render default Flight:

Flight::map('render', function(string $template, array $data): void {
  Flight::view()->assign($data);
  Flight::view()->display($template);
});

Latte

Inilah cara Anda menggunakan mesin template Latte untuk tampilan Anda:


// Mendaftarkan Latte sebagai kelas tampilan
// Juga berikan fungsi callback untuk mengonfigurasi Latte saat dimuat
Flight::register('view', Latte\Engine::class, [], function (Latte\Engine $latte) {
  // Di sinilah Latte akan menyimpan cache template Anda untuk mempercepat segalanya
    // Satu hal yang menarik tentang Latte adalah bahwa ia secara otomatis menyegarkan
    // cache Anda saat Anda melakukan perubahan pada template Anda!
    $latte->setTempDirectory(__DIR__ . '/../cache/');

    // Beritahu Latte di mana direktori root untuk tampilan Anda.
    $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../views/'));
});

// Dan menyimpulkan sehingga Anda dapat menggunakan Flight::render() dengan benar
Flight::map('render', function(string $template, array $data): void {
  // Ini seperti $latte_engine->render($template, $data);
  echo Flight::view()->render($template, $data);
});

Learn/flight_vs_fat_free

Flight vs Fat-Free

Apa itu Fat-Free?

Fat-Free (dikenal dengan penuh kasih sebagai F3) adalah sebuah mikro-framework PHP yang kuat namun mudah digunakan, dirancang untuk membantu Anda membangun aplikasi web yang dinamis dan tangguh - dengan cepat!

Flight dibandingkan dengan Fat-Free dalam banyak hal dan mungkin merupakan kerabat terdekat dalam hal fitur dan kesederhanaan. Fat-Free memiliki banyak fitur yang tidak dimiliki oleh Flight, tetapi juga memiliki banyak fitur yang dimiliki oleh Flight. Fat-Free mulai menunjukkan usianya dan tidak sepopuler dulu.

Pembaruan menjadi semakin jarang dan komunitas tidak seaktif dulu. Kode ini cukup sederhana, tetapi terkadang kurangnya disiplin sintaks dapat membuatnya sulit untuk dibaca dan dipahami. Ini berfungsi untuk PHP 8.3, tetapi kode itu sendiri masih terlihat seolah-olah berada di PHP 5.3.

Kelebihan dibandingkan Flight

Kekurangan dibandingkan Flight

Learn/extending

Memperpanjang

Flight dirancang untuk menjadi framework yang dapat diperluas. Framework ini dilengkapi dengan sejumlah metode dan komponen standar, tetapi memungkinkan Anda untuk memetakan metode Anda sendiri, mendaftar kelas Anda sendiri, atau bahkan menggantikan kelas dan metode yang ada.

Jika Anda mencari DIC (Dependency Injection Container), silakan menuju halaman Dependency Injection Container.

Memetakan Metode

Untuk memetakan metode kustom sederhana Anda sendiri, Anda menggunakan fungsi map:

// Pemetaan metode Anda
Flight::map('hello', function (string $name) {
  echo "hello $name!";
});

// Memanggil metode kustom Anda
Flight::hello('Bob');

Meskipun dimungkinkan untuk membuat metode kustom sederhana, disarankan untuk hanya membuat fungsi standar di PHP. Ini memiliki autocomplete di IDE dan lebih mudah dibaca. Padanan dari kode di atas adalah:

function hello(string $name) {
  echo "hello $name!";
}

hello('Bob');

Ini lebih sering digunakan ketika Anda perlu melewatkan variabel ke dalam metode Anda untuk mendapatkan nilai yang diharapkan. Menggunakan metode register() seperti di bawah ini lebih untuk melewatkan konfigurasi dan kemudian memanggil kelas yang telah dipra-konfigurasi.

Mendaftar Kelas

Untuk mendaftarkan kelas Anda sendiri dan mengonfigurasinya, Anda menggunakan fungsi register:

// Mendaftar kelas Anda
Flight::register('user', User::class);

// Mendapatkan instance dari kelas Anda
$user = Flight::user();

Metode register juga memungkinkan Anda untuk melewatkan parameter ke konstruktor kelas Anda. Jadi ketika Anda memuat kelas kustom Anda, itu akan datang dengan pra-inisialisasi. Anda dapat mendefinisikan parameter konstruktor dengan melewatkan array tambahan. Berikut adalah contoh memuat koneksi database:

// Mendaftar kelas dengan parameter konstruktor
Flight::register('db', PDO::class, ['mysql:host=localhost;dbname=test', 'user', 'pass']);

// Mendapatkan instance dari kelas Anda
// Ini akan membuat objek dengan parameter yang telah ditentukan
//
// new PDO('mysql:host=localhost;dbname=test','user','pass');
//
$db = Flight::db();

// dan jika Anda memerlukannya nanti dalam kode Anda, Anda hanya perlu memanggil metode yang sama sekali lagi
class SomeController {
  public function __construct() {
    $this->db = Flight::db();
  }
}

Jika Anda melewatkan parameter callback tambahan, itu akan dieksekusi segera setelah konstruktor kelas. Ini memungkinkan Anda untuk melakukan prosedur persiapan untuk objek baru Anda. Fungsi callback mengambil satu parameter, sebuah instance dari objek baru.

// Callback akan menerima objek yang telah dibangun
Flight::register(
  'db',
  PDO::class,
  ['mysql:host=localhost;dbname=test', 'user', 'pass'],
  function (PDO $db) {
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
);

Secara default, setiap kali Anda memuat kelas Anda, Anda akan mendapatkan instance bersama. Untuk mendapatkan instance baru dari kelas, cukup melewatkan false sebagai parameter:

// Instance bersama dari kelas
$shared = Flight::db();

// Instance baru dari kelas
$new = Flight::db(false);

Ingat bahwa metode yang dipetakan memiliki prioritas lebih tinggi daripada kelas yang terdaftar. Jika Anda mendeklarasikan keduanya dengan nama yang sama, hanya metode yang dipetakan yang akan dipanggil.

Mengganti Metode Framework

Flight memungkinkan Anda untuk mengganti fungsionalitas bawaannya sesuai kebutuhan Anda sendiri, tanpa harus memodifikasi kode apa pun. Anda dapat melihat semua metode yang dapat Anda ganti di sini.

Sebagai contoh, ketika Flight tidak dapat mencocokkan URL dengan rute, ia memanggil metode notFound yang mengirimkan respons HTTP 404 umum. Anda dapat mengganti perilaku ini dengan menggunakan metode map:

Flight::map('notFound', function() {
  // Tampilkan halaman 404 kustom
  include 'errors/404.html';
});

Flight juga memungkinkan Anda untuk mengganti komponen inti dari framework. Sebagai contoh, Anda dapat mengganti kelas Router standar dengan kelas kustom Anda sendiri:

// Mendaftar kelas kustom Anda
Flight::register('router', MyRouter::class);

// Ketika Flight memuat instance Router, itu akan memuat kelas Anda
$myrouter = Flight::router();

Namun, metode-framework seperti map dan register tidak dapat diganti. Anda akan mendapatkan kesalahan jika mencoba melakukannya.

Learn/flight_vs_slim

Flight vs Slim

Apa itu Slim?

Slim adalah kerangka mikro PHP yang membantu Anda dengan cepat menulis aplikasi web dan API yang sederhana namun kuat.

Banyak inspirasi untuk beberapa fitur v3 dari Flight sebenarnya datang dari Slim. Pengelompokan rute, dan menjalankan middleware dalam urutan tertentu adalah dua fitur yang terinspirasi oleh Slim. Slim v3 diluncurkan dengan mengutamakan kesederhanaan, tetapi terdapat ulasan campuran mengenai v4.

Kelebihan dibandingkan Flight

Kekurangan dibandingkan Flight

Learn/autoloading

Autoloading

Autoloading adalah konsep dalam PHP di mana Anda menentukan satu direktori atau beberapa direktori untuk memuat kelas. Ini jauh lebih menguntungkan daripada menggunakan require atau include untuk memuat kelas. Ini juga merupakan persyaratan untuk menggunakan paket Composer.

Secara default, setiap kelas Flight dimuat otomatis untuk Anda berkat composer. Namun, jika Anda ingin memuat otomatis kelas Anda sendiri, Anda dapat menggunakan metode Flight::path() untuk menentukan direktori yang akan memuat kelas.

Contoh Dasar

Mari kita anggap kita memiliki pohon direktori seperti berikut:

# Contoh path
/home/user/project/my-flight-project/
├── app
│   ├── cache
│   ├── config
│   ├── controllers - berisi kontroler untuk proyek ini
│   ├── translations
│   ├── UTILS - berisi kelas untuk aplikasi ini saja (ini huruf kapital semua dengan tujuan sebagai contoh nanti)
│   └── views
└── public
    └── css
    └── js
    └── index.php

Anda mungkin telah memperhatikan bahwa ini adalah struktur file yang sama dengan situs dokumentasi ini.

Anda dapat menentukan setiap direktori untuk dimuat dari seperti ini:


/**
 * public/index.php
 */

// Tambahkan path ke autoloader
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');

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

// tidak ada namespace yang diperlukan

// Semua kelas yang dimuat otomatis disarankan untuk menggunakan Pascal Case (setiap kata dengan huruf kapital, tanpa spasi)
// Mulai dari 3.7.2, Anda dapat menggunakan Pascal_Snake_Case untuk nama kelas Anda dengan menjalankan Loader::setV2ClassLoading(false);
class MyController {

    public function index() {
        // lakukan sesuatu
    }
}

Namespace

Jika Anda memiliki namespace, sebenarnya menjadi sangat mudah untuk menerapkan ini. Anda harus menggunakan metode Flight::path() untuk menentukan direktori root (bukan document root atau folder public/) aplikasi Anda.


/**
 * public/index.php
 */

// Tambahkan path ke autoloader
Flight::path(__DIR__.'/../');

Sekarang inilah yang mungkin terlihat seperti kontroler Anda. Lihat contoh di bawah ini, tetapi perhatikan komentar untuk informasi penting.

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

// namespace diperlukan
// namespace sama dengan struktur direktori
// namespace harus mengikuti huruf besar yang sama dengan struktur direktori
// namespace dan direktori tidak dapat memiliki garis bawah (kecuali Loader::setV2ClassLoading(false) diset)
namespace app\controllers;

// Semua kelas yang dimuat otomatis disarankan untuk menggunakan Pascal Case (setiap kata dengan huruf kapital, tanpa spasi)
// Mulai dari 3.7.2, Anda dapat menggunakan Pascal_Snake_Case untuk nama kelas Anda dengan menjalankan Loader::setV2ClassLoading(false);
class MyController {

    public function index() {
        // lakukan sesuatu
    }
}

Dan jika Anda ingin memuat otomatis kelas di direktori utilitas Anda, Anda akan melakukan hal yang hampir sama:


/**
 * app/UTILS/ArrayHelperUtil.php
 */

// namespace harus cocok dengan struktur direktori dan huruf besar (perhatikan direktori UTILS semua huruf kapital
//     seperti pada pohon file di atas)
namespace app\UTILS;

class ArrayHelperUtil {

    public function changeArrayCase(array $array) {
        // lakukan sesuatu
    }
}

Garis Bawah dalam Nama Kelas

Mulai dari 3.7.2, Anda dapat menggunakan Pascal_Snake_Case untuk nama kelas Anda dengan menjalankan Loader::setV2ClassLoading(false);. Ini akan memungkinkan Anda untuk menggunakan garis bawah dalam nama kelas Anda. Ini tidak disarankan, tetapi tersedia untuk mereka yang membutuhkannya.


/**
 * public/index.php
 */

// Tambahkan path ke autoloader
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');
Loader::setV2ClassLoading(false);

/**
 * app/controllers/My_Controller.php
 */

// tidak ada namespace yang diperlukan

class My_Controller {

    public function index() {
        // lakukan sesuatu
    }
}

Learn/troubleshooting

Pemecahan Masalah

Halaman ini akan membantu Anda memecahkan masalah umum yang mungkin Anda temui saat menggunakan Flight.

Masalah Umum

404 Tidak Ditemukan atau Perilaku Rute Tak Terduga

Jika Anda melihat kesalahan 404 Tidak Ditemukan (tetapi Anda bersumpah bahwa itu benar-benar ada dan bukan kesalahan ketik) ini sebenarnya bisa menjadi masalah dengan Anda yang mengembalikan nilai di titik akhir rute Anda alih-alih hanya mencetaknya. Alasan untuk ini adalah disengaja tetapi bisa mengganggu beberapa pengembang.


Flight::route('/hello', function(){
    // Ini mungkin menyebabkan kesalahan 404 Tidak Ditemukan
    return 'Hello World';
});

// Apa yang mungkin Anda inginkan
Flight::route('/hello', function(){
    echo 'Hello World';
});

Alasan untuk ini adalah karena mekanisme khusus yang dibangun ke dalam router yang menangani keluaran pengembalian sebagai sinyal untuk "melanjutkan ke rute berikutnya". Anda dapat melihat perilaku ini didokumentasikan di bagian Routing.

Kelas Tidak Ditemukan (autoloading tidak bekerja)

Ada beberapa alasan mengapa ini tidak terjadi. Di bawah ini adalah beberapa contoh tetapi pastikan Anda juga memeriksa bagian autoloading.

Nama File yang Salah

Yang paling umum adalah bahwa nama kelas tidak cocok dengan nama file.

Jika Anda memiliki kelas bernama MyClass maka file tersebut harus dinamai MyClass.php. Jika Anda memiliki kelas bernama MyClass dan file tersebut dinamai myclass.php maka autoloader tidak akan dapat menemukannya.

Namespace yang Salah

Jika Anda menggunakan namespace, maka namespace harus cocok dengan struktur direktori.

// kode

// jika MyController Anda berada di direktori app/controllers dan memiliki namespace
// ini tidak akan berfungsi.
Flight::route('/hello', 'MyController->hello');

// Anda perlu memilih salah satu dari opsi ini
Flight::route('/hello', 'app\controllers\MyController->hello');
// atau jika Anda memiliki pernyataan use di atas

use app\controllers\MyController;

Flight::route('/hello', [ MyController::class, 'hello' ]);
// juga bisa ditulis
Flight::route('/hello', MyController::class.'->hello');
// juga...
Flight::route('/hello', [ 'app\controllers\MyController', 'hello' ]);

path() tidak didefinisikan

Dalam aplikasi kerangka kerja, ini didefinisikan di dalam file config.php, tetapi agar kelas Anda dapat ditemukan, Anda perlu memastikan bahwa metode path() didefinisikan (kemungkinan ke root direktori Anda) sebelum Anda mencoba menggunakannya.


// Tambahkan path ke autoloader
Flight::path(__DIR__.'/../');

License

Lisensi MIT (MIT)

Hak Cipta © 2024 @mikecao, @n0nag0n

Izin diberikan di sini, tanpa biaya, kepada setiap orang yang mendapatkan salinan perangkat lunak ini dan dokumentasi terkait (disebut "Perangkat Lunak"), untuk berurusan dengan Perangkat Lunak tanpa pembatasan, termasuk tanpa batasan hak untuk menggunakan, menyalin, memodifikasi, menggabungkan, menerbitkan, mendistribusikan, sublisensikan, dan/atau menjual salinan Perangkat Lunak, dan untuk mengizinkan orang-orang yang menerima Perangkat Lunak untuk melakukannya, dengan syarat berikut:

Pemberitahuan hak cipta di atas dan pemberitahuan izin ini harus disertakan dalam semua salinan atau bagian substansial dari Perangkat Lunak.

PERANGKAT LUNAK DIBERIKAN "SEBAGAIMANA ADANYA", TANPA JAMINAN DALAM BENTUK APAPUN, TERSURAT ATAU TERSIRAT, TERMASUK NAMUN TIDAK TERBATAS PADA JAMINAN KELAYAKAN PERDAGANGAN, KECOCOKAN UNTUK TUJUAN TERTENTU DAN TIDAK MELANGGAR. DALAM HAL APA PUN PENULIS ATAU PEMEGANG HAK CIPTA TIDAK BERTANGGUNG JAWAB ATAS CLAIM, KERUSAKAN ATAU TANGGUNG JAWAB LAINNYA, BAIK DALAM TINDAKAN KONTRAK, TORT ATAU SEBALIKNYA, YANG TIMBUL DARI, DARI ATAU SEHUBUNGAN DENGAN PERANGKAT LUNAK ATAU PENGGUNAAN ATAU TRANSAKSI LAINNYA DALAM PERANGKAT LUNAK.

About

Apa itu Flight?

Flight adalah framework PHP yang cepat, sederhana, dan dapat diperluas. Ini cukup serbaguna dan dapat digunakan untuk membangun jenis aplikasi web apa pun. Ia dibangun dengan kesederhanaan dalam pikiran dan ditulis dengan cara yang mudah dipahami dan digunakan.

Flight adalah framework yang hebat untuk pemula yang baru mengenal PHP dan ingin belajar cara membangun aplikasi web. Ini juga merupakan framework yang hebat untuk pengembang berpengalaman yang ingin memiliki lebih banyak kontrol atas aplikasi web mereka. Ini dirancang untuk dengan mudah membangun API RESTful, aplikasi web sederhana, atau aplikasi web yang kompleks.

Mulai Cepat

<?php

// jika dipasang dengan composer
require 'vendor/autoload.php';
// atau jika dipasang secara manual dengan file zip
// require 'flight/Flight.php';

Flight::route('/', function() {
  echo 'halo dunia!';
});

Flight::route('/json', function() {
  Flight::json(['halo' => 'dunia']);
});

Flight::start();

Aplikasi Skeleton/Boilerplate

Ada aplikasi contoh yang dapat membantu Anda memulai dengan Flight Framework. Kunjungi flightphp/skeleton untuk petunjuk tentang cara memulai! Anda juga dapat mengunjungi halaman contoh untuk inspirasi tentang beberapa hal yang dapat Anda lakukan dengan Flight.

Komunitas

Kami ada di Matrix Chat bersama kami di #flight-php-framework:matrix.org.

Kontribusi

Ada dua cara Anda dapat berkontribusi pada Flight:

  1. Anda dapat berkontribusi pada framework inti dengan mengunjungi repositori inti.
  2. Anda dapat berkontribusi pada dokumentasi. Situs web dokumentasi ini dihosting di Github. Jika Anda melihat kesalahan atau ingin mengembangkan sesuatu yang lebih baik, silakan untuk memperbaikinya dan kirimkan permintaan tarik! Kami berusaha untuk terus mengikuti hal-hal tersebut, tetapi pembaruan dan terjemahan bahasa sangat diterima.

Persyaratan

Flight memerlukan PHP 7.4 atau yang lebih besar.

Catatan: PHP 7.4 didukung karena pada saat penulisan ini (2024) PHP 7.4 adalah versi default untuk beberapa distribusi Linux LTS. Memaksa migrasi ke PHP >8 dapat menyebabkan banyak masalah bagi pengguna tersebut. Framework ini juga mendukung PHP >8.

Lisensi

Flight dirilis di bawah lisensi MIT.

Awesome-plugins/php_cookie

Cookies

overclokk/cookie adalah perpustakaan sederhana untuk mengelola cookie dalam aplikasi Anda.

Instalasi

Instalasi sangat sederhana dengan composer.

composer require overclokk/cookie

Penggunaan

Penggunaan semudah mendaftarkan metode baru pada kelas Flight.


use Overclokk\Cookie\Cookie;

/*
 * Set di file bootstrap atau public/index.php Anda
 */

Flight::register('cookie', Cookie::class);

/**
 * ExampleController.php
 */

class ExampleController {
    public function login() {
        // Set sebuah cookie

        // Anda ingin ini menjadi false agar Anda mendapatkan instance baru
        // gunakan komentar di bawah jika Anda ingin autocomplete
        /** @var \Overclokk\Cookie\Cookie $cookie */
        $cookie = Flight::cookie(false);
        $cookie->set(
            'stay_logged_in', // nama cookie
            '1', // nilai yang ingin Anda atur
            86400, // jumlah detik cookie harus bertahan
            '/', // jalur yang akan tersedia untuk cookie
            'example.com', // domain yang akan tersedia untuk cookie
            true, // cookie hanya akan ditransmisikan melalui koneksi HTTPS yang aman
            true // cookie hanya akan tersedia melalui protokol HTTP
        );

        // opsional, jika Anda ingin mempertahankan nilai default
        // dan memiliki cara cepat untuk mengatur cookie untuk waktu yang lama
        $cookie->forever('stay_logged_in', '1');
    }

    public function home() {
        // Periksa apakah Anda memiliki cookie
        if (Flight::cookie()->has('stay_logged_in')) {
            // tempatkan mereka di area dasbor misalnya.
            Flight::redirect('/dashboard');
        }
    }
}

Awesome-plugins/php_encryption

Enkripsi PHP

defuse/php-encryption adalah perpustakaan yang dapat digunakan untuk mengenkripsi dan mendekripsi data. Memulai dan menjalankan cukup sederhana untuk mulai mengenkripsi dan mendekripsi data. Mereka memiliki tutorial yang sangat membantu menjelaskan dasar-dasar cara menggunakan perpustakaan serta implikasi keamanan penting terkait enkripsi.

Instalasi

Instalasi sangat sederhana dengan composer.

composer require defuse/php-encryption

Pengaturan

Kemudian Anda perlu menghasilkan kunci enkripsi.

vendor/bin/generate-defuse-key

Ini akan menghasilkan kunci yang perlu Anda simpan dengan aman. Anda bisa menyimpan kunci di file app/config/config.php Anda di array di bagian bawah file. Meskipun itu bukan tempat yang sempurna, paling tidak itu adalah sesuatu.

Penggunaan

Sekarang Anda memiliki perpustakaan dan kunci enkripsi, Anda dapat mulai mengenkripsi dan mendekripsi data.


use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

/*
 * Tetapkan di file bootstrap atau public/index.php Anda
 */

// Metode enkripsi
Flight::map('encrypt', function($raw_data) {
    $encryption_key = /* $config['encryption_key'] atau file_get_contents tempat Anda meletakkan kunci */;
    return Crypto::encrypt($raw_data, Key::loadFromAsciiSafeString($encryption_key));
});

// Metode dekripsi
Flight::map('decrypt', function($encrypted_data) {
    $encryption_key = /* $config['encryption_key'] atau file_get_contents tempat Anda meletakkan kunci */;
    try {
        $raw_data = Crypto::decrypt($encrypted_data, Key::loadFromAsciiSafeString($encryption_key));
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
        // Sebuah serangan! Entah kunci yang salah dimuat, atau ciphertext telah
        // berubah sejak dibuat -- baik rusak di database atau
        // sengaja dimodifikasi oleh Eve yang mencoba melakukan serangan.

        // ... tangani kasus ini dengan cara yang sesuai untuk aplikasi Anda ...
    }
    return $raw_data;
});

Flight::route('/encrypt', function() {
    $encrypted_data = Flight::encrypt('Ini adalah rahasia');
    echo $encrypted_data;
});

Flight::route('/decrypt', function() {
    $encrypted_data = '...'; // Ambil data terenkripsi dari suatu tempat
    $decrypted_data = Flight::decrypt($encrypted_data);
    echo $decrypted_data;
});

Awesome-plugins/php_file_cache

Wruczek/PHP-File-Cache

Kelas caching in-file PHP yang ringan, sederhana, dan mandiri

Keuntungan

Klik di sini untuk melihat kode.

Instalasi

Instal melalui composer:

composer require wruczek/php-file-cache

Penggunaan

Penggunaan cukup sederhana.

use Wruczek\PhpFileCache\PhpFileCache;

$app = Flight::app();

// Anda mengirimkan direktori tempat cache akan disimpan ke dalam konstruktor
$app->register('cache', PhpFileCache::class, [ __DIR__ . '/../cache/' ], function(PhpFileCache $cache) {

    // Ini memastikan bahwa cache hanya digunakan saat dalam mode produksi
    // ENVIRONMENT adalah sebuah konstanta yang diatur dalam file bootstrap Anda atau di tempat lain dalam aplikasi Anda
    $cache->setDevMode(ENVIRONMENT === 'development');
});

Kemudian Anda dapat menggunakannya dalam kode Anda seperti ini:


// Ambil instance cache
$cache = Flight::cache();
$data = $cache->refreshIfExpired('simple-cache-test', function () {
    return date("H:i:s"); // mengembalikan data untuk dicache
}, 10); // 10 detik

// atau
$data = $cache->retrieve('simple-cache-test');
if(empty($data)) {
    $data = date("H:i:s");
    $cache->store('simple-cache-test', $data, 10); // 10 detik
}

Dokumentasi

Kunjungi https://github.com/Wruczek/PHP-File-Cache untuk dokumentasi lengkap dan pastikan Anda melihat folder contoh.

Awesome-plugins/permissions

FlightPHP/Permissions

Ini adalah modul izin yang dapat digunakan dalam proyek Anda jika Anda memiliki beberapa peran di aplikasi Anda dan setiap peran memiliki sedikit fungsi yang berbeda. Modul ini memungkinkan Anda untuk mendefinisikan izin untuk setiap peran dan kemudian memeriksa apakah pengguna saat ini memiliki izin untuk mengakses halaman tertentu atau melakukan tindakan tertentu.

Klik di sini untuk repositori di GitHub.

Instalasi

Jalankan composer require flightphp/permissions dan Anda sudah siap!

Penggunaan

Pertama, Anda perlu mengatur izin Anda, lalu Anda memberi tahu aplikasi Anda apa arti izin tersebut. Pada akhirnya, Anda akan memeriksa izin Anda dengan $Permissions->has(), ->can(), atau is(). has() dan can() memiliki fungsionalitas yang sama, tetapi dinamai berbeda untuk membuat kode Anda lebih mudah dibaca.

Contoh Dasar

Mari kita anggap Anda memiliki fitur dalam aplikasi Anda yang memeriksa apakah seorang pengguna sudah masuk. Anda dapat membuat objek izin seperti ini:

// index.php
require 'vendor/autoload.php';

// beberapa kode

// lalu Anda mungkin memiliki sesuatu yang memberi tahu Anda siapa peran saat ini dari orang tersebut
// kemungkinan Anda memiliki sesuatu di mana Anda mengambil peran saat ini
// dari variabel sesi yang mendefinisikan ini
// setelah seseorang masuk, jika tidak, mereka akan memiliki peran 'tamu' atau 'publik'.
$current_role = 'admin';

// mengatur izin
$permission = new \flight\Permission($current_role);
$permission->defineRule('loggedIn', function($current_role) {
    return $current_role !== 'guest';
});

// Anda mungkin ingin menyimpan objek ini di Flight di suatu tempat
Flight::set('permission', $permission);

Kemudian di dalam controller di suatu tempat, Anda mungkin memiliki sesuatu seperti ini.

<?php

// beberapa controller
class SomeController {
    public function someAction() {
        $permission = Flight::get('permission');
        if ($permission->has('loggedIn')) {
            // lakukan sesuatu
        } else {
            // lakukan sesuatu yang lain
        }
    }
}

Anda juga dapat menggunakan ini untuk melacak apakah mereka memiliki izin untuk melakukan sesuatu dalam aplikasi Anda. Sebagai contoh, jika Anda memiliki cara bagi pengguna untuk berinteraksi dengan posting di perangkat lunak Anda, Anda dapat memeriksa apakah mereka memiliki izin untuk melakukan tindakan tertentu.

$current_role = 'admin';

// mengatur izin
$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);

Kemudian di dalam controller di suatu tempat...

class PostController {
    public function create() {
        $permission = Flight::get('permission');
        if ($permission->can('post.create')) {
            // lakukan sesuatu
        } else {
            // lakukan sesuatu yang lain
        }
    }
}

Menginjeksi ketergantungan

Anda dapat menginjeksi ketergantungan ke dalam closure yang mendefinisikan izin. Ini berguna jika Anda memiliki semacam toggle, id, atau titik data lain yang ingin Anda periksa. Hal ini juga berlaku untuk panggilan jenis Class->Method, kecuali Anda mendefinisikan argumen dalam metode tersebut.

Closure

$Permission->defineRule('order', function(string $current_role, MyDependency $MyDependency = null) {
    // ... kode
});

// di file controller Anda
public function createOrder() {
    $MyDependency = Flight::myDependency();
    $permission = Flight::get('permission');
    if ($permission->can('order.create', $MyDependency)) {
        // lakukan sesuatu
    } else {
        // lakukan sesuatu yang lain
    }
}

Kelas

namespace MyApp;

class Permissions {

    public function order(string $current_role, MyDependency $MyDependency = null) {
        // ... kode
    }
}

Pintasan untuk mengatur izin dengan kelas

Anda juga dapat menggunakan kelas untuk mendefinisikan izin Anda. Ini berguna jika Anda memiliki banyak izin dan Anda ingin menjaga kode Anda tetap bersih. Anda bisa melakukan sesuatu seperti ini:

<?php

// kode bootstrap
$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) {
        // Mengasumsikan Anda telah mengatur ini sebelumnya
        /** @var \flight\database\PdoWrapper $db */
        $db = Flight::db();
        $allowed_permissions = [ 'read' ]; // semua orang dapat melihat sebuah pesanan
        if($current_role === 'manager') {
            $allowed_permissions[] = 'create'; // manajer dapat membuat pesanan
        }
        $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'; // jika pengguna memiliki toggle khusus, mereka dapat memperbarui pesanan
        }
        if($current_role === 'admin') {
            $allowed_permissions[] = 'delete'; // admin dapat menghapus pesanan
        }
        return $allowed_permissions;
    }
}

Bagian yang keren adalah bahwa ada juga pintasan yang dapat Anda gunakan (yang juga dapat dicache!!!) di mana Anda cukup memberi tahu kelas izin untuk memetakan semua metode dalam sebuah kelas ke dalam izin. Jadi jika Anda memiliki metode bernama order() dan metode bernama company(), ini akan secara otomatis dipetakan sehingga Anda cukup menjalankan $Permissions->has('order.read') atau $Permissions->has('company.read') dan itu akan berhasil. Mendefinisikan ini sangat sulit, jadi ikutlah bersama saya di sini. Anda hanya perlu melakukan ini:

Buat kelas izin yang ingin Anda kelompokkan bersama.

class MyPermissions {
    public function order(string $current_role, int $order_id = 0): array {
        // kode untuk menentukan izin
        return $permissions_array;
    }

    public function company(string $current_role, int $company_id): array {
        // kode untuk menentukan izin
        return $permissions_array;
    }
}

Kemudian buat izin tersebut dapat ditemukan menggunakan pustaka ini.

$Permissions = new \flight\Permission($current_role);
$Permissions->defineRulesFromClassMethods(MyApp\Permissions::class);
Flight::set('permissions', $Permissions);

Akhirnya, panggil izin di basis kode Anda untuk memeriksa apakah pengguna diizinkan untuk melakukan izin tertentu.

class SomeController {
    public function createOrder() {
        if(Flight::get('permissions')->can('order.create') === false) {
            die('Anda tidak bisa membuat sebuah pesanan. Maaf!');
        }
    }
}

Cache

Untuk mengaktifkan caching, lihat pustaka sederhana wruczak/phpfilecache. Contoh untuk mengaktifkannya ada di bawah ini.


// $app ini bisa menjadi bagian dari kode Anda, atau
// Anda bisa langsung meneruskan null dan itu akan
// mengambil dari Flight::app() di dalam konstruktor
$app = Flight::app();

// Untuk saat ini, ini menerima sebagai cache file. Lainnya dapat dengan mudah
// ditambahkan di masa depan. 
$Cache = new Wruczek\PhpFileCache\PhpFileCache;

$Permissions = new \flight\Permission($current_role, $app, $Cache);
$Permissions->defineRulesFromClassMethods(MyApp\Permissions::class, 3600); // 3600 adalah berapa detik untuk menyimpan cache ini. Biarkan ini kosong untuk tidak menggunakan caching

Dan Anda sudah siap!

Awesome-plugins/pdo_wrapper

Kelas Pembantu PDO PdoWrapper

Flight hadir dengan kelas pembantu untuk PDO. Kelas ini memungkinkan Anda untuk dengan mudah melakukan kueri ke basis data Anda dengan semua persiapan/eksekusi/fetchAll() yang membingungkan. Ini sangat menyederhanakan cara Anda dapat melakukan kueri ke basis data Anda. Setiap hasil baris dikembalikan sebagai kelas Koleksi Flight yang memungkinkan Anda mengakses data Anda melalui sintaks array atau sintaks objek.

Mendaftar Kelas Pembantu PDO

// Daftarkan kelas pembantu 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
    ]
]);

Penggunaan

Objek ini memperluas PDO sehingga semua metode PDO normal tersedia. Metode berikut ditambahkan untuk mempermudah kueri ke basis data:

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

Gunakan ini untuk INSERTS, UPDATES, atau jika Anda berencana menggunakan SELECT dalam loop while

$db = Flight::db();
$statement = $db->runQuery("SELECT * FROM table WHERE something = ?", [ $something ]);
while($row = $statement->fetch()) {
    // ...
}

// Atau menulis ke basis data
$db->runQuery("INSERT INTO table (name) VALUES (?)", [ $name ]);
$db->runQuery("UPDATE table SET name = ? WHERE id = ?", [ $name, $id ]);

fetchField(string $sql, array $params = []): mixed

Mengambil field pertama dari kueri

$db = Flight::db();
$count = $db->fetchField("SELECT COUNT(*) FROM table WHERE something = ?", [ $something ]);

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

Mengambil satu baris dari kueri

$db = Flight::db();
$row = $db->fetchRow("SELECT id, name FROM table WHERE id = ?", [ $id ]);
echo $row['name'];
// atau
echo $row->name;

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

Mengambil semua baris dari kueri

$db = Flight::db();
$rows = $db->fetchAll("SELECT id, name FROM table WHERE something = ?", [ $something ]);
foreach($rows as $row) {
    echo $row['name'];
    // atau
    echo $row->name;
}

Catatan dengan sintaks IN()

Ini juga memiliki pembungkus yang berguna untuk pernyataan IN(). Anda cukup memasukkan tanda tanya tunggal sebagai placeholder untuk IN() dan kemudian array nilai. Berikut adalah contoh seperti apa itu:

$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 ]);

Contoh Lengkap

// Contoh rute dan cara Anda akan menggunakan pembungkus ini
Flight::route('/users', function () {
    // Dapatkan semua pengguna
    $users = Flight::db()->fetchAll('SELECT * FROM users');

    // Streaming semua pengguna
    $statement = Flight::db()->runQuery('SELECT * FROM users');
    while ($user = $statement->fetch()) {
        echo $user['name'];
        // atau echo $user->name;
    }

    // Dapatkan satu pengguna
    $user = Flight::db()->fetchRow('SELECT * FROM users WHERE id = ?', [123]);

    // Dapatkan satu nilai
    $count = Flight::db()->fetchField('SELECT COUNT(*) FROM users');

    // Sintaks IN() khusus untuk membantu (pastikan IN ditulis dengan huruf kapital)
    $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [[1,2,3,4,5]]);
    // Anda juga dapat melakukan ini
    $users = Flight::db()->fetchAll('SELECT * FROM users WHERE id IN (?)', [ '1,2,3,4,5']);

    // Memasukkan pengguna baru
    Flight::db()->runQuery("INSERT INTO users (name, email) VALUES (?, ?)", ['Bob', 'bob@example.com']);
    $insert_id = Flight::db()->lastInsertId();

    // Memperbarui pengguna
    Flight::db()->runQuery("UPDATE users SET name = ? WHERE id = ?", ['Bob', 123]);

    // Menghapus pengguna
    Flight::db()->runQuery("DELETE FROM users WHERE id = ?", [123]);

    // Dapatkan jumlah baris yang terpengaruh
    $statement = Flight::db()->runQuery("UPDATE users SET name = ? WHERE name = ?", ['Bob', 'Sally']);
    $affected_rows = $statement->rowCount();

});

Awesome-plugins/session

Ghostff/Session

Manajer Sesi PHP (non-blocking, flash, segmen, enkripsi sesi). Menggunakan PHP open_ssl untuk enkripsi/dekripsi data sesi secara opsional. Mendukung File, MySQL, Redis, dan Memcached.

Klik di sini untuk melihat kodenya.

Instalasi

Install menggunakan composer.

composer require ghostff/session

Konfigurasi Dasar

Anda tidak perlu meneruskan apapun untuk menggunakan pengaturan default dengan sesi Anda. Anda dapat membaca lebih banyak tentang pengaturan di Github Readme.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('session', Session::class);

// satu hal yang perlu diingat adalah bahwa Anda harus mengkomit sesi Anda pada setiap pemuatan halaman
// atau Anda perlu menjalankan auto_commit dalam konfigurasi Anda.

Contoh Sederhana

Berikut adalah contoh sederhana tentang bagaimana Anda mungkin menggunakan ini.

Flight::route('POST /login', function() {
    $session = Flight::session();

    // lakukan logika login Anda di sini
    // validasi kata sandi, dll.

    // jika login berhasil
    $session->set('is_logged_in', true);
    $session->set('user', $user);

    // setiap kali Anda menulis ke sesi, Anda harus mengkomitnya secara sengaja.
    $session->commit();
});

// Pemeriksaan ini bisa ada dalam logika halaman terbatas, atau dibungkus dengan middleware.
Flight::route('/some-restricted-page', function() {
    $session = Flight::session();

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

    // lakukan logika halaman terbatas Anda di sini
});

// versi middleware
Flight::route('/some-restricted-page', function() {
    // logika halaman reguler
})->addMiddleware(function() {
    $session = Flight::session();

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

Contoh yang Lebih Kompleks

Berikut adalah contoh yang lebih kompleks tentang bagaimana Anda mungkin menggunakan ini.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

// atur path kustom untuk file konfigurasi sesi Anda dan berikan string acak untuk id sesi
$app->register('session', Session::class, [ 'path/to/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) {
        // atau Anda dapat secara manual menimpa opsi konfigurasi
        $session->updateConfiguration([
            // jika Anda ingin menyimpan data sesi Anda dalam database (baik jika Anda ingin sesuatu seperti, "keluarkan saya dari semua perangkat" fungsionalitas)
            Session::CONFIG_DRIVER        => Ghostff\Session\Drivers\MySql::class,
            Session::CONFIG_ENCRYPT_DATA  => true,
            Session::CONFIG_SALT_KEY      => hash('sha256', 'my-super-S3CR3T-salt'), // silakan ganti ini menjadi sesuatu yang lain
            Session::CONFIG_AUTO_COMMIT   => true, // hanya lakukan ini jika memerlukannya dan/atau sulit untuk mengkomit sesi Anda.
                                                   // tambahan Anda bisa melakukan Flight::after('start', function() { Flight::session()->commit(); });
            Session::CONFIG_MYSQL_DS         => [
                'driver'    => 'mysql',             # Driver database untuk dns PDO eg(mysql:host=...;dbname=...)
                'host'      => '127.0.0.1',         # Host database
                'db_name'   => 'my_app_database',   # Nama database
                'db_table'  => 'sessions',          # Tabel database
                'db_user'   => 'root',              # Nama pengguna database
                'db_pass'   => '',                  # Kata sandi database
                'persistent_conn'=> false,          # Hindari biaya overhead untuk membuat koneksi baru setiap kali skrip perlu berbicara ke database, yang mengakibatkan aplikasi web yang lebih cepat. TEMUKAN BELAKANGNYA SENDIRI
            ]
        ]);
    }
);

Bantuan! Data Sesi Saya Tidak Persisten!

Apakah Anda mengatur data sesi Anda dan tidak persisten antara permintaan? Anda mungkin lupa untuk mengkomit data sesi Anda. Anda dapat melakukan ini dengan memanggil $session->commit() setelah Anda mengatur data sesi Anda.

Flight::route('POST /login', function() {
    $session = Flight::session();

    // lakukan logika login Anda di sini
    // validasi kata sandi, dll.

    // jika login berhasil
    $session->set('is_logged_in', true);
    $session->set('user', $user);

    // setiap kali Anda menulis ke sesi, Anda harus mengkomitnya secara sengaja.
    $session->commit();
});

Cara lain untuk mengatasi ini adalah ketika Anda mengatur layanan sesi Anda, Anda harus mengatur auto_commit menjadi true dalam konfigurasi Anda. Ini akan secara otomatis mengkomit data sesi Anda setelah setiap permintaan.


$app->register('session', Session::class, [ 'path/to/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) {
        $session->updateConfiguration([
            Session::CONFIG_AUTO_COMMIT   => true,
        ]);
    }
);

Selain itu, Anda dapat melakukan Flight::after('start', function() { Flight::session()->commit(); }); untuk mengkomit data sesi Anda setelah setiap permintaan.

Dokumentasi

Kunjungi Github Readme untuk dokumentasi lengkap. Opsi konfigurasi didokumentasikan dengan baik dalam default_config.php file itu sendiri. Kodenya mudah untuk dipahami jika Anda ingin meneliti paket ini sendiri.

Awesome-plugins/runway

Jalur

Jalur adalah aplikasi CLI yang membantu Anda mengelola aplikasi Flight Anda. Ini dapat menghasilkan pengontrol, menampilkan semua rute, dan banyak lagi. Ini didasarkan pada pustaka adhocore/php-cli yang sangat baik.

Klik di sini untuk melihat kodenya.

Instalasi

Instal dengan composer.

composer require flightphp/runway

Konfigurasi Dasar

Kali pertama Anda menjalankan Jalur, itu akan memandu Anda melalui proses pengaturan dan membuat file konfigurasi .runway.json di akar proyek Anda. File ini akan berisi beberapa konfigurasi yang diperlukan agar Jalur berfungsi dengan baik.

Penggunaan

Jalur memiliki sejumlah perintah yang dapat Anda gunakan untuk mengelola aplikasi Flight Anda. Ada dua cara mudah untuk menggunakan Jalur.

  1. Jika Anda menggunakan proyek tulang, Anda dapat menjalankan php runway [command] dari akar proyek Anda.
  2. Jika Anda menggunakan Jalur sebagai paket yang diinstal melalui composer, Anda dapat menjalankan vendor/bin/runway [command] dari akar proyek Anda.

Untuk setiap perintah, Anda dapat melewatkan bendera --help untuk mendapatkan informasi lebih lanjut tentang cara menggunakan perintah tersebut.

php runway routes --help

Berikut adalah beberapa contoh:

Menghasilkan Pengontrol

Berdasarkan konfigurasi dalam file .runway.json Anda, lokasi default akan menghasilkan pengontrol untuk Anda di direktori app/controllers/.

php runway make:controller MyController

Menghasilkan Model Rekaman Aktif

Berdasarkan konfigurasi dalam file .runway.json Anda, lokasi default akan menghasilkan pengontrol untuk Anda di direktori app/records/.

php runway make:record users

Jika misalnya Anda memiliki tabel users dengan skema berikut: id, name, email, created_at, updated_at, sebuah file yang mirip dengan yang berikut akan dibuat di file app/records/UserRecord.php:

<?php

declare(strict_types=1);

namespace app\records;

/**
 * Kelas ActiveRecord untuk tabel users.
 * @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
 * // Anda juga bisa menambahkan hubungan di sini setelah Anda mendefinisikannya di array $relations
 * @property CompanyRecord $company Contoh hubungan
 */
class UserRecord extends \flight\ActiveRecord
{
    /**
     * @var array $relations Tetapkan hubungan untuk model
     *   https://docs.flightphp.com/awesome-plugins/active-record#relationships
     */
    protected array $relations = [];

    /**
     * Konstruktor
     * @param mixed $databaseConnection Koneksi ke database
     */
    public function __construct($databaseConnection)
    {
        parent::__construct($databaseConnection, 'users');
    }
}

Tampilkan Semua Rute

Ini akan menampilkan semua rute yang saat ini terdaftar dengan Flight.

php runway routes

Jika Anda ingin hanya melihat rute tertentu, Anda dapat melewatkan bendera untuk menyaring rute.

# Tampilkan hanya rute GET
php runway routes --get

# Tampilkan hanya rute POST
php runway routes --post

# dll.

Menyesuaikan Jalur

Jika Anda membuat paket untuk Flight, atau ingin menambahkan perintah kustom Anda sendiri ke dalam proyek Anda, Anda dapat melakukannya dengan membuat direktori src/commands/, flight/commands/, app/commands/, atau commands/ untuk proyek/paket Anda. Jika Anda memerlukan penyesuaian lebih lanjut, lihat bagian di bawah tentang Konfigurasi.

Untuk membuat perintah, Anda cukup memperluas kelas AbstractBaseCommand, dan menerapkan setidaknya metode __construct dan metode execute.

<?php

declare(strict_types=1);

namespace flight\commands;

class ExampleCommand extends AbstractBaseCommand
{
    /**
     * Konstruktor
     *
     * @param array<string,mixed> $config Konfigurasi JSON dari .runway-config.json
     */
    public function __construct(array $config)
    {
        parent::__construct('make:example', 'Buat contoh untuk dokumentasi', $config);
        $this->argument('<funny-gif>', 'Nama gif lucu');
    }

    /**
     * Menjalankan fungsi
     *
     * @return void
     */
    public function execute(string $controller)
    {
        $io = $this->app()->io();

        $io->info('Membuat contoh...');

        // Lakukan sesuatu di sini

        $io->ok('Contoh dibuat!');
    }
}

Lihat adhocore/php-cli Documentation untuk informasi lebih lanjut tentang cara membangun perintah kustom Anda sendiri ke dalam aplikasi Flight Anda!

Konfigurasi

Jika Anda perlu menyesuaikan konfigurasi untuk Jalur, Anda dapat membuat file .runway-config.json di akar proyek Anda. Di bawah ini adalah beberapa konfigurasi tambahan yang dapat Anda tetapkan:

{

    // Ini adalah tempat direktori aplikasi Anda berada
    "app_root": "app/",

    // Ini adalah direktori tempat file indeks akar Anda berada
    "index_root": "public/",

    // Ini adalah jalur ke akar proyek lainnya
    "root_paths": [
        "/home/user/different-project",
        "/var/www/another-project"
    ],

    // Jalur dasar kemungkinan besar tidak perlu dikonfigurasi, tapi ada di sini jika Anda menginginkannya
    "base_paths": {
        "/includes/libs/vendor", // jika Anda memiliki jalur yang sangat unik untuk direktori vendor Anda atau sesuatu
    },

    // Jalur akhir adalah lokasi dalam proyek untuk mencari file perintah
    "final_paths": {
        "src/diff-path/commands",
        "app/module/admin/commands",
    },

    // Jika Anda ingin hanya menambahkan jalur lengkap, silakan saja (absolut atau relatif terhadap akar proyek)
    "paths": [
        "/home/user/different-project/src/diff-path/commands",
        "/var/www/another-project/app/module/admin/commands",
        "app/my-unique-commands"
    ]
}

Awesome-plugins/tracy_extensions

Tracy Flight Panel Extensions

Ini adalah serangkaian ekstensi untuk membuat kerja dengan Flight sedikit lebih kaya.

Ini adalah Panel

Flight Bar

Dan setiap panel menampilkan informasi yang sangat berguna tentang aplikasi Anda!

Flight Data Flight Database Flight Request

Klik di sini untuk melihat kode.

Instalasi

Jalankan composer require flightphp/tracy-extensions --dev dan Anda sudah siap!

Konfigurasi

Ada sangat sedikit konfigurasi yang perlu Anda lakukan untuk memulai ini. Anda perlu memulai debugger Tracy sebelum menggunakan ini https://tracy.nette.org/en/guide:

<?php

use Tracy\Debugger;
use flight\debug\tracy\TracyExtensionLoader;

// kode bootstrap
require __DIR__ . '/vendor/autoload.php';

Debugger::enable();
// Anda mungkin perlu menentukan lingkungan Anda dengan Debugger::enable(Debugger::DEVELOPMENT)

// jika Anda menggunakan koneksi database dalam aplikasi Anda, ada 
// pembungkus PDO yang diperlukan untuk digunakan HANYA DI PENGEMBANGAN (bukan produksi, tolong!)
// Ini memiliki parameter yang sama dengan koneksi PDO biasa
$pdo = new PdoQueryCapture('sqlite:test.db', 'user', 'pass');
// atau jika Anda melampirkan ini ke framework Flight
Flight::register('db', PdoQueryCapture::class, ['sqlite:test.db', 'user', 'pass']);
// sekarang setiap kali Anda melakukan kueri, akan menangkap waktu, kueri, dan parameter

// Ini menghubungkan titik-titik
if(Debugger::$showBar === true) {
    // Ini perlu false atau Tracy tidak bisa benar-benar merender :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app());
}

// lebih banyak kode

Flight::start();

Konfigurasi Tambahan

Data Sesi

Jika Anda memiliki pengendali sesi kustom (seperti ghostff/session), Anda dapat meneruskan array data sesi apa pun ke Tracy dan secara otomatis akan mengeluarkannya untuk Anda. Anda mengirimkannya dengan kunci session_data di parameter kedua konstruktor TracyExtensionLoader.


use Ghostff\Session\Session;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('session', Session::class);

if(Debugger::$showBar === true) {
    // Ini perlu false atau Tracy tidak bisa benar-benar merender :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app(), [ 'session_data' => Flight::session()->getAll() ]);
}

// rute dan hal-hal lain...

Flight::start();

Latte

Jika Anda telah menginstal Latte di proyek Anda, Anda dapat menggunakan panel Latte untuk menganalisis template Anda. Anda dapat meneruskan instance Latte ke konstruktor TracyExtensionLoader dengan kunci latte di parameter kedua.


use Latte\Engine;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('latte', Engine::class, [], function($latte) {
    $latte->setTempDirectory(__DIR__ . '/temp');

    // di sinilah Anda menambahkan Panel Latte ke Tracy
    $latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
});

if(Debugger::$showBar === true) {
    // Ini perlu false atau Tracy tidak bisa benar-benar merender :(
    Flight::set('flight.content_length', false);
    new TracyExtensionLoader(Flight::app());
}

Awesome-plugins/tracy

Tracy

Tracy adalah penangan kesalahan yang luar biasa yang dapat digunakan dengan Flight. Ia memiliki sejumlah panel yang dapat membantu Anda dalam mendebug aplikasi Anda. Ini juga sangat mudah untuk diperluas dan menambahkan panel Anda sendiri. Tim Flight telah membuat beberapa panel khusus untuk proyek Flight dengan plugin flightphp/tracy-extensions.

Instalasi

Instal dengan composer. Dan Anda akan ingin menginstal ini tanpa versi dev karena Tracy dilengkapi dengan komponen penanganan kesalahan produksi.

composer require tracy/tracy

Konfigurasi Dasar

Ada beberapa opsi konfigurasi dasar untuk memulai. Anda dapat membaca lebih lanjut tentang mereka di Dokumentasi Tracy.


require 'vendor/autoload.php';

use Tracy\Debugger;

// Mengaktifkan Tracy
Debugger::enable();
// Debugger::enable(Debugger::DEVELOPMENT) // kadang-kadang Anda harus eksplisit (juga Debugger::PRODUCTION)
// Debugger::enable('23.75.345.200'); // Anda juga dapat menyediakan array alamat IP

// Di sinilah kesalahan dan pengecualian akan dicatat. Pastikan direktori ini ada dan dapat ditulisi.
Debugger::$logDirectory = __DIR__ . '/../log/';
Debugger::$strictMode = true; // tampilkan semua kesalahan
// Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // semua kesalahan kecuali pemberitahuan kadaluarsa
if (Debugger::$showBar) {
    $app->set('flight.content_length', false); // jika bilah Debugger terlihat, maka panjang konten tidak dapat diatur oleh Flight

    // Ini khusus untuk Ekstensi Tracy untuk Flight jika Anda telah menyertakannya
    // jika tidak, silakan komentari ini.
    new TracyExtensionLoader($app);
}

Tips Berguna

Saat Anda mendebug kode Anda, ada beberapa fungsi yang sangat berguna untuk mengeluarkan data untuk Anda.

Awesome-plugins/active_record

Flight Active Record

Sebuah rekaman aktif adalah pemetaan entitas basis data ke dalam objek PHP. Secara sederhana, jika Anda memiliki tabel pengguna di basis data Anda, Anda dapat "mentranslasi" sebuah baris di tabel tersebut menjadi kelas User dan objek $user dalam basis kode Anda. Lihat contoh dasar.

Klik di sini untuk repositori di GitHub.

Contoh Dasar

Mari kita asumsikan Anda memiliki tabel berikut:

CREATE TABLE users (
    id INTEGER PRIMARY KEY, 
    name TEXT, 
    password TEXT 
);

Sekarang Anda dapat menyiapkan kelas baru untuk merepresentasikan tabel ini:

/**
 * Kelas ActiveRecord biasanya tunggal
 * 
 * Sangat direkomendasikan untuk menambahkan properti dari tabel sebagai komentar di sini
 * 
 * @property int    $id
 * @property string $name
 * @property string $password
 */ 
class User extends flight\ActiveRecord {
    public function __construct($database_connection)
    {
        // Anda dapat menetapkannya dengan cara ini
        parent::__construct($database_connection, 'users');
        // atau dengan cara ini
        parent::__construct($database_connection, null, [ 'table' => 'users']);
    }
}

Sekarang saksikan keajaiban terjadi!

// untuk sqlite
$database_connection = new PDO('sqlite:test.db'); // ini hanya untuk contoh, Anda mungkin akan menggunakan koneksi basis data yang nyata

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

// atau mysqli
$database_connection = new mysqli('localhost', 'username', 'password', 'test_db');
// atau mysqli dengan penciptaan non-objek
$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();
// atau $user->save();

echo $user->id; // 1

$user->name = 'Joseph Mamma';
$user->password = password_hash('some cool password again!!!');
$user->insert();
// tidak bisa menggunakan $user->save() di sini atau akan berpikir ini adalah pembaruan!

echo $user->id; // 2

Dan begitu mudahnya untuk menambahkan pengguna baru! Sekarang ada baris pengguna di basis data, bagaimana cara mengambilnya keluar?

$user->find(1); // cari id = 1 di basis data dan kembalikan.
echo $user->name; // 'Bobby Tables'

Dan bagaimana jika Anda ingin menemukan semua pengguna?

$users = $user->findAll();

Bagaimana dengan kondisi tertentu?

$users = $user->like('name', '%mamma%')->findAll();

Lihat betapa menyenangkannya ini? Mari kita instal dan mulai!

Instalasi

Cukup instal dengan Composer

composer require flightphp/active-record 

Penggunaan

Ini bisa digunakan sebagai pustaka mandiri atau dengan Flight PHP Framework. Sepenuhnya terserah Anda.

Mandiri

Pastikan Anda melewatkan koneksi PDO ke konstruktor.

$pdo_connection = new PDO('sqlite:test.db'); // ini hanya untuk contoh, Anda mungkin akan menggunakan koneksi basis data yang nyata

$User = new User($pdo_connection);

Tidak ingin selalu menetapkan koneksi basis data Anda di konstruktor? Lihat Manajemen Koneksi Basis Data untuk ide lainnya!

Daftarkan sebagai metode dalam Flight

Jika Anda menggunakan Flight PHP Framework, Anda dapat mendaftar kelas ActiveRecord sebagai layanan, tetapi sebenarnya Anda tidak perlu.

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

// kemudian Anda dapat menggunakannya seperti ini di kontroler, fungsi, dll.

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

Metode runway

runway adalah alat CLI untuk Flight yang memiliki perintah khusus untuk pustaka ini.

# Penggunaan
php runway make:record database_table_name [class_name]

# Contoh
php runway make:record users

Ini akan membuat kelas baru di direktori app/records/ sebagai UserRecord.php dengan konten berikut:

<?php

declare(strict_types=1);

namespace app\records;

/**
 * Kelas ActiveRecord untuk tabel pengguna.
 * @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 Tetapkan hubungan untuk model
     *   https://docs.flightphp.com/awesome-plugins/active-record#relationships
     */
    protected array $relations = [
        // 'relation_name' => [ self::HAS_MANY, 'RelatedClass', 'foreign_key' ],
    ];

    /**
     * Konstruktor
     * @param mixed $databaseConnection Koneksi ke basis data
     */
    public function __construct($databaseConnection)
    {
        parent::__construct($databaseConnection, 'users');
    }
}

Fungsi CRUD

find($id = null) : boolean|ActiveRecord

Temukan satu rekaman dan tetapkan ke objek saat ini. Jika Anda melewatkan $id dari jenis tertentu, itu akan melakukan lookup pada kunci utama dengan nilai tersebut. Jika tidak ada yang dilewatkan, itu hanya akan menemukan rekaman pertama di tabel.

Selain itu, Anda dapat melewatkan metode bantu lainnya untuk kueri tabel Anda.

// temukan rekaman dengan beberapa kondisi sebelumnya
$user->notNull('password')->orderBy('id DESC')->find();

// temukan rekaman berdasarkan id tertentu
$id = 123;
$user->find($id);

findAll(): array<int,ActiveRecord>

Menemukan semua rekaman dalam tabel yang Anda tentukan.

$user->findAll();

isHydrated(): boolean (v0.4.0)

Mengembalikan true jika rekaman saat ini telah dihidrasi (diambil dari basis data).

$user->find(1);
// jika rekaman ditemukan dengan data...
$user->isHydrated(); // true

insert(): boolean|ActiveRecord

Menyisipkan rekaman saat ini ke dalam basis data.

$user = new User($pdo_connection);
$user->name = 'demo';
$user->password = md5('demo');
$user->insert();
Kunci Utama Berbasis Teks

Jika Anda memiliki kunci utama berbasis teks (seperti UUID), Anda dapat menetapkan nilai kunci utama sebelum menyisipkan dengan salah satu dari dua cara.

$user = new User($pdo_connection, [ 'primaryKey' => 'uuid' ]);
$user->uuid = 'some-uuid';
$user->name = 'demo';
$user->password = md5('demo');
$user->insert(); // atau $user->save();

atau Anda dapat membuat kunci utama secara otomatis untuk Anda melalui peristiwa.

class User extends flight\ActiveRecord {
    public function __construct($database_connection)
    {
        parent::__construct($database_connection, 'users', [ 'primaryKey' => 'uuid' ]);
        // Anda juga dapat menetapkan primaryKey ini dengan cara ini sebagai pengganti array di atas.
        $this->primaryKey = 'uuid';
    }

    protected function beforeInsert(self $self) {
        $self->uuid = uniqid(); // atau bagaimana pun Anda perlu membuat id unik Anda
    }
}

Jika Anda tidak menetapkan kunci utama sebelum menyisipkan, itu akan disetel ke rowid dan basis data akan menghasilkan untuk Anda, tetapi tidak akan bertahan karena field tersebut mungkin tidak ada di tabel Anda. Inilah sebabnya mengapa disarankan untuk menggunakan peristiwa untuk menangani ini secara otomatis untuk Anda.

update(): boolean|ActiveRecord

Memperbarui rekaman saat ini ke dalam basis data.

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

save(): boolean|ActiveRecord

Menyisipkan atau memperbarui rekaman saat ini ke dalam basis data. Jika rekaman memiliki id, itu akan diperbarui, jika tidak akan disisipkan.

$user = new User($pdo_connection);
$user->name = 'demo';
$user->password = md5('demo');
$user->save();

Catatan: Jika Anda memiliki hubungan yang ditentukan dalam kelas, itu akan secara rekursif menyimpan hubungan tersebut juga jika telah ditentukan, diinstansiasi, dan memiliki data kotor untuk diperbarui. (v0.4.0 dan lebih tinggi)

delete(): boolean

Menghapus rekaman saat ini dari basis data.

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

Anda juga dapat menghapus beberapa rekaman dengan melakukan pencarian terlebih dahulu.

$user->like('name', 'Bob%')->delete();

dirty(array $dirty = []): ActiveRecord

Data kotor mengacu pada data yang telah diubah dalam suatu rekaman.

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

// tidak ada yang "kotor" pada saat ini.

$user->email = 'test@example.com'; // sekarang email dianggap "kotor" karena sudah diubah.
$user->update();
// sekarang tidak ada data yang kotor karena sudah diperbarui dan dipertahankan di basis data

$user->password = password_hash('newpassword'); // sekarang ini kotor
$user->dirty(); // melewatkan tidak ada yang akan membersihkan semua entri kotor.
$user->update(); // tidak ada yang akan memperbarui karena tidak ada yang tertangkap sebagai kotor.

$user->dirty([ 'name' => 'something', 'password' => password_hash('a different password') ]);
$user->update(); // baik nama dan password diperbarui.

copyFrom(array $data): ActiveRecord (v0.4.0)

Ini adalah alias untuk metode dirty(). Ini sedikit lebih jelas tentang apa yang Anda lakukan.


$user->copyFrom([ 'name' => 'something', 'password' => password_hash('a different password') ]);
$user->update(); // baik nama dan password diperbarui.

Awesome-plugins/latte

Latte

Latte adalah mesin templating dengan fitur lengkap yang sangat mudah digunakan dan terasa lebih dekat dengan sintaks PHP dibandingkan Twig atau Smarty. Ini juga sangat mudah untuk diperluas dan menambahkan filter serta fungsi Anda sendiri.

Instalasi

Instal dengan composer.

composer require latte/latte

Konfigurasi Dasar

Ada beberapa opsi konfigurasi dasar untuk memulai. Anda dapat membaca lebih lanjut tentang mereka di Dokumentasi Latte.


use Latte\Engine as LatteEngine;

require 'vendor/autoload.php';

$app = Flight::app();

$app->register('latte', LatteEngine::class, [], function(LatteEngine $latte) use ($app) {

    // Di sinilah Latte akan menyimpan cache untuk template Anda untuk mempercepat proses
    // Satu hal menarik tentang Latte adalah bahwa ia secara otomatis menyegarkan 
    // cache saat Anda membuat perubahan pada template Anda!
    $latte->setTempDirectory(__DIR__ . '/../cache/');

    // Beri tahu Latte di mana direktori root untuk tampilan Anda akan berada.
    // $app->get('flight.views.path') diatur di file config.php
    //   Anda juga bisa melakukan sesuatu seperti `__DIR__ . '/../views/'`
    $latte->setLoader(new \Latte\Loaders\FileLoader($app->get('flight.views.path')));
});

Contoh Layout Sederhana

Ini adalah contoh sederhana dari file layout. Ini adalah file yang akan digunakan untuk membungkus semua tampilan Anda yang lain.

<!-- app/views/layout.latte -->
<!doctype html>
<html lang="en">
    <head>
        <title>{$title ? $title . ' - '}Aplikasi Saya</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <nav>
                <!-- elemen navigasi Anda di sini -->
            </nav>
        </header>
        <div id="content">
            <!-- Ini adalah keajaiban yang terjadi di sini -->
            {block content}{/block}
        </div>
        <div id="footer">
            &copy; Hak Cipta
        </div>
    </body>
</html>

Dan sekarang kita memiliki file Anda yang akan dirender di dalam blok konten tersebut:

<!-- app/views/home.latte -->
<!-- Ini memberi tahu Latte bahwa file ini "di dalam" file layout.latte -->
{extends layout.latte}

<!-- Ini adalah konten yang akan dirender di dalam layout di dalam blok konten -->
{block content}
    <h1>Halaman Utama</h1>
    <p>Selamat datang di aplikasi saya!</p>
{/block}

Kemudian saat Anda pergi untuk merender ini di dalam fungsi atau kontroler Anda, Anda akan melakukan sesuatu seperti ini:

// rute sederhana
Flight::route('/', function () {
    Flight::latte()->render('home.latte', [
        'title' => 'Halaman Utama'
    ]);
});

// atau jika Anda menggunakan kontroler
Flight::route('/', [HomeController::class, 'index']);

// HomeController.php
class HomeController
{
    public function index()
    {
        Flight::latte()->render('home.latte', [
            'title' => 'Halaman Utama'
        ]);
    }
}

Lihat Dokumentasi Latte untuk informasi lebih lanjut tentang cara menggunakan Latte untuk potensi penuh!

Awesome-plugins/awesome_plugins

Plugin yang Menakjubkan

Flight sangat dapat diperluas. Ada sejumlah plugin yang dapat digunakan untuk menambahkan fungsionalitas pada aplikasi Flight Anda. Beberapa didukung secara resmi oleh Tim Flight dan yang lainnya adalah pustaka mikro/lite untuk membantu Anda memulai.

Autentikasi/Otorisasi

Autentikasi dan Otorisasi sangat penting untuk aplikasi apa pun yang memerlukan kontrol tentang siapa yang dapat mengakses apa.

Penyimpanan Sementara

Penyimpanan sementara adalah cara yang bagus untuk mempercepat aplikasi Anda. Ada beberapa pustaka penyimpanan sementara yang dapat digunakan dengan Flight.

CLI

Aplikasi CLI adalah cara yang baik untuk berinteraksi dengan aplikasi Anda. Anda dapat menggunakannya untuk menghasilkan pengendali, menampilkan semua rute, dan lainnya.

Kue

Kue adalah cara yang bagus untuk menyimpan sedikit data di sisi klien. Mereka dapat digunakan untuk menyimpan preferensi pengguna, pengaturan aplikasi, dan lainnya.

Pen-debugan

Pen-debugan sangat penting saat Anda mengembangkan di lingkungan lokal Anda. Ada beberapa plugin yang dapat meningkatkan pengalaman pen-debugan Anda.

Basis Data

Basis data adalah inti dari sebagian besar aplikasi. Ini adalah bagaimana Anda menyimpan dan mengambil data. Beberapa pustaka basis data adalah pembungkus untuk menulis kueri dan beberapa adalah ORM yang sepenuhnya berfungsi.

Enkripsi

Enkripsi sangat penting untuk aplikasi apa pun yang menyimpan data sensitif. Melakukan enkripsi dan dekripsi data tidak terlalu sulit, tetapi menyimpan kunci enkripsi dengan benar dapat menjadi sulit. Hal yang paling penting adalah jangan pernah menyimpan kunci enkripsi Anda di direktori publik atau mengkomitnya ke repositori kode Anda.

Sesi

Sesi tidak begitu berguna untuk API, tetapi untuk membangun aplikasi web, sesi dapat sangat penting untuk mempertahankan status dan informasi login.

Penataan

Penataan adalah inti dari aplikasi web mana pun dengan antarmuka pengguna. Ada sejumlah mesin penataan yang dapat digunakan dengan Flight.

Berkontribusi

Apakah Anda memiliki plugin yang ingin Anda bagikan? Kirimkan permintaan tarik untuk menambahkannya ke daftar!

Media

Media

Kami telah berusaha untuk melacak apa yang kami bisa dari berbagai jenis media di internet tentang Flight. Lihat di bawah untuk berbagai sumber yang dapat Anda gunakan untuk mempelajari lebih lanjut tentang Flight.

Artikel

Video

Examples

Butuh memulai dengan cepat?

Anda memiliki dua opsi untuk memulai dengan Flight:

Butuh Inspirasi?

Meskipun ini tidak secara resmi disponsori oleh Tim Flight, ini dapat memberikan Anda ide tentang bagaimana menyusun proyek Anda sendiri yang dibangun dengan Flight!

Ingin Membagikan Contoh Anda Sendiri?

Jika Anda memiliki proyek yang ingin Anda bagikan, silakan kirim permintaan tarik untuk menambahkannya ke daftar ini!

Install/install

Instalasi

Unduh berkas

Pastikan Anda memiliki PHP terinstal di sistem Anda. Jika tidak, klik di sini untuk petunjuk tentang cara menginstalnya di sistem Anda.

Jika Anda menggunakan Composer, Anda dapat menjalankan perintah berikut:

composer require flightphp/core

ATAU Anda dapat mengunduh berkas langsung dan mengekstraknya ke direktori web Anda.

Konfigurasikan Server Web Anda

Server Pengembangan PHP Bawaan

Ini adalah cara termudah untuk memulai dan menjalankan aplikasi. Anda dapat menggunakan server bawaan untuk menjalankan aplikasi Anda dan bahkan menggunakan SQLite untuk basis data (selama sqlite3 terinstal di sistem Anda) dan tidak memerlukan banyak hal! Jalankan perintah berikut setelah PHP terinstal:

php -S localhost:8000

Kemudian buka browser Anda dan pergi ke http://localhost:8000.

Jika Anda ingin membuat akar dokumen proyek Anda ke direktori yang berbeda (Mis: proyek Anda adalah ~/myproject, tetapi akar dokumen Anda adalah ~/myproject/public/), Anda dapat menjalankan perintah berikut setelah Anda berada di direktori ~/myproject:

php -S localhost:8000 -t public/

Kemudian buka browser Anda dan pergi ke http://localhost:8000.

Apache

Pastikan Apache sudah terinstal di sistem Anda. Jika tidak, cari tahu cara menginstal Apache di sistem Anda.

Untuk Apache, edit file .htaccess Anda dengan yang berikut:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

Catatan: Jika Anda perlu menggunakan flight di subdirektori, tambahkan baris RewriteBase /subdir/ tepat setelah RewriteEngine On.

Catatan: Jika Anda ingin melindungi semua berkas server, seperti berkas db atau env. Tempatkan ini di file .htaccess Anda:

RewriteEngine On
RewriteRule ^(.*)$ index.php

Nginx

Pastikan Nginx sudah terinstal di sistem Anda. Jika tidak, cari tahu cara menginstal Nginx di sistem Anda.

Untuk Nginx, tambahkan yang berikut ke deklarasi server Anda:

server {
  location / {
    try_files $uri $uri/ /index.php;
  }
}

Buat file index.php Anda

<?php

// Jika Anda menggunakan Composer, persyaratan autoloader.
require 'vendor/autoload.php';
// jika Anda tidak menggunakan Composer, muat kerangka kerja secara langsung
// require 'flight/Flight.php';

// Kemudian tetapkan rute dan tetapkan fungsi untuk menangani permintaan.
Flight::route('/', function () {
  echo 'hello world!';
});

// Akhirnya, mulai kerangka kerja.
Flight::start();

Instalasi PHP

Jika Anda sudah memiliki php terinstal di sistem Anda, silakan lewati petunjuk ini dan lanjut ke bagian unduh

macOS

Menginstal PHP menggunakan Homebrew

  1. Instal Homebrew (jika belum terinstal):

    • Buka Terminal dan jalankan:
      /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  2. Instal PHP:

    • Instal versi terbaru:
      brew install php
    • Untuk menginstal versi tertentu, misalnya, PHP 8.1:
      brew tap shivammathur/php
      brew install shivammathur/php/php@8.1
  3. Beralih antara versi PHP:

    • Lepaskan versi saat ini dan tautkan versi yang diinginkan:
      brew unlink php
      brew link --overwrite --force php@8.1
    • Verifikasi versi yang diinstal:
      php -v

Windows 10/11

Menginstal PHP secara manual

  1. Unduh PHP:

    • Kunjungi PHP untuk Windows dan unduh versi terbaru atau versi tertentu (misalnya, 7.4, 8.0) sebagai berkas zip yang tidak aman untuk thread.
  2. Ekstrak PHP:

    • Ekstrak berkas zip yang diunduh ke C:\php.
  3. Tambahkan PHP ke PATH sistem:

    • Masuk ke Properti Sistem > Variabel Lingkungan.
    • Di bawah variabel sistem, cari Path dan klik Edit.
    • Tambahkan jalur C:\php (atau di mana pun Anda mengekstrak PHP).
    • Klik OK untuk menutup semua jendela.
  4. Konfigurasi PHP:

    • Salin php.ini-development ke php.ini.
    • Edit php.ini untuk mengonfigurasi PHP sesuai kebutuhan (misalnya, mengatur extension_dir, mengaktifkan ekstensi).
  5. Verifikasi instalasi PHP:

    • Buka Command Prompt dan jalankan:
      php -v

Menginstal Beberapa Versi PHP

  1. Ulangi langkah di atas untuk setiap versi, menempatkan masing-masing di direktori terpisah (misalnya, C:\php7, C:\php8).

  2. Beralih antara versi dengan menyesuaikan variabel PATH sistem untuk menunjuk ke direktori versi yang diinginkan.

Ubuntu (20.04, 22.04, dll.)

Menginstal PHP menggunakan apt

  1. Perbarui daftar paket:

    • Buka Terminal dan jalankan:
      sudo apt update
  2. Instal PHP:

    • Instal versi PHP terbaru:
      sudo apt install php
    • Untuk menginstal versi tertentu, misalnya, PHP 8.1:
      sudo apt install php8.1
  3. Instal modul tambahan (opsional):

    • Misalnya, untuk menginstal dukungan MySQL:
      sudo apt install php8.1-mysql
  4. Beralih antara versi PHP:

    • Gunakan update-alternatives:
      sudo update-alternatives --set php /usr/bin/php8.1
  5. Verifikasi versi yang diinstal:

    • Jalankan:
      php -v

Rocky Linux

Menginstal PHP menggunakan yum/dnf

  1. Aktifkan repositori EPEL:

    • Buka Terminal dan jalankan:
      sudo dnf install epel-release
  2. Instal repositori Remi:

    • Jalankan:
      sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
      sudo dnf module reset php
  3. Instal PHP:

    • Untuk menginstal versi default:
      sudo dnf install php
    • Untuk menginstal versi tertentu, misalnya, PHP 7.4:
      sudo dnf module install php:remi-7.4
  4. Beralih antara versi PHP:

    • Gunakan perintah modul dnf:
      sudo dnf module reset php
      sudo dnf module enable php:remi-8.0
      sudo dnf install php
  5. Verifikasi versi yang diinstal:

    • Jalankan:
      php -v

Catatan Umum