模块简单写法
最小一方模块的 manifest、ServiceProvider、路由和控制器示例。
模块简单写法
本文用 demo 作为示例说明一个最小一方模块怎么写。示例只说明结构和写法,实际模块请替换为自己的业务代码。
一、目录
modules/demo/
├─ composer.json
├─ manifest.json
├─ src/
│ ├─ DemoServiceProvider.php
│ ├─ Http/Controllers/DemoAdminController.php
│ └─ Services/DemoService.php
├─ routes/admin.php
├─ routes/web.php
├─ database/migrations/
├─ resources/views/
└─ resources/assets/
二、composer.json
{
"autoload": {
"psr-4": {
"Modules\\Demo\\": "src/"
}
}
}
三、manifest.json
{
"code": "demo",
"name": "示例模块",
"version": "1.0.0",
"type": "module",
"providers": [
"Modules\\Demo\\DemoServiceProvider"
],
"routes": {
"web": "routes/web.php",
"admin": "routes/admin.php"
},
"requires": {
"tanzcms": "^1.2"
},
"tables": [
"demo_items"
],
"menus": [
{
"top": "content",
"group": "content.demo",
"group_title": "示例模块",
"group_icon": "file",
"id": "module.demo.items",
"title": "示例数据",
"url": "modules/demo/items",
"permission": "module.demo.item",
"sort": 10
}
]
}
模块菜单只声明入口;接口权限还要在权限配置中注册。
四、ServiceProvider
<?php
namespace Modules\Demo;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
class DemoServiceProvider extends ServiceProvider
{
public function register(): void
{
//
}
public function boot(): void
{
$base = dirname(__DIR__);
if (! $this->app->routesAreCached()) {
Route::middleware('web')->group($base.'/routes/web.php');
Route::middleware('web')->group($base.'/routes/admin.php');
}
$this->loadViewsFrom($base.'/resources/views', 'module-demo');
$this->loadMigrationsFrom($base.'/database/migrations');
$this->loadTranslationsFrom($base.'/resources/lang', 'module-demo');
}
}
如果模块有控制台命令,应在 manifest.json 的 console_commands 中声明,并在 ServiceProvider 中注册命令。
五、后台路由
routes/admin.php:
<?php
use Illuminate\Support\Facades\Route;
use Modules\Demo\Http\Controllers\DemoAdminController;
Route::prefix('/admin/modules/demo')->group(function (): void {
Route::get('/items', [DemoAdminController::class, 'page']);
Route::get('/items/data', [DemoAdminController::class, 'data']);
Route::post('/items', [DemoAdminController::class, 'store']);
});
实际项目应根据当前后台入口和权限中间件接入方式注册,不要让模块后台接口裸奔。
六、控制器
<?php
namespace Modules\Demo\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class DemoAdminController extends Controller
{
public function page(): string
{
return view('module-demo::items')->render();
}
public function data(Request $request): JsonResponse
{
return response()->json([
'data' => [],
'count' => 0,
]);
}
public function store(Request $request): JsonResponse
{
$data = $request->validate([
'title' => ['required', 'string', 'max:120'],
]);
return response()->json([
'message' => '保存成功',
'data' => $data,
]);
}
}
七、迁移
模块表迁移放在:
modules/demo/database/migrations/
表结构只写业务表名,表前缀由数据库连接统一处理。
八、模块写法禁忌
- 不把模块控制器放进
app/。 - 不把模块资源当源码维护在
public/assets/modules。 - 不在核心路由里硬编码模块业务路由。
- 不让模块包覆盖核心
app/、config/或公共后台 JS。 - 不在模块中承载第三方可选插件能力。