
Dilihat dari sejarahnya sebenarnya konsep MVC ini sudah ada sejak lama. Konsep MVC ini pertama kali diperkenalkan oleh para peneliti XEROX PARC yang bekerja dalam pembuatan bahasa pemrograman Smalltalk sekitar tahun 1970-1980. Pada dasarnya MVC adalah sebuah metode untuk membuat sebuah aplikasi dengan memisahkan data (Model), tampilan (View) dan cara bagaimana memprosesnya (Controller).
Sampai saat ini framework yang dalam aplikasi website kebanyakan berbasis arsitektur MVC, misalnya CodeIgniter, Simphony, Kohana, cakePHP dan lain sebagainya. Kebanyakan framework yang ada sekarang ini bersifat open source sehingga siapapun bisa mengembangkannya sesuai dengan kebutuhan.Gambar disamping ini menjelaskan bagaimana konsep dasar struktur framework MVC.

Dalam tulisan kali ini sengaja di buat tema "Hierachical Framework MVC", memang framework ini mendukung banyak aplikasi dalam satu framework. Jadi slogan yang diusung adalah "One Framework Many application". Nah untuk membedakan aplikasi website satu dengan yang lain disusunlah model hierarki. Konsep inilah yang membedakan framework ini dengan konsep framework CodeIgniter.
Tole : "Pakdhe..Pakdhe..coba sampean lihat gambarnya...kok mirip seperti becak ya?Dari percakapan antara si Pakdhe Sakiyun dan Tole Dulkamit inilah, akhirnya muncul inspirasi tentang penamaan framework yang dibangun ini. Dari hasil"
Pakdhe :"Huss...gimana to?kok mirip becak?apa gara-gara ada 3 bagian itu?oalah..imajinasi sampean itu lho,kok ya aneh-aneh saja"
Tole :"Lha ya itu, coba to sampean perhatiin lagi...bener kan mirip becak?"
Pakdhe :"Whooo..iya ya...bener sampean, kalau tak perhatikan dengan seksama memang mirip becak je.Ya sudah kalau begitu framework yang kita bikin nanti kita namakan becak aja, piye?setuju nggak sampean?"
Tole : "wheladalah...setuju buanget Pakdhe...Becak MVC Framework made in Pakdhe Sakiyun, keren kan Pakdhe"
OK,kita lanjutkan saja. Secara garis besar cara kerja framework kita ini dapat dilihat pada gambar dibawah ini.



Jika secara keseluruhan framework ini saya analogikan sebagai mobil, maka sistem core ini ibaratnya seperti mesinnya. penggerak utama dari keseluruhan sistem dalam framework ini adalah sistem core. Sedangkan database, library dan helper adalah fungsi-fungsi tambahan sebagai pelengkap dari keseluruhan sistem. Untuk database, library dan helper akan saya bahas pada artikel yang lain. Untuk saat ini kita konsentrasi ke sistem core saja.
Sedangkan sistem application (lingkaran 2 warna merah) fungsinya untuk apa? pada application inilah nantinya aplikasi web yang dikembangkan oleh pengguna framework ini berada. Jadi pada intinya Ibarat ingin membuat sebuah mobil, para pengembang aplikasi web itu tidak perlu lagi capek-capek membuat semua komponen mobil mulai dari awal. Mereka cukup memanfaatkan dan merangkai fasilitas-fasilitas yang sudah tersedia menjadi sebuah mobil. Dengan konsep kerja semacam ini tentunya siapapun akan lebih mudah dalam mengembangkan sebuah aplikasi web. Hanya saja tata cara pembuatan web tersebut tentunya harus mengikuti aturan main yang distandarisasikan oleh pengembang framework.
Jadi kesimpulannya framework ini boleh dimanfaatkan sebebas-bebasnya untuk membuat aplikasi apapun asalkan para pengembang aplikasi web bersedia mengikuti aturan mainnya
OK, kembali lagi ke sistem core, sebenarnya class yang paling pokok dalam sistem core tersebut adalah class controller. Class controller inilah nantinya akan diturunkan (extends) ke semua class controller yang dibuat oleh pengembang web site. Perlu kita pahami bahwa tugas utama class controller adalah memuat (loaded) semua object yang dibutuhkan oleh sistem, seperti misalnya library, helper, database, view, plugins dan lain sebagainya. Oleh karena itu agar codingnya tidak terlalu panjang maka fungsi-fungsi untuk memuat berbagai macam object tersebut kita tuliskan kedalam class loader. Secara umum desain class diagram sistem core ini terlihat seperti gambar dibawah ini.

Tole :"Pakdhe...kok kayaknya rumit ya?apa memang framework itu rumit?"
Pakdhe :"Yang rumit apanya Tole?ini kan baru pengantarnya saja, Pakdhe belum bahas programnya lho"
Tole :"Waduh...pengantarnya saja sudah bikin saya pusing Pakdhe, apalagi programnya
Pakdhe "Sabar Tole, diikuti saja dulu nanti kan lama-lama ngerti juga.Makanya dengerin Pakdhe cerita dulu biar nggak pusing

OK. Pertama-tama coba saya bahas bagaimana membangun modul core terlebih dahulu. Sebelum dilanjut ke desain sistem, perlu saya jelaskan terlebih dahulu struktur directory modul core-nya. Lihat gambar disamping. Perhatikan letak directory modul core (lingkaran nomor 1). Sedangkan global_controller.php (lingkaran nomor 2) akan saya bahas lebih lanjut pada sub bagian 7 pada artikel ini. Pada folder system/core tersebut terdapat 6 program yaitu :
- base
- bootstrap
- common
- controller
- loader
- model
class base ini berfungsi untuk digunakan untuk menyimpan instance object. Dalam susunan hierarki, base class ini menempati urutan tertinggi atau dapat diistilahkan root class. Tidak ada yang istimewa dalam class ini. Hanya saja fungsi dasarnya adalah menukarkan isi variable object itu sendiri ($this) ke variable $instance. Berikut ini script class base yang saya maksud.
- <?php defined('SYS') or exit('Access Denied!');
- /*
- * Becak MVC Framework version 1.0
- *
- * File : base.php
- * Directory : system/core
- * Author : Eko Heri Susanto
- * Description : class base adalah class yang digunakan untuk menyimpan instance object
- */
- class base {
- private static $instance;
- public static $helpers = array();
- public static $models = array();
- public static $databases = array();
- public function __construct(){
- self::$instance = &$this;
- }
- public static function getInstance(){
- return self::$instance;
- }
- }
- function this(){ return base::getInstance(); }
- ?>
Bootstrap ini bukan sebuah class. program ini berfungsi hanya untuk meng-include-kan/memanggil program-program penting lain yang diperlukan oleh aplikasi. Selain itu bootstrap ini juga berfungsi untuk mengeksekusi controller yang yang dipanggil oleh user.
- <?php defined('SYS') or exit('Access Denied!');
- /*
- * Becak MVC Framework version 1.0
- *
- * File : becak.php
- * Directory : system/core
- * Author : Eko Heri Susanto
- * Description : routine untuk memuat (loaded) system utama serta routine untuk menjalankan default controller
- */
- //panggil class inti (core)
- require (SYS.'constant'.DS.'file.php');
- require (SYS.'core'.DS.'common.php');
- require (SYS .'error'. DS .'errors.php');
- require (SYS.'libraries'. DS .'benchmark_library.php');
- $benchmark = common::register('Benchmark');
- $benchmark->mark('total_execution_time_start');
- require (SYS.'core'.DS.'loader.php');
- require (SYS.'core'.DS.'base.php');
- require (SYS.'core'.DS.'controller.php');
- require (SYS.'core'.DS.'model.php');
- require (SYS.'libraries'.DS.'router_library.php');
- require (SYS.'libraries'.DS.'uri_library.php');
- require (SYS.'libraries'.DS.'output_library.php');
- require (SYS.'libraries'.DS.'config_library.php');
- date_default_timezone_set(common::config_item('timezone_set'));
- $uri = common::register('Uri');
- $router = common::register('Router');
- $output = common::register('Output');
- if ($output->_display_cache($uri) == TRUE) { exit; }
- $GLOBALS['d'] = $router->fetch_directory(); // Get requested directory
- $GLOBALS['c'] = $router->fetch_class(); // Get requested controller
- $GLOBALS['m'] = $router->fetch_method(); // Get requested method
- //panggil default controller pada directory application/controller
- if(! file_exists(DIR.$GLOBALS['d'].DS.'controllers'.DS.$GLOBALS['c'].PHP_EXT)) {
- if($router->query_string)
- show_404("{$GLOBALS['d']}/{$GLOBALS['c']}/{$GLOBALS['m']}");
- throw new Exception('Unable to load your default controller.Please make sure the controller specified in your Routes.php file is valid.');
- }
- require (DIR.$GLOBALS['d'].DS.'controllers'.DS.$GLOBALS['c'].PHP_EXT);
- if ( ! class_exists($GLOBALS['c'])
- OR $GLOBALS['m'] == 'controller'
- OR in_array(strtolower($GLOBALS['m']), array_map('strtolower', get_class_methods('Controller')))
- ){
- show_404("Class {$GLOBALS['d']}/{$GLOBALS['c']}/{$GLOBALS['m']}");
- }
- $MC = new $GLOBALS['c']();
- if ( ! in_array(strtolower($GLOBALS['m']), array_map('strtolower', get_class_methods($MC)))){
- show_404("{$GLOBALS['d']}/{$GLOBALS['c']}/{$GLOBALS['m']}");
- }
- call_user_func_array(array($MC, $GLOBALS['m']), array_slice($uri->rsegments, 3));
- $output->_display();
- while (ob_get_level() > 0) { ob_end_flush(); }
- ?>
Class common ini berisi penanganan fungsi-fungsi umum misalnya register object, membaca configurasi dan operasi file. Telah disinggung diatas bahwa tugas dari class loader adalah memuat berbagai macam object yang dibutuhkan oleh sistem. Dalam class ini ada 2 (dua) function yang sangat penting yaitu singleton dan register. Apa itu singleton dan register? ada sub bab class Loader dibawah akan saya ulas lebih lanjut.
- <?php defined('SYS') or exit('Access Denied!');
- /*
- * Becak MVC Framework version 1.0
- *
- * File : common.php
- * Directory : system/core
- * Author : Eko Heri Susanto
- * Description : class umum
- */
- //class registry digunakan untuk mendaftarkan variable menjadi object
- class common {
- private static $object = array();
- private static $instance;
- //singleton
- private static function singleton(){
- if(!isset(self::$instance))
- self::$instance = new self();
- return self::$instance;
- }
- private function get($id){
- if(isset(self::$object[$id])){
- return self::$object[$id];
- }
- return NULL;
- }
- private function set($id, $value){
- self::$object[$id] = $value;
- }
- private static function getObject($id) {
- return self::singleton()->get($id);
- }
- private static function setObject($id, $instance){
- return self::singleton()->set($id, $instance);
- }
- private static function get_static($filename = 'config', $var = '', $folder = '')
- {
- static $static = array();
- if ( ! isset($static[$filename]))
- {
- if ( ! file_exists($folder. DS .$filename. PHP_EXT))
- throw new Exception('The static file '. DS .$folder. DS .$filename. PHP_EXT .' does not exist.');
- require($folder. DS .$filename. PHP_EXT);
- if($var == '') $var = &$filename;
- if ( ! isset($$var) OR ! is_array($$var))
- {
- throw new Exception('The static file '. DS .$folder. DS .$filename. PHP_EXT .' file does not appear to be formatted correctly.');
- }
- $static[$filename] =& $$var;
- }
- return $static[$filename];
- }
- public static function get_config($filename = 'config', $var = '')
- {
- return self::get_static($filename, $var, APP. DS. 'config');
- }
- /* Fungsi register digunakan untuk mendaftarkan variable menjadi object.*/
- public static function register($ClassName){
- $Obj = self::singleton();
- $ClassName = strtolower($ClassName);
- if($Obj->getObject($ClassName) != NULL){
- return $Obj->getObject($ClassName);
- }
- $Class = $ClassName;
- $Obj->setObject($ClassName, new $Class());
- $Object = $Obj->getObject($ClassName);
- if(is_Object($Object)) return $Object;
- }
- public static function config_item($item, $config_name = 'config')
- {
- static $config_item = array();
- if ( ! isset($config_item[$item]))
- {
- $config_name = self::get_config($config_name);
- if ( ! isset($config_name[$item])) return FALSE;
- $config_item[$item] = $config_name[$item];
- }
- return $config_item[$item];
- }
- public static function is_really_writable($file)
- {
- // If we're on a Unix server with safe_mode off we call is_writable
- if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == FALSE)
- {
- return is_writable($file);
- }
- // For windows servers and safe_mode "on" installations we'll actually
- // write a file then read it. Bah...
- if (is_dir($file))
- {
- $file = rtrim($file, '/').'/'.md5(rand(1,100));
- if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE)
- {
- return FALSE;
- }
- fclose($fp);
- @chmod($file, DIR_WRITE_MODE);
- @unlink($file);
- return TRUE;
- }
- elseif (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE)
- {
- return FALSE;
- }
- fclose($fp);
- return TRUE;
- }
- }//end class
- ?>
Seperti yang sudah saya jelaskan diatas, class controller inilah dijadikan induk dari keseluruhan controller yang dibuat oleh user. Pada class ini hanya terdapat konstrktor yang menjalankan function _init, dimana dalam function _init tersebut bertugas mendaftarkan library utama guna mendukung jalannya aplikasi. Apa itu library utama? nanti saya jelaskan di artikel lain yang khusus membahas tentang library.
- <?php defined('SYS') or exit('Access Denied!');
- /*
- * Becak MVC Framework version 1.0
- *
- * File : controller.php
- * Directory : system/core
- * Author : Eko Heri Susanto
- * Description : class controller ini adalah induk dari semua controller
- */
- require(APP .'globals'. DS .'global_controller'. PHP_EXT);
- class controller extends global_controller {
- public function __construct(){
- parent::__construct();
- $this->_init();
- }
- private function _init()
- {
- $Classes = array(
- 'config' => 'Config',
- 'router' => 'Router',
- 'uri' => 'URI',
- 'output' => 'Output'
- );
- foreach ($Classes as $public_var => $Class)
- {
- $this->$public_var = common::register($Class);
- }
- }
- }//end class
- ?>
Telah disinggung diatas bahwa tugas class loader adalah memuat berbagai macam object yang dibutuhkan oleh sistem. Namun kenyataannya pada saat memuat sebuah object, bisa saja object yang sama sudah pernah termuat sebelumnya. Jika hal ini dibiarkan maka akan mengakibatkan terjadinya penumpukan inisialisasi object yang sama pada memory. Penumpukan inisialisasi object ini tentu saja mengakitbatkan pemborosan pemakaian memory. Untuk menghindari hal tersebut maka dibutuhkan pola desain (design pattern) singleton yang contoh programmnya sudah saya copy-paste pada sub bab common diatas.
Tugas utama singleton adalah memastikan bahwa tidak ada object yang sama dimuat lebih dari satu kali. Penghematan penggunaan memory wajib kita lakukan dengan harapan manakala web site kita sudah diakses oleh banyak orang, maka bisa kita minimalisir kemungkinan terjadinya macet (down) web server kita. Pada contoh program yang saya lampirkan, penulisan fungsi singleton ini bisa anda temui pada file common.php. Berikut ini source code class Loader yang saya maksud.
- <?php defined('SYS') or exit('Access Denied!');
- /*
- * Becak MVC Framework version 1.0
- *
- * File : loader.php
- * Directory : system/core
- * Author : Eko Heri Susanto
- * Description : class loader berfungsi untuk memuat (loaded) library, helper, view, model
- */
- class loader {
- private static $helpers = array();
- private static $sys_helpers = array();
- public static function sys_library($library){
- self::_library($library, 'system');
- }
- public static function app_library($library){
- self::_library($library, 'application');
- }
- public static function library($library){
- self::_library($library, 'directories');
- }
- private static function _library($library, $folder = 'system'){
- if($library=='')return false;
- $library = strtolower($library);
- switch($folder){
- case 'system' : $lib_folder = SYS.'libraries'.DS;break;
- case 'application' : $lib_folder = APP.'libraries'.DS;break;
- case 'directories' : $lib_folder = DIR.$GLOBALS['d'].DS.'libraries'.DS;break;
- }
- if(file_exists($lib_folder.$library.'_library'.PHP_EXT )) {
- require ($lib_folder.$library.'_library'.PHP_EXT );
- base::getInstance()->$library = common::register($library);
- } else throw new Exception("Can't load library file: " . $library);
- }
- public static function sys_helper($helper) {
- self::_helper($helper, 'system');
- }
- public static function app_helper($helper='') {
- self::_helper($helper, 'application');
- }
- public static function helper($helper =''){
- self::_helper($helper, 'directories');
- }
- private static function _helper($helper, $folder = 'system') {
- if($helper=='')return false;
- if( isset(self::$helpers[$helper]) ){
- return;
- }
- $helper = strtolower($helper);
- switch($folder){
- case 'system' : $hlp_folder = SYS.'helpers'. DS;break;
- case 'application' : $hlp_folder = APP.'helpers'. DS;break;
- case 'directories' : $hlp_folder = DIR.$GLOBALS['d'].DS.'helpers'.DS;break;
- }
- if(file_exists($hlp_folder . $helper.'_helper'. PHP_EXT)){
- include($hlp_folder . $helper.'_helper'. PHP_EXT);
- self::$helpers[$helper] = $helper;
- return;
- } else throw new Exception("Can't load helper file: " . $helper);
- }
- public static function app_model($model_name){
- self::_model($model_name, 'application');
- }
- public static function model($model_name){
- self::_model($model_name, 'directories');
- }
- private static function _model($model_name, $folder = 'system'){
- if($model_name=='')return;
- $model_name = strtolower($model_name);
- $model_var = &$model_name;
- if (isset(base::getInstance()->$model_var) AND is_object(base::getInstance()->$model_var))
- { return; }
- switch($folder){
- case 'application' : $mdl_folder = APP.'models'.DS;break;
- case 'directories' : $mdl_folder = DIR.$GLOBALS['d'].DS.'models'.DS;break;
- }
- if(file_exists($mdl_folder.$model_name.PHP_EXT )) {
- require ($mdl_folder.$model_name.PHP_EXT );
- base::getInstance()->$model_var = new $model_name();
- base::getInstance()->$model_var->_assign_db_objects();
- base::$models[$model_var] = base::getInstance()->$model_var;
- } else throw new Exception("Can't load model file: " . $model);
- }
- public static function database($db_name = 'db'){
- $db_var = $db_name;
- $obj = base::getInstance();
- if (isset($obj->{$db_var}) AND is_object($obj->{$db_var}) ) {
- return;
- }
- require (SYS .'database'. DS .'db_factory'. PHP_EXT);
- $obj->{$db_var} = db_factory::callDB($db_name);
- base::$databases[$db_var] = $db_var;
- if (count(base::$models) >= 0) {
- foreach (base::$models as $model_name)
- $obj->$model_name->$db_var = &$obj->$db_var;
- }
- }
- }//end class loader
- ?>
Terakhir adalah class model. Class ini difungsikan sebagai induk dari model yang dibuat oleh user. Class model ini sebenarnya hanya berfungsi untuk mendaftar instance database ke base class. Pertanyaannyam kenapa kok instance database tersebut perlu disimpan dan didaftarkan? Framework ini memang didesain mampu mendukung multi connection database. Dikarenakan hal itulah maka masing-masing koneksi perlu disimpan ke memory agar supaya jikalau ada banyak koneksi database yang harus dijalankan, maka variable koneksi tersebut masih tersimpan di memory dan masih bisa digunakan.
- <?php defined('SYS') or exit('Access Denied!');
- /*
- * Becak MVC Framework version 1.0
- *
- * File : model.php
- * Directory : system/core
- * Author : Eko Heri Susanto
- * Description : class model ini adalah induk dari semua model
- */
- class model extends base {
- public function __construct(){
- $this->_assign_db_objects();
- }
- public function _assign_db_objects(){
- foreach(base::$databases as $key){
- $this->$key = &base::getInstance()->$key;
- }
- }
- }//end class model
- ?>
Global controller adalah class yang digunakan untuk deklarasi variable-variable global, misalnya base_url, directory resource gambar, CSS, javascript dsb. Atau bisa juga digunakan untuk memanggil library dan helper yang nantinya digunakan pada seluruh aplikasi. Lokasi program global controller pada framework ini tersimpan di folder application/globals(Lihat gambar diatas-lingkaran nomor 2). Global controller ini sebenarnya mempunyai fungsi yang mirip seperti perintah $_GLOBAL. Jadi pada class inilah tempat mendeklarasikan semua variabel-variabel ataupun function yang sifatnya umum.
- <?php defined('SYS') or exit('Access Denied!');
- class global_controller extends base {
- public $base, $base_url, $base_img;
- public $title, $head, $meta;
- public $calendar='';
- public function __construct(){
- parent::__construct();
- loader::sys_helper('view');
- loader::sys_helper('head_tag');
- $this->base = common::config_item('base_url');
- $this->base_url = common::config_item('base_url') . common::config_item('index_page');
- $this->base_img = common::config_item('source_url').'images/';
- $this->meta = meta('Content-type', 'text/html; charset=utf-8', 'equiv');
- $this->meta .= meta('author', 'Eko Heri Susanto');
- }
- }
- ?>
Tentunya anda sudah paham apa kegunaan dari index.php kan? apa hayo? Index.php adalah file yang secara default akan dijalankan pertama kali ketika ada user (pengguna) yang mengkases web site. Nah ini source code-nya
- <?php
- error_reporting(E_ALL | E_STRICT);
- define('DS', DIRECTORY_SEPARATOR);
- define('SYS', 'system'.DS);
- define('APP', 'application'.DS);
- define('DIR', APP . 'directories'.DS);
- define('PHP_EXT', '.php');
- define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME));
- if ( get_magic_quotes_gpc() ) {
- function stripslashes_gpc(&$value){
- $value = stripslashes($value);
- }
- array_walk_recursive($_GET, 'stripslashes_gpc');
- array_walk_recursive($_POST, 'stripslashes_gpc');
- array_walk_recursive($_COOKIE, 'stripslashes_gpc');
- array_walk_recursive($_REQUEST, 'stripslashes_gpc');
- }
- require(SYS .'core'.DS.'bootstrap.php');
- ?>
http://www.blogkomputer.com/data-tutorial-membangun-sistem-core.html
Tidak ada komentar:
Posting Komentar