Tái cấu trúc dự án bằng Laravel packages

Tái cấu trúc dự án bằng Laravel packages

Thông thường các lập trình viên khi phát triển ứng dụng Laravel thường sử dụng cấu trúc mặc định MVC trong project Laravel. Tuy nhiên khi ứng dụng mở rộng với nhiều chức năng và nhiều module thì cách làm này đã bộc lộ ra nhiều nhược điểm như khó maintain do file dài và cấu trúc project có thể bị phá vỡ. Vì thế thiết kế ứng dụng theo hướng package là phương pháp nhằm tái cấu trúc và mở rộng chức năng cho project Laravel. Packages có thể là bất cứ cái gì, giúp cho các lập trình viên dễ dàng làm việc với ngày tháng như thư viện Carbon, hoặc là packages để tạo ra cấu trúc Nested Sets, xử lí ảnh với ImageIntervention hoặc làm việc với Redis. Điều này giúp tiết kiệm thời gian và cho phép tái sử dụng các packages mình đã viết trong các dự án khác.

Keyword: Boilerplate, Composer, HMVC, Laravel, Package

1. Đặt vấn đề

Về cơ bản Project Laravel nếu không chia modules sẽ được cấu trúc như sau: Với Controller sẽ đặt 2 modules (Module1 và Module2) trong thư mục App\Http\Controllers, mỗi module đều có Controller riêng cho từng module đó. Các Controller đều extends từ Controller chung hoặc BaseController (Áp dụng với Project chỉ làm API, còn Project làm cả API và Web thì sẽ có thêm 2 thư mục nữa: Api\Module1Web\Module1

Controllers với 2 module Module1 và Module2

Đối với các project có làm việc với blade template trong views cũng chia tương tự như controller ở trên. Tuy nhiên nếu số lượng chức năng lớn dần thì số lượng module cũng lớn dần thì số lượng files config, Service Provider, routes, Commands, v.v cũng tăng dần.

Hình 2: Chia views theo modules

Cách chia project trên có ưu điểm nhanh, phù hợp với các dự án nhỏ. Tuy nhiên nếu trong dự án với chức năng lớn và số lượng modules ngày càng nhiều thì cách chia này không còn phù hợp. Các modules lớn dần làm cho project khó maintain nếu thêm chức năng mới. Một ví du là các files routes/web.php hoặc api.php sẽ ngày càng dài và càng khó đọc hơn

Ví dụ routes/web.php của một module

Có một ý kiến khác cho rằng để khắc phục các routes quá dài thì nên chia routes thành các file routes nhỏ hơn như sau

Chia routes thành 2 module chính: admin và web

Cách này cũng là một hướng giải quyết vấn đề nêu trên. Tuy nhiên nếu ứng dụng mở rộng thì số lượng files routing sẽ nhiều lên, gây khó khăn cho những người tham gia dự án – họ chưa chắc đã biết được cần phải viết route gì và route này được dành cho module nào

Đồng thời nếu muốn tích hợp các chức năng cơ bản của modules này cho 1 dự án khác (Ví dụ như tích hợp SSO module vào dự án khác) thì phải copy bằng tay từng file một vào project.

Giải pháp được đưa ra là: Tạo ra các modules theo mô hình HMVC, mỗi project sẽ có controllers, models, migrations, routes, viewsconfig riêng cho từng module.

2. Triển khai

2.1. Cài đặt Laravel và Packages

Cài đặt project Laravel như bình thường thông qua Composer như sau:

composer create-project laravel/laravel [app_name]

Sau khi tạo xong project Laravel from scratch, thay vì tự tạo package từ đầu thì sử dụng trang https://laravelpackageboilerplate.com/ để tạo boilerplate nhanh cho từng Package

Trong trang này sau khi nhập thông tin Vendor và Packages thì sẽ tạo ra boilerplate chứa ServiceProvider

Tạo thêm một thư mục chứa packages mình viết (tên tuỳ chọn, ở đây chọn là packages) kèm với tên package mình tạo (cardinfo) – có chứa code sau khi tạo packages

Package card-info được tạo trong thư mục packages, trong đó chứa toàn bộ MVC và các files cần thiết

Sau đó vào packages/card-info/app/Providers/CardInfoServiceProvider.php và xoá bỏ các file cần thiết như Facade và Class thông thường, chỉ giữ lại config như sau

Giữ lại config, loại bỏ class thông thường và Facade khi sử dụng package generator

File `composer.json` trong module cũng được chỉnh sửa sao cho giống với thư mục laravel bên ngoài như sau (khung vàng)

Hình 7: Chỉnh sửa composer.json

Việc load namespace tùy theo từng team, cấu trúc package cũng tương tự như một project Laravel thu nhỏ (HMVC)

2. Cấu hình packages

Để packages nhận routes, config và views, etc. cần vào thư mục Providers và cấu hình lại như sau

Từ Providers/.. (app)/..(src)/ routes/web.php

Trong trường hợp nhận config thì chỉ cần uncomment code ở trên và sửa lại đường dẫn đến thư mục views hoặc config tương ứng

Load views (Dòng 20) và load config (Dòng 29)

3. Tích hợp Packages vào Laravel.

Vào phần composer.json thuộc thư mục root trong project Laravel, thêm 1 key có tên là repositories và link đường dẫn đến package (type = path, url là đường dẫn tới thư mục card-info packages. Với type = composer thì dùng luôn packagist.org” để lấy packages từ packagist về)

Thêm repositories key vào composer.json tại thư mục root

Sau khi thêm vào repositories key xong, tiến hành chạy composer require trello/cardinfo để tiến hành cài đặt package mình có. Tên trello/cardinfo là name của composer.json thuộc module

Lấy tên packages là trello/cardinfo

Sau khi cài đặt xong thì trong composer.json đã có project local của mình

Package trello/cardinfo được tích hợp trong composer.json root directory

4. Kiểm thử

Thêm một route vào routes/web.php như sau

Thêm một route mới vào routes/web.php ứng với controller và action

File WelcomeController.php

Thêm controller WelcomeController và view welcome.index vào module thuộc view

Chú ý trong view có sử dụng kí tự “::”, kí tự này được dùng để lấy view thuộc package được chỉ định, ở đây là cardinfo. Ở đây là lấy view welcome.index trong package cardinfo. Khi test trên trình duyệt

Route trong module được load thành công

Test load route api

Route api

5. Gỡ cài đặt Package:

Trong trường hợp không có nhu cầu sử dụng package nữa thì có thể dễ dàng gỡ bỏ package như như package Composer thông thường


Ví dụ file composer.json sau khi đã add package bao gồm trello/card-info (dòng 15) và frontend/adtech (dòng 9)

composer.json chứa cả frontend/adtech và trello/cardinfo

Khi cần gỡ package chỉ cần chạy composer remove [package] ví dụ composer remove frontend/adtech là xong. Sau khi chạy câu lệnh này xong thì không còn sử dụng được các chức năng trong package vừa được xóa nữa

Xoá package Frontend/adtech

Kiểm tra lại trong file composer.json gốc

Package frontend/adtech đã bị gỡ.

Reference Gitlab: https://gitlab.com/repositories2/laravel-modules.git

Admicro link: https://lab.admicro.vn/research/laravel-packages.git