CATATAN
Berikut beberapa hal yang perlu kamu ketahui pada penulisan dokumentasi ini:
  • Beberapa code snippet pada dokumentasi ini menyertakan `...`, maksudnya adalah pada bagian tersebut dapat berisi "kode lain" yang tidak berhubungan dengan topik yang dibahas. Kamu tidak perlu menuliskan `...`seperti itu.
  • Kata 'Controller' pada dokumentasi disini maksudnya adalah 'Route handler' yang dapat berupa callable atau class Controller.

Memulai

Kebutuhan

  • PHP 5.5 keatas.
  • Composer untuk instalasi.

Instalasi

Pertama-tama, siapkan direktori proyekmu:

cd /var/www
mkdir my-project

Setelah itu, install rakit framework menggunakan perintah composer dibawah ini:

composer require "rakit/framework"

Hello World

Buat file index.php, lalu ketikkan kode berikut:

<?php
        
use Rakit\Framework\App;

require("vendor/autoload.php");

// inisialisasi App
$app = new App('my-awesome-app');

// mendaftarkan route
$app->get('/', function() {
    return "Hello World!";
});

// menjalankan app
$app->run();

Jalankan server (disini kami menggunakan PHP built-in server):

php -S localhost:8000

Kemudian buka ‘http://localhost:8000’ pada web browser, dan voila!

Panduan

Konfigurasi

Rakit framework pada dasarnya dapat berjalan tanpa konfigurasi apapun. Namun seringkali kita ingin menyimpan beberapa pengaturan pada aplikasi, Rakit framework menyajikan beberapa API untuk mempermudah hal tersebut.

Berikut adalah beberapa hal yang mesti kamu ketahui tentang konfigurasi pada Rakit framework:

Get/Set Konfigurasi

Konfigurasi pada rakit framework tersimpan pada objek config yang mengimplementasikan ArrayAccess. Untuk itu, kamu dapat menyimpan dan mengambil konfigurasi layaknya memberikan dan mengambil nilai dari array.

Berikut contohnya:

// set konfigurasi 'something'
$app->config['something'] = 'value';

// mengambil konfigurasi 'something'
echo $app->config['something'];

Memahami Dot Notation pada Konfigurasi

Perlu kamu ketahui, rakit framework memiliki kemampuan untuk mengambil konfigurasi dengan dot notation. Jika pada array biasa kamu melakukan hal seperti ini:

// set konfigurasi
$configs['database'] = [
    'host' => 'localhost',
    'username' => 'root',
    'password' => 's3cR3t',
    'name' => 'my_db'
];

...

// mengambil konfigurasi (pada file lain)
$db_host = isset($configs['database']['host']) ? $configs['database']['host'] : 'localhost';
$db_username = isset($configs['database']['username']) ? $configs['database']['username'] : 'root';
$db_password = isset($configs['database']['password']) ? $configs['database']['password'] : '';

Dengan rakit framework, kode diatas akan jadi seperti ini’

// set konfigurasi
$app->config['database'] = [
    'host' => 'localhost',
    'username' => 'root',
    'password' => 's3cR3t',
    'name' => 'my_db'
];

...

// mengambil konfigurasi (pada file lain)
$db_host = $app->config['database.host'] ?: 'localhost';
$db_username = $app->config['database.username'] ?: 'root';
$db_password = $app->config['database.password'] ?: '';

Lebih enak dipandang bukan? ya itulah kegunaan dot notation. Untuk meminimalisir isset-isset itu.

Jika kunci (key) yang diakses dengan dot notation tidak ada, nilai yang dikembalikan adalah null

Load Konfigurasi pada Direktori

Jika kamu pernah menggunakan framework-framework full stack seperti Laravel, Codeigniter, dsb kamu akan menemukan kalau file konfigurasi dikumpulkan kedalam sebuah direktori yang dikelompokkan kedalam file. Rakit framework memfasilitasi hal tersebut. Kamu dapat memuat seluruh file konfigurasi pada direktori dengan perintah loadDir($directory).

Pada contoh dibawah ini, dimisalkan kita memiliki 2 buah file konfigurasi pada direktori ‘configs’ sebagai berikut:

<?php
// file configs/app.php
return [
    'base_url' => 'http://localhost:3000',
    'debug' => true
];
<?php
// file configs/database.php
return [
    'host' => 'localhost',
    'username' => 'root',
    'password' => 's3cR3t',
    'name' => 'my_db'
];

Untuk mendaftarkan konfigurasi pada direktori ‘configs’ tersebut, gunakan perintah loadDirseperti dibawah ini:

<?php
// file index.php

use Rakit\Framework\App;

require('vendor/autoload.php');

$app = new App('my-awesome-app');

// load configs
$app->config->loadDir(__DIR__.'/configs');

// then here is the results
echo $app->config['app.base_url'];        // http://localhost:3000
echo $app->config['app.debug'];           // 1 (true)
echo $app->config['database.host'];       // localhost
echo $app->config['database.username'];   // root
echo $app->config['database.password'];   // s3cR3t
echo $app->config['database.name'];       // my_db

Ya, nama file akan menjadi prefix dari masing-masing konfigurasi.

Mengaktifkan Mode Debug

Secara default, rakit framework menonaktifkan mode debug. Jadi jika terjadi error, browser hanya akan menampilkan ‘Something went wrong’.

Untuk mengaktifkan mode debug, set konfigurasi app.debugmenjadi trueseperti dibawah ini:

<?php
// file index.php

use Rakit\Framework\App;

require('vendor/autoload.php');

$app = new App('my-awesome-app');
$app->config['app.debug'] = true;

Dengan begitu, jika terjadi error, aplikasi akan menampilkan sesuatu seperti ini:

Sample error

Routing

Berikut ini method yang dapat kamu gunakan untuk mendaftarkan route:

$app->get('/get', function() {
    return 'Hanya dapat menerima metode GET';
});

$app->post('/post', function() {
    return 'Hanya dapat menerima metode POST';
});

$app->put('/put', function() {
    return 'Hanya dapat menerima metode PUT';
});

$app->patch('/patch', function() {
    return 'Hanya dapat menerima metode PATCH';
});

$app->delete('/delete', function() {
    return 'Hanya dapat menerima metode DELETE';
});

// mendaftarkan beberapa method sekaligus pada sebuah route
$app->router->map(['GET', 'POST', 'PUT'], '/some-methods', function() {
    return 'Route ini dapat menerima metode GET, POST, dan PUT';
});

Catatan: Setiap route pada rakit framework harus diawali dengan ‘/’

Route Parameter

Untuk mendaftarkan parameter pada route, gunakan :nama_parameter seperti kode berikut:

$app->get('/user/:username', function($username) {
    return "Halo $username";
});

Kode diatas memungkinkan kamu untuk mengakses ‘/user/foo’, ‘/user/123’, ‘/user/foo123’, dsb.

Route Optional Parameter

Gunakan tanda kurung pada path dan parameter yang ingin dijadikan optional, lalu set nilai default pada argumen parameter tersebut.

Contoh:

$app->get('/user(/:username)', function($username = 'Anonymous') {
    return "Halo $username";
});
Jika tanda '/' pada `(/:username)`ditaruh diluar menjadi seperti `/user/(:username)` maka route tersebut tidak menerima '/user', melainkan harus '/user/'.

Route Conditional Parameter

Secara default, parameter akan menerima karakter apapun selain ‘/’. Jika kamu mengiginkan parameter hanya dapat menerima karakter tertentu, kamu bisa menambahkan ->where('param', 'regex') setelah mendefinisikan route.

Contoh:

$app->get('/user/:username', function() {
    return "Halo $username";
})->where('username', '[a-zA-Z0-9]+');

Dengan begitu route hanya akan dianggap cocok jika parameter ‘username’ terdiri dari rangkaian huruf dan angka (a-z, 0-9). Bila tidak, aplikasi akan menampilkan halaman 404.

Route Group

Route group digunakan untuk mengelompokan route kamu sehingga lebih mudah dibaca dan dimaintain jika sewaktu-waktu ada perubahan pada path atau middleware group tersebut.

Contoh menggunakan route group:

$app->group('/admin', function($admin) {
    $admin->get('/dashboard', function() {
        return 'Halaman dashboard';
    });

    $admin->get('/settings', function() {
        return 'Halaman pengaturan';
    });

    $admin->post('/settings', function() {
        return 'Menyimpan pengaturan';
    });
});

Pada kode diatas, kita mendaftarkan 3 buah route, yaitu:

  • GET ‘/admin/dashboard’
  • GET ‘/admin/settings’
  • POST ‘/admin/settings’

Middleware

Middleware adalah sebuah fungsi yang melapisi controller, atau middleware pada lapisan dibawahnya. Middleware dapat digunakan untuk filter request, manipulasi response, setup beberapa hal, dsb.

Middleware pada rakit framework sendiri hanya dapat didaftarkan pada route atau route group.

Berikut contoh-contoh penggunaan middleware:

Middleware untuk Filter Request

Ini adalah fungsi yang paling umum dari middleware. Yaitu untuk autentikasi dan autorisasi.

Pada contoh dibawah ini kita akan membuat middleware ‘auth’ yang berfungsi untuk mengecek apakah user sudah login atau belum berdasarkan session. Jika belum, maka tampilkan respon 401 (Unauthenticated request).

Pertama kamu perlu mendaftarkan middleware ‘auth’ tersebut:

$app->setMiddleware('auth', function($req, $res, $next) {
    if (!isset($_SESSION['user_id'])) {
        return $res->send('Unauthenticated request', 401);
    }

    return $next();
});

Setelah itu, middleware ‘auth’ tersebut dapat kamu gunakan pada route atau route group seperti ini:

// mendaftarkan middleware pada route 
$app->get('/article/edit', 'ArticleController@formEdit')->auth();

// mendaftarkan middleware pada route group
$app->group('/admin', function($admin) {
    $admin->get('/article', 'ArticleController@pageIndex');
    $admin->get('/article/create', 'ArticleController@formCreate');
    $admin->post('/article/create', 'ArticleController@postCreate');
})->auth();

Pada contoh diatas, middleware ‘auth’ akan melapisi controller didalamnya, dan dijalankan terlebih dahulu sebelum controller. Middleware tersebut akan mengecek apakah terdapat session ‘user_id’ atau tidak. Jika tidak ada, aplikasi akan menampilkan ‘Unauthenticated Request’ dengan status 401. Jika ada, middleware akan meneruskan request ke controller (lapisan dibawahnya) dengan perintah $next().

Perlu diingat kalau middleware dan controller pada rakit framework selalu menggunakan returnuntuk mengembalikan hasil.

Middleware untuk Manipulasi Response

Terkadang kamu mungkin mau mengubah respon atau hasil yang dikirimkan oleh controller seperti menghapus karakter ilegal, replace sesuatu, menginsert sesuatu ke JSON yang dihasilkan, dsb.

Pada contoh berikut ini kita akan membuat middleware ‘api’ yang berguna untuk menambahkan ‘status’ ke dalam JSON.

1) Mendaftarkan middleware:

$app->setMiddleware('api', function($req, $res, $next) {
    $result = $next();
    return array_merge([
      'status' => 'ok'
    ], $result);
});

2) Mendaftarkan middleware ke route.

$app->get('/api/something', function() {
    return [
        'message' => 'Hola!'
    ];
})->api();

Pada contoh diatas, jika kamu mengakses ‘/api/something’ maka hasilnya adalah JSON sebagai berikut:

{
    "status": "ok",
    "message": "Hola!"
}

Middleware dengan Parameter

Seringkali kita mendapatkan kasus dimana aplikasi yang kita kembangkan memiliki berbagai macam kategori user, seperti ‘admin’, ‘guru’, ‘murid’. Jika kamu ingin membuat middleware untuk autentikasi 3 kategori user tersebut, terdapat 2 cara, yaitu:

  1. Buat 3 buah middleware untuk masing-masing kategori.
  2. Cukup buat sebuah middleware yang menerima parameter.

Berikut contoh penggunaan middleware dengan parameter untuk kasus tersebut:

1) Mendaftarkan middleware. Tambahkan parameter $categorypada akhir Closure.

$app->setMiddleware('auth', function($req, $res, $next, $category) {
    // cek apakah user sudah login
    if (!isset($_SESSION['user']) OR !is_array($_SESSION['user'])) {
        return $res->send('Anda belum login', 401);
    }

    // cek apakah kategori user sesuai $category
    if ($_SESSION['user']['category'] != $category) {
        return $res->send('Anda tidak memiliki hak akses ke halaman ini', 403);
    }

    return $next();
});

2) Mendaftarkan middleware ke route. Masukkan parameter ke middleware authyang telah dibuat.

$app->get('/admin/dashboard', function() {
    return "Halo admin";
})->auth('admin');

$app->get('/guru/dashboard', function() {
    return "Halo guru";
})->auth('guru');

$app->get('/murid/dashboard', function() {
    return "Halo Murid";
})->auth('murid');

Request

Objek request adalah objek yang menyimpan request data seperti $_GET, $_POST, $_FILES, request method, path, uri, dll.

Mengambil Data GET atau POST

Pada rakit framework, $_GET dan $_POST disatukan, dimana jika terdapat key yang sama, maka key $_POST yang akan diambil.

Untuk mengambil data $_GET atau $_POST, gunakan method get($key).

Contoh:

$app->post('/login', function() {
    // mengambil per key
    $username = $this->request->get('username');
    $password = $this->request->get('password');

    // mengambil hanya 'username' dan 'password'
    $data = $this->request->only(['username', 'password']);

    // mengmabil semua data, kecuali 'A', 'B', 'C' 
    $data = $this->request->except(['A', 'B', 'C']);
});

Perlu kamu ketahui, method get ini dapat menggunakan dot notation. Jadi untuk mengambil array kamu dapat melakukan seperti ini:

$app->get('/products', function() {
    // mengambil $_GET['filter']['category']
    $filterCategory = $this->request->get('filter.category');
});

Upload Single File

Gunakan method file($key) untuk mengambil objek UploadedFile, kemudian kamu dapat mengupload file ke direktori proyek menggunakan method move.

Contoh:

$app->post('/register', function() {
    $avatar = $this->request->file('avatar');
    // memastikan $avatar tidak kosong (NULL)
    if ($avatar) {
        $avatar->name = 'new-name'; // set nama file output
        $avatar->move('my/upload/dir');
    }
});

Jika kamu mengupload file test.png, maka file akan tersimpan di my/upload/dir/new-name.png.

Upload Multiple File

Mirip-mirip dengan single file. Hanya saja untuk mengambil multiple upload file method yang digunakan adalah multiFiles($key). Nilai yang dikembalikan adalah array UploadedFile, jadi kamu perlu loop untuk menguploadnya satu per satu.

$app->post('/register', function() {
    $documents = $this->request->multipleFiles('documents');
    foreach ($documents as $document) {
        $document->move('my/upload/dir');
    }
});

Mengambil Route yang Aktif

Untuk mengambil objek route yang sedang diakses, gunakan method route().

$app->get('/foo/bar/baz', function() {
    $currentRoute = $this->request->route();
    return $currentRoute->getPath(); // => '/foo/bar/baz'
});

Cek Apakah Request Berupa AJAX

Untuk mengetahui apakah request berupa AJAX, gunakan method isAjax().

$app->get('/foo/bar/baz', function() {
    if ($this->request->isAjax()) {
        return "request berupa ajax";
    } else {
        return "request bukan berupa ajax";
    }
});

Mengecek atau Mendapatkan Request Method

Untuk mengetahui atau mengecek request method yang digunakan, kamu dapat gunakan beberapa method ini:

  • isMethodPost(): untuk mengetahui apakah request berupa POST?
  • isMethodGet(): untuk mengetahui apakah request berupa GET?
  • isMethodPatch(): untuk mengetahui apakah request berupa PATCH?
  • isMethodPut(): untuk mengetahui apakah request berupa PUT?
  • isMethodDelete(): untuk mengetahui apakah request berupa DELETE?
  • method(): untuk mengambil method yang digunakan, sama seperti $_SERVER['REQUEST_METHOD'].

Mengambil Path URL

Untuk mengambil path dari url kamu dapat menggunakan methog path(). Contoh:

// misal url = http://localhost:3000/foo/bar/baz?x=12&y=10
$app->get('/foo/bar/baz', function() {
    return $this->request->path(); // => '/foo/bar/baz'
});

Mengambil URI Segment

Untuk mengambil URI segment, gunakan method segment($n) dimana $n adalah urutan segment. Contoh:

// misal url = http://localhost:3000/foo/bar/baz?x=12&y=10
$app->get('/foo/bar/baz', function() {
    return $this->request->segment(2); // => 'bar'
});

Response

TODO: write this

Container

Container adalah tempat menampung dan mengelola layanan atau objek pada aplikasi. Setiap instance rakit framework sendiri seperti App, Router, Http Request, Http Response, Configurator, dsb tersimpan di dalam sebuah Container sehingga kamu dapat mengaksesnya dengan mudah pada bagian lain dari aplikasi.

Objek container pada rakit framework sendiri berada di $app->container.

Container pada rakit framework mengimplementasikan ArrayAccess, jadi kamu dapat mengakses container layaknya mengakses sebuah array.

Contoh Sederhana

Berikut ini adalah beberapa cara mendaftarkan objek sederhana kedalam container.

// cara 1
$app->container->register(PDO::class, new PDO($dsn));

// cara 2 
$app->container[PDO::class] = new PDO($dsn);

// cara 3
$app[PDO::class] = new PDO($dsn);
Buat kamu yang belum tahu, `PDO::class` adalah string nama class dari PDO. Konstanta `class` ini diperkenalkan sejak PHP versi 5.5.

Setelah mendaftarkan nilai kedalam container, kamu dapat mengambil nilai tersebut dengan beberapa cara dibawah ini:

// cara 1
$cara1 = $app->container->get(PDO::class);

// cara 2 
$cara2 = $app->container[PDO::class];

// cara 3
$cara3 = $app[PDO::class];

Sebenarnya ada satu cara lagi yang lebih singkat dan mungkin lebih nyaman. Yaitu:

// mendaftarkan
$app->pdo = new PDO($dsn);

// mengambil
$pdo = $app->pdo;

Hanya saja, cara tersebut tidak dapat kamu gunakan untuk automatic injection karena key container (‘pdo’) tidak sama dengan nama classnya (‘PDO’). Cara ini lebih cocok jika kamu ingin nilai hanya dapat diakses langsung melalui instance dari app.

Jika kamu ingin mendaftarkan sebuah nilai menggunakan beberapa key sekaligus, kamu dapat gunakan cara no.1, yaitu register. Contoh:

$app->container->register(['pdo', PDO::class], new PDO($dsn));

// mengambil dan membandingkan nilai
var_dump($app->pdo === $app[PDO::class]); // true

Pada perbandingan diatas hasilnya true karena instance bersifat singleton didalam container.

Lazy Loading

Pada container, lazy loading adalah teknik dimana instance dibuat hanya jika dibutuhkan. Pada contoh diatas kita mendaftarkan objek PDO, padahal belum tentu setiap route menggunakan objek PDO tersebut. Hal ini dapat menambah beban memori ke aplikasi kamu. Untuk itulah lazy loading seringkali diperlukan.

Untuk menerapkan lazy loading, kamu perlu membungkus instantiator (pembentuk instance) kedalam sebuah Closure seperti dibawah ini:

$app[PDO::class] = function() use ($app) {
    $dsn = $app->config['database.dsn'];
    return new PDO($dsn);
};

Dengan begitu, objek PDO hanya dibuat saat aplikasi mengambil objek PDO tersebut.

CATATAN PENTING: saat mendaftarkan layanan dengan Closure seperti kode diatas, objek akan dibuat instancenya setiap kali kamu mengakses objek tersebut.

Contoh pada PDO diatas:

$pdo1 = $app[PDO::class];
$pdo2 = $app[PDO::class];

var_dump($pdo1 === $pdo2); // hasilnya false
var_dump($app[PDO::class] === $app[PDO::class]); // hasilnya false

Untuk itu, jika kamu menginginkan instance yang sama sekaligus lazy loading, kamu dapat mencoba method singleton yang akan dijelaskan pada bagian selanjutnya.

Singleton

Singleton adalah design pattern dimana sebuah class hanya dapat memiliki 1 instance saja. Jika kamu pernah mempelajari pattern ini, singleton yang dimaksud pada bagian ini bukanlah singleton yang ditangani oleh class itu sendiri dimana contructor pada class dibuat protected atau private. Tapi singleton disini adalah bagaimana container aplikasi hanya memberikan sebuah instance yang sama pada setiap kali pengambilan.

Untuk mendaftarkan objek supaya menjadi singleton, ada 2 cara, yaitu:

  1. Mendaftarkan instance secara langsung seperti contoh sederhana diatas. Dengan cara ini, objek tidak bersifat lazy loading.
  2. Menggunakan $app->container->singleton. Dengan cara ini, objek menjadi bersifat lazy loading.

Berikut contoh menggunakan cara kedua masih pada kasus PDO seperti sebelumnya:

$app[PDO::class] = $app->container->singleton(function() use ($app) {
    $dsn = $app->config['database.dsn'];
    return new PDO($dsn);
});

// contoh untuk memastikan instance sama
$pdo1 = $app[PDO::class];
$pdo2 = $app[PDO::class];
var_dump($pdo1 === $pdo2); // true

Automatic Injection

Container pada rakit framework memiliki kemampuan untuk membuat instance suatu class secara otomatis dengan memperhatikan dependency dari constructor class tersebut (constructor injection). Selain itu, container juga dapat memanggil method atau function dengan memperhatikan dependency dari method atau function tersebut (callable injection).

Rakit framework akan melakukan injeksi otomatis ke route handler dan constructor controller kamu. Namun kamu dapat melakukan constructor injection dengan $app->container->make dan callable injection dengan $app->container->call.

Sebagai contoh, pertama kamu daftarkan PDO kedalam aplikasi seperti pada contoh-contoh sebelumnya:

$app[PDO::class] = $app->container->singleton(function() {
    return new PDO('mysql:host-localhost;dbname=mydb', 'username', 'password');
});

Setelah itu, berikut beberapa contoh penerapan automatic injectionnya:

1) Pada route handler

$app->get('/product/detail/:id', function($id, PDO $pdo) {
    // lakukan sesuatu dengan PDO disini
})->where('id', '\d+');

2) Pada constructor class controller

<?php

use Rakit\Framework\Controller;
use Rakit\Framework\App;

class ProductController extends Controller
{
    public function __construct(App $app, PDO $pdo)
    {
        parent::__construct($app);
        $this->pdo = $pdo;
    }

    public function detail($id)
    {
        // lakukan sesuatu dengan $this->pdo
    }

    public function delete($id)
    {
        // lakukan sesuatu dengan $this->pdo
    }    
}

Pemanggilan parent::__construct digunakan supaya controller dapat mengakses instance dari App dengan $this.

3) Menggunakan constructor injection. Disini dicontohkan kita ingin injeksi PDO kedalam class ProductRepository.

Pertama buat dulu ProductRepository.php-nya:

<?php

// file: repositories/ProductRepository.php

class ProductRepository
{

    public function __construct(PDO $pdo, $arg1, $arg2)
    {
        $this->pdo = $pdo;
        $this->arg1 = $arg1;
        $this->arg2 = $arg2;
    }

    public function findById($id)
    {
        // lakukan sesuatu dengan $this->pdo
    }    

}

Kemudian kamu dapat membentuk instance dari ProductRepository dengan cara berikut:

$productRepository = $app->container->make(ProductRepository::class, [$arg1, $arg2]);
$product = $productRepository->findById(5);

4) Menggunakan callable injection.

Dimisalkan kita mempunyai function seperti ini:

function do_something(PDO $pdo) {
    // do something with PDO
}

Kamu dapat inject PDO secara otomatis dengan cara dibawah ini:

$result = $app->container->call('do_something');

Callable injection tidak hanya berlaku pada function saja, tapi juga berlaku pada jenis callable lainnya.

Binding Interface

Katakanlah kamu memiliki class MysqlBuilder yang berisi query builder sederhana untuk CRUD dengan database mysql, dan class tersebut sudah kamu inject ke 20 class yang membutuhkannya. Tapi ternyata suatu saat kamu diharuskan pindah ke SQL Server, dengan begitu kamu harus membuat SqlServerBuilder, kemudian mengubah 20 class yang sebelumnya menggunakan MysqlBuilder.

Cara seperti itu tidaklah efisien.

Solusinya adalah kamu membuat interface QueryBuilderInterface, dimana MysqlBuilder mengimplementasikan interface tersebut. Kemudian pada 20 class yang akan di-inject, gunakan QueryBuilderInterface sebagai type hint-nya.

Jadi jika sewaktu-waktu ada perubahan dari mysql ke sql server, postgresql, oracle atau apapun, kamu cukup membuat class yang mengimplementasikan QueryBuilderInterface tersebut. Container rakit framework akan membantu kamu melakukan adaptasi secara otomatis dengan binding interface.

Tidak ada method spesial untuk melakukan binding interface, karena pada dasarnya key yang didaftarkan ke container dapat berupa apapun, tidak harus sama dengan classnya. Jadi kamu bisa saja menggunakan interface sebagai keynya seperti dibawah ini:

$app[QueryBuilderInterface::class] = function () {
    return new MysqlBuilder;
};

Dan sewaktu-waktu kamu ingin merubah mysql ke sql server, kamu cukup mengubah kode tersebut menjadi:

$app[QueryBuilderInterface::class] = function () {
    return new SqlServerBuilder;
};

Dengan begitu, semua constructor ataupun callable yang di-inject menggunakan container->make ataupun container->call akan menerima instance dari SqlServerBuilder (bukan lagi MysqlBuilder).