Module System
Giới thiệu
PHP Framework sử dụng kiến trúc module hóa để tổ chức business logic. Mỗi module là một đơn vị độc lập chứa controllers, services, models, DTOs, migrations và tests riêng. Module system giúp:
- Phân chia trách nhiệm rõ ràng
- Dễ bảo trì và mở rộng
- Tái sử dụng code giữa các dự án
- Team có thể làm việc độc lập trên từng module
Cấu trúc Module
Mỗi module nằm trong thư mục modules/ và có cấu trúc chuẩn:
modules/
└── booking/
├── booking.module.php # File cấu hình module
├── src/
│ ├── Controllers/ # HTTP Controllers
│ │ └── BookingController.php
│ ├── Services/ # Business logic
│ │ └── BookingService.php
│ ├── Models/ # Eloquent Models
│ │ └── Booking.php
│ ├── DTOs/ # Data Transfer Objects
│ │ ├── CreateBookingDTO.php
│ │ └── UpdateBookingDTO.php
│ ├── Providers/ # Service Providers
│ │ └── BookingServiceProvider.php
│ ├── Migrations/ # Database Migrations
│ ├── Rules/ # Custom Validation Rules
│ ├── Enums/ # PHP Enums
│ │ └── BookingStatus.php
│ └── MessageHandler/ # Queue Message Handlers
└── tests/ # Module Tests
└── BookingTest.php
File cấu hình Module
Mỗi module bắt buộc có file {module_name}.module.php:
<?php
// modules/booking/booking.module.php
return [
// Bắt buộc: tên module
'name' => 'Booking',
// Tùy chọn: mô tả
'description' => 'Quản lý đặt phòng và tour',
// Tùy chọn: danh sách Service Providers
'providers' => [
Vietiso\Modules\Booking\Providers\BookingServiceProvider::class,
],
];
- Tên thư mục module phải trùng với tên file
.module.php(không có extension) - Ví dụ:
modules/booking/booking.module.php - Nếu không khớp, module sẽ không được load
Namespace & Autoloading
Module classes sử dụng namespace Vietiso\Modules\{ModuleName}:
<?php
namespace Vietiso\Modules\Booking\Controllers;
class BookingController
{
// ...
}
Framework tự động convert tên module từ snake_case sang PascalCase cho namespace:
| Thư mục | Namespace |
|---|---|
modules/booking/ | Vietiso\Modules\Booking |
modules/mail_template/ | Vietiso\Modules\MailTemplate |
modules/electronic_contracts/ | Vietiso\Modules\ElectronicContracts |
Đường dẫn file: modules/{module_name}/src/{remaining_path}.php
Vietiso\Modules\Booking\Controllers\BookingController
→ modules/booking/src/Controllers/BookingController.php
Vietiso\Modules\MailTemplate\Models\Template
→ modules/mail_template/src/Models/Template.php
Module Discovery & Installation
Khi ứng dụng khởi động, ModuleInstaller tự động:
- Scan thư mục
modules/tìm tất cả file*.module.php - Validate tên thư mục khớp với tên file
- Load cấu hình module
- Register module vào
ModuleManager - Boot Service Providers của module
// Quá trình install (tự động)
foreach ($modules as $module) {
// 1. Đăng ký module
$moduleManager->add($module->getId(), $module);
// 2. Register & boot providers
foreach ($module->providers() as $provider) {
$serviceProviderManager->register($provider);
$serviceProviderManager->boot($provider);
}
}
Module Service Provider
Mỗi module nên có ít nhất một Service Provider để đăng ký services và routes:
<?php
namespace Vietiso\Modules\Booking\Providers;
use Vietiso\Core\Container\ServiceProvider;
use Vietiso\Modules\Booking\Services\BookingService;
class BookingServiceProvider extends ServiceProvider
{
public function register(): void
{
// Đăng ký services
$this->app->singleton(BookingService::class, fn ($app) => new BookingService(
$app->get('database'),
$app->get('cache'),
));
}
public function boot(): void
{
// Đăng ký routes
$routeCollection = $this->app->get('route.collection');
$module = $this->app->get('module.manager')->get('booking');
$routeCollection->register(
BookingController::class,
$module,
);
// Đăng ký event listeners
$events = $this->app->get('events');
$events->listen(BookingCreated::class, SendBookingConfirmation::class);
}
}
Module Controller
Controllers trong module sử dụng attribute-based routing:
<?php
namespace Vietiso\Modules\Booking\Controllers;
use Vietiso\Core\Route\Attributes\Get;
use Vietiso\Core\Route\Attributes\Post;
use Vietiso\Core\Route\Attributes\Put;
use Vietiso\Core\Route\Attributes\Delete;
use Vietiso\Core\Route\Attributes\Group;
#[Group(
prefix: 'api/v1/bookings',
middlewares: [AuthMiddleware::class],
)]
class BookingController
{
public function __construct(
private BookingService $bookingService,
) {}
#[Get('')]
public function index(ListBookingDTO $dto)
{
return $this->bookingService->list($dto);
}
#[Post('')]
public function store(CreateBookingDTO $dto)
{
return $this->bookingService->create($dto);
}
#[Get('{id}')]
public function show(int $id)
{
return $this->bookingService->findOrFail($id);
}
#[Put('{id}')]
public function update(int $id, UpdateBookingDTO $dto)
{
return $this->bookingService->update($id, $dto);
}
#[Delete('{id}')]
public function destroy(int $id)
{
return $this->bookingService->delete($id);
}
}
Truy cập Module
ModuleManager
Truy cập thông tin module từ ModuleManager:
use Vietiso\Core\Module\ModuleManager;
$moduleManager = app('module.manager');
// Kiểm tra module tồn tại
if ($moduleManager->has('booking')) {
$module = $moduleManager->get('booking');
echo $module->getName(); // "Booking"
echo $module->getDescription(); // "Quản lý đặt phòng và tour"
echo $module->getPrefix(); // "bookings"
echo $module->getPath(); // "/path/to/modules/booking"
}
// Lặp qua tất cả modules
foreach ($moduleManager as $module) {
echo $module->getName();
}
// Lấy tất cả modules
$allModules = $moduleManager->all();
Module Extensions
Đăng ký extension callbacks để mở rộng chức năng module:
$moduleManager->addExtend('permissions', function (array $permissions, Module $module) {
// Tự động đăng ký permissions từ module config
foreach ($permissions as $permission) {
Permission::register($permission, $module->getId());
}
});
Trong module config:
// modules/booking/booking.module.php
return [
'name' => 'Booking',
'providers' => [...],
'permissions' => [
'booking.view',
'booking.create',
'booking.update',
'booking.delete',
],
];
After Install Callbacks
Chạy logic sau khi mỗi module được install:
$moduleManager->addAfterInstall(function (Module $module) {
// Log module loaded
Log::info("Module installed: {$module->getName()}");
});
Module Middleware
Đăng ký middleware chỉ áp dụng cho một module:
// Trong file vietiso hoặc middleware config
$middlewares->add(BookingAuthMiddleware::class, 'booking');
Middleware này chỉ chạy cho routes thuộc module booking.
Tạo Module mới
CLI Command
php vietiso make:module payment
Thủ công
- Tạo thư mục
modules/payment/ - Tạo file cấu hình
modules/payment/payment.module.php:
<?php
return [
'name' => 'Payment',
'description' => 'Payment processing module',
'prefix' => 'payments',
'providers' => [
Vietiso\Modules\Payment\Providers\PaymentServiceProvider::class,
],
];
- Tạo cấu trúc
src/:
modules/payment/
├── payment.module.php
└── src/
├── Controllers/
│ └── PaymentController.php
├── Services/
│ └── PaymentService.php
├── Models/
│ └── Payment.php
├── DTOs/
│ ├── CreatePaymentDTO.php
│ └── PaymentCallbackDTO.php
└── Providers/
└── PaymentServiceProvider.php
- Restart server - module sẽ tự động được discover và load.
Best Practices
- Mỗi module một trách nhiệm: Module
bookingchỉ xử lý booking, không chứa logic payment - Giao tiếp qua services/events: Modules không nên trực tiếp gọi nhau, sử dụng Events hoặc inject service qua Container
- Module config đơn giản: Chỉ khai báo
name,providers, và metadata cần thiết - Providers lazy boot: Chỉ boot những gì cần thiết, tránh load không cần thiết
- Tests trong module: Đặt tests trong
modules/{name}/tests/để giữ mọi thứ gọn gàng