Thiết kế cấu trúc folder HMVC cho Laravel

Bài viết được sự cho phép của tác giả Duy Phan

Ở 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.

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

Khởi tạo thư mục chứa các modules HMVC

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ỏi composer.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 modules core và plugins để hiển thị dữ liệu và thao tác với người dùng.

  Repository Design Pattern và ứng dụng của nó trong Laravel

  Những mẹo nhỏ khi làm việc với Laravel Eloquent

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:

cau-truc-package

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ư controllerrequestmiddlewaremigrationfacadeview 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.

create-module

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

code-for-view

Đế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.

Xem thêm nhiều chương trình tuyển dụng Laravel hấp dẫn trên TopDev

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.

module-render-success

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ư ControllerModelProvider,…

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).

webed-cms-structure

Đâ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/basecomposer.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 😀 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.

Bài viết gốc được đăng tải tại duypt.dev

Xem thêm:

Tham khảo thêm các vị trí tuyển dụng ngành IT tại Topdev