Appearance
Meeting 10
Pada pertemuan kali ini, kita akan membahas Paradigma Baru dalam PHP. Dunia pengembangan PHP terus berkembang, dan dengan penambahan fitur-fitur baru dalam PHP, kita juga akan memakai pengelola dependensi PHP yang biasa kita kenal dengan Composer.
Composer
Composer adalah alat manajemen paket (package management tool) untuk bahasa pemrograman PHP. digunakan oleh pengembang PHP untuk mengelola dependensi (library, framework, atau komponen lainnya) untuk pengembangan lebih terstruktur dan mudah dikelola.
Autoloading
Autoloading adalah teknik yang digunakan untuk memuat kelas PHP secara otomatis tanpa perlu menggunakan pernyataan require atau include secara manual. Dalam PHP, Anda dapat menggunakan PSR-4 (PHP-FIG Standard Recommendation 4) untuk mengatur autoloading kelas. Composer akan membantu untuk mengatur autoloading dengan mudah.
Pembuatan Proyek PHP Dengan PSR-4 Autoload
Pada kali ini kita akan membuat aplikasi dari PHP dengan cara yang lebih yang paling baru yaitu dengan Autoload, kita akan membuat mini proyek dan akan kita beri nama MiniMarkPlace. untuk langkah pertama memulai pembuatan aplikasi kita buatlah folder baru dengan nama mini-mark-place.
Inisiasi Autoload
- masuk ke folder mini-mark-place dan buka terminal lalu ketikan perintah berikut:sh
composer initcomposer initDetail Inisiasi
- makan akan keluar beberapa pengaturan untuk pengerjaan dari aplikasi yang akan di kerjakan.
Package name (<vendor>/<name>): masukan nama proyek yang akan di kerjakan contohlatihan/mini-mark-place.Description []: masukan sedikit penjelasan tentang aplikasi yang akan di buat, atau boleh di kosongkan.Author: masukan nama pembuat, atau boleh di kosongkan.Minimum Stability []: Bisa dikosongkan, namun jika dimasukan akan menjadi minimal versi dari dependensi yang akan digunakan.Package Type (e.g. library, project, metapackage, composer-plugin) []: lewati saja langkah ini, untuk menggunakan pengaturan defult dari composer.License []: dapat dikosongkan, atau jika kita memiliki lisensi atas produk kita sendiri bisa diisi.Add PSR-4 autoload mapping: tambahkan/srcuntuk menentukan autoload, mengeksekusipathaplikasi
- Jika sudah menginisiasi
composerdan mengukuti langkahnya, maka akan menghasilkan folder dan file baru seperti di bawah ini:
├── src
├── vendor
└── composer.json├── src
├── vendor
└── composer.json- untuk membuat prefix yang lebih bagus dalam pemanggilan class ubah sintaks di
composer.jsonpada bagian autoload menjadi
json
"autoload": {
"psr-4": {
"MiniMarkPlace\\": "src/"
}
},"autoload": {
"psr-4": {
"MiniMarkPlace\\": "src/"
}
},- buat file baru di dalam folder
srcdengan namaindex.phpdengan sintaks di bawah ini.
php
<?php
require __DIR__.'/../vendor/autoload.php';
echo "Hello world";<?php
require __DIR__.'/../vendor/autoload.php';
echo "Hello world";Penjelasan Code
index.phpfile ini akan menjadi pintu masuk untuk aplikasi yang akan kita buatrequire __DIR__.'/../vendor/autoload.php': menggunakan autoloader yang sudah terinstall__DIR__merupakan function dari php mengembalikan letak path dari file.echo "Hello World": menampilkan teks hello world
- Jalan kan aplikasi di terminal dengan sintaks
sh
php -S localhost:2000 -t srcphp -S localhost:2000 -t srcAtau jika ingin menjalan kan melalui laragon, buat file baru di folder proyek dengan nama .htaccess, dan tambahkan sintaks di bawah ini
txt
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/src/
RewriteRule ^(.*)$ /src/$1 [L]RewriteEngine On
RewriteCond %{REQUEST_URI} !^/src/
RewriteRule ^(.*)$ /src/$1 [L]dan struktur akhir proyek kita akan menjadi seperti ini:
├── src
│ ├── index.php
├── vendor
├── .htaccess
└── composer.json├── src
│ ├── index.php
├── vendor
├── .htaccess
└── composer.jsonRoute
Untuk membuat route, kita harus mempunyai class dasar yang berfungsi sebagai routing, seperti yang kita tahu, routing dasar dari php sesuai dengna penamaan folder dan nama file, namun disini kita akan mengubah itu, agar php bisa menghasilkan url yang gampang di baca.
Basic Route Class
- Pertama - tama buatlah folder baru di dalam
srcfolder, dengan namaLibraries - buatlah file baru di dalam folder
Librariesdengan namaRouting.php
Code Routing.php
php
<?php
namespace MiniMarkPlace\Libraries;
class Routing
{
private $routes = [];
public function add(string $path, $action)
{
$this->routes[$path] = $action;
}
public function run()
{
$path = $_SERVER['PATH_INFO'] ?? '/';
if (!isset($this->routes[$path])) {
header('HTTP/1.1 404 Not Found');
die('404 Not Found');
}
$action = $this->routes[$path];
return call_user_func($action);
}
}<?php
namespace MiniMarkPlace\Libraries;
class Routing
{
private $routes = [];
public function add(string $path, $action)
{
$this->routes[$path] = $action;
}
public function run()
{
$path = $_SERVER['PATH_INFO'] ?? '/';
if (!isset($this->routes[$path])) {
header('HTTP/1.1 404 Not Found');
die('404 Not Found');
}
$action = $this->routes[$path];
return call_user_func($action);
}
}Penjelasan Code
NamespaceDiawali dengannamespace, konsep ini ada sejak php versi 5.3 di karnakan banyaknya konflik karena penamaan class yang sama, dan dapat memudahkan kita untuk memanggil atau mengimport file yang berbeda.- Class
Routingmemiliki property$routes, yang merupakan array asosiatif antara path dan tindakan yang harus dilakukan saat route itu diakses. - Method
add(string $path, $action):method ini digunakan untuk menambahkan route baru ke dalam daftar routes - Method
run(): method menjalankan aplikasi, dan memeriksa alamat route yang sedang diakses, Jika route yang diminta tidak ada dalam daftar route, aplikasi akan memberi tahu pengguna bahwa halaman tidak ditemukan (404 Not Found)
- lalu kita akan mendaftarkan beberapa route, Ubah sintaks file
index.phpmenjadi seperti di bawah ini:
php
<?php
require __DIR__.'/../vendor/autoload.php';
use MiniMarkPlace\Libraries\Routing;
$router = new Routing();
// Home page route
$router->add('/', function() {
return 'Hello world';
});
// About page route
$router->add('/about', function() {
return 'About page';
});
// Run the router
echo $router->run();<?php
require __DIR__.'/../vendor/autoload.php';
use MiniMarkPlace\Libraries\Routing;
$router = new Routing();
// Home page route
$router->add('/', function() {
return 'Hello world';
});
// About page route
$router->add('/about', function() {
return 'About page';
});
// Run the router
echo $router->run();- coba jalankan aplikasi dan akses route yang sudah kita buat
/dan/about
Route With Method
class Routing yang kita buat sudah bisa berjalan, namun pada kali ini kita akan menambahkan agar class Routing yang sudah kita buat bisa menerima untuk perbedaan method, seperti yang kita pelajari sebelumnya terdapat lebih dari satu metode untuk http
php
$router->add('GET', '/', function() {
return 'Hello world';
});
$router->add('GET', '/product-category', function() {
return 'data produk kategori';
});
$router->add('POST', '/product-category', function() {
return 'tambah produk kategori';
});$router->add('GET', '/', function() {
return 'Hello world';
});
$router->add('GET', '/product-category', function() {
return 'data produk kategori';
});
$router->add('POST', '/product-category', function() {
return 'tambah produk kategori';
});php
<?php
namespace MiniMarkPlace\Libraries;
class Routing
{
private $routes = [];
public function add(string $method, string $path, $callback)
{
$this->routes[] = [
'method' => $method,
'path' => $path,
'callback' => $callback
];
}
public function run()
{
$method = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
foreach ($this->routes as $route) {
if ($route['method'] != $method) {
continue;
}
if ($route['path'] == $uri) {
return call_user_func($route['callback']);
}
}
header('HTTP/1.1 404 Not Found');
die('404 Not Found');
}
}<?php
namespace MiniMarkPlace\Libraries;
class Routing
{
private $routes = [];
public function add(string $method, string $path, $callback)
{
$this->routes[] = [
'method' => $method,
'path' => $path,
'callback' => $callback
];
}
public function run()
{
$method = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
foreach ($this->routes as $route) {
if ($route['method'] != $method) {
continue;
}
if ($route['path'] == $uri) {
return call_user_func($route['callback']);
}
}
header('HTTP/1.1 404 Not Found');
die('404 Not Found');
}
}Penjelasan Code
- Method
add(): kita melakukan perubahan pada method ini, yang sebelumnya lebih sederhana hanya menerima dua parameter saja, pada update ini kita menambah satu parameter lagi untuk kebutuhmethod httpyang akan di terima. - Method
run(): kita juga perlu memperbaharui Methodrun(), dan menambahkan logika untuk mencari route yang berdasarkanmethod httpyang sudah di daftarkan. - Pada file index.php kita menambahkan 2 route baru dengan
method httpyang berbedaGETdanPOST
Route With Paramater
Agar class Routing kita dapat menerima paramater, kita akan sedikit mengubah lagi sintaks dari class Routing. Parameter di route cukup penting untuk kebutuhan UPDATE, DELETE dan Detail Data(SHOW), prefix url parameter yang akan kita buat adalah seperti ini /product-category/:id
php
$router->add('GET', '/product-category/:id', function($id) {
return 'detail data produk kategori dengan id = ' . $id;
});$router->add('GET', '/product-category/:id', function($id) {
return 'detail data produk kategori dengan id = ' . $id;
});php
$regexPattern = preg_replace_callback('/:\w+/', function ($params) {
return '([^/]+)';
},
$route['path']
);
if (preg_match("#^{$regexPattern}$#", $uri, $params)) {
array_shift($params);
return call_user_func_array($route['callback'], $params);
}$regexPattern = preg_replace_callback('/:\w+/', function ($params) {
return '([^/]+)';
},
$route['path']
);
if (preg_match("#^{$regexPattern}$#", $uri, $params)) {
array_shift($params);
return call_user_func_array($route['callback'], $params);
}Penjelasan Code
- untuk perbaharuan kali ini pada class Routing hanya pada method
run():php$regexPattern = preg_replace_callback('/:\w+/', function ($params) { return '([^/]+)'; }, $route['path'] ); if (preg_match("#^{$regexPattern}$#", $uri, $params)) { array_shift($params); return call_user_func_array($route['callback'], $params); }$regexPattern = preg_replace_callback('/:\w+/', function ($params) { return '([^/]+)'; }, $route['path'] ); if (preg_match("#^{$regexPattern}$#", $uri, $params)) { array_shift($params); return call_user_func_array($route['callback'], $params); }- menggunakan pattern dari regex untuk mengambil parameter yang diisi di uri.
- melakukan cek apakah uri ditemukan di dalam regexPattern dan jika ditemukan maka akan mengembalikan hasilnya ke callback terkait dengan parameter yang dikirim sebagai argumen.
- Menambahkan route baru di index.php untuk mencoba apakah penerapan perbaharuan yang kita lakukan dapat bekerja.
php
$router->add('GET', '/product-category/:id', function($id) {
return 'detail data produk kategori dengan id = ' . $id;
});$router->add('GET', '/product-category/:id', function($id) {
return 'detail data produk kategori dengan id = ' . $id;
});Kita juga bisa memakai lebih dari satu parameter sebagai contoh:
php$router->add('GET', '/url/:param1/:param2/:param3', function($param1, $param2, $param3) { return "{$param1}, {$param2}, {$param3}"; });$router->add('GET', '/url/:param1/:param2/:param3', function($param1, $param2, $param3) { return "{$param1}, {$param2}, {$param3}"; });
Route With Controller
class Routing yang sudah kita buat sudah berjalan dengan baik, namun kita tidak bisa langsung manaruh logika pemrograman kita pada file index.php, setiap sintaks dari route akan sangat panjang, apalagi kalau aplikasi yang kita buat lebih dari satu module, seperti kategori produk dan produk.
- Buatlah folder baru dengan nama folder
Controllers - lalu buat file baru di dalam folder tersebut dengan nama file
ProductCategoryController.php
php
<?php
namespace MiniMarkPlace\Controllers;
class ProductCategoryController
{
public function index()
{
return "data produk kategori";
}
public function store()
{
return "tambah produk kategori";
}
public function show($id)
{
return 'detail data produk kategori dengan id = ' . $id;
}
public function update($id)
{
return 'update data produk kategori dengan id = ' . $id;
}
public function delete($id)
{
return 'menghapus data produk kategori dengan id = ' . $id;
}
}<?php
namespace MiniMarkPlace\Controllers;
class ProductCategoryController
{
public function index()
{
return "data produk kategori";
}
public function store()
{
return "tambah produk kategori";
}
public function show($id)
{
return 'detail data produk kategori dengan id = ' . $id;
}
public function update($id)
{
return 'update data produk kategori dengan id = ' . $id;
}
public function delete($id)
{
return 'menghapus data produk kategori dengan id = ' . $id;
}
}- Perbaharui sintaks dari class
Routingagar dapat meneruskan aksi ke class controller yang sudah kita buat yaitu classProductCategoryController
php
if (preg_match("#^{$regexPattern}$#", $uri, $params)) {
array_shift($params);
if (is_callable($route['callback'])) {
return call_user_func_array($route['callback'], $params);
} else {
list($controller, $method) = $route['callback'];
$instance = new $controller();
return $instance->$method(...$params);
}
}if (preg_match("#^{$regexPattern}$#", $uri, $params)) {
array_shift($params);
if (is_callable($route['callback'])) {
return call_user_func_array($route['callback'], $params);
} else {
list($controller, $method) = $route['callback'];
$instance = new $controller();
return $instance->$method(...$params);
}
}- dan terkahir perbaharui cara pemanggilan route dari file
index.php, sintaks akan menjadi seperti dibawah ini.
php
$router->add('GET', '/product-category', [ProductCategoryController::class, 'index']);
$router->add('GET', '/product-category/:id', [ProductCategoryController::class, 'show']);
$router->add('POST', '/product-category', [ProductCategoryController::class, 'store']);
$router->add('PUT', '/product-category/:id', [ProductCategoryController::class, 'update']);
$router->add('DELETE', '/product-category/:id', [ProductCategoryController::class, 'delete']);$router->add('GET', '/product-category', [ProductCategoryController::class, 'index']);
$router->add('GET', '/product-category/:id', [ProductCategoryController::class, 'show']);
$router->add('POST', '/product-category', [ProductCategoryController::class, 'store']);
$router->add('PUT', '/product-category/:id', [ProductCategoryController::class, 'update']);
$router->add('DELETE', '/product-category/:id', [ProductCategoryController::class, 'delete']);Dengan begini base untuk class Routing kita dapat menangani segala kondisi, dan url pada aplikasi yang kita buat menjadi lebih bagus, dan struktur aplikasi yang kita buat akan menjadi seperti:
├── src
│ ├── Controllers
│ │ ├── ProductCategoryController.php
│ ├── Libraries
│ │ ├── Routing.php
│ ├── index.php
├── vendor
├── .htaccess
└── composer.json├── src
│ ├── Controllers
│ │ ├── ProductCategoryController.php
│ ├── Libraries
│ │ ├── Routing.php
│ ├── index.php
├── vendor
├── .htaccess
└── composer.json