从零开始学习使用ThinkPHP 6.0构建功能完善的博客系统
ThinkPHP 6.0简介
ThinkPHP是一个免费开源的轻量级PHP开发框架,遵循Apache2开源协议发布。ThinkPHP 6.0版本基于PHP 7.1+,优化了核心架构,引入了新特性,提供了更强大的开发体验。
主要特性:
- 简洁的路由定义和强大的路由功能
- 完善的ORM支持,支持多种数据库
- 强大的模板引擎,支持标签库
- 丰富的扩展机制和类库支持
- 支持Composer依赖管理
- PSR规范支持,易于与其他框架集成
环境搭建与项目创建
在开始之前,确保您的系统满足以下要求:
- PHP >= 7.1.0
- PDO PHP Extension
- MBstring PHP Extension
- Composer工具
安装ThinkPHP 6.0
# 使用Composer创建项目
composer create-project topthink/think tp-blog
# 进入项目目录
cd tp-blog
# 启动内置服务器
php think run
配置数据库
修改config/database.php文件,配置数据库连接信息:
return [
// 默认数据库连接
'default' => 'mysql',
// 数据库连接信息
'connections' => [
'mysql' => [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'blog',
// 用户名
'username' => 'root',
// 密码
'password' => 'password',
// 端口
'hostport' => '3306',
// 连接dsn
'dsn' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8mb4',
// 数据库表前缀
'prefix' => 'blog_',
// 数据库调试模式
'debug' => true,
],
],
];
项目结构说明
ThinkPHP 6.0采用模块化设计,标准目录结构如下:
tp-blog/
├── app/ // 应用目录
│ ├── controller/ // 控制器目录
│ ├── model/ // 模型目录
│ ├── view/ // 视图目录
│ └── ... // 其他目录
├── config/ // 配置目录
├── public/ // WEB部署目录
├── route/ // 路由定义目录
├── runtime/ // 运行时目录
├── vendor/ // 第三方类库目录
└── extend/ // 扩展类库目录
多应用模式配置
ThinkPHP 6.0默认采用单应用模式,我们可以启用多应用模式:
# 安装多应用模式扩展
composer require topthink/think-multi-app
# 创建应用目录
cd app
mkdir index blog admin
# 在每个应用目录中创建必要的子目录
mkdir controller model view
数据库设计与迁移
我们将创建以下数据表来支持博客系统:
数据表设计
- 文章表(blog_articles):存储文章内容
- 分类表(blog_categories):文章分类
- 标签表(blog_tags):文章标签
- 文章标签关联表(blog_article_tags):文章和标签的多对多关系
- 评论表(blog_comments):文章评论
- 用户表(blog_users):后台管理员
创建数据库迁移文件
# 创建文章表迁移
php think make:migration CreateArticlesTable
# 编辑迁移文件
# database/migrations/20230101000000_create_articles_table.php
迁移文件示例
<?php
use thinkmigrationMigrator;
use thinkmigrationdbColumn;
class CreateArticlesTable extends Migrator
{
public function change()
{
$table = $this->table('blog_articles', ['engine' => 'InnoDB', 'comment' => '文章表']);
$table->addColumn('category_id', 'integer', ['limit' => 10, 'default' => 0, 'comment' => '分类ID'])
->addColumn('title', 'string', ['limit' => 255, 'default' => '', 'comment' => '文章标题'])
->addColumn('content', 'text', ['comment' => '文章内容'])
->addColumn('excerpt', 'string', ['limit' => 500, 'default' => '', 'comment' => '文章摘要'])
->addColumn('status', 'integer', ['limit' => 1, 'default' => 0, 'comment' => '状态:0草稿,1发布'])
->addColumn('views', 'integer', ['limit' => 10, 'default' => 0, 'comment' => '浏览量'])
->addColumn('is_top', 'integer', ['limit' => 1, 'default' => 0, 'comment' => '是否置顶'])
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP', 'comment' => '创建时间'])
->addColumn('updated_at', 'timestamp', ['null' => true, 'comment' => '更新时间'])
->addIndex(['category_id'])
->addIndex(['status'])
->create();
}
}
执行数据库迁移
# 运行迁移
php think migrate:run
博客系统功能实现
下面我们将实现博客系统的核心功能,包括文章管理、分类管理、标签管理和评论功能。
1. 创建文章模型
<?php
namespace appindexmodel;
use thinkModel;
use thinkmodelconcernSoftDelete;
class Article extends Model
{
use SoftDelete;
// 设置表名
protected $name = 'blog_articles';
// 设置自动时间戳
protected $autoWriteTimestamp = 'datetime';
protected $createTime = 'created_at';
protected $updateTime = 'updated_at';
protected $deleteTime = 'deleted_at';
protected $defaultSoftDelete = null;
// 定义状态常量
const STATUS_DRAFT = 0; // 草稿
const STATUS_PUBLISHED = 1; // 已发布
// 分类关联
public function category()
{
return $this->belongsTo(Category::class);
}
// 标签多对多关联
public function tags()
{
return $this->belongsToMany(Tag::class, 'blog_article_tags');
}
// 评论一对多关联
public function comments()
{
return $this->hasMany(Comment::class);
}
// 获取器 - 状态文字描述
public function getStatusTextAttr($value, $data)
{
$status = $data['status'] ?? 0;
$statusMap = [
self::STATUS_DRAFT => '草稿',
self::STATUS_PUBLISHED => '已发布'
];
return $statusMap[$status] ?? '未知';
}
// 获取器 - 格式化创建时间
public function getCreatedAtTextAttr($value, $data)
{
return date('Y-m-d H:i', strtotime($data['created_at']));
}
// 范围查询 - 已发布文章
public function scopePublished($query)
{
$query->where('status', self::STATUS_PUBLISHED);
}
// 范围查询 - 置顶文章
public function scopeTop($query)
{
$query->where('is_top', 1);
}
}
2. 创建文章控制器
<?php
namespace appindexcontroller;
use thinkfacadeView;
use appindexmodelArticle as ArticleModel;
use appindexmodelCategory;
use appindexmodelTag;
class Article extends Base
{
// 文章列表
public function index()
{
$categoryId = input('category_id', 0);
$tagId = input('tag_id', 0);
$keyword = input('keyword', '');
// 构建查询条件
$query = ArticleModel::with(['category', 'tags'])
->published()
->order('is_top DESC, created_at DESC');
if ($categoryId) {
$query->where('category_id', $categoryId);
}
if ($tagId) {
$query->whereHas('tags', function($query) use ($tagId) {
$query->where('tag_id', $tagId);
});
}
if ($keyword) {
$query->whereLike('title|content', '%' . $keyword . '%');
}
$articles = $query->paginate(10);
// 获取分类和标签用于侧边栏
$categories = Category::withCount('articles')->select();
$tags = Tag::withCount('articles')->select();
View::assign([
'articles' => $articles,
'categories' => $categories,
'tags' => $tags,
'category_id' => $categoryId,
'tag_id' => $tagId,
'keyword' => $keyword
]);
return View::fetch();
}
// 文章详情
public function detail($id)
{
$article = ArticleModel::with(['category', 'tags', 'comments' => function($query) {
$query->where('status', 1)->order('created_at DESC');
}])->published()->findOrFail($id);
// 增加浏览量
$article->setInc('views');
View::assign('article', $article);
return View::fetch();
}
// 搜索文章
public function search()
{
$keyword = input('keyword', '');
if (empty($keyword)) {
return redirect('index/article/index');
}
$articles = ArticleModel::with(['category', 'tags'])
->published()
->whereLike('title|content', '%' . $keyword . '%')
->order('created_at DESC')
->paginate(10, false, ['query' => ['keyword' => $keyword]]);
View::assign([
'articles' => $articles,
'keyword' => $keyword
]);
return View::fetch('index');
}
}
3. 配置路由
在route/route.php中定义路由规则:
<?php
use thinkfacadeRoute;
// 文章列表页
Route::get('article', 'index/article/index');
Route::get('article/category/:id', 'index/article/index');
// 文章详情页
Route::get('article/:id', 'index/article/detail')
->pattern(['id' => 'd+']);
// 搜索页面
Route::get('search', 'index/article/search');
// 标签页面
Route::get('tag/:id', 'index/article/index')
->pattern(['id' => 'd+']);
// 提交评论
Route::post('comment/add', 'index/comment/add');
4. 创建视图模板
创建文章列表视图模板view/index/article/index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>文章列表 - {$site.title}</title>
<meta name="keywords" content="{$site.keywords}">
<meta name="description" content="{$site.description}">
</head>
<body>
{include file="common/header" /}
<div class="container">
<div class="row">
<div class="col-md-8">
<div class="page-header">
<h1>
{if $category_id}
{$categories->where('id', $category_id)->value('name')}
{elseif $tag_id}
标签: {$tags->where('id', $tag_id)->value('name')}
{elseif $keyword}
搜索: {$keyword}
{else}
最新文章
{/if}
</h1>
</div>
{volist name="articles" id="article"}
<div class="article-item">
{if $article.is_top}
<span class="label label-primary">置顶</span>
{/if}
<h2><a href="{:url('index/article/detail', ['id' => $article.id])}" rel="external nofollow" rel="external nofollow" >{$article.title}</a></h2>
<div class="article-meta">
<span><i class="fa fa-calendar"></i> {$article.created_at_text}</span>
<span><i class="fa fa-folder"></i> {$article.category.name}</span>
<span><i class="fa fa-eye"></i> {$article.views}</span>
</div>
<div class="article-excerpt">
{$article.excerpt|default=$article.content|mb_substr=0,200}
</div>
<div class="article-footer">
<a href="{:url('index/article/detail', ['id' => $article.id])}" rel="external nofollow" rel="external nofollow" class="btn btn-primary">阅读更多</a>
</div>
</div>
{/volist}
<div class="pagination">
{$articles|raw}
</div>
</div>
<div class="col-md-4">
{include file="common/sidebar" /}
</div>
</div>
</div>
{include file="common/footer" /}
</body>
</html>
5. 后台管理功能
创建后台文章管理控制器:
<?php
namespace appadmincontroller;
use thinkfacadeView;
use appadminmodelArticle as ArticleModel;
use appadminmodelCategory;
use appadminmodelTag;
class Article extends Base
{
// 文章列表
public function index()
{
$status = input('status', -1);
$categoryId = input('category_id', 0);
$keyword = input('keyword', '');
$query = ArticleModel::with(['category', 'tags']);
if ($status != -1) {
$query->where('status', $status);
}
if ($categoryId) {
$query->where('category_id', $categoryId);
}
if ($keyword) {
$query->whereLike('title', '%' . $keyword . '%');
}
$articles = $query->order('is_top DESC, id DESC')->paginate(15);
$categories = Category::select();
View::assign([
'articles' => $articles,
'categories' => $categories,
'status' => $status,
'category_id' => $categoryId,
'keyword' => $keyword
]);
return View::fetch();
}
// 添加文章
public function add()
{
if ($this->request->isPost()) {
$data = $this->request->post();
$validate = new appadminvalidateArticle;
if (!$validate->check($data)) {
$this->error($validate->getError());
}
$article = ArticleModel::create($data);
// 处理标签
if (!empty($data['tags'])) {
$tagIds = Tag::saveTags($data['tags']);
$article->tags()->attach($tagIds);
}
$this->success('添加成功', 'index');
}
$categories = Category::select();
View::assign('categories', $categories);
return View::fetch();
}
// 编辑文章
public function edit($id)
{
$article = ArticleModel::with('tags')->findOrFail($id);
if ($this->request->isPost()) {
$data = $this->request->post();
$validate = new appadminvalidateArticle;
if (!$validate->check($data)) {
$this->error($validate->getError());
}
$article->save($data);
// 更新标签
if (!empty($data['tags'])) {
$tagIds = Tag::saveTags($data['tags']);
$article->tags()->detach();
$article->tags()->attach($tagIds);
}
$this->success('更新成功', 'index');
}
$categories = Category::select();
View::assign([
'article' => $article,
'categories' => $categories
]);
return View::fetch();
}
// 删除文章
public function delete($id)
{
$article = ArticleModel::findOrFail($id);
$article->delete();
$this->success('删除成功');
}
// 设置文章状态
public function setStatus($id, $status)
{
$article = ArticleModel::findOrFail($id);
$article->status = $status;
$article->save();
$this->success('操作成功');
}
}
总结
通过本文的教程,我们使用ThinkPHP 6.0构建了一个功能完整的博客系统,涵盖了以下核心内容:
实现的功能:
- 文章管理(增删改查、状态管理)
- 分类和标签管理
- 文章评论系统
- 文章搜索功能
- 前后台分离架构
- 响应式页面设计
使用的ThinkPHP特性:
- 模型和ORM操作
- 控制器和请求处理
- 视图模板和标签库
- 路由定义和URL生成
- 验证器和数据验证
- 中间件和权限控制
这个博客系统可以作为学习ThinkPHP的入门项目,也可以作为实际项目的基础框架进行扩展。ThinkPHP 6.0提供了丰富的功能和灵活的扩展机制,能够满足各种Web开发需求。
希望本文能帮助您更好地理解和使用ThinkPHP框架,在实际开发中发挥其强大的功能。