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!