TanzCMS开源CMS系统

模块简单写法

最小一方模块的 manifest、ServiceProvider、路由和控制器示例。

更新:2026-05-31 03:07:49 浏览:3

模块简单写法

本文用 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.jsonconsole_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。
  • 不在模块中承载第三方可选插件能力。