轻松掌握ThinkPHP数据库数据显示技巧从连接数据库到页面渲染的详细教程
1. ThinkPHP框架简介
ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,遵循Apache2开源协议发布。它自2006年诞生以来,一直致力于为Web应用开发提供简洁、高效、安全的解决方案。ThinkPHP采用了MVC(Model-View-Controller)架构模式,使代码组织更加清晰,便于维护和扩展。
在数据库操作方面,ThinkPHP提供了强大的ORM(对象关系映射)功能,使开发者可以以面向对象的方式操作数据库,而不需要编写复杂的SQL语句。同时,ThinkPHP还提供了丰富的查询构造器和数据模型,大大简化了数据库操作。
2. 数据库连接配置
在ThinkPHP中,数据库连接配置非常简单。首先,我们需要在配置文件中设置数据库连接信息。在ThinkPHP 6.x/8.x中,数据库配置文件位于config/database.php
。
以下是一个典型的MySQL数据库配置示例:
<?php return [ // 默认使用的数据库连接配置 'default' => env('database.driver', 'mysql'), // 自定义时间查询规则 'time_query_rule' => [], // 自动写入时间戳字段 'auto_timestamp' => true, // 时间字段取出后的默认时间格式 'datetime_format' => 'Y-m-d H:i:s', // 数据库连接配置信息 'connections' => [ 'mysql' => [ // 数据库类型 'type' => 'mysql', // 服务器地址 'hostname' => env('database.hostname', '127.0.0.1'), // 数据库名 'database' => env('database.database', 'thinkphp'), // 用户名 'username' => env('database.username', 'root'), // 密码 'password' => env('database.password', ''), // 端口 'hostport' => env('database.hostport', '3306'), // 数据库连接参数 'params' => [], // 数据库编码默认采用utf8 'charset' => env('database.charset', 'utf8'), // 数据库表前缀 'prefix' => env('database.prefix', ''), // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) 'deploy' => 0, // 数据库读写是否分离 主从式有效 'rw_separate' => false, // 读写分离后 主服务器数量 'master_num' => 1, // 指定从服务器序号 'slave_no' => '', // 是否严格检查字段是否存在 'fields_strict' => true, // 是否需要断线重连 'break_reconnect' => false, // 监听SQL 'trigger_sql' => env('app_debug', true), // 开启字段缓存 'fields_cache' => false, ], ], ];
在这个配置文件中,我们设置了数据库类型、服务器地址、数据库名、用户名、密码等基本信息。ThinkPHP支持多种数据库类型,包括MySQL、PostgreSQL、SQLite等。
除了在配置文件中设置数据库连接信息外,我们还可以在模型中动态设置数据库连接:
<?php namespace appmodel; use thinkModel; class User extends Model { // 设置当前模型的数据库连接 protected $connection = 'mysql'; // 或者使用DSN配置 // protected $connection = 'mysql://root:123456@127.0.0.1:3306/thinkphp#utf8'; }
3. 数据库模型操作
在ThinkPHP中,模型是与数据库表对应的类,通过模型我们可以方便地进行数据库操作。创建一个模型非常简单,只需要继承thinkModel
类即可。
3.1 创建模型
假设我们有一个用户表user
,我们可以创建一个对应的模型:
<?php namespace appmodel; use thinkModel; class User extends Model { // 设置表名,如果不设置,默认为模型名的小写形式 protected $name = 'user'; // 设置主键,默认为id protected $pk = 'id'; // 自动写入时间戳 protected $autoWriteTimestamp = true; // 定义时间戳字段名 protected $createTime = 'create_time'; protected $updateTime = 'update_time'; }
3.2 模型基础操作
模型提供了丰富的方法来进行数据库操作,以下是一些常用的基础操作:
3.2.1 新增数据
// 使用模型新增数据 $user = new User; $user->name = '张三'; $user->email = 'zhangsan@example.com'; $user->age = 25; $user->save(); // 使用create方法静态创建 User::create([ 'name' => '李四', 'email' => 'lisi@example.com', 'age' => 30 ]);
3.2.2 更新数据
// 查找并更新 $user = User::find(1); $user->name = '王五'; $user->email = 'wangwu@example.com'; $user->save(); // 使用update方法静态更新 User::where('id', 1)->update([ 'name' => '赵六', 'email' => 'zhaoliu@example.com' ]);
3.2.3 删除数据
// 查找并删除 $user = User::find(1); $user->delete(); // 使用destroy方法静态删除 User::destroy(1); // 条件删除 User::where('age', '<', 18)->delete();
4. 数据查询方法
ThinkPHP提供了丰富的数据查询方法,可以满足各种查询需求。
4.1 基本查询
// 查询单条数据 $user = User::find(1); // 或者 $user = User::where('id', 1)->find(); // 查询多条数据 $users = User::select(); // 或者 $users = User::where('status', 1)->select(); // 查询某个字段的值 $email = User::where('id', 1)->value('email'); // 查询某一列的值 $names = User::where('status', 1)->column('name'); // 指定id作为索引 $names = User::where('status', 1)->column('name', 'id');
4.2 条件查询
// where条件 $users = User::where('status', 1)->select(); $users = User::where('status', 1)->where('age', '>', 18)->select(); // 使用表达式 $users = User::where('age', '>', 18)->select(); $users = User::where('name', 'like', '%张%')->select(); $users = User::where('age', 'in', [18, 20, 25])->select(); // 使用闭包 $users = User::where(function($query) { $query->where('status', 1) ->where('age', '>', 18); })->select(); // OR条件 $users = User::where('status', 1) ->whereOr('age', '>', 18) ->select();
4.3 排序和限制
// 排序 $users = User::order('id', 'desc')->select(); $users = User::order(['age' => 'asc', 'id' => 'desc'])->select(); // 限制结果数量 $users = User::limit(10)->select(); $users = User::limit(10, 20)->select(); // 从第20条开始,取10条 // 分页 $users = User::page(1, 10)->select(); // 第一页,每页10条
4.4 聚合查询
// 计数 $count = User::count(); $count = User::where('status', 1)->count(); // 最大值 $maxAge = User::max('age'); $maxAge = User::where('status', 1)->max('age'); // 最小值 $minAge = User::min('age'); // 平均值 $avgAge = User::avg('age'); // 求和 $sumAge = User::sum('age');
4.5 关联查询
在ThinkPHP中,我们可以定义模型之间的关联关系,方便地进行关联查询。
4.5.1 定义关联关系
假设我们有一个文章表article
和用户表user
,文章属于用户,用户有多篇文章。
// 文章模型 <?php namespace appmodel; use thinkModel; class Article extends Model { // 定义文章与用户的关联关系 public function user() { return $this->belongsTo(User::class); } } // 用户模型 <?php namespace appmodel; use thinkModel; class User extends Model { // 定义用户与文章的关联关系 public function articles() { return $this->hasMany(Article::class); } }
4.5.2 使用关联查询
// 查询文章及其作者信息 $article = Article::with('user')->find(1); echo $article->title; echo $article->user->name; // 查询用户及其所有文章 $user = User::with('articles')->find(1); echo $user->name; foreach ($user->articles as $article) { echo $article->title; } // 延迟获取关联数据 $article = Article::find(1); $user = $article->user; // 延迟获取用户信息
5. 数据处理和转换
在获取数据后,我们通常需要对数据进行处理和转换,以便在视图中显示。ThinkPHP提供了多种方式来处理和转换数据。
5.1 获取器
获取器可以自动处理模型中的数据,例如将时间戳转换为日期格式,将状态码转换为状态文本等。
<?php namespace appmodel; use thinkModel; class User extends Model { // 定义获取器,将status字段的值转换为文本 public function getStatusTextAttr($value, $data) { $status = [-1 => '删除', 0 => '禁用', 1 => '正常', 2 => '待审核']; return $status[$data['status']] ?? '未知'; } // 定义获取器,格式化时间 public function getCreateTimeAttr($value) { return date('Y-m-d H:i:s', $value); } }
使用获取器后,我们可以直接访问处理后的数据:
$user = User::find(1); echo $user->status_text; // 输出状态文本 echo $user->create_time; // 输出格式化后的时间
5.2 修改器
修改器可以在数据写入数据库前对数据进行处理,例如对密码进行加密,对时间进行转换等。
<?php namespace appmodel; use thinkModel; class User extends Model { // 定义修改器,对密码进行加密 public function setPasswordAttr($value) { return password_hash($value, PASSWORD_DEFAULT); } // 定义修改器,将日期转换为时间戳 public function setBirthdayAttr($value) { return strtotime($value); } }
使用修改器后,我们在保存数据时可以直接使用原始数据:
$user = new User; $user->password = '123456'; // 会自动加密 $user->birthday = '1990-01-01'; // 会自动转换为时间戳 $user->save();
5.3 数据集处理
ThinkPHP的数据集对象提供了丰富的方法来处理数据。
// 获取用户列表 $users = User::select(); // 将数据集转换为数组 $userArray = $users->toArray(); // 隐藏指定字段 $users->hidden(['password', 'update_time']); // 只显示指定字段 $users->visible(['id', 'name', 'email']); // 添加额外属性 $users->append(['status_text']); // 对数据集进行筛选 $adults = $users->filter(function($user) { return $user->age >= 18; }); // 对数据集进行排序 $sortedUsers = $users->order('age', 'desc'); // 对数据集进行分页 $pageUsers = $users->page(1, 10);
5.4 数据分页
在Web应用中,数据分页是非常常见的需求。ThinkPHP提供了简单易用的分页功能。
// 简单分页 $users = User::paginate(10); // 获取分页数据 $list = $users->items(); // 获取当前页的数据 $total = $users->total(); // 获取总记录数 $page = $users->currentPage(); // 获取当前页码 $lastPage = $users->lastPage(); // 获取总页数 // 在视图中渲染分页 <div class="pagination"> {$users|raw} </div>
我们还可以自定义分页样式:
// 自定义分页样式 $users = User::paginate([ 'list_rows' => 10, // 每页数量 'path' => '/user/index', // URL路径 'query' => [], // 额外参数 'fragment' => '', // 锚点 'var_page' => 'page', // 分页变量 'type' => 'bootstrap', // 分页样式类 ]);
6. 视图渲染和数据显示
在获取和处理数据后,我们需要将数据传递给视图并在页面上显示。ThinkPHP提供了灵活的视图渲染机制。
6.1 控制器与视图交互
在控制器中,我们可以使用assign
方法将数据传递给视图,然后使用fetch
方法渲染视图。
<?php namespace appcontroller; use appBaseController; use appmodelUser; class UserController extends BaseController { public function index() { // 获取用户列表 $users = User::paginate(10); // 将数据传递给视图 $this->assign('users', $users); $this->assign('title', '用户列表'); // 渲染视图 return $this->fetch(); } public function detail($id) { // 获取用户详情 $user = User::find($id); // 将数据传递给视图 $this->assign('user', $user); // 渲染视图 return $this->fetch(); } }
6.2 视图文件
视图文件通常位于view
目录下,与控制器对应。例如,UserController
的视图文件位于view/user/
目录下。
以下是一个用户列表视图的示例:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{$title}</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> </head> <body> <div class="container"> <h1 class="mt-4 mb-4">{$title}</h1> <table class="table table-bordered"> <thead> <tr> <th>ID</th> <th>姓名</th> <th>邮箱</th> <th>年龄</th> <th>状态</th> <th>创建时间</th> <th>操作</th> </tr> </thead> <tbody> {volist name="users" id="user"} <tr> <td>{$user.id}</td> <td>{$user.name}</td> <td>{$user.email}</td> <td>{$user.age}</td> <td>{$user.status_text}</td> <td>{$user.create_time}</td> <td> <a href="{:url('user/detail', ['id' => $user.id])}" class="btn btn-sm btn-info">查看</a> <a href="{:url('user/edit', ['id' => $user.id])}" class="btn btn-sm btn-warning">编辑</a> <a href="{:url('user/delete', ['id' => $user.id])}" class="btn btn-sm btn-danger" onclick="return confirm('确定要删除吗?')">删除</a> </td> </tr> {/volist} </tbody> </table> <div class="pagination"> {$users|raw} </div> </div> <script src="/static/js/jquery.min.js"></script> <script src="/static/js/bootstrap.min.js"></script> </body> </html>
6.3 视图标签
ThinkPHP提供了丰富的视图标签,方便在视图中处理数据。
6.3.1 变量输出
<!-- 输出变量 --> {$name} <!-- 使用函数 --> {$name|substr=0,10} <!-- 使用默认值 --> {$user.name|default='匿名'} <!-- 格式化输出 --> {$user.create_time|date='Y-m-d H:i:s'}
6.3.2 循环标签
<!-- volist循环 --> {volist name="users" id="user"} <p>{$user.name}</p> {/volist} <!-- foreach循环 --> {foreach $users as $user} <p>{$user.name}</p> {/foreach} <!-- for循环 --> {for start="1" end="10" step="1"} <p>{$i}</p> {/for}
6.3.3 条件标签
<!-- if条件 --> {if $user.age >= 18} <p>成年人</p> {else/} <p>未成年人</p> {/if} <!-- switch条件 --> {switch $user.status} {case 1} <p>正常</p> {/case} {case 0} <p>禁用</p> {/case} {default/} <p>未知</p> {/switch}
6.3.4 包含文件
<!-- 包含头部文件 --> {include file="public/header" /} <!-- 包含侧边栏文件,并传递参数 --> {include file="public/sidebar" title="用户管理" /} <!-- 包含底部文件 --> {include file="public/footer" /}
6.4 视图继承
ThinkPHP支持视图继承,可以创建一个基础模板,其他模板继承这个基础模板。
6.4.1 基础模板
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{block name="title"}网站标题{/block}</title> {block name="head"}{/block} </head> <body> <header> {block name="header"} <h1>网站头部</h1> {/block} </header> <div class="container"> {block name="content"}内容区域{/block} </div> <footer> {block name="footer"} <p>网站底部</p> {/block} </footer> {block name="script"}{/block} </body> </html>
6.4.2 继承模板
{extend name="layout" /} {block name="title"}用户列表{/block} {block name="head"} <link rel="stylesheet" href="/static/css/user.css"> {/block} {block name="content"} <h2>用户列表</h2> <table class="table"> <!-- 表格内容 --> </table> {/block} {block name="script"} <script src="/static/js/user.js"></script> {/block}
7. 实例演示
现在,让我们通过一个完整的实例来演示ThinkPHP数据库数据显示的整个过程。我们将创建一个简单的用户管理系统,包括用户列表、用户详情和用户搜索功能。
7.1 数据库准备
首先,我们需要创建一个用户表:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL COMMENT '姓名', `email` varchar(100) NOT NULL COMMENT '邮箱', `age` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '年龄', `gender` tinyint(1) NOT NULL DEFAULT '0' COMMENT '性别:0未知,1男,2女', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:-1删除,0禁用,1正常,2待审核', `create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间', `update_time` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
7.2 创建模型
创建用户模型app/model/User.php
:
<?php namespace appmodel; use thinkModel; class User extends Model { // 设置表名 protected $name = 'user'; // 自动写入时间戳 protected $autoWriteTimestamp = true; // 定义时间戳字段名 protected $createTime = 'create_time'; protected $updateTime = 'update_time'; // 定义获取器,将status字段的值转换为文本 public function getStatusTextAttr($value, $data) { $status = [-1 => '删除', 0 => '禁用', 1 => '正常', 2 => '待审核']; return $status[$data['status']] ?? '未知'; } // 定义获取器,将gender字段的值转换为文本 public function getGenderTextAttr($value, $data) { $gender = [0 => '未知', 1 => '男', 2 => '女']; return $gender[$data['gender']] ?? '未知'; } // 定义获取器,格式化时间 public function getCreateTimeAttr($value) { return date('Y-m-d H:i:s', $value); } // 定义获取器,格式化时间 public function getUpdateTimeAttr($value) { return date('Y-m-d H:i:s', $value); } // 搜索器,按姓名搜索 public function searchNameAttr($query, $value, $data) { if ($value) { $query->where('name', 'like', "%{$value}%"); } } // 搜索器,按邮箱搜索 public function searchEmailAttr($query, $value, $data) { if ($value) { $query->where('email', 'like', "%{$value}%"); } } // 搜索器,按状态搜索 public function searchStatusAttr($query, $value, $data) { if (is_numeric($value)) { $query->where('status', $value); } } }
7.3 创建控制器
创建用户控制器app/controller/User.php
:
<?php namespace appcontroller; use appBaseController; use appmodelUser; use thinkfacadeView; class UserController extends BaseController { // 用户列表 public function index() { // 获取搜索参数 $param = $this->request->param(); // 搜索用户 $users = User::withSearch(['name', 'email', 'status'], $param) ->order('id', 'desc') ->paginate([ 'list_rows' => 10, 'query' => $param ]); // 传递数据到视图 View::assign([ 'users' => $users, 'title' => '用户列表', 'param' => $param ]); // 渲染视图 return View::fetch(); } // 用户详情 public function detail($id) { // 获取用户详情 $user = User::find($id); if (!$user) { return $this->error('用户不存在'); } // 传递数据到视图 View::assign([ 'user' => $user, 'title' => '用户详情' ]); // 渲染视图 return View::fetch(); } }
7.4 创建视图
创建用户列表视图view/user/index.html
:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{$title}</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> </head> <body> <div class="container mt-4"> <h1 class="mb-4">{$title}</h1> <!-- 搜索表单 --> <div class="card mb-4"> <div class="card-body"> <form class="form-inline" method="get" action=""> <div class="form-group mr-2"> <input type="text" class="form-control" name="name" value="{$param.name|default=''}" placeholder="姓名"> </div> <div class="form-group mr-2"> <input type="text" class="form-control" name="email" value="{$param.email|default=''}" placeholder="邮箱"> </div> <div class="form-group mr-2"> <select class="form-control" name="status"> <option value="">所有状态</option> <option value="1" {if $param.status == '1'}selected{/if}>正常</option> <option value="0" {if $param.status == '0'}selected{/if}>禁用</option> <option value="2" {if $param.status == '2'}selected{/if}>待审核</option> </select> </div> <button type="submit" class="btn btn-primary">搜索</button> <a href="{:url('user/index')}" class="btn btn-default">重置</a> </form> </div> </div> <!-- 用户列表 --> <div class="card"> <div class="card-body"> <table class="table table-bordered table-striped"> <thead> <tr> <th>ID</th> <th>姓名</th> <th>邮箱</th> <th>年龄</th> <th>性别</th> <th>状态</th> <th>创建时间</th> <th>操作</th> </tr> </thead> <tbody> {volist name="users" id="user"} <tr> <td>{$user.id}</td> <td>{$user.name}</td> <td>{$user.email}</td> <td>{$user.age}</td> <td>{$user.gender_text}</td> <td> {if $user.status == 1} <span class="badge badge-success">{$user.status_text}</span> {elseif $user.status == 0} <span class="badge badge-danger">{$user.status_text}</span> {else/} <span class="badge badge-warning">{$user.status_text}</span> {/if} </td> <td>{$user.create_time}</td> <td> <a href="{:url('user/detail', ['id' => $user.id])}" class="btn btn-sm btn-info">查看</a> </td> </tr> {/volist} </tbody> </table> <!-- 分页 --> <div class="mt-3"> {$users|raw} </div> </div> </div> </div> <script src="/static/js/jquery.min.js"></script> <script src="/static/js/bootstrap.min.js"></script> </body> </html>
创建用户详情视图view/user/detail.html
:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{$title}</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> </head> <body> <div class="container mt-4"> <h1 class="mb-4">{$title}</h1> <!-- 用户详情 --> <div class="card"> <div class="card-body"> <div class="row"> <div class="col-md-6"> <table class="table table-bordered"> <tr> <th width="30%">ID</th> <td>{$user.id}</td> </tr> <tr> <th>姓名</th> <td>{$user.name}</td> </tr> <tr> <th>邮箱</th> <td>{$user.email}</td> </tr> <tr> <th>年龄</th> <td>{$user.age}</td> </tr> </table> </div> <div class="col-md-6"> <table class="table table-bordered"> <tr> <th width="30%">性别</th> <td>{$user.gender_text}</td> </tr> <tr> <th>状态</th> <td> {if $user.status == 1} <span class="badge badge-success">{$user.status_text}</span> {elseif $user.status == 0} <span class="badge badge-danger">{$user.status_text}</span> {else/} <span class="badge badge-warning">{$user.status_text}</span> {/if} </td> </tr> <tr> <th>创建时间</th> <td>{$user.create_time}</td> </tr> <tr> <th>更新时间</th> <td>{$user.update_time}</td> </tr> </table> </div> </div> <div class="mt-3"> <a href="{:url('user/index')}" class="btn btn-primary">返回列表</a> </div> </div> </div> </div> <script src="/static/js/jquery.min.js"></script> <script src="/static/js/bootstrap.min.js"></script> </body> </html>
7.5 配置路由
最后,我们需要在路由配置文件中添加用户相关的路由。打开config/route.php
文件,添加以下内容:
<?php use thinkfacadeRoute; // 用户路由 Route::get('user', 'UserController/index'); Route::get('user/detail/:id', 'UserController/detail');
7.6 运行测试
现在,我们可以运行测试我们的用户管理系统了。访问以下URL:
- 用户列表:http://yourdomain.com/user
- 用户详情:http://yourdomain.com/user/detail/1
在用户列表页面,我们可以进行搜索、分页等操作;在用户详情页面,我们可以查看用户的详细信息。
总结
通过本教程,我们学习了ThinkPHP数据库数据显示的完整流程,包括:
- 数据库连接配置
- 模型创建和使用
- 数据查询方法
- 数据处理和转换
- 视图渲染和数据显示
- 实例演示
ThinkPHP提供了强大而灵活的数据库操作和数据显示功能,使我们能够轻松地开发各种Web应用。通过掌握这些技巧,我们可以更加高效地开发出功能完善、用户友好的Web应用。
希望本教程能够帮助你更好地理解和使用ThinkPHP的数据库数据显示功能。如果你有任何问题或建议,欢迎留言讨论。