Thiết kế cấu trúc folder HMVC cho Laravel
Ở bài viết này mình sẽ hướng dẫn bạn bắt đầu xây dựng một ứng dụng HMVC với Laravel, và tận dụng sức mạnh của Composer khi quản lí modules.
Thiết kế kiến trúc cho ứng dụng quy mô lớn với Laravel
Tạo mới một dự án Laravel
Khởi tạo một dự án Laravel mới bằng dòng lệnh sau
$ composer create-project --prefer-dist laravel/laravel hmvc-project
$ cd hmvc-project
Lúc này cấu trúc thư mục của chúng ta sẽ có dạng như thế này
|- app/
|- Console/
|- Exceptions/
|- Http/
|- Providers/
User.php
|- bootstrap/
|- config/
|- database/
|- public/
|- resources
|- routes/
|- storages/
|- tests/
|- vendor/
...
Khởi tạo thư mục chứa các modules HMVC
Chúng ta sẽ cố gắng không sử dụng cấu trúc thư mục mặc định để tránh tối đa sự xung đột hoặc khó khăn lúc nâng cấp lên các phiên bản cao hơn khi mà Laravel định kỳ release 6 tháng một lần. Điều này cũng giúp bạn đạt được sự thuận tiện tối đa khi tích hợp vào một dự án sẵn có.
Từ thư mục Laravel gốc, bạn tạo các thư mục tương ứng qua các dòng lệnh sau:
$ mkdir platform
$ mkdir platform/core
$ mkdir platform/plugins
$ mkdir platform/themes
Lúc này chúng ta sẽ có cấu trúc thư mục như sau
Tất cả source code của chúng ta sẽ được gói gọn bên trong folder platform
.
core
: chứa tất cả các modules không thể thiếu để có thể khởi chạy ứng dụng.plugins
: chứa các modules được thực thi dưới dạng trình cắm. Khi chúng ta xóa bỏ hoặc vô hiệu hóa chúng ra khỏicomposer.json
thì chúng sẽ không được khởi chạy, nhưng cũng không ảnh hưởng đến hệ thống hiện tại.themes
: chứa danh sách các themes của hệ thống. Một thời điểm chỉ nên có một theme được kích hoạt. Theme sẽ là phần sử dụng các modulescore
vàplugins
để hiển thị dữ liệu và thao tác với người dùng.
Chỉnh sửa file composer.json
Thêm đoạn khai báo sau vào trong file composer.json
từ thư mục gốc của dự án. Đoạn khai báo này giúp composer
biết được nơi tìm kiếm các custom module của bạn.
"repositories": [
{
"type": "path",
"url": "./platform/core/*"
},
{
"type": "path",
"url": "./platform/plugins/*"
},
{
"type": "path",
"url": "./platform/themes/*"
}
]
Cấu trúc một module trong dự án sẽ tương tự một Laravel pakage. Bạn có thể tham khảo thêm ở liên kết https://laravel.com/docs/7.x/packages.
Từ thư mục platform/plugins
, bạn cần tạo ra cấu trúc thư mục như sau:
Việc tạo ra một cấu trúc như vầy khá là tốn công sức, nên mình có viết một Laravel package giúp các bạn thực hiện việc này nhanh chóng ^_^
Bạn mở cửa sổ terminal từ thư mục gốc dự án và thực thi dòng lệnh:
$ composer require duyphan2502/hmvc-tools
Mình có hỗ trợ một số lệnh như:
- Tạo một module mới
- Tạo các tập tin thường hay sử dụng, ví dụ như
controller
,request
,middleware
,migration
,facade
,view composer
...
Bạn có thể xem tài liệu hướng dẫn kỹ hơn ở liên kết sau https://github.com/duyphan2502/hmvc-tools.
Để tạo ra module mới, từ cửa sổ terminal bạn thực thi câu lệnh:
$ php artisan module:create test-module
Hệ thống sẽ gợi ý bạn chỉ định loại module mà bạn muốn khởi tạo. Ở đây bạn sẽ chọn plugins
.
Khi mở tập tin composer.json
trong thư mục platform/plugins/test-module
, bạn sẽ thấy đoạn khai báo sau:
{
"name": "plugins/test-module",
"require": {},
"require-dev": {},
"autoload": {
"psr-4": {
"TestModule\\": "src/"
}
},
"extra": [],
"minimum-stability": "dev",
"description": "Test HMVC module"
}
Bạn cũng đừng quên đăng ký provider TestModule\Providers\ModuleServiceProvider:class
vào config/app.php
trong thư mục gốc.
Nếu bạn không muốn đăng ký một cách thủ công như vậy, bạn có thể đăng ký auto register cho Laravel bằng cách cập nhật lại tập tin platform/plugins/test-module/composer.json
.
{
...,
"extra": {
"laravel": {
"providers": [
"TestModule\\Providers\\ModuleServiceProvider"
]
}
},
}
Tiếp theo, chúng ta sẽ khai báo module này vào composer.json
của dự án bằng dòng lệnh:
$ composer require plugins/test-module:*
Khởi tạo một controller mới cho module của chúng ta:
$ php artisan module:make:controller test-module Test --resource
Mở tập tin platform/plugins/test-module/routes/web.php
và cập nhật thông tin route:
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;
$moduleRoute = 'test-module';
Route::group(['prefix' => $moduleRoute], function (Router $router) {
$router->resource('', 'TestController');
});
Tiếp theo, tạo ra một tập tin platform/plugins/test-module/resources/views/index.blade.php
và cập nhật nội dung cho nó như sau
Đến đây, mọi thứ cơ bản đã hoàn thành. Chúng ta bắt đầu kiểm tra xem module mới tạo đã hoạt động đúng chưa.
Từ terminal, thực thi câu lệnh:
$ php artisan serve
Laravel development server started: http://127.0.0.1:8000
Mở trình duyệt của bạn lên và truy cập theo đường dẫn http://127.0.0.1:8000/test-module
.
Các bạn có thể tải xuống mã nguồn của bản demo này theo link sau https://github.com/duyphan2502/demo-hmvc.
Tổng kết
Bạn có thể thấy rằng, bản chất của module chính là một ứng dụng Laravel thu nhỏ, với đầy đủ các thành phần như Controller, Model, Provider,...
Phía trên chỉ là một ví dụ khá đơn giản, khi mà chỉ có một plugin duy nhất.
Bên dưới là cấu trúc mà CMS mà mình đang xây dựng thực tế (Webed CMS).
Đây cũng là CMS mà blog này đang sử dụng.
Tất cả các core
modules sẽ được require bởi module core/base
, composer.json
ở thư mục gốc chỉ cần require core/base
là đủ. Bạn cũng cần đảm bảo việc các plugins
được load sau core
modules bằng cách require core/base
ở các composer.json
của plugins
.
Do kiến trúc đã được định nghĩa ngay từ đầu, nên khi có lỗi ở đâu đó xảy ra, mình và đồng nghiệp rất dễ dàng debug và tìm ra root cause. Khi dự án lớn dần thì cũng dễ dàng kiểm soát và mở rộng hơn. Việc merge code giữa các team hoặc thành viên trong nhóm cũng trở nên đơn giản nhiều.
Ví dụ như mình cần một bạn trong nhóm phát triển tính năng tích hợp hệ thống với GHN thì bạn đó sẽ làm việc trên một module riêng biệt, không tác động tới những phần khác. Thậm chí việc loại bỏ một module cũng dễ dàng khi chỉ cần xóa nó ra khỏi composer.json
.
Kết thúc chương trình truyền hình đến đây là hết :D hẹn gặp lại các bạn trong các series chọc phá laravel sắp tới. Nếu các bạn có ý kiến hay đóng góp về bài viết thì để lại bình luận bên dưới nhé.
Cám ơn các bạn đã theo dõi.