Apa itu MVC?
MVC, atau Model View Controller, merupakan salah satu implementasi
prinsip SoC untuk aplikasi yang kita kembangkan. Dalam MVC, kita membagikan
bentuk aplikasi dalam tiga bagian utama, yaitu:
1. Model, yaitu bagian kode aplikasi yang
berhubungan dengan basis data.
2. View, yaitu bagian kode yang berhubungan
dengan tampilan ke pengguna.
3. Controller, yaitu bagian kode yang
menghubungkan antara Model dan View.
Note
Sebagai prinsip yang memberikan solusi untuk
permasalahan umum, MVC juga merupakan design
pattern. Meskipun
memberikan prinsip dasar yang sama, implementasi MVC biasanya akan
berbeda-beda, tergantung siapa yang mengimplementasikannya.
Secara kasar, berikut adalah arsitektur
aplikasi web kita jika dikembangkan dengan menggunakan pola MVC:
Arsitektur
Sederhana MVC
Alur kerja aplikasi web kita ketika user
mengunjungi salah satu halaman yaitu:
1. Browser berhubungan dengan server untuk akses halaman.
2. Request (permintaan) browser ditangani oleh
bagian Controller dari kode kita.
3. Controller akan melakukan pemanggilan ke
Model untuk mendapatkan data yang relevan, dan kemudian mempersiapkan data
tersebut untuk ditampilkan.
4. Controller memberikan data yang
diperlukan kepada view.
5. View menampilkan data dan berbagai
elemen antarmuka tambahan yang diperlukan.
Meskipun memerlukan banyak langkah hanya
untuk menampilkan satu halaman web, kita dapat langsung melihat keuntungan
tambahan dari penggunaan MVC, yaitu bagaimana setiap bagian memiliki tanggung
jawab masing-masing. Ingin mengubah query yang digunakan agar menjadi lebih cepat?
Langsung saja edit kode pada bagian Model. Designer juga dapat bekerja pada
bagian view jika ingin mengubah tampilan, tanpa perlu takut merusak keseluruhan
kode. Pastinya hal seperti ini akan mempercepat dan mempermudah pengembangan
web kita!
Tertarik untuk melihat bagaimana membuat
framework MVC sederhana? Mari kita segera coba!
Include File Otomatis dan index.php
Salah satu fitur framework yang paling memudahkan kita adalah
fitur yang memungkinkan kita untuk memanggil class dan fungsi-fungsi yang dibuat secara
otomatis, tanpa harus menggunakan fungsi include atau require.
Fitur ini dikenal dengan nama “Autoloading”, yang dapat kita kembangkan dengan
menggunakan fungsi dasar PHP: spl_autoload_register.
Mari kita mulai pengembangan framework kita dengan memberikan fitur autoloading
ini terlebih dahulu.
Include
File Otomatis
Langsung saja, buat sebuah file dengan nama Autoloader.php di dalam direktori utama kode, yang
berisikan dua baris kode berikut:
1
2
3
4
|
<?php
spl_autoload_extensions(".php"); spl_autoload_register(); |
Apa yang baru saja kita lakukan? Fungsi spl_autoload_extensions merupakan fungsi yang memberitahukan PHP
untuk memberikan semua file dengan ekstensi yang kita berikan (“.php”) untuk dibaca oleh fungsi lain, yaitu __autoload().
Fungsi __autoload sendiri merupakan fungsi yang dipanggil
secara otomatis oleh PHP ketika fitur autoloading diaktifkan. Lalu bagaimana cara
aktivasi fitur autoloading? Dengan
memanggil fungsi spl_autoload atau spl_autoload_register.
Kita memanggil fungsi spl_autoload_register tanpa memberikan parameter apapun, yang
artinya PHP akan menggunakan aturan standar, yaitu tempat penyimpanan file
kelas akan sama dengan nama direktori yang kita gunakan untuk namespace dari kelas tersebut. Hal ini berarti
jika kita memiliki kelas dengan kode seperti ini:
1
2
3
4
5
6
7
|
<?php
namespace lib\MVC; // Direktori harus sama!
class Loader { // ... } |
Maka kita harus menyimpan file kelas tersebut pada direktori lib/MVC, relatif
terhadap kode yang kita gunakan. Jika menggunakan aturan dengan tepat, ketika
memanggil kelas tersebut ktia tidak lagi perlu memanggil fungsi include atau require. Mudah bukan?
Router
Selain fitur pemanggilan kelas secara otomatis, biasanya sebuah framework
PHP juga memberikan kemudahan dalam hal memperindah URL. Struktur URL secara
standar akan diberikan oleh framework, misalnya dalam format http://web.com/controller/action/id.
Fitur ini dikenal dengan nama URL Rewriting, yang dapat diimplementasikan
dengan kombinasi antara pengaturan web server dan kode PHP. Kita akan
mengembangkan fitur yang sama sekarang, sebelum mulai membuat file index.php.
URL
Rewriting pada Server
Sebelum mulai, kita harus membuat satu asumsi terlebih dahulu:
yaitu web server yang digunakan adalah Apache HTTPD. Apache merupakan salah
satu web server yang paling populer, dan biasanya digunakan oleh operator shared
hosting, sehingga kita dapat berasumsi secara umum bahwa
konfigurasi kita dapat digunakan. Jika tempat hosting anda tidak mengaktifkan
fitur ini, silahkan hubungi tempat hosting anda untuk aktivasi fitur. Untuk
server lokal, ikuti
tutorial berikut untuk aktivasi fitur URL Rewriting Apache.
Setelah aktivasi fitur URL Rewriting, kita harus membuat sebuah
file bernama .htaccess (tanda
titik di awal file sangat penting).
Letakkan file ini pada direktori utama kode (sama dengan Autoloader.php),
dan isikan file dengan kode berikut:
1
2
3
4
|
Options +FollowSymLinks
RewriteEngine on
RewriteRule ^([a-zA-Z]*)/?([a-zA-Z]*)?/?([a-zA-Z0-9]*)?/?$ \
index.php?controller=$1&action=$2&id=$3 [NC,L]
|
Apa yang baru saja kita lakukan? Dua baris pertama kode di atas
merupakan perintah untuk aktivasi fitur URL Rewrite pada direktori kode program
kita, sehingga setiap kali menerima URL pada direktori tersebut Apache akan
mengubahnya sesuai dengan aturan yang telah kita tentukan. Seperti yang telah
dapat ditebak, aturan perubahan URL terdapat pada baris ketiga. Aturan
dituliskan dengan Regular Expression (Regex),
dengan format RewriteRule <URL Asli (Regex)> <URL Hasil Konversi>.
Aturan yang kita tetapkan sangat sederhana: setiap URL dengan
format http://web.com/kode1/kode2/kode3 akan diubah menjadi http://web.com/index.php?controller=kode1&action=kode2&id=kode3.
Kode2 dan Kode3 bersifat opsional, yang berarti boleh diisikan boleh tidak.
(Akan perlu penjelasan mengenai Regex panjang lebar untuk detil dari kenapa aturannya dibaca seperti ini.
Pembahasan akan dilakukan lain waktu).
URL
Rewriting pada PHP
Selesai konfigurasi server, pastinya kita harus mempersiapkan
kode PHP yang dapat membaca hasil konversi URL tersebut. Mari kita mulai dengan
membuat file yang menangani hal ini, yaitu Router.php. Simpan file Router.php di dalam direktori lib/MVC untuk memastikan kode kita tersimpan
dengan rapi. Berikut adalah isi dari file Router.php:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
<?php
namespace lib\MVC;
class Router { private $controller; private $action; private $urlParams;
private $Controller_Namespace = "\\controllers\\"; private $Base_Controller_Name = "lib\\MVC\\Controller\\BaseController";
public function __construct($urlParams) { $this->urlParams = $urlParams;
if (empty($this->urlParams["controller"])) { $this->controller = $this->Controller_Namespace . "Home"; } else { $this->controller = $this->Controller_Namespace . $this->urlParams["controller"]; }
if (empty($this->urlParams["action"])) { $this->action = "index"; } else { $this->action = $this->urlParams["action"]; }
}
public function getController() { if (class_exists($this->controller)) { $parent = class_parents($this->controller);
if (in_array($this->Base_Controller_Name, $parent)) { if (method_exists($this->controller, $this->action)) { return new $this->controller($this->action, $this->urlParams); } else { throw new \Exception("Action not found!"); }
} else { throw new \Exception("Wrong class for controller. Not derived from BaseController."); }
} else { throw new \Exception("Controller not found!"); }
}
} |
Apa yang baru saja kita buat? Kelas Router bertanggung jawab untuk menemukan
Controller yang tepat, beserta memanggil fungsi (action) yang tepat dari
Controller tersebut. Kita akan mengirimkan parameter GET ketika pertama kali
membuat kelas ini, seperti berikut:
1
|
$route = new Router($_GET) |
Sehingga Router dapat
memproses data GET tersebut dan memilih Controller yang tepat. Kode untuk
memilih Controller yang tepat sendiri sangat sederhana, hanya memanggil sesuai
dengan parameter yang dikirimkan oleh pengguna. Kode untuk pemlihan Controller
dan Action cukup gamblang, silahkan dibaca pada fungsi __construct().
Setelah memilih Controller dengan benar, tentunya kita pasti
ingin mengambil Controller tersebut, agar proses pengolahan halaman dapat
berjalan dengan benar. Fitur pengambilan Controller ini diimplementasikan oleh
fungsi getController(),
yang juga cukup sederhana isinya: cek apakah Controller merupakan turunan dari BaseController(detil
ada pada bagian selanjutnya), lalu cek apakah kelas dan method controller dapat
ditemukan atau tidak. Kalau dapat ditemukan, panggil, kalau tidak lemparkan
Exception.
Index.php
Sekarang kita telah menyelesaikan semua kode-kode awal yang
dibutuhkan untuk menjalankan framework kita, walaupun belum dapat menampilkan
apa-apa. Mari kita buat halaman awal framework, yang fungsinya adalah untuk
memanggil dan mempersiapkan semua kode yang kita tuliskan sampai sejauh ini.
Buat file index.php pada
direktori utama kode anda, yaitu direktori yang sama dengan tempat .htaccess dan Autoloader.php disimpan. Isi dari index.php hanyalah pemanggilan terhadap Autoloader.php dan kelas Router:
1
2
3
4
5
6
7
8
|
<?php
require_once __DIR__ . "/AutoLoader.php";
use lib\MVC\Router;
$kernel = new Router($_GET); $controller = $kernel->getController(); |
Sampai titik ini, jika menjalankan kode kita, kita akan
mendapatkan pesan kesalahan seperti ini:
Pesan
Kesalahan Awal
Apa arti kesalahan ini? Inti kesalahan ada di pesan Class
controllersHome could not be loaded, yang artinya PHP gagal
menemukan kelas controllers\Home, yang artinya kode kita
bekerja dengan benar sampai titik ini! Hurrah! Tahap selanjutnya, mari segera
fokus untuk membuat Controller!
Controller
Seperti yang telah dibahas pada bagian Apa itu MVC?,
peran utama dari Controller adalah menghubungkan antara view dengan model. Pada
bagian ini kita akan membangun fondasi dari Controller: sebuah kelas abstrak
yang nantinya akan diwariskan oleh pengguna framework ketika mereka ingin membuat
Controller. Setiap Controller harus mewariskan sifat dari kelas abstrak
Controller yang akan kita kembangkan ini, untuk memastikan seluruh Controller
yang ada dapat memanggil view dengan benar. Kelas abstrak ini memiliki dua
fungsi utama: menjalankan action yang sesuai dengan permitaan pengguna, dan memanggil
view yang relevan dengan action tersebut.
Fondasi
Controller: BaseController.php
Agar tidak terlalu mengambang dan bingung dengan penjelasan yang
diberikan, mari kita lihat langsung bagaimana kode yang dimaksud di atas. Buat
sebuah file dengan nama BaseController.php pada direktori lib/MVC/Controller.
Isikan kode di bawah ke dalam file BaseController.php:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<?php
namespace lib\MVC\Controller;
abstract class BaseController { protected $urlParams; protected $action;
public function __construct($action, $urlParams) { $this->action = $action; $this->urlParams = $urlParams; }
public function ExecuteAction() { return $this->{$this->action}(); }
protected function RenderView($viewModel, $fullView = true) { $classData = explode("\\", get_class($this)); $className = end($classData);
$content = __DIR__ . "/../../../views/" . $className . "/" . $this->action . ".php";
if ($fullView) { require __DIR__ . "/../../../views/template.php"; } else { require $content; }
}
} |
Apa yang baru saja kita kerjakan? Pastinya kita telah membuat
sebuah kelas abstrak BaseController, yang memiliki dua buah
data: $urlParams dan $action. Sesuai dengan namanya, $urlParams menyimpan seluruh data GET yang diberikan
oleh server, sementara $action menyimpan
nama action yang akan dijalankan oleh pengguna.
Variabel $viewModel merupakan
variabel yang menampung data yang akan kita dapatkan melalui bagian Model
nanti, sementara variabel $fullView digunakan
untuk menentukan apakah View akan ditampilkan dengan lengkap (beserta dengan
tag <html><head> ...)
atau tidak.
Method ExecuteAction() berfungsi untuk memanggil method action
yang dibuat oleh Controller yang mengimplementasikan kelas abstrak ini. Secara
otomatis, nama method untuk action yang akan dipanggil harus sama dengan nama
action itu sendiri. Hal ini berarti URL http://web.com/home/about akan memanggil method about() pada Controller Home.
Method RenderView() bertanggung jawab untuk memanggil View
yang tepat, dan memberikan data Model yang didapatkan ke View tersebut. Dua
baris awal dari kode dalam method ini:
1
2
3
4
5
|
// contoh isi $classData: array("lib", "MVC", "Controller", "BaseController") $classData = explode("\\", get_class($this));
// isi $className: "BaseController" $className = end($classData); |
Berguna untuk mengambil nama Controller akan ditampilkan
View-nya. Baris pertama mengambil nama Controller melalui fungsi get_class().
Karena nilai kembalikan dari fungsi get_class() memberikan
nama kelas beserta dengan namespace-nya, maka kita harus mengolahnya terlebih
dahulu untuk mendapatkan hanya nama kelas saja. Fungsi explode() digunakan untuk memecah namespace dan
nama kelas tersebut ke dalam array, dan fungsi end() digunakan untuk mengambil elemen terakhir
dari array yang didapatkan pada baris pertama. Nama kelas selalu muncul pada
akhir namespace, sehingga kita dapat yakin fungsi end() akan memberikan nama kelas yang benar.
Setelah mendapatkan nama Controller yang relevan, kita kemudian
mencoba mengakses direktori view pada
direktori utama kode (tempat file Autoloader.php dan index.php berada).
Setiap View harus disimpan dalam direktori viewtersebut, dan di dalam direktori view terdapat direktori untuk View dari
masing-masing Controller. Nama file untuk masing-masing View dirancang untuk
harus sama dengan nama action, agar terdapat keseragaman dan kemudahan
perawatan kode.
Kita akan melengkapi seluruh bagian View pada bagian
selanjutnya, sehingga sekarang tidak perlu terlalu khawatir jika belum terlalu
mengerti method RenderView(). Bagian selanjutnya akan
menjelaskan hal-hal yang masih “kosong” pada bagian ini. Untuk sekarang, kita
akan coba mebuat sebuah Controller standar terlebih dahulu, yaitu Controller
Home.
Controller
Pertama: Home.php
Langkah untuk pembuatan Controller baru sangat mudah: buat kelas
sesuai dengan nama Controller yang diinginkan pada direktori controllers.
Direktori controllers harus berada di dalam direktori utama
kode. Jadi, langkah pertamanya adalah membuat direktori controllers,
yang berisikan satu file saja, yaitu Home.php. Isi dari Home.phpadalah
sebagai berikut:
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
namespace controllers;
use lib\MVC\Controller\BaseController;
class Home extends BaseController { protected function Index() { $viewModel = "DATA"; $this->RenderView($viewModel); }
} |
Simpel kan? Kunci dari membuat sebuah Controller ada dua, yaitu:
1.
Lakukan
implementasi terhadap BaseController
2.
Nama
method yang dibuat di dalam Controller akan menjadi nama rute URL secara
otomatis.
Sesuai dengan poin kedua, method Index() pada Controller “Home” dapat diakses
dengan mengakses /home/index/atau hanya dengan mengakses / saja. Misalnya, jika seluruh kode anda
disimpan pada direktori framework, maka anda dapat mengakses
halmana http://localhost/framework/ atau http://localhost/framework/home/index.
Terakhir, kita juga perlu menambahkan kode pada file index.php,
yang menjalaknak ExecuteAction. Ganti isi index.phpmenjadi
seperti berikut:
1
2
3
4
5
6
7
8
9
10
|
<?php
require_once __DIR__ . "/AutoLoader.php";
use lib\MVC\Router; use lib\MVC\Controller;
$kernel = new Router($_GET); $controller = $kernel->getController(); $controller->ExecuteAction(); |
Sampai titik ini, jika mengakses halaman utama kita akan
mendapatkan pesan kesalahan:
Pesan
Kesalahan Selesai Membuat Controller
Sesuai dengan keterangannya, aplikasi yang dibangun mencoba
mengakses View, yang tidak dapat ditemukan. Kenapa View tidak dapat ditemukan?
Karena kita belum membuat View! Mari kita kembangkan View sekarang!
View
Selesai membuat Controller pada bagian sebelumnya <3-Controller>,
sekarang kita akan membuat bagian yang berinteraksi dengan pengguna: View.
Karena aplikasi yang dikembangkan merupakan aplikasi web, maka kita hanya memiliki
satu pilihan bahasa untuk membuat antarmuka: HTML.
Note
Sebenarnya
kita dapat menggunakan lebih dari satu pilihan bahasa untuk antarmuka. Terdapat
banyak bahasa lain yang dapat dikompilasi menjadi HTML seperti Jade, Twig dan HAML. Untuk
kesederhanaan, kita hanya akan menggunakan HTML standar (bahasa-bahasa lainnya
toh pada akhirnya juga dikompilasi ke HTML).
Seperti layaknya Controller yang mengandalkan konvensi penamaan
file dan kelas, kita juga akan menggunakan aturan penamaan untuk membuat View.
Terdapat tiga aturan utama untuk View:
1.
Seluruh
file View disimpan dalam direktori views. Direktori views terletak pada direktori
utama kode.
2.
File
View untuk Controller spesifik disimpan pada sub-direktori di dalam views. Sub-direktori ini diberi
nama sama dengan nama Controller.
3.
Nama
dari file View yang dibuat harus sama dengan nama action yang ada.
Ketiga aturan ini kita terapkan ketika membuat method RenderView() pada kelas BaseController.
Untuk mengingatkan, berikut adalah kode dari method tersebut:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
protected function RenderView($viewModel, $fullView = true) { $classData = explode("\\", get_class($this)); $className = end($classData);
$content = __DIR__ . "/../../../views/" . $className . "/" . $this->action . ".php";
if ($fullView) { require __DIR__ . "/../../../views/template.php"; } else { require $content; } } |
Seperti yang terlihat di atas, kita terlebih dahulu harus
membuat file utama dari View, yang menampung bagian-bagian umum dari antarmuka
aplikasi web kita. Bagian umum ini adalah bagian-bagian dari antarmuka yang
dimiliki oleh seluruh aplikasi web, seperti header dan menu aplikasi.
Halaman
Penampung: Template.php
Langsung saja, kita dapat memulai dengan membuat file template.php dalam direktori views,
dengan isi seperti berikut:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
<html> <head> <title>Framework Testing</title>
<base href="http://localhost/framework/"> <link rel="stylesheet" href="public/css/bootstrap.journal.min.css"/> </head>
<body> <header class="container"> <nav class="navbar navbar-default" role="navigation"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#"> Framework Sederhana
</a> </div>
<!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Home</a></li> <li><a href="#">About</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> News
<b class="caret"></b> </a> <ul class="dropdown-menu"> <li><a href="#">Articles</a></li> <li><a href="#">Editorials</a></li> <li><a href="#">Features</a></li> <li class="divider"></li> <li><a href="#">Reader's Digest</a></li> <li><a href="#">Ask Me Anything</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left" role="search"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default"> Submit
</button> </form> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Login</a></li> </ul> </div><!-- /.navbar-collapse --> </nav> </header>
<div class="container"> <?php require($content) ?> </div>
<script type="text/javascript" src="public/js/jquery.min.js"></script> <script type="text/javascript" src="public/js/bootstrap.min.js"></script> </body> </html> |
Mayoritas kode di dalam template.php merupakan kode standar untuk membangun
menu menggunakan framework Bootstrap. Hanya ada dua bagian kode yang relevan
untuk framework kita, yaitu:
1
2
3
4
5
6
7
8
9
|
<!-- ... -->
<base href="http://localhost/framework/">
<!-- ... -->
<div class="container"> <?php require($content) ?> </div> |
Note
Apa kegunaan dua bagian kode di atas?
1.
Elemen <base> merupakan elemen yang
menentukan URL dasar dari seluruh halaman kita. Dengan menggunakan elemen ini,
ketika kita menuliskan public/css/style.css pada kode HTML kita,
browser akan membacanya sebagai http://localhost/framework/public/css/style.css. Bagian ini cukup penting
untuk memastikan seluruh file CSS dan Javascript dimasukkan dengan benar. Ingat
juga untuk menyesuaikan nilai href dengan tempat anda
menyimpan kode.
2.
Kode
PHP <?php require($content) ?> merupakan kode yang
menggabungkan file View dari Controller terhadap template. Ingat bahwa variabel $content dibuat pada fungsi RenderView() pada BaseController.
Selesai membuat template.php, selanjutnya kita akan
membuat View untuk Controller “Home”.
View untuk
Controller “Home”
Sesuai dengan aturan yang telah dibahas pada bagian sebelumnya,
membuat View dari Controller “Home” tidaklah sulit. Cukup buat sebuah file baru
pada direktori views/Home dengan
nama Index.php. Isi
dari file Index.php adalah seperti berikut:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<table class="table table-striped table-hover"> <thead> <tr> <th>Nama Pengguna</th> <th>Email</th> </tr> </thead>
<tbody> <tr> <td colspan="2">Kosong</td> </tr> </tbody> </table> |
Ingat bahwa kita tidak lagi perlu menuliskan kode lengkap HTML,
karena BaseController->RenderView() akan secara otomatis menggabungkan file Index.php dengan tempalte.php. Sampai titik ini jika menjalankan
aplikasi dengan berkunjung dari browser maka kita akan mendapatkan tampilan
dasar yang agak rusak seperti ini:
Tampilan
Awal yang Masih Kurang Sempurna
Untuk menyempurnakan tampilan, kita perlu menambahkan CSS dari
bootstrap.
File
Statis (CSS, Javascript, Gambar)
Seluruh file statis yang kita miliki akan kita masukkan ke dalam
direktori public pada direktori utama kode (setara dengan controllers, views, dan lib).
Karena telah mengikutkan file CSS dan Javascript Bootstrap pada template.php,
maka kita akan menambahkan file bootstrap ke dalam direktori public saja.
Langkah pertamanya, tentunya, adalah mengambil
kode bootstrap. Ekstrak file hasil download di direktori public,
sehingga isi dari direktori public menjadi
seperti berikut:
Isi
Direktori Public
Dan dengan menambahkan file Bootstrap, maka kita akan
mendapatkan tampilan akhir seperti berikut:
Hasil
Akhir Sementara
Akhir Kata
Sekarang kita telah berhasil membuat aplikasi bekerja dengan
benar! Akhirnya! Selanjutnya kita akan menambahkan bagian Model untuk koneksi
ke database. Tetapi tunggu dulu. Sebelum langsung membaca bagian Model, coba
tambahkan sebuah action terlebih dahulu (misalnya untuk URL /about).
Kenapa perlu melakukan hal ini? Untuk memastikan bahwa anda telah benar-benar
mengerti semua konsep yang dibaca sampai sekarang. Jika ada pertanyaan,
silahkan tinggalkan komentar.
Jadi, tunggu apa lagi? Selamat mencoba!
Model
Mayoritas dari aplikasi web yang kita
kembangkan akan berhubungan dengan data. Mungkin kita ingin menampilkan data,
melakukan pengolahan data, ataupun menyimpan data. Data dapat saja disimpan
dalam basis data seperti MySQL ataupun dalam bentuk lainnya, seperti file. Tidak
penting apapun yang dilakukan dengan data dan media penyimpanannya, bagian
Model akan bertanggung jawab menangani hal tersebut.
Sebagai contoh, kita akan membuat sebuah
kelas sederhana untuk melakukan query ke basis data MySQL. Tentunya pada aplikasi web yang
sebenarnya kita akan perlu tidak hanya Model untuk basis data, tetapi juga
banyak Model lainnya, seperti model untuk data Session Cookies
<http://php.net/manual/en/memcached.sessions.php> untuk status pengguna, Cache, dan
lainnya. Prinsip dasar untuk implementasi model yang kita kembangkan dapat
digunakan untuk bentuk data lain tersebut juga, hanya saja pengembangan harus
dilakukan secara terpisah.
Tanpa banyak bicara lagi, kita akan
langsung membuat kelas dasar untuk koneksi basis data, menggunakan PDO
(PHP Data Objects) <http://www.php.net/manual/en/book.pdo.php>. Pertama-tama, buat file BaseModel.php yang
disimpan dalam lib/MVC/Model. Seluruh kelas yang berhubungan dengan
basis data akan mengimplementasikan kelas dasar ini nantinya. Berikut adalah
isi dari BaseModel.php:
1
2
3
4
5
6
7
8
9
10
|
<?php
namespace lib\MVC\Model;
abstract class BaseModel {
public static function getDB() {
return new \PDO("mysql:host=localhost;dbname=framework",
"userframework", "password");
}
}
|
Ingat bahwa anda harus menggantikan
seluruh parameter yang dikirimkan kepada PDO, sesuai dengan konfigurasi basis
data anda. Silahkan baca dokumentasi
PDO untuk
melihat detil dari parameter konfigurasi yang ada.
Setelah membuat kelas BaseModel, kita
dapat mengimplementasikan kelas tersebut sesuai dengan kebutuhan kita. Misalkan
jika kita memiliki basis data pengguna seperti berikut:
Isi Tabel
Pengguna
Maka kita dapat membuat sebuah kelas Pengguna yang
berfungsi khusus untuk melakukan query terhadap tabel Pengguna. Mari kita
kembangkan kelas tersebut. Pertama-tama, buat sebuah file baru bernama Pengguna.php yang
diletakkan di direktori baru juga, models. Direktori models ini berada
dalam direktori utama kode, yaitu setingkat dengan views dan controllers. Isi dari Pengguna.php adalah
seperti berikut:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<?php
namespace models;
use lib\MVC\Model\BaseModel;
class Pengguna extends BaseModel {
public $nama;
public $email;
public function __construct($nama, $email) {
$this->nama = $nama;
$this->email = $email;
}
public static function getPengguna() {
$query = self::getDB()->prepare("SELECT * FROM `pengguna`");
$query->execute();
$result = array();
while ($row = $query->fetch()) {
array_push($result,
new Pengguna($row["nama"], $row["email"]));
}
return $result;
}
}
|
Pada dasarnya kelas Pengguna hanya berfungsi
untuk menyimpan data pengguna, dengan satu fungsi statis, getPengguna(). Fungsi
ini seperti namanya bertanggung jawab untuk mengambil seluruh data pengguna
yang ada, dalam bentuk array dari kelas Pengguna. Kita kemudian dapat memanggil fungsi
ini pada Controller, untuk kemudian dikirimkan kepada View. View lah yang
kemudian akan menampilkan data, dalam bentuk apapun yang kita inginkan.
Misalkan jika kita ingin menmapilkan
data pengguna dalam bentuk tabel, maka kita dapat melakukan hal berikut:
1. Tambahkan kode untuk pengambilan data
pada action dalam Controller yang relevan. Dalam contoh ini, kita akan
menambahkan kode pada action Index() di dalam Controller “Home”. Edit fungsi Index() pada
Controller “Home” menjadi seperti berikut (perhatikan juga bahwa kita
menambahkan use models\Pengguna pada awal kode):
1
2
3
4
5
6
7
8
9
10
11
|
namespace controllers;
use lib\MVC\Controller\BaseController;
use models\Pengguna;
class Home extends BaseController {
protected function Index() {
$viewModel =
Pengguna::getPengguna();
$this->RenderView($viewModel);
}
}
|
2. Ganti View yang relevan dengan logika
untuk penampilan data. Karena data dikirimkan dalam bentuk array, kita dapat
langsung melakukan iterasi dan menampilkan data tersebut dengan perintah echo. Gantikan
isi Index.phpyang ada di
dalam views/Home menjadi seperti
berikut:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<table class="table
table-striped table-hover">
<thead>
<tr>
<th>Nama
Pengguna</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<?php foreach ($viewModel as $pengguna): ?>
<tr>
<td><?php echo $pengguna->nama ?></td>
<td><?php echo $pengguna->email ?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
|
Sudah selesai. Cukup dengan dua langkah
saja maka kita dapat menghasilkan tampilan seperti berikut:
Hasil Akhir
Tampilan dengan Data dari Basis Data
Tentu saja implementasi yang kita buat
sangat sederhana, dan masih perlu banyak pengembangan. Karena data merupakan
hal yang sangat penting, disarankan untuk mengintegrasikan solusi data lengkap
seperti Doctrine untuk mendapatkan fitur maksimal dengan resiko
minimal. Ingat bahwa yang ingin diperlihatkan dari tulisan ini hanyalah konsep
dasar untuk membangun framework dan garis besar cara kerjanya.
Penutup dan Pengembangan Lebih Panjut
Sejauh ini kita telah melihat bagaimana mengembangkan sebuah
framework PHP dengan memperhatikan prinsip Seperation
of Concern. Tentunya masih terdapat sangat banyak kekurangan dari
framework kecil-kecilan yang kita kembangkan, baik dari segi fitur maupun dari
sisi lainnya seperti keamanan atau performa. Kembali diingatkan bahwa tujuan
utama dari tulisan ini adalah untuk memberikan pengertian mendasar dan abstrak
akan cara kerja framework umumnya, bukan demonstrasi bagaimana membuat
framework yang dapat dipakai di lingkugnan produksi.
Selama mengikuti tulisan bagian 1 sampai 5, kita telah berhasil
membuat sebuah framework MVC sederhana. Konsep dasar yang digunakan hampir
semua framework MVC hampir sama: terdapat kelas Router untuk mengatur URL dan memetakan URL ke
kelas Controller, kemudian kelas Controller tersebut akan memanggil View yang
tepat. Koneksi ke Model dilakukan secara otomatis, dan index.php,
sebagai halaman awal aplikasi, kebanyakan hanya diisi dengan konfigurasi awal
aplikasi.
Jika ingin mengembangkan aplikasi yang menggunakan framework
MVC, biasanya kita harus melakukan hal-hal berikut:
1.
Buat template utama yang menampung seluruh tampilan
antarmuka.
2.
Kembangkan
kode untuk pengambilan / pengolahan data melalui kelas Model.
3.
Buat
method atau action untuk Controller yang relevan. Pastikan untuk memanggil kode
Model yang baru dikembangkan pada langkah 2.
4.
Rancang
tampilan pada file View yang sesuai dengan konvensi framework, sehingga View
selalu terpetakan ke Controller.
Dengan mengerti konsep dasar di atas, maka kita dapat
mempelajari framework PHP yang ada dengan lebih cepat, dan bisa dikatakan
menjadi tidak asing lagi dengan pola rancangan MVC. Tentu saja langkah-langkah
di atas ini juga berlaku untuk framework yang kita kembangkan (coba saja
tambahkan fitur baru dengan mengikuti langkah 2-4).
Pengembangan
Lebih Lanjut
Jika tertarik untuk lebih lanjut mengembangkan framework
sederhana ini, baik sebagai pembelajaran maupun tantangan tambahan, berikut
adalah fitur-fitur penting untuk lingkungan produksi yang belum diimplementasikan:
- Penanganan
kesalahan yang baik. Pada kelas Router misalnya, ketika URL tidak
ditemukan, kita langsung hanya melemparkan Exception.
Idealnya framework mampu memberikan kode 404 atau halaman khusus 404
ketika rute tidak ditemukan. Jika memang terdapat Exception,
harusnya framework mengembalikan kode 503 atau halaman khusus 503.
- Pembacaan
parameter POST dan lainnya. Ketika pengguna mengirimkan data melalui form
HTML, akan lebih aman jika kita menggunakan POST daripada GET. Anda dapat
mengembangkan kelas yang mengolah baik GET maupun POST untuk dikirimkan ke
Controller, sehingga Controller mampu menangani kedua jenis parameter ini.
Untuk sekarang, kita hanya membaca parameter GET.
- Validasi
Model. Hal ini berkaitan dengan validasi data yang masuk dan keluar dari
Model. Validasi sangat penting untuk memastikan tidak terdapat data yang
salah atau tidak diinginkan di dalam sistem. Tentu saja bagian ini tidak
perlu dikembangkan lagi jika mengambil rute implementasi dengan solusi
data seperti Doctrine.
- dan
masih banyak fitur-fitur umum sebuah dari framework.
Penutup
Setelah membaca tulisan ini dari awal sampai akhir, penulis
berharap pembaca dapat meresapi inti dari MVC, mulai dari komponen pembangun
sampai dengan cara kerjanya. Mudah-mudahan dengan mengerti MVC, penggunaan
framework MVC modern seperti Symfony atau Laravel tidak lagi menjadi momok bagi anda.
Meskipun anda mampu mengembangkan sebuah framework, penulis tetap lebih
menyarankan untuk mengggunakan framework yang sudah ada, karena framework
seperti Symfony atau lainnya telah matang teruji dan mengalami banyak perbaikan
keamanan dan bug. Mengerti konsep dasar dan ide pengembangan framework adalah
satu hal, mengembangkan framework yang sudah teruji dan matang dengan puluhan
ribu jam pengembangan dan ratusan kontributor adalah hal yang berbeda.
Akhir kata, terima kasih telah membaca, dan tentunya silahkan
tinggalkan kritik, saran, ataupun masukan-masukan lainnya pada kolom komentar
yang ada! Sekali lagi, terima kasih!