Để xây dựng một ứng dụng theo mô hình MVC (Model-View-Controller) trong PHP thuần, bạn cần nắm rõ cách các thành phần chính tương tác với nhau. Tôi sẽ hướng dẫn bạn triển khai các chức năng như bài viết, chuyên mục bài viết, trang chủ theo mô hình MVC
Trước hết, chúng ta cần tổ chức cấu trúc thư mục cho dự án:
/config/database.php
/config/routes.php
)Định nghĩa các tuyến đường (routes) trong ứng dụng:
{id}
Giải thích
routes.php
, các route có thể chứa tham số dưới dạng {id}
, {slug}
, v.v. Ví dụ /post/{id}
.{id}
, {slug}
thành các regex có thể khớp với các phần URL tương ứng. Cụ thể, {id}
trở thành ([a-zA-Z0-9_]+)
.$matches
.call_user_func_array
, chúng ta truyền các tham số từ $matches
vào phương thức của controller.Ví dụ thực tế
Với cấu hình trên, nếu bạn truy cập vào URL /post/1
, hệ thống sẽ:
/post/{id}
.1
từ URL và truyền nó vào phương thức show
của PostController
.Phương thức show
trong PostController
sẽ nhận tham số $id
và có thể sử dụng nó như sau:
Việc truyền tham số vào phương thức của controller có thể được thực hiện trực tiếp trong index.php
, như tôi đã trình bày ở trên. Tuy nhiên, nếu ứng dụng của bạn phức tạp hoặc bạn muốn tổ chức mã nguồn một cách rõ ràng và dễ bảo trì hơn, bạn có thể tách việc xử lý logic đó ra một hàm hoặc lớp riêng biệt. Dưới đây, tôi sẽ so sánh hai cách tiếp cận này để bạn có thể lựa chọn giải pháp phù hợp nhất.
index.php
Ưu điểm:
index.php
giúp giảm thiểu số lượng tệp tin và lớp cần phải quản lý.Nhược điểm:
index.php
có thể trở nên phức tạp và khó bảo trì nếu chứa quá nhiều logic.Ưu điểm:
Nhược điểm:
Dưới đây là một cách tiếp cận sử dụng lớp Router
riêng để xử lý route và truyền tham số:
Router
index.php
Dự án nhỏ hoặc đơn giản: Nếu bạn đang phát triển một ứng dụng nhỏ hoặc đơn giản, việc xử lý trực tiếp trong index.php
có thể là đủ.
Dự án lớn hoặc cần bảo trì lâu dài: Nếu dự án của bạn có khả năng mở rộng hoặc cần bảo trì trong thời gian dài, tách logic xử lý routing và truyền tham số vào một lớp hoặc hàm riêng biệt sẽ là lựa chọn tốt hơn. Điều này giúp tổ chức mã nguồn tốt hơn, dễ bảo trì và mở rộng trong tương lai.
/app/Controllers/BaseController.php
)BaseController là lớp cha mà tất cả các Controller khác sẽ kế thừa:
/app/Controllers/PostController.php
/app/Models/BaseModel.php
)Lớp BaseModel quản lý kết nối cơ sở dữ liệu và các chức năng chung:
/app/Models/PostModel.php
/app/Views/posts/index.php
)Views sẽ hiển thị dữ liệu từ Controller:
/app/Middlewares/CheckAuth.php
CheckAuth.php
Dưới đây là ví dụ về middleware CheckAuth
:
routes.php
Router
để xử lý MiddlewareLớp Router
sẽ được cập nhật để xử lý middleware trước khi gọi controller. Dưới đây là cách bạn có thể triển khai:
Router
Mỗi tệp ngôn ngữ sẽ chứa một mảng các chuỗi văn bản được sử dụng trong ứng dụng.
Tệp en.php
vn.php
Bạn cần một helper để nạp các tệp ngôn ngữ và lấy chuỗi văn bản tương ứng. Tạo một helper trong app/Helpers/Localization.php
:
index.php
Bạn có thể sử dụng Helper để dịch các chuỗi văn bản trong Views và Controllers.
/app/Helpers/url_helper.php
Giả sử bạn đã có các helper tương ứng trong thư mục /app/Helpers/
như url_helper.php
, string_helper.php
, và array_helper.php
. Ví dụ:
url_helper.php
string_helper.php
array_helper.php
index.php
để Nạp HelperTrong file index.php
, bạn sẽ cần thêm logic để tự động nạp các Helper được liệt kê trong file cấu hình.
config/helpers.php
string_helper.php
array_helper.php
Khi bạn đã cấu hình và nạp các helper, bạn có thể sử dụng các hàm như base_url()
, str_contains()
, và array_get()
ở bất kỳ đâu trong ứng dụng mà không cần phải nạp lại chúng.
Bằng cách sử dụng một cấu hình mảng để quản lý các helper, bạn tạo ra một hệ thống linh hoạt và dễ bảo trì. Khi bạn cần thêm helper mới, bạn chỉ cần cập nhật file cấu hình config/helpers.php
, giúp mã nguồn của bạn dễ dàng mở rộng và sạch sẽ hơn.
Bạn có thể sử dụng Composer để cài đặt các thư viện bên thứ 3:
/app/Helpers/log_helper.php
/app/Cache/Cache.php
)Sử dụng file caching:
namespace AppCache; class Cache { public static function set($key, $value, $expiration = 3600) { $file = __DIR__ . "/$key.cache"; $data = ['expiration' => time() + $expiration, 'value' => $value]; file_put_contents($file, serialize($data)); } public static function get($key) { $file = __DIR__ . "/$key.cache"; if (file_exists($file)) { $data = unserialize(file_get_contents($file)); if ($data['expiration'] >= time()) { return $data['value']; } unlink($file); // Xóa cache nếu đã hết hạn } return null; } }
Hooks có thể được sử dụng để thực hiện một số hành động trước hoặc sau khi các sự kiện nhất định xảy ra. Ví dụ, bạn có thể sử dụng hooks trước khi một controller xử lý:
class BaseController { protected function before() { // Code chạy trước khi phương thức controller thực thi } protected function after() { // Code chạy sau khi phương thức controller thực thi } public function __call($name, $arguments) { $this->before(); call_user_func_array([$this, $name], $arguments); $this->after(); } }
Trong ví dụ này, các phương thức before
và after
sẽ tự động được gọi trước và sau khi controller thực thi các phương thức khác.
Trên đây là hướng dẫn chi tiết cách thiết kế một ứng dụng PHP theo mô hình MVC với các chức năng yêu cầu. Bạn có thể tùy chỉnh và mở rộng theo nhu cầu thực tế của dự án.