Skip to main content

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,
],
];
Quy tắc đặt tên
  • 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ụcNamespace
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:

  1. Scan thư mục modules/ tìm tất cả file *.module.php
  2. Validate tên thư mục khớp với tên file
  3. Load cấu hình module
  4. Register module vào ModuleManager
  5. 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

  1. Tạo thư mục modules/payment/
  2. 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,
],
];
  1. 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
  1. Restart server - module sẽ tự động được discover và load.

Best Practices

  1. Mỗi module một trách nhiệm: Module booking chỉ xử lý booking, không chứa logic payment
  2. 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
  3. Module config đơn giản: Chỉ khai báo name, providers, và metadata cần thiết
  4. Providers lazy boot: Chỉ boot những gì cần thiết, tránh load không cần thiết
  5. Tests trong module: Đặt tests trong modules/{name}/tests/ để giữ mọi thứ gọn gàng