| |
|
Mọi
thứ đều đã tập trung về file index.php nên router của chúng ta phải đặt
tại đây để xử lý request, add code sau vào index.php: Code:
# Load router $router = new Router($registry); $registry->set ('router', $router); Tạo class Router.php: Code:
<?php class Router { private $registry; private $path; private $args = array(); function __construct($registry) { $this->registry = $registry; } } ?> Ở đây, chúng ta đã truyền registry vào router để nó có thể truyền tiếp cho các file xử lý reuqest. Tiếp tục, để Router tìm ra file xử lý, ta đặt cho nó một folder mặc định làm gốc để bắt đầu chuyện mò kim đáy bể: Code:
function setPath($path) { $path = trim($path, '/\\'); $path .= DIRSEP; if (is_dir($path) == false) { throw new Exception ('Invalid controller path: `' . $path . '`'); } $this->path = $path; } Trong MVC, các xử lý logic gọi là Controller và nhiệm vụ của router là tìm đúng controller để gửi gắm việc xử lý yêu cầu của client, vì thế, tạm gọi folder chức các controller của chúng ta là "controllers" luôn. Thêm dòng sau vào index.php Code:
$router->setPath (site_path . 'controllers'); Bạn cũng cần tạo luôn foldere controller ngang cấp với index.php. Tiếp theo, ta viết một hàm để tìm kiếm controller dựa trên thông tin nhận được từ query string qua tham số route (xem bài 1). Code:
private function getController(&$file, &$controller, &$action, &$args) { $route = (empty($_GET['route'])) ? '' : $_GET['route']; if (empty($route)) { $route = 'index'; } // Get separate parts $route = trim($route, '/\\'); $parts = explode('/', $route); // Find right controller $cmd_path = $this->path; foreach ($parts as $part) { $fullpath = $cmd_path . $part; // Is there a dir with this path? if (is_dir($fullpath)) { $cmd_path .= $part . DIRSEP; array_shift($parts); continue; } // Find the file if (is_file($fullpath . '.php')) { $controller = $part; array_shift($parts); break; } } if (empty($controller)) { $controller = 'index'; }; // Get action $action = array_shift($parts); if (empty($action)) { $action = 'index'; } $file = $cmd_path . $controller . '.php'; $args = $parts; } Hàm lằng nhằng này chỉ phục vụ ý tưởng đơn giản là tìm hai tham số của route, được phân cách bởi / trong đó tham số thứ nhất là controller, tham số thứ 2 là action. Nếu chúng ta không tìm ra gì hết thì controller mặc định là index.php và action mặc định là 'index'. Quá trình tìm kiếm bắt đầu từ root folder mà ta đã định nghĩa là /controller. Chúng ta sẽ đi qua các sub-folder chỉ ra như là một đường dẫn trong route Với mỗi điểm trên đường dẫn ta sẽ kiểm tra đó là folder hay file. Nếu là folder thì đi tiếp, file thì coi đó là file controller. Khi đã tìm ra controller thì điểm tiếp theo trên đường dẫn là tên action. Ở đây có một chút phức tạm mà tôi vẫn thực hiện là việc đi qua nhiều sub-folder. Việc này giúp tổ chức file trong một web application được dễ hơn vì ta có thể chia application ra thành nhiều module con, mỗi module là 1 folder và trong folder đó mới có các controller. Nếu route của chúng ta là: index.php?route=member/view thì chúng ta cần có member.php trong /controllers. Trong member.php, chúng ta sẽ viết 1 function có tên là view để thực hiện xử lý action 'view' như được yêu cầu. Nói thêm về tham số $args. Ở đây ta dùng rewrite_url và cơ chế thực hiện là mọi thứ tham số đều truyền qua route. Vì vậy, bạn thấy rằng cuối hàm getController, $args được gán bằng $parts là phần còn lại của route sau khi ta loại bỏ controller và action. Phần $args này thường sẽ có 1 số chẵn các phần tử trong đó cứ mỗi cặp thì ta có 1 phần tử là parameter name, phần tử kia là parameter value. Tạm thời ta không đi sâu vào xử lý $args. Trên thực tế để có một MVC "xịn" hơn thì ta sẽ tiếp tục phân tích $args bằng một rewrite engine nữa do ta tự quy định. Ví dụ, $args chuẩn để view một member dựa trên username sẽ là: route=member/view/name/hung5s. Rewrite engine mà ta tự viết có thể căn cứ vào controller và action để đưa ra các luật riêng của mình, khi đó ta tự hiểu rằng với controller member và action view thì chỉ cần 1 tham số là username. Lúc này, route viết lại là: route=member/view/hung5s <<<< Bạnt thấy URL như vậy có đẹp hơn không ? Trở lại với class Router của chúng ta, sau khi đã phân tích xong request, việc cuối cùng là thực hiện reuqest theo "lệnh" của client: Code: function delegate() { // Analyze route $this->getController($file, $controller, $action, $args); // File available? if (is_readable($file) == false) { die ('404 Not Found'); } // Include the file include ($file); // Initiate the class $class = $controller; $controller = new $class($this->registry); // (1) // Action available? if (is_callable(array($controller, $action)) == false) { die ('404 Not Found'); } // Run action $controller->$action($args); // (2) } Nếu bạn đọc hàm này, lại chú ý về cái tôi đã nói trước đó về quy cách đặt tên ảnh hưởng tới việc xây dựng 1 cơ chế cho MVC framework của chúng ta. Ở đây, tôi dùng tên class trùng với tên controller nên trong ví dụ trên, member.php phải khai báo class Member{}. Trong đoạn này, bạn cũng cần chú ý hai điểm cực mạnh của PHP là gọi class và hàm bằng tham số, xem điểm (1) và (2) như tôi đánh dấu. Cuối cùng, ta thêm dòng gọi delegate trong index.php: Code:
$router->delegate(); Đã tới đoạn kết của phần 2, bây giờ ta có thể xây dựng các controller để thử nghiệm năng lực của router của chúng ta. Nhưng đầu tiên, nhớ lại rằng khi không có action nào được yêu cầu trong request, ta mặc định xử lý một action tên là 'index'. Do vậy, tôi sẽ lại viết tiếp về khả năng sử dụng OOP trong thiết kế ứng dụng để ép người coder phải tuân theo một vài quy định cụ thể. Các controller của ta sẽ đều thừa kế 1 abstract class là ControllerBase trong đó định nghĩa sẵn function index(). Sau này, controller của bạn sẽ phải implement function này. Code:
<?php Abstract Class ControllerBase { protected $registry; function __construct($registry) { $this->registry = $registry; } abstract function index($args); } ?> Bây giờ, ta tạo index.php là file index thực sự theo cách viết web application thông thường không dùng MVC để xử lý các request. File /controllers/index.php Code:
<?php class index Extends ControllerBase { function index($params) { echo 'Hello from my MVC system'; } } ?> Tới đây, bạn có thể run thử nghiệm ứng dụng của mình: http://localhost/mymvc. Do không có tham số nên route của chúng ta sẽ phân tích ra các thông tin mặc định là dùng controller có tên index và gọi action tên là index. Nếu muốn, bạn có thể tạo thêm controller member để test ví dụ ở trên: route=member/view/username/hung5s Code:
<?php Class Members Extends ControllerBase { function index($params) { echo 'Default action of member is executed.'; } function view($params) { echo 'You are viewing the members'.$params[1]; } } ?> Pheewwww! tới đây, chúng ta chỉ còn 2 phần là model và view để cài đặt cho MVC hoàn chỉnh. Hãy theo dõi bài tiếp theo nhé. Nguồn http://thegioiweb.vn/Story/vn/laptrinhweb/laptrinhweb_PHP/2008/7/5921.html |
Tiếp
tục tập 2, tập hóc búa nhất của MVC. Bây giờ chúng ta đi xây dựng
Router - bộ phân tích và xử lý request như đã nói ở tập 1.