TP5第二天
十五、数据库操作
在TP5操作数据库常用有两种方式:
- 通过Db构造器
如:Db::table(‘think_user’)->where(‘status’,1)->select(); // #带数据表前缀
如:Db::name(‘user’)->where(‘status’,1)->select(); #不带表前缀
- 通过模型类
如:取出主键为1的数据
$user = User::get(1);
首先配置数据库的连接信息
创建数据库数据表,配置数据库信息
在application/database.php文件中添加下面的配置参数:
同时创建好数据库和数据表:
- 创建数据库article:
create database article;
2、创建数据表tp_user(用户表)、tp_category(分类表)、tp_article(文章表)
tp_user表结构:
create table tp_user(
user_id int not null auto_increment,
username varchar(30) not null default ” comment ‘用户名’,
password char(32) not null default ” comment ‘密码’,
primary key(user_id)
)engine = Innodb default charset = utf8;
tp_category表结构:
create table tp_category(
cat_id smallint not null auto_increment,
cat_name varchar(30) not null default ” comment ‘分类名称’,
pid smallint not null default 0 comment ‘父分类的id’,
create_time int not null default 0 comment ‘创建时间’,
update_time int not null default 0 comment ‘更新时间’,
primary key(cat_id)
)engine = Innodb default charset = utf8;
tp_article表结构:
create table tp_article(
article_id smallint not null auto_increment,
title varchar(30) not null default ” comment ‘文章标题’,
content text comment ‘文章内容’,
cat_id smallint not null default 0 comment ‘文章所属分类’,
ori_img varchar(150) not null default ” comment ‘原图的路径’,
thumb_img varchar(150) not null default ” comment ‘缩略图的路径’,
create_time int not null default 0 comment ‘创建时间’,
update_time int not null default 0 comment ‘更新时间’,
primary key(article_id)
)engine = Innodb default charset = utf8;
注:表名加前缀tp_,用于区分多个项目。
- 测试数据库是否连接成功,可以向表添加几条数据,进行查询
结果:
说明连接成功。
模型
模型认识
M:Model模型
作用:主要对数据库进行一些增删改查的操作。
模型的定义
一般而言,一个表对应一个模型,如果只是对表进行最基本的增删改查,不建模型也是可以操作表数据的,但是如果数据逻辑比较复杂,我们可以把这些数据逻辑定义在模型中,为了和业务逻辑分开,代码结构也比较清晰,也方便后期维护。
个人建议最好的做法就是以下两点:
①业务逻辑写在控制器中
②数据逻辑写在模型中
如有一个文章分类表,名为tp_category,此表对应的模型类名和模型文件定义如下:
模型类名: Category 注:驼峰法,除开表前缀的数据表名称。
模型类文件:Category.php 表名+.php
模型类文件所在位置:模块名/model/Category.php
给表tp_category建立模型文件如下:
其中模型中定义的属性pk为表的主键名称,若不指定则框架会自动识别。
有关表名的注意事项:
手册位置: 模型->定义
(3)实例化模型
方式一:在控制器中实例化模型首先引入其模型类所在的命名空间,如引入上面的Category
模型:
use app\admin\model\Category;
然后实例化模型:
// 静态调用
$data = Category::get(1); //获取主键值为1的数据
// 实例化模型
$cate= new Category();
$data = $cate->get(1);
其中打印$dataObj是一个当前数据的对象:
或者:
方式二:或者直接可以使用助手函数model:
$cate = model(‘Category’);
$data = $cate->get(1);
十六、模型CURD操作
C-create:新增数据
U-update:更新数据
R-read:查询数据
D-delete:删除数据
新增数据
手册位置:模型->新增
(1)添加一条数据
$model->save($data);
参数:$data为一维数组,其中[‘字段名’=>’数据’]
返回:成功返回写入的记录数
获取自增后的主键值
$model->save($data);
echo $model->主键字段名;
数据表数据如下:
(3)过滤非数据表字段
- 只允许数据表的字段写入
$model->allowField(true)->save($data) ;
- 只允许name和email字段写入
$model->allowField([‘name’,’email’])->save($data) ;
代码:
(4)添加多条数据
- $model->saveAll();
成功:返回数组对象集合。
注:其中每条数据都是作为当前模型类的对象。
数据表如下:
更新数据-U
手册位置:模型–>更新
更新方式一
- $model->save($data,更新条件)
- $model->isUpdate(true)->save($data)
可以通过isUpdate方法指定save为执行更新操作,其中$data中必须带更新的主键值
- 若需要过滤非数据表的字段数据,使用:
$model->->isUpdate(true)->allowField(true)->save($data)
(2)更新方式二
- $model->update($data)
参数$data为一维数组,键名为表字段名,其中更新必须指定更新条件,否则更新失败。
成功返回当前数据对象。
删除数据-D
(1)调用静态方法删除一条数据
模型类名::destroy(1); 如:User::destroy(1) 删除主键为1的记录
(2)调用静态方法批量删除多个数据
模型类名::destroy(‘1,2,3’); 删除主键为1,2,3的记录
或
模型类名::destroy([1,2,3]);
代码如下:
查询数据-R
(1)根据主键值获取记录一条记录
$dataObj = 模型类名::get(主键值)
$dataObj = 模型类名::find(主键值)
成功返回当前数据的对象。
(2)根据主键值获取多条记录
$dataObj= 模型类名::all(‘1,2,3’); //获取主键值为1,2,3的记录
或
$dataObj= 模型类名::all([1,2,3]); //获取主键值为1,2,3的记录
$dataObj= 模型类名::select(); //获取表中的所有数据
或
$dataObj= 模型类名::all();
all和select都是返回当前查询数组的数据对象集合。
连贯操作
手册位置:数据库–>查询构造器–>链式操作
注: 模型的链式操作方法和Db构造器链式操作的方法都通用;
TP5常用的模型连贯操作方法如下:
方法说明:
- field(“field1,field2…”):查询指定的字段field1和field2,多个用逗号隔开
- alias(‘数据表别名’):给当前数据表设置别名,join联表时用的多
- where(查询条件):查询条件可以为表达式查询、数组查询、字符串查询。
- order(“field desc”):把查询的到结果集进行字段field降序(desc)或升序(asc)。
- group(“field”): 把查询的到结果集进行字段field分组。
- limit(offset,length): 获取结果集指定条数的数据, offset为起始位置,length为获取记录的条数。
- join():与其他表进行关联查询
注意:
以上的连贯操作方法都是返回当前模型的对象,即方法底层都是返回当前模型对象即return $this,所以他们之间的调用顺序不用按照原生的sql顺序来调用,但如果是查询数据,查询语句的最末端一定要确保是select或者是find方法。
在原生的sql语句中一定要按照先后顺序调用:
原生sql语句执行的先后顺序: join==>where ==> group ==> having==>order==>limit
在tp5中以上的连贯操作都不需要按照顺序。
(1)where表达式查询条件
代码如下:
例1:
获取生成组装的sql语句: buildSql()
可见,多个where连续调用,默认是and连接符。 如果想使用or,可以使用方法whereOr()
(2)where数组查询条件
完整语法:
$where = [
‘字段名1’=> [表达式,‘值’]
‘字段名2’=> [表达式,‘值’]
]
如果是等值(=)查询,可以不用指定表达式,直接写值即可
$where = [
‘字段名’ => ‘值’
]
//默认多字段查询,是and链接。
例1:
(3)where字符串查询条件
where(字符串条件)
注:只能是类名::才可以调用方法,如果是对象调用,需要实例化对象,通过对象->去调用:
其中连贯操作方法
- field(“field1,field2…”):查询指定的字段field1和field2,多个用逗号隔开
- alias(‘数据表别名’):给当前数据表设置别名,join联表时用的多
- where(查询条件):查询条件可以为表达式查询、数组查询、字符串查询。
- order(“field desc”):把查询的到结果集进行字段field降序(desc)或升序(asc)。
- group(“field”): 把查询的到结果集进行字段field分组。
- limit(offset,length): 获取结果集指定条数的数据, offset为起始位置,length为获取记录的条数。
- join():与其他表进行关联查询
注意:
以上的连贯操作方法都是返回当前模型的对象,即方法底层都是返回当前模型对象即return $this,所以他们之间的调用顺序不用按照原生的sql顺序来调用,但如果是查询数据,查询语句的最末端一定要确保是select或者是find方法。
例1:
结果:
注:通过模型数据对象->toArray();可以转化为关联数组,看起来更加直观。
例2:
例3:
结果:
默认select方法返回数组对象集合,只有取出具体的数据对象才可以调用toArray()转化为关联数组,如何把select方法的返回结果直接变为关联数组?
解决办法:把applciation/database.php文件的以下配置返回结果设置为think\Collection
这样就可以使用select调用toAarray()返回关联数组:
例4、join联表
- 联表查询出分类的所属父分类:
使用模型的join方法来实现:
手册位置:数据库–>查询构造器–>链式操作–>join
语法:
结果:
- 联表查询出文章的所属分类:
在模型中使用join进行联表
- 给表tp_article建立表模型
b、联表
结果:
6、聚合(统计)函数
常用的有以下几个聚合(统计)函数
注意:调用统计函数前均支持连贯方法操作,但必须保证最末端是统计函数。
代码如下:
模型完成时间戳的自动维护
手册位置:模型–>时间戳
- 给表设置update_time、create_time字段。
- 在当前模型中开启时间戳的自动写入
开启时间戳自动写入之后,只要使用模型完成新增或编辑的操作,就会对表的两个时间字段字段自动维护。
十七、通过Db构造器操作数据库
通Db构造器查询数据库无需实例化模型也可对数据进行curd操作。
手册位置:数据库–>查询构造器
查询数据-R
- 查询一条数据
如:Db::table(‘think_user’)->field(‘username,email’)->where(id,1)->find();
- 查询多条数据
如:Db::table(‘think_user’)->where(id,1)->select();
如:Db::name(‘user’)->order(‘id’,’desc’)->select(); #不带表前缀
注: Db::table()需要完整表名,带表前缀,DB::name()是不带表前缀,且他们都支持连贯操作方法,只需保证最末端是select或是find或统计函数。
代码如下:
结果:
执行原生sql语句
查询:Db::query(“select”);
增删改:Db::execute(“insert/update/delete”);
添加数据-C
- 添加一条数据
$data = [‘foo’ => ‘bar’, ‘bar’ => ‘foo’];
Db::table(‘think_user’)->insert($data);
insert 方法添加数据成功返回添加成功的条数,insert 正常情况返回 1
- 或者直接使用insertGetId方法新增数据并返回主键值:
Db::name(‘user’)->insertGetId($data);
- 添加多条数据
添加多条数据直接向 Db 类的 insertAll 方法传入需要添加的数据即可
$data = [
[‘foo’ => ‘bar’, ‘bar’ => ‘foo’],
[‘foo’ => ‘bar1’, ‘bar’ => ‘foo1’],
[‘foo’ => ‘bar2’, ‘bar’ => ‘foo2’]
];
Db::name(‘user’)->insertAll($data);
insertAll 方法添加数据成功返回添加成功的条数
删除数据-D
- 根据主键删除
Db::table(‘think_user’)->delete(1);
Db::table(‘think_user’)->delete([1,2,3]);
- 条件删除
Db::table(‘think_user’)->where(‘id’,1)->delete();
Db::table(‘think_user’)->where(‘id’,'<‘,10)->delete();
delete 方法返回影响数据的条数,没有删除返回 0
4、更新数据-U
手册为主:数据库–>查询构造器–>更新数据
更新数据表中的数据
Db::table(‘think_user’)->where(‘id’, 1)->update([‘name’ => ‘thinkphp’]);
如果数据中包含主键,可以直接使用:
Db::table(‘think_user’)->update([‘name’ => ‘thinkphp’,’id’=>1]);
update 方法返回影响数据的条数,没修改任何数据返回 0
更新某个字段的值
Db::table(‘think_user’)->where(‘id’,1)->setField(‘name’, ‘thinkphp’);
setField 方法返回影响数据的条数,没修改任何数据字段返回 0
自增或自减一个字段的值
setInc/setDec 如不加第二个参数,默认值为1
// score 字段加 1
Db::table(‘think_user’)->where(‘id’, 1)->setInc(‘score’);
// score 字段加 5
Db::table(‘think_user’)->where(‘id’, 1)->setInc(‘score’, 5);
// score 字段减 1
Db::table(‘think_user’)->where(‘id’, 1)->setDec(‘score’);
// score 字段减 5
Db::table(‘think_user’)->where(‘id’, 1)->setDec(‘score’, 5);
助手db函数完成更新
// 更新数据表中的数据
db(‘user’)->where(‘id’,1)->update([‘name’ => ‘thinkphp’]);
// 更新某个字段的值
db(‘user’)->where(‘id’,1)->setField(‘name’,’thinkphp’);
// 自增 score 字段
db(‘user’)->where(‘id’, 1)->setInc(‘score’);
// 自减 score 字段
db(‘user’)->where(‘id’, 1)->setDec(‘score’);
完成后台登录功能
般用户表的第一个用户都是自己手工添加的。
- 在配置文件config.php中添加一个password_salt的配置
- 把加密的结果复制到用户表的password字段中
- 修改login.html登录表单
- 在login方法中判断是post请求,完成入库
- 在User模型中定义一个检出用户名和密码是否匹配的方法
登录成功后,把session中的用户名信息回显到后台首页中(top.html)
效果:
完成后台退出功能
核心:清除登录成功写入的session信息即可
- 在Public控制器中建立一个logout的方法,清除session
- 修改top.html模板的退出链接地址
二十、完成登录防翻墙
核心思想: 建立一个公共的控制器如:CommonController,在此控制器中做权限验证,判断是否有没有session,其他需要验证用户登录session信息的控制器就需要继承此控制器即可。
把需要验证session的后台index控制器继承Common控制器即可:
注:Public控制器不可以继承,因为此时还没有session信息。
二十一、完成登录验证
概述:ThinkPHP5.0验证使用独立的\think\Validate类或者验证器进行验证。
手册位置:验证器。
手册示例:
//定义验证规则语法:
$rule = [
‘表单name值’ => 规则(多个规则竖线|隔开)
]
//定义验证不通过的提示信息
$msg = [
‘表单name值.规则名’ => ‘此规则的不通过的提示信息’
]
代码如下:
提示效果: