Cài đặt ứng dụng PHP thuần sử dụng MVC và OOP
1.1. Định nghĩa MVC là một mô hình thiết kế, giúp bạn tổ chức code theo từng phần độc lập với nhau, và các phần tương tác với nhau theo một cách nhất định. 1.2. Cách mà mô hình hoạt động Trình duyệt gửi một request lên server, server nhận được request sẽ phân tích và gửi dữ liệu vào ...
1.1. Định nghĩa
MVC là một mô hình thiết kế, giúp bạn tổ chức code theo từng phần độc lập với nhau, và các phần tương tác với nhau theo một cách nhất định.
1.2. Cách mà mô hình hoạt động
Trình duyệt gửi một request lên server, server nhận được request sẽ phân tích và gửi dữ liệu vào controller dựa vào router điều hướng. Trong vài trường hợp thì controller sẽ render luôn ra view (một template được chuyển thành HTML) và gửi trả về cho trình duyệt. Nhưng thông thường, cho các trang web động, controller sẽ tương tác với một model (đại diện cho một phần tử ví dụ như Post, chịu trách nhiệm giao tiếp với cơ sở dữ liệu). Sau khi gọi vào model, controller sẽ render view với dữ liệu lấy được và trả kết quả về cho trình duyệt để hiển thị.
2.1. Cấu trúc thư mục
|-- demo_mvc |-- assets |-- fonts |-- images |-- javascripts |-- stylesheets |-- controllers |-- models |-- views |-- layouts |-- application.php |-- connection.php |-- index.php |-- routes.php
Giải thích về cấu trúc thư mục trên:
- Thư mục demo_mvc là thư mục chứa project.
- Thư mục assets gồm các file font chữ, hình ảnh, javascript, css...
- Thư mục controlers chứa các file định nghĩa các lớp controller, có các hàm trong đó tương tác với model và gọi ra view để trả về cho người dùng.
- Thư mục models chứa các file định nghĩa các lớp model, chịu trách nhiệm thao tác với CSDL.
- Thư mục views chứa thư mục layouts chứa template hiển thị chung của trang web trong file application.php
- Còn các file sẽ được giới thiệu rõ hơn ở các phần bên dưới.
2.2. Cơ sở dữ liệu
Trước hết, hãy tạo một cơ sở dữ liệu đơn giản có tên là demo_mvc có bảng posts với 3 trường: id (INT PRIMARY auto_increment), title (VARCHAR 255), content (TEXT) Bắt tay vào code thôi nào.
2.3. Điều hướng luồng dữ liệu
Đầu tiên, tạo file index.php với nội dung như sau:
# index.php <?php require_once('connection.php'); if (isset($_GET['controller'])) { $controller = $_GET['controller']; if (isset($_GET['action'])) { $action = $_GET['action']; } else { $action = 'index'; } } else { $controller = 'pages'; $action = 'home'; } require_once('routes.php');
File này sẽ là file nhận mọi yêu cầu truy vấn lên server. Bởi vậy, mọi đường dẫn truy cập đều phải có dạng /?param=value hoặc /index.php?param=value. Trước tiên, index.php chạy nội dung trong file connection.php được dùng để kết nối và truy vấn đến cơ sở dữ liệu, sử dụng PDO:
# connection.php <?php class DB { private static $instance = NULl; public static function getInstance() { if (!isset(self::$instance)) { try { self::$instance = new PDO('mysql:host=localhost;dbname=demo_mvc', 'root', '); self::$instance->exec("SET NAMES 'utf8'"); } catch (PDOException $ex) { die($ex->getMessage()); } } return self::$instance; } }
Bạn cần chỉnh sửa lại phần new PDO('mysql:host=<host name>;dbname=<database name>', '<username>', '<password>') sao cho trùng với thông tin kết nối tới CSDL của mình. Sau khi chạy file connection.php, file index.php sẽ xử lý các tham số của đường dẫn, cụ thể là lấy ra 2 tham số controller và action, rồi lưu giá trị của chúng vào các biến để sau này dùng cho việc quyết định sẽ làm việc gì hay hiển thị nội dung gì... Mặc định nếu không có các tham số này thì chúng sẽ được gán giá trị là controller thì trỏ đến pages, còn action thì trỏ đến home. Và đây, file routes.rb sẽ chịu trách nhiệm phân tích 2 biến mà chúng ta vừa lấy được ở bước trên sau đó xác định phần view nào sẽ được hiển thị.
# routes.php <?php $controllers = array( 'pages' => ['home', 'error'] ); // Các controllers trong hệ thống và các action có thể gọi ra từ controller đó. // Nếu các tham số nhận được từ URL không hợp lệ (không thuộc list controller và action có thể gọi // thì trang báo lỗi sẽ được gọi ra. if (!array_key_exists($controller, $controllers) || !in_array($action, $controllers[$controller])) { $controller = 'pages'; $action = 'error'; } // Nhúng file định nghĩa controller vào để có thể dùng được class định nghĩa trong file đó include_once('controllers/' . $controller . '_controller.php'); // Tạo ra tên controller class từ các giá trị lấy được từ URL sau đó gọi ra để hiển thị trả về cho người dùng. $klass = str_replace('_', ', ucwords($controller, '_')) . 'Controller'; $controller = new $klass; $controller->$action();
2.4. Xây dựng BaseController
Mình sẽ tạo 1 lớp BaseController để làm lớp cha cho các controller của hệ thống. Khi đó, mình sẽ có thể định nghĩa các hàm mà mọi controller đều có thể gọi ra mà không phải định nghĩa lại ở mỗi controller. Tạo file base_controller.php trong thư mục controllers:
# controllers/base_controller.php <?php class BaseController { protected $folder; // Biến có giá trị là thư mục nào đó trong thư mục views, chứa các file view template của phần đang truy cập. // Hàm hiển thị kết quả ra cho người dùng. function render($file, $data = array()) { // Kiểm tra file gọi đến có tồn tại hay không? $view_file = 'views/' . $this->folder . '/' . $file . '.php'; if (is_file($view_file)) { // Nếu tồn tại file đó thì tạo ra các biến chứa giá trị truyền vào lúc gọi hàm extract($data); // Sau đó lưu giá trị trả về khi chạy file view template với các dữ liệu đó vào 1 biến chứ chưa hiển thị luôn ra trình duyệt ob_start(); require_once($view_file); $content = ob_get_clean(); // Sau khi có kết quả đã được lưu vào biến $content, gọi ra template chung của hệ thống đế hiển thị ra cho người dùng require_once('views/layouts/application.php'); } else { // Nếu file muốn gọi ra không tồn tại thì chuyển hướng đến trang báo lỗi. header('Location: index.php?controller=pages&action=error'); } } }
Hãy tạo file application.php trong thư mục views/layouts với nội dung như sau:
# views/layouts/application.php <DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta content="awidth=device-awidth, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <title>Demo PHP MVC</title> </head> <body> <?= @$content ?> </body> </html>
2.5. Xây dựng các trang tĩnh
Giờ chúng ta sẽ viết controller đầu tiên cho hệ thống, đó là PagesController, là file pages_controller.php được đặt trong thư mục controllers:
# controllers/pages_controller.php <?php require_once('controllers/base_controller.php'); class PagesController extends BaseController { function __construct() { $this->folder = 'pages'; } public function home() { $data = array( 'name' => 'Sang Beo', 'age' => 22 ); $this->render('home', $data); } public function error() { $this->render('error'); } }
Trong thư mục views, tạo thư mục pages chứa 2 file home.php và error.php với nội dung như sau:
# views/pages/home.php <?php echo "Tên tôi là: $name, năm nay tôi $age tuổi"; ?>
# views/pages/error.php <?php echo 'Có lỗi xảy ra!'; ?>
Bây giờ bạn thử truy cập đến trang /index.php hoặc trang /index.php?controller=pages&action=error để xem kết quả