项目概述:企业级CMS系统架构设计
本教程将基于ThinkPHP 6.x框架,开发一个功能完整的企业级内容管理系统(CMS)。系统将包含多租户支持、权限管理、内容发布、SEO优化等核心功能。
系统架构设计:
cms-system/
├── app/
│ ├── controller/ # 控制器层
│ │ ├── admin/ # 后台控制器
│ │ └── api/ # API控制器
│ ├── model/ # 模型层
│ │ ├── relation/ # 模型关联
│ │ └── trait/ # 模型特性
│ ├── middleware/ # 中间件
│ ├── service/ # 服务层
│ ├── validate/ # 验证器
│ └── common.php # 公共函数
├── config/
├── database/
├── public/
├── route/
├── vendor/
└── runtime/
开发环境配置与项目初始化
1. 使用Composer创建项目
# 创建ThinkPHP 6.x项目
composer create-project topthink/think cms-system
# 进入项目目录
cd cms-system
# 安装常用扩展
composer require topthink/think-multi-app
composer require topthink/think-migration
2. 多应用配置
// config/app.php
return [
// 开启多应用
'auto_multi_app' => true,
'app_express' => true,
// 默认应用
'default_app' => 'index',
// 默认时区
'default_timezone' => 'Asia/Shanghai',
];
3. 数据库配置
// config/database.php
return [
// 默认数据连接标识
'default' => 'mysql',
// 数据库连接信息
'connections' => [
'mysql' => [
'type' => 'mysql',
'hostname' => '127.0.0.1',
'database' => 'cms_system',
'username' => 'root',
'password' => '',
'hostport' => '3306',
'charset' => 'utf8mb4',
'prefix' => 'cms_',
'debug' => true,
],
],
];
数据库设计与模型构建
1. 数据表结构设计
// database/migrations/20231215001_create_cms_tables.php
<?php
use thinkmigrationMigrator;
class CreateCmsTables extends Migrator
{
public function change()
{
// 用户表
$table = $this->table('users', ['comment' => '用户表']);
$table->addColumn('username', 'string', ['limit' => 50, 'comment' => '用户名'])
->addColumn('email', 'string', ['limit' => 100, 'comment' => '邮箱'])
->addColumn('password', 'string', ['limit' => 255, 'comment' => '密码'])
->addColumn('status', 'integer', ['default' => 1, 'comment' => '状态'])
->addTimestamps()
->addIndex(['username'], ['unique' => true])
->addIndex(['email'], ['unique' => true])
->create();
// 文章表
$table = $this->table('articles', ['comment' => '文章表']);
$table->addColumn('title', 'string', ['limit' => 200, 'comment' => '标题'])
->addColumn('content', 'text', ['comment' => '内容'])
->addColumn('excerpt', 'string', ['limit' => 500, 'comment' => '摘要'])
->addColumn('user_id', 'integer', ['comment' => '作者ID'])
->addColumn('category_id', 'integer', ['comment' => '分类ID'])
->addColumn('status', 'integer', ['default' => 0, 'comment' => '状态'])
->addColumn('views', 'integer', ['default' => 0, 'comment' => '浏览量'])
->addTimestamps()
->addIndex(['user_id'])
->addIndex(['category_id'])
->addIndex(['status'])
->create();
// 分类表
$table = $this->table('categories', ['comment' => '分类表']);
$table->addColumn('name', 'string', ['limit' => 50, 'comment' => '分类名称'])
->addColumn('parent_id', 'integer', ['default' => 0, 'comment' => '父级ID'])
->addColumn('sort', 'integer', ['default' => 0, 'comment' => '排序'])
->addTimestamps()
->create();
}
}
?>
2. 模型定义与关联
// app/model/User.php
<?php
namespace appmodel;
use thinkModel;
use thinkmodelconcernSoftDelete;
class User extends Model
{
use SoftDelete;
protected $name = 'users';
protected $pk = 'id';
// 自动时间戳
protected $autoWriteTimestamp = true;
// 字段类型转换
protected $type = [
'status' => 'integer',
];
// 密码自动加密
public function setPasswordAttr($value)
{
return password_hash($value, PASSWORD_DEFAULT);
}
// 定义文章关联
public function articles()
{
return $this->hasMany(Article::class, 'user_id');
}
}
?>
// app/model/Article.php
<?php
namespace appmodel;
use thinkModel;
class Article extends Model
{
protected $name = 'articles';
protected $pk = 'id';
protected $autoWriteTimestamp = true;
protected $type = [
'status' => 'integer',
'views' => 'integer',
];
// 自动写入摘要
public function setExcerptAttr($value, $data)
{
if (empty($value) && isset($data['content'])) {
return mb_substr(strip_tags($data['content']), 0, 200);
}
return $value;
}
// 定义作者关联
public function author()
{
return $this->belongsTo(User::class, 'user_id');
}
// 定义分类关联
public function category()
{
return $this->belongsTo(Category::class, 'category_id');
}
// 状态获取器
public function getStatusTextAttr($value, $data)
{
$status = $data['status'] ?? 0;
$statusMap = [0 => '草稿', 1 => '已发布', 2 => '已下线'];
return $statusMap[$status] ?? '未知';
}
}
?>
核心模块开发实战
1. 后台文章管理控制器
// app/admin/controller/Article.php
<?php
namespace appadmincontroller;
use appBaseController;
use appmodelArticle as ArticleModel;
use appmodelCategory;
use thinkfacadeView;
use thinkfacadeRequest;
class Article extends BaseController
{
protected $middleware = [
'auth' => ['except' => []]
];
public function index()
{
$page = Request::param('page', 1);
$limit = Request::param('limit', 15);
$keyword = Request::param('keyword', '');
$query = ArticleModel::with(['author', 'category'])
->order('id', 'desc');
if (!empty($keyword)) {
$query->whereLike('title', "%{$keyword}%");
}
$list = $query->paginate([
'list_rows' => $limit,
'page' => $page
]);
return View::fetch('index', [
'list' => $list,
'keyword' => $keyword
]);
}
public function create()
{
if (Request::isPost()) {
$data = Request::post();
try {
$article = ArticleModel::create($data);
return json(['code' => 1, 'msg' => '创建成功', 'data' => $article]);
} catch (Exception $e) {
return json(['code' => 0, 'msg' => '创建失败: ' . $e->getMessage()]);
}
}
$categories = Category::select();
return View::fetch('create', ['categories' => $categories]);
}
public function edit($id)
{
$article = ArticleModel::find($id);
if (!$article) {
$this->error('文章不存在');
}
if (Request::isPost()) {
$data = Request::post();
try {
$article->save($data);
return json(['code' => 1, 'msg' => '更新成功']);
} catch (Exception $e) {
return json(['code' => 0, 'msg' => '更新失败: ' . $e->getMessage()]);
}
}
$categories = Category::select();
return View::fetch('edit', [
'article' => $article,
'categories' => $categories
]);
}
public function delete($id)
{
$article = ArticleModel::find($id);
if (!$article) {
return json(['code' => 0, 'msg' => '文章不存在']);
}
try {
$article->delete();
return json(['code' => 1, 'msg' => '删除成功']);
} catch (Exception $e) {
return json(['code' => 0, 'msg' => '删除失败: ' . $e->getMessage()]);
}
}
}
?>
2. API接口控制器
// app/api/controller/Article.php
<?php
namespace appapicontroller;
use appBaseController;
use appmodelArticle as ArticleModel;
use appmodelCategory;
use thinkfacadeRequest;
class Article extends BaseController
{
public function index()
{
$page = Request::param('page', 1);
$limit = Request::param('limit', 10);
$categoryId = Request::param('category_id', 0);
$query = ArticleModel::with(['author', 'category'])
->where('status', 1)
->order('id', 'desc');
if ($categoryId > 0) {
$query->where('category_id', $categoryId);
}
$list = $query->paginate([
'list_rows' => $limit,
'page' => $page
]);
return json([
'code' => 1,
'data' => $list->items(),
'total' => $list->total(),
'page' => $list->currentPage()
]);
}
public function read($id)
{
$article = ArticleModel::with(['author', 'category'])
->where('status', 1)
->find($id);
if (!$article) {
return json(['code' => 0, 'msg' => '文章不存在']);
}
// 增加浏览量
$article->setInc('views');
return json(['code' => 1, 'data' => $article]);
}
}
?>
3. 自定义中间件:权限验证
// app/middleware/Auth.php
<?php
namespace appmiddleware;
use thinkfacadeRequest;
use thinkfacadeSession;
class Auth
{
public function handle($request, Closure $next)
{
// 检查用户是否登录
if (!Session::has('admin_user')) {
if ($request->isAjax()) {
return json(['code' => 401, 'msg' => '请先登录']);
} else {
return redirect('/admin/login');
}
}
// 权限验证逻辑
$user = Session::get('admin_user');
$currentController = $request->controller();
$currentAction = $request->action();
// 这里可以添加更复杂的权限验证逻辑
if (!$this->checkPermission($user, $currentController, $currentAction)) {
if ($request->isAjax()) {
return json(['code' => 403, 'msg' => '权限不足']);
} else {
return redirect('/admin/error/403');
}
}
return $next($request);
}
private function checkPermission($user, $controller, $action)
{
// 简化版权限验证,实际项目中应该更复杂
$superAdmin = [1]; // 超级管理员ID
if (in_array($user['id'], $superAdmin)) {
return true;
}
// 普通用户权限验证逻辑
$allowedActions = [
'Article' => ['index', 'create', 'edit'],
// 更多控制器和动作的权限配置
];
return isset($allowedActions[$controller]) &&
in_array($action, $allowedActions[$controller]);
}
}
?>
ThinkPHP高级特性应用
1. 服务层与依赖注入
// app/service/ArticleService.php
<?php
namespace appservice;
use appmodelArticle;
use thinkfacadeCache;
class ArticleService
{
protected $articleModel;
public function __construct(Article $article)
{
$this->articleModel = $article;
}
public function getHotArticles($limit = 10)
{
$cacheKey = 'hot_articles_' . $limit;
return Cache::remember($cacheKey, function() use ($limit) {
return $this->articleModel
->where('status', 1)
->order('views', 'desc')
->limit($limit)
->select();
}, 3600); // 缓存1小时
}
public function createArticle($data)
{
// 数据验证
$validate = new appvalidateArticle();
if (!$validate->check($data)) {
throw new Exception($validate->getError());
}
// 创建文章
$article = $this->articleModel->create($data);
// 清除相关缓存
Cache::delete('hot_articles_10');
Cache::delete('recent_articles_10');
return $article;
}
}
?>
2. 事件系统应用
// app/event/ArticleEvent.php
<?php
namespace appevent;
class ArticleEvent
{
public function onCreated($article)
{
// 文章创建后的处理
thinkfacadeLog::info('文章创建: ' . $article->title);
// 发送通知等
// $this->sendNotification($article);
}
public function onUpdated($article)
{
// 文章更新后的处理
thinkfacadeLog::info('文章更新: ' . $article->title);
// 清除缓存
thinkfacadeCache::tag('article')->clear();
}
}
// 在模型中使用事件
class Article extends Model
{
protected static function init()
{
// 注册模型事件
self::event('after_insert', function ($article) {
event('ArticleCreated', $article);
});
self::event('after_update', function ($article) {
event('ArticleUpdated', $article);
});
}
}
?>
3. 自定义验证器
// app/validate/Article.php
<?php
namespace appvalidate;
use thinkValidate;
class Article extends Validate
{
protected $rule = [
'title|标题' => 'require|max:200',
'content|内容' => 'require|min:10',
'category_id|分类' => 'require|number',
'status|状态' => 'require|in:0,1,2',
];
protected $message = [
'title.require' => '标题不能为空',
'title.max' => '标题长度不能超过200个字符',
'content.require' => '内容不能为空',
'content.min' => '内容长度不能少于10个字符',
'category_id.require' => '请选择分类',
'status.in' => '状态值不合法',
];
protected $scene = [
'create' => ['title', 'content', 'category_id', 'status'],
'update' => ['title', 'content', 'category_id', 'status'],
];
}
?>
性能优化与生产部署
1. 路由优化配置
// route/app.php
<?php
use thinkfacadeRoute;
// 后台路由组
Route::group('admin', function () {
Route::get('login', 'admin/Login/index');
Route::post('login', 'admin/Login/doLogin');
Route::group('', function () {
Route::get('', 'admin/Index/index');
Route::get('index', 'admin/Index/index');
// 文章管理
Route::get('articles', 'admin/Article/index');
Route::get('articles/create', 'admin/Article/create');
Route::post('articles/create', 'admin/Article/create');
Route::get('articles/edit/:id', 'admin/Article/edit');
Route::post('articles/edit/:id', 'admin/Article/edit');
Route::post('articles/delete/:id', 'admin/Article/delete');
})->middleware(appmiddlewareAuth::class);
});
// API路由组
Route::group('api', function () {
Route::get('articles', 'api/Article/index');
Route::get('articles/:id', 'api/Article/read');
})->allowCrossDomain();
2. 缓存配置优化
// config/cache.php
return [
// 默认缓存驱动
'default' => env('CACHE_DRIVER', 'redis'),
// 缓存连接配置
'stores' => [
'file' => [
'type' => 'File',
'path' => '../runtime/cache/',
],
'redis' => [
'type' => 'redis',
'host' => '127.0.0.1',
'port' => 6379,
'password' => '',
'select' => 0,
'timeout' => 0,
'persistent' => false,
'prefix' => 'cms:',
],
],
];
3. 生产环境配置
// .env.production
APP_DEBUG = false
APP_TRACE = false
# 数据库配置
DATABASE_HOSTNAME = 127.0.0.1
DATABASE_DATABASE = cms_production
DATABASE_USERNAME = production_user
DATABASE_PASSWORD = secure_password
# 缓存配置
CACHE_DRIVER = redis
# Session配置
SESSION_TYPE = redis
4. 部署脚本示例
#!/bin/bash
# deploy.sh
echo "开始部署CMS系统..."
# 拉取最新代码
git pull origin main
# 安装依赖
composer install --no-dev --optimize-autoloader
# 生成优化文件
php think optimize:route
php think optimize:schema
# 设置权限
chmod -R 755 runtime
chmod -R 755 public/uploads
# 重启服务
systemctl reload php-fpm
echo "部署完成!"
项目总结与最佳实践
本CMS系统核心特性:
- 基于ThinkPHP 6.x的多应用架构
- 完整的RBAC权限管理系统
- 前后端分离的API设计
- 高性能的缓存策略
- 完善的日志和错误处理
ThinkPHP开发最佳实践:
- 合理使用模型关联和软删除
- 中间件处理通用业务逻辑
- 服务层封装复杂业务
- 验证器确保数据安全
- 事件系统解耦业务逻辑