Theo kinh nghiệm của tôi là bạn mà hãy bắt đầu với MVC chuẩn mà tôi sẽ hướng dẫn sau đây để hiểu cơ chế làm việc sau đó có thể chọn 1 trong các framework FW trên để học, vì các CMS hay F
Trang 1MVC là một mô hình chuẩn Một mẫu thiết kế mà giúp tạo nên một cấu trúc mã cho phép cho các khuôn khổ ứng dụng nhân rộng một cách nhanh chóng Bạn có thể nghĩ đây như một khung sườn, một khuôn khổ mà trên đó các ứng dụng của bạn sẽ được xây dựng
Trích dẫn:Tại sao ta phải viết theo mô hình MVC? Mô hình MVC có những lợi ích gì? Và
hầu hết các CMS hiện đại như: joomla, e-commence, drupal, e-shop, open cart; và cả các framework nổi tiếng như: CI (CodeIgniter), CakePHP, Zend, Yii đều phải tuân theo mô hình MVC này?
Để không mất thời gian, tôi chỉ hướng dẫn các bạn tổ chức 1 project MVC, các bạn có thể tham khảo video về mô sau để hiểu rõ thêm về mô hình
này:http://cione.com.vn/Videos/248/huong-dan -trong-php
Và các bạn sẽ hay đặt câu hỏi phân vân là tôi nên học framework gì? Joomla, Drupal, CI, CakePHP hay Zend, ? Theo kinh nghiệm của tôi là bạn mà hãy bắt đầu với MVC chuẩn
mà tôi sẽ hướng dẫn sau đây để hiểu cơ chế làm việc sau đó có thể chọn 1 trong các framework (FW) trên để học, vì các CMS hay FW này đều tuân theo mô hình MVC thì chỉ khác nhau về các phương thức hỗ trợ thôi, chứ về bản chất và cấu trúc các phần (MVC) đều giống nhau cả! Theo tôi thì nên chọn từ FW dễ đến khó để học được cái hay của mỗi
FW, hãy bắt đầu với CI hoặc CakePHP, mình đánh giá cao về CI (chạy nhanh, dễ phát triển và đặt biệt đa số LTV ở VN hay sài FW này)
Giới thiệu: Đây là bài hướng dẫn cách xây dựng 1 MVC framework đơn giản từ mới bắt đầu đến kết thúc
Theo như hình vẽ ở trên các bạn sẽ thấy các lớp như: Controller, Model, View được tách
ra rõ rệt: Client request đến Controller, Controller sẽ quyết định có nên sử dụng Model hay trực tiếp qua View
Trong loạt hướng dẫn sau, tôi sẽ liệt kê 1 số điểm quan trọng, như việc đầu tiên mà
framework cần làm là tạo điểm bắt đầu (vd: index.php), đó là nơi mà cho phép tất cả các controller có thể thông qua và hoạt động
Để làm điều này ta sử dụng mod_rewrite, 1 mặt giúp ta có thể tạo ra điểm bắt đầu để
Trang 2các controller hoạt động, 1 mặt giúp ta tạo ra 1 đường dẫn thân thiện (SEO URL) giúp các
bộ máy tìm kiếm index nhanh hơn
VD: File htaccess sẽ viết lại đường dẫn cho ta có dạng:
http://www.example.com/news/show
Nếu như không dùng thì dưởng dẫn ra có dạng:
http://www.example.com/index.php?rt=news/show
Đây là file htaccess của ứng dụng:
Mã PHP: (SELECT ALL)
RewriteEngine on
# Cho nay la duong dan chinh cua thu muc lam viec (http://localhost/) => RewriteBase /
# Neu thuc muc la http://localhost/shop/ => RewriteBase /shop/
RewriteBase /
RewriteCond %{ REQUEST_FILENAME } !- f
RewriteCond %{ REQUEST_FILENAME } !- d
RewriteRule ^(.*)$ index php ? rt =$ 1 [ , QSA ]
Cấu trúc của ứng dụng MVC:
Mã PHP: (SELECT ALL)
application
controller
includes
model
views
htaccess
index php
Phần Index: /index.php
Như đã đề cập trước đó, tập tin index.php là điểm duy nhất để chúng ta truy cập ứng dụng Như vậy, nó cung cấp không gian lý tưởng để khai báo các biến và cấu hình trang web rộng Trong tập tin này tôi cũng sẽ gọi một hay một vài tập tin trợ giúp để khởi tạo biến, cấu hình, Tập tin này sẽ được gọi là init.php và nó sẽ được đặt trong includes: /index.php:
Mã PHP: (SELECT ALL)
<?php
/*** error reporting on ***/
error_reporting ( E_ALL );
Trang 3/*** define the site path ***/
$site_path = realpath ( dirname ( FILE ));
define (' SITE_PATH', $site_path );
/*** include the config.php file ***/
include 'config.php';
/*** include the init.php file ***/
include 'includes/init.php';
?>
index.php thiết lập các báo cáo lỗi (error_reporting), include tập tin init.php, và define hằng số đường dẫn tĩnh của website ( SITE_PATH)
Và tại đây htaccess sẽ bắt đầu xây dựng registry, các object registry này đã được xây dựng thông qua những biến toàn cục mà ta đã xây dựng, để tạo ra đối tượng này ta tạo
ra init.php:
Dĩ nhiên là trước khi tạo ra tập tin này, chúng ta cần phải định nghĩa các lớp cần thiết cho
hệ thống như: controller, registry, router, template Các lớp này sẽ tự động include vào chương trình (bắt buộc để hệ thống hoạt động)
/includes/init.php
Mã PHP: (SELECT ALL)
<?php
/*** include the controller class ***/
include SITE_PATH '/application/' 'controller_base.class.php';
/*** include the view class ***/
include SITE_PATH '/application/' 'view_base.class.php';
/*** include the model class ***/
include SITE_PATH '/application/' 'model_base.class.php';
/*** include the registry class ***/
include SITE_PATH '/application/' 'registry.class.php';
/*** include the router class ***/
include SITE_PATH '/application/' 'router.class.php';
/*** a new registry object ***/
Trang 4$registry = new registry ;
?>
Phần Registry:
Registry là 1 đối tượng (registry object) cho phép lưu set() và truy xuất get() các
biến mà ta không cần phải sử dụng biến toàn cục (global variable)
Mã PHP: (SELECT ALL)
<?php
Class Registry {
/*
* @the vars array
* @access private
*/
private $vars = array();
/**
*
* @set undefined vars
*
* @param string $index
*
* @param mixed $value
*
* @return void
*
*/
public function set ( $index , $value )
{
$this -> vars [ $index ] = $value ;
}
/**
*
* @get variables
*
* @param mixed $index
*
* @return mixed
Trang 5*
*/
public function get ( $index )
{
return $this -> vars [ $index ];
}
}
?>
[php]
Chúng ta thấy có 2 phương thức tự động: set() và get() để tạo ra các biến sử dụng xuyên suốt t rong chương trình như global variable Cách sử dụng:
[php] $registry->newval = 'This is value of variable name newval';
echo $registry->newval;
Phần Router:
Đây là lớp giúp mô hình MVC chọn đúng controller làm việc:
Ví dụ ta có 1 router sử dụng controller "new":
http://www.example.com/index.php?rt=news
Nếu ta sử dụng mod_rewrite thì url có dạng:
http://www.example.com/news
/application/router.class.php:
Mã PHP: (SELECT ALL)
<?php
class router {
/*
* @the registry
*/
private $registry ;
/*
* @the controller path
*/
private $path ;
private $args = array();
Trang 6public $file ;
public $controller ;
public $action ;
function construct ( $registry ) {
$this -> registry = $registry ;
}
Phương thức khởi tạo class router sẽ giúp ta tạo mới 1 object router thông qua object
$registry mà ta đã tạo sẵn trong init.php Thêm đoạn mã sau để thực hiện tạo mới 1 router trong index.php:
Mã PHP: (SELECT ALL)
*** load the router ***/
$registry -> router = new router ( $registry );
Để chọn được thư mục controller làm việc ta viết thêm phương thức setPath trong router.class.php:
Mã PHP: (SELECT ALL)
/**
*
* @set controller directory path
*
* @param string $path
*
* @return void
*
*/
function setPath ( $path ) {
/*** check if path i sa directory ***/
if ( is_dir ( $path ) == false )
{
throw new Exception ('Invalid controller path: `' $path '`');
}
/*** set the path ***/
$this -> path = $path ;
}
Và bây giờ ta truyền thư mục controller làm việc cho lớp router trong index.php:
Mã PHP: (SELECT ALL)
Trang 7/*** set the path to the controllers directory ***/
$router -> setPath ( SITE_PATH 'controller');
Sau khi router kiểm tra tính hợp lệ của controller truyền vào qua phương thức setPath(),
ta tiếp tục load controller:
Mã PHP: (SELECT ALL)
/**
*
* @load the controller
*
* @access public
*
* @return void
*
*/
public function loader ()
{
/*** check the route ***/
$this -> getController ();
/*** if the file is not there diaf ***/
if ( is_readable ( $this -> file ) == false )
{
$this -> file = $this -> path '/error404.php';
$this -> controller = 'error404';
}
/*** include the controller ***/
include $this -> file ;
/*** a new controller class instance ***/
$class = $this -> controller 'Controller';
$controller = new $class ( $this -> registry );
/*** check if the action is callable ***/
if ( is_callable (array( $controller , $this -> action )) == false )
{
$action = 'index';
}
else
{
$action = $this -> action ;
Trang 8}
/*** run the action ***/
if(!empty( $this -> args ))
$controller -> $action ( $this -> args );
else
$controller -> $action ();
}
Phương thức loader() sẽ triệu gọi phương thức getController() với ý nghĩa getController()
sẽ thông qua query string: $_GET['rt'] mà ta truyền (http://example/index.php?
rt=news/view/3) để xác định controller mà ta thực hiện
Trong trường hợp với controller "news" với url (http://example/index.php?rt=news) thì controller sẽ sử dụng lớp news controller với phương thức index()
Trường hợp với controller "news/view" với url (http://example/index.php?rt=news/view/3) thì controller sẽ sử dụng lớp news controller với phương thức view($arg) với $arg[1] = 3 Chúng ta sẽ hiểu rõ về router hơn ở phần viết 1 ứng dụng blog nho nhỏ!
Mã PHP: (SELECT ALL)
/**
*
* @get the controller
*
* @access private
*
* @return void
*
*/
private function getController () {
/*** get the route from the url ***/
$route = (empty( $_GET ['rt'])) ? '' : $_GET ['rt'];
if (empty( $route ))
{
$route = 'index';
}
else
{
/*** get the parts of the route ***/
$parts = explode ('/', $route );
$this -> controller = $parts [ ];
if(isset( $parts [ ]))
{
Trang 9$this -> action = $parts [ ];
}
if(isset( $parts [ ]))
{
$count_args = count ( $parts );
$k = 1
$args = array();
for( $i = 2 ; $i < $count_args ; $i ++)
$args [ $k ++] = $parts [ $i ];
$this -> args = $args ;
}
}
if (empty( $this -> controller ))
{
$this -> controller = 'index';
}
/*** Get action ***/
if (empty( $this -> action ))
{
$this -> action = 'index';
}
/*** set the file path ***/
$this -> file = $this -> path '/' $this -> controller 'Controller.php';
}
Phần Controller:
Controller (C trong MVC) là 1 lớp trừu tượng định nghĩa ra tất cả các controller của ứng dụng, nó bao gồm: object $registry hỗ trợ truyền dữ liệu, object $model để lấy dữ liệu từ Model (M), object $view để truyền data và xuất View (V) phương thức mặc định index() cho controller không có action (task) như ví dụ truyền vào router với 2 tham số "news và news/view/id" ở ví dụ ở phần Router
Mã PHP: (SELECT ALL)
<?php
Abstract Class baseController {
/*
* @registry object
*/
protected $registry ;
Trang 10protected $model ;
protected $view ;
function construct ( $registry ) {
$this -> registry = $registry ;
$this -> model = & baseModel :: getInstance ();
$this -> view = & baseView :: getInstance ();
}
/**
* @all controllers must contain an index method
*/
abstract function index ();
}
?>
Phần Model: Model (M trong MVC) Thành phần xử lý các dữ liệu từ textfile, database, objects, baseModel sẽ được triệu gọi từ Controller khi cần đến, baseModel có nhiệm vụ thao tác với Database
Mã PHP: (SELECT ALL)
<?php
class baseModel {
private static $instance ;
function construct () {
}
public static function getInstance () {
if (! self :: $instance )
{
self :: $instance = new baseModel ();
}
return self :: $instance ;
}
public function get ( $name ){
$file = SITE_PATH '/model/' str_replace ("model","", strtolower ( $name ))."Model.php";
if( file_exists ( $file ))
{
include ( $file );
$class = str_replace ("model","", strtolower ( $name ))."Model";
return new $class ;
Trang 11}
return NULL ;
}
function destruct () {
}
}
Phần View:
View (V trong MVC) là phần định dạng dữ liệu, gởi và nhận dữ liệu từ form, hiển thị html
& css,
View ngoài phương thức set dùng để gởi data từ controller sang, view còn phương thức show() để giúp controller
chọn lựa tên view cần sử dụng:
/application/view_base.class.php
Mã PHP: (SELECT ALL)
<?php
Class baseView {
/*
* @Variables array
* @access public
*/
public $data = array();
private static $instance ;
/**
*
* @constructor
*
* @access public
*
* @return void
*
*/
function construct () {
}
public static function getInstance () {
if (! self :: $instance )
Trang 12{
self :: $instance = new baseView ();
}
return self :: $instance ;
}
/**
*
* @set undefined vars
*
* @param string $index
*
* @param mixed $value
*
* @return void
*
*/
public function set ( $index , $value )
{
$this -> vars [ $index ] = $value ;
}
function show ( $name ) {
$path = SITE_PATH '/views' '/' $name '.php';
if ( file_exists ( $path ) == false )
{
throw new Exception ('Template not found in ' $path ); return false ;
}
// Load variables
foreach ( $this -> data as $key => $value )
{
$ $key = $value ;
}
include ( $path );
}
}
Trang 13Viết ứng dụng:
Viết 1 ứng dụng blog có chức năng như sau:
1/ Nếu người dùng truy cập http://example.com/ thì sẽ xuất ra màn hình dòng chữ
"Welcome to My Blog!"
Mặc định nếu người dùng không gõ Controller, thì hệ thống sẽ chọn lấy indexController để làm việc (nếu không có thì sẽ dùng /controller/error404.php)
Ta tạo: /controller/error404.php khi không tìm thấy Controller thì sẽ hiển thị ra nội dung:
Mã PHP: (SELECT ALL)
<?php
Class error404Controller Extends baseController {
public function index ()
{
$this -> view -> data ['blog_heading'] = 'This is the 404';
$this -> view -> show ('error404');
}
}
?>
Với error404Controller có sử dụng View "error404"
Ta tạo /views/error404.php có nội dung sau:
Mã PHP: (SELECT ALL)
< h1 ><? php echo $blog_heading ; ?> </h1>
<p>This is a custom 404 error page.</p>
<p>You can put whatever content you like here such as search for your site</p>
Tiếp theo ta tạo Controller Index:
Ta tạo: /controller/indexController.php với phương thức index() là phương thức mặc định:
Mã PHP: (SELECT ALL)
<?php
Class indexController Extends baseController {
public function index () {
/*** set a template variable ***/
$this -> view -> data ['welcome'] = 'Welcome to My Blog!';
/*** load the index template ***/
$this -> view -> show ('index');
}
Trang 14?>
Với indexController có sử dụng View "index"
Ta tạo /views/index.php có nội dung sau:
Mã PHP: (SELECT ALL)
< h1 ><? php echo $welcome ; ?> </h1>
Như vậy là xong, bây giờ ta test kết quả:
Gõ http://example.com/ thì sẽ xuất ra màn hình dòng chữ "Welcome to My Blog!"
Gõ http://example.com/noway thì sẽ xuất ra thông báo lỗi không tìm thấy trang
2/ Nếu người dùng truy cập http://example.com/blog thì sẽ xuất ra màn hình tất cả các bài Blog
Đầu tiên ta tạo 1 database đơn giản có tên "framework" và 1 table "blog" gồm 3 trường
id, name và content
Mã PHP: (SELECT ALL)
CREATE TABLE IF NOT EXISTS `blog` (
`id` int ( 11 ) NOT NULL AUTO_INCREMENT ,
`name` varchar ( 50 ) NOT NULL ,
`content` varchar ( 500 ) NOT NULL ,
PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = latin1 AUTO_INCREMENT = 3 ;
Dumping data for table `blog`
INSERT INTO `blog` (`id`, `name`, `content`) VALUES
( , 'MVC Introduction', 'This is content of MVC Introduction'),
( , 'PHP framework', 'This is a content of PHP framework');
Tiếp theo ta cấu hình kết nối trong: /config.php
Mã PHP: (SELECT ALL)
<?php
define ('DB_NAME', 'framework'); // Database name
define ('DB_USER', 'root'); // User database
define ('DB_PASSWORD', 'vertrigo'); // Password database
define ('DB_HOST', 'localhost'); // IP host
?>
Tương tự như index Controller ta tạo ra blog Controller với action index() cho chức năng