缓存功能

一.缓存功能

系统内置了很多类型的缓存,除了 File,其它均需要结合相关产品;
我们这里主要演示 File 文本缓存,其它的需要学习相关产品;
在 app.php 中,配置文件 cache.php 进行缓存配置,可以用::init();

  1. // 驱动方式
  2. 'type'
  3. => 'File',
  4. // 缓存保存目录(默认 runtime/cache)
  5. 'path'
  6. =>
  7. '',
  8. // 缓存前缀
  9. 'prefix' =>
  10. '',
  11. // 缓存有效期 0 表示永久缓存
  12. 'expire' => 0,

::set()方法,可以设置一个缓存,然后再 runtime/cache 查看生成结果;
Cache::set(‘user’, ‘Mr.Lee’);
::inc()和::dec()实现缓存数据的自增和自减操作;
Cache::inc(‘num’);
Cache::inc(‘price’,
3);
Cache::dec(‘num’);
Cache::dec(‘price’,
3);
::has()方法,判断缓存是否存在,返回布尔值;
Cache::has(‘user’);
::get()方法,从缓存中获取到相应的数据,无数据返回 null;
Cache::get(‘user’);
::delete()方法,可以删除指定的缓存文件;
Cache::rm(‘user’);
::pull()方法,先获取缓存值,然后再删除掉这个缓存,无数据返回 null;
Cache::pull(‘user’);
::clear()方法,可以清除所有缓存;
Cache::clear();
::tag()标签,可以将多个缓存归类到标签中,方便统一管理,比如清除;
Cache::tag(‘tag’)->set(‘user’, ‘Mr.Lee’);
Cache::tag(‘tag’)->set(‘age’, 20);
Cache::set(‘user’, ‘Mr.Lee’);
Cache::set(‘age’,
Cache::tag(‘tag’,
[‘user’, ‘age’]);
Cache::clear(‘tag’);
助手函数的使用:cache();
//设置缓存
cache(‘user’, ‘Mr.Lee’, 3600);
//输出缓存
echo cache(‘user’);
//删除指定缓存
cache(‘user’, null);

验证码功能

一.验证码功能

验证码功能不是系统内置的功能了,需要通过 composer 引入进来;
composer require topthink/think-captcha=2.0.
引入进来之后,我们在模版中,验证一下验证码是否能正常显示;

{:captcha_img()}

captcha

创建一个模版页面,设置一个验证码和文本框提交比对;
method=”post”>
type=”text”
name=”code”>
type=”submit” value=”验证”>

创建 Code 控制器,用于接受表单的值,然后采用 validate 验证验证码;
class Code
extends Controller
{
public
function
index()
{
$data = [
‘code’
=>
Request::post(‘code’)
];
$flag = $this->validate($data, [
‘code|验证码’ => ‘require|captcha’
]);
dump($flag);
}
}
第二种方法,可以通过对象的方式来实现,使用 Captcha 类;
public function show()
{
$captcha = new Captcha();
return $captcha->entry();
}
5月24日学习 - 图2

public function check()
{
$captcha = new Captcha();
dump($captcha->check(Request::post(‘code’)));
}
如果一个页面生成了多个验证码,那需要通过 id 设置标识来确认;
return $captcha->entry(1);
$captcha->check(Request::post(‘code’), 1)
还有一个独立的验证码检测函数来验证是否匹配;
captcha_check(Request::post(‘code’), 1)
验证码的所有配置参数如下,根据需要进行调用:
可以通过创建对象的方式,来传入配置参数;
$config = [
//字体大小
‘fontSize’
=>
30,
//验证码位数
‘length’
=>
3,
//验证码杂点
‘useNoise’
=>
true,
];
$captcha = new
Captcha($config)
对象方式,也可以采用动态方式设置,具体如下:
$captcha = new Captcha();
$captcha->length
=
3;
$captcha->useNoise
=
true;
$captcha->fontSize
=
30;
如果没有采用创建对象的方式,那么可以采用在 config 创建 captcha.php;
return [
//字体大小
‘fontSize’
=>
30,
//验证码位数
‘length’
=>
*3
,
//验证码杂点
‘useNoise’
=>
false,
];
在下载的验证码语言包里:vendor/topthink/…下,有.ttf 字体;
//字体选择
‘fontttf’
=> ‘1.ttf’
也可以设置指定的背景图片,开启中文验证,指定验证码等等;
//背景图片
‘useImgBg’
=>
true
//中文验证
‘useZh’
=>
true

图像处理功能

一.图像处理功能

图像处理功能不是系统内置的功能了,需要通过 composer 引入进来;
composer
require topthink/think-image
引入进来之后,首先创建图像处理对象;
$image =
Image::open(‘image.png’);
获得了图像处理对象后,可以得到这张图片的各种属性;
//图片宽度
echo $image->width();
//图片高度
echo $image->height();
//图片类型
echo $image->type();
//图片 mime
echo $image->mime();
//图片大小
dump($image->size());
使用 crop()方法可以裁剪图片,并使用 save()方法保存到指定路径;
可以点击追踪方法内部,参看源码参数,了解更多的传值方法;
//裁剪图片
$image->crop(550,400)->save(‘crop1.png’);
使用 thumb()方法,可以生成缩略图,配合 save()把缩略图保存下来;
//生成缩略图
$image->thumb(500,500)->save(‘thumb1.png’);
这里要注意一个问题,虽然设置了宽和高,但高度变成了 282,说明是等比例的;
可以点击追逐方法内部,第三个参数默认为:$type = self::THUMB_SCALING;
而这个常量设置的定义如下:
/ 缩略图相关常量定义
/
const
THUMB_SCALING
=
1;
//常量,标识缩略图等比例缩放类型
const
THUMB_FILLED
=
2;
//常量,标识缩略图缩放后填充类型
const
THUMB_CENTER
=
3;
//常量,标识缩略图居中裁剪类型

使用 rotate()方法,可以旋转图片,默认是 90 度,参数可以设置;
$image->rotate(180)->save(‘rotate1.png’);
save()方法可以配置的参数除了保存文件名的路径,还有以下几个:
save(‘路径’,[‘类型’,’质量’,’是否隔行扫描’]),追踪到方法查看;
save($pathname, $type = null, $quality = 80, $interlace = true)
water()方法,可以给图片增加一个图片水印,默认位置为右下角,可看源码常量;
$image->water(‘mr.lee.png’)->save(‘water1.png’);
text()方法,可以给图片增加一个文字水印,具体如下:
$image->text(‘Mr.Lee’,getcwd().’/1.ttf’,20,’#ffffff’)->save(‘text1.png’);

数据库和模型事件

一.数据库事件

当你执行增删改查的时候,可以触发一些事件来执行额外的操作;
这些额外的操作事件,可以部署在构造方法里等待激活执行;
数据库事件方法为 Db::event(‘事件名’, ‘执行函数’),具体事件名如下:
数据库事件只支持:find、select、update、delete、insert 这几个方法;
在控制器端,事件一般可以写在构造方法里,方便统一管理;
public function initialize()
{
Db::event(‘before_select’, function ($query) {
echo ‘执行了批量查询操作!’;
});
Db::event(‘after_update’, function ($query) {
echo ‘执行了修改操作!’;
});
}

二.模型事件

和数据库事件类似,模型事件也是将事件存放在 init 静态方法里等待触发;
支持的事件类型更加的丰富,具体如下:
在模型端创建 init()方法,写入模型事件,可以使用 event 或快捷方式;
self::event(‘before_update’, function ($query) {
echo ‘准备开始更新数据…’;
});
self::event(‘after_update’, function ($query) {
echo ‘数据已经更新完毕…’;
});

关联模型初探

一.关联模型定义

关联模型,顾名思义,就是将表与表之间进行关联和对象化,更高效的操作数据;
我们已经有了一张 tpuser 表,主键为:id;我们需要一个附属表,来进行关联;
附属表:tp_profile,建立两个字段:user_id 和 hobby,外键是 user_id;
User 模型端,需要关联 Profile,具体方式如下:
class User
extends Model
{
public
function profile()
{
//hasOne 表示一对一关联,参数一表示附表,参数二外键,默认 user_id
return $this->hasOne(‘Profile’,’user_id’);
}
}
创建一个控制器用于测试输出:Grade.php;
$user = _UserModel
::get(21);
return
json($user->profile);
return
$user->profile->hobby
对于关联方式,系统提供了 8 种方案,具体如下:
一般来说,模型都在同一个命名空间下,直接指定模型的类名即可;
除非你设置的关联模型,不在同一个命名空间下,就需要指定完整的路径;
//如果不在同一个命名空间下,请用命名空间路径指定关联
return $this->hasOne(‘app\model\Profile’,’userid’);
上面的例子,我们采用了一对一的关联模型,它还有相对的反向关联;
class Profile extends Model
{
public function user()
{
return $this->belongsTo(‘User’);
}
}
$profile = _ProfileModel
::get(1);
return $profile->user->email;
正反向关联也就是关联关系和相对的关联关系,具体如下表:
image.png

一对一关联查询

一.hasOne 模式

hasOne 模式,适合主表关联附表,具体设置方式如下:
hasOne(‘关联模型’,[‘外键’,’主键’]);
return $this->hasOne(‘Profile’,’userid’, ‘id’);
关联模型(必须):关联的模型名或者类名
外键:默认的外键规则是当前模型名(不含命名空间,下同)+_id ,例如 user_id
主键:当前模型主键,默认会自动获取也可以指定传入
在上一节课,我们了解了表与表关联后,实现的查询方案;
$user = _UserModel
::get(21);
return $user->profile->hobby;
使用 save()方法,可以设置关联修改,通过主表修改附表字段的值;
$user = UserModel::get(19);
$user->profile->save([‘hobby’=>’酷爱小姐姐’]);
->profile 属性方式可以修改数据,->profile()方法方式可以新增数据;
$user->profile()->save([‘hobby’=>’不喜欢吃青椒’]);

二.belongsTo 模式

belongsTo 模式,适合附表关联主表,具体设置方式如下:
belongsTo(‘关联模型’,[‘外键’,’关联主键’]);
return $this->belongsTo(‘Profile’,’userid’, ‘id’);
关联模型(必须):模型名或者模型类名
外键:当前模型外键,默认的外键名规则是关联模型名+_id
关联主键:关联模型主键,一般会自动获取也可以指定传入
对于 belongsTo()的查询方案,上一节课已经了解过,如下:
$profile = _ProfileModel
::get(1);
return $profile->user->email
使用 hasOne()也能模拟 belongsTo()来进行查询;
//参数一表示的是 User 模型类的 profile 方法,而非 Profile 模型类
$user = UserModel::hasWhere(‘profile’, [‘id’=>2])->find();
return json($user);
//采用闭包,这里是两张表操作,会导致 id 识别模糊,需要指明表
$user = UserModel::hasWhere(‘profile’, function ($query) {
$query->where(‘profile.id’, 2);
})->select();
return json($user);

一对多关联查询

一.hasMany 模式

hasMany 模式,适合主表关联附表,实现一对多查询,具体设置方式如下:
hasMany(‘关联模型’,[‘外键’,’主键’]);
return $this->hasMany(‘Profile’,’userid’, ‘id’);
关联模型(必须):模型名或者模型类名
外键:关联模型外键,默认的外键名规则是当前模型名+_id
主键:当前模型主键,一般会自动获取也可以指定传入
在上一节课,我们了解了表与表关联后,实现的查询方案;
$user = _UserModel
::get(19);
return json($user->profile);
使用->profile()方法模式,可以进一步进行数据的筛选;
return json($user->profile()->where(‘id’, ‘>’, 10)->select());
使用 has()方法,查询关联附表的主表内容,比如大于等于 2 条的主表记录;
UserModel::has(‘profile’, ‘>=’, 2)->select();
使用 hasWhere()方法,查询关联附表筛选后记录,比如兴趣审核通过的主表记录;
UserModel::hasWhere(‘profile’, [‘status’=>1])->select();
使用 save()和 saveAll()进行关联新增和批量关联新增,方法如下:
$user = UserModel::get(19);
$user->profile()->save([‘hobby’=>’测试喜好’, ‘status’=>1]);
$user->profile()->saveAll([
[‘hobby’=>’测试喜好’,
‘status’=>1],
[‘hobby’=>’测试喜好’,
‘status’=>1]
]);
使用 together()方法,可以删除主表内容时,将附表关联的内容全部删除;
$user = UserModel::get(227, ‘profile’);
$user->together(‘profile’)->delete();

关联预载入

一.关联预载入

在普通的关联查询下,我们循环数据列表会执行 n+1 次 SQL 查询;
$list =
UserModel::all([19, 20, 21]);
foreach
($list as $user) {
dump($user->profile);
}
上面继续采用一对一的构建方式,打开 trace 调试工具,会得到四次查询;
如果采用关联预载入的方式,将会减少到两次,也就是起步一次,循环一次;
$list =
UserModel::with(‘profile’)->all([19, 20, 21]);
foreach
($list as $user) {
dump($user->profile);
}
关联预载入减少了查询次数提高了性能,但是不支持多次调用;
如果你有主表关联了多个附表,都想要进行预载入,可以传入多个模型方法即可;
为此,我们再创建一张表 tpbook,和 tp_profile 一样,关联 tp_user;
$list =
_UserModel
::with(‘profile,book’)->all([19, 20, 21]);
foreach
($list as $user) {
dump($user->profile.$user->book);
}
上面的方式,还有一种简要写法,如下:
UserModel::all([19, 20, 21], ‘profile,book’);
with()是 IN 方式的查询,如果想使用 JOIN 查询,可以使用 withJoin():
UserModel::withJoin(‘profile’)->all([19, 20, 21])
在使用 JOIN 查询方案下,限定字段,可以使用 withField()方法来进行;
$list = UserModel::withJoin([‘profile’=>function ($query)
{
$query->withField(‘hobby’);
}])->all([19, 20, 21]);
或者:
UserModel::withJoin([‘profile’=>[‘hobby’]])->all([19, 20,
21]
关联预载入还提供了一个延迟预载入,就是先执行 all()再 load()载入;
$list = UserModel::all([19, 20, 21]);
$list->load(‘profile’);
foreach ($list as $user) {
dump($user->profile);
}

关联统计和输出

一.关联统计

使用 withCount()方法,可以统计主表关联附表的个数,输出用 profilecount;
$list =
_UserModel
::withCount(‘profile’)->all([19,20,21]);
foreach
($list as $user) {
echo $user->profilecount;
}
关联统计的输出采用“关联方法名”
count,这种结构输出;
不单单支持 Count,还有如下统计方法,均可支持;
withMax()、withMin()、withSum()、withAvg()等;
除了 withCount()不需要指定字段,其它均需要指定统计字段;
$list =
UserModel::withSum(‘profile’, ‘status’)->all([19,20,21]);
foreach
($list as $user) {
echo $user->profilesum.’
‘;
}
对于输出的属性,可以自定义:
$list =
_UserModel
::withSum([‘profile’=>’p_s’], ‘status’)->all([19,20,21]);
foreach
($list as $user) {
echo $user->p_s.’
‘;
}

二.关联输出

使用 hidden()方法,隐藏主表字段或附属表的字段;
$list = UserModel::with(‘profile’)->select();
return
json($list->hidden([‘profile.status’]));
或:
return
json($list
->hidden([‘username’,’password’,’profile’=>[‘status’,’id’]]));
使用 visible()方法,只显示相关的字段;
$list->visible([‘profile.status’])
使用 append()方法,添加一个额外字段,比如另一个关联的对象属性;
$list->append([‘book.title’])

多对多关联查询

一.多对多关联

复习一下一对一,一个用户对应一个用户档案资料,是一对一关联;
复习一下一对多,一篇文章对应多个评论,是一对多关联;
多对多怎么理解,分解来看,一个用户对应多个角色,而一个角色对应多个用户;
那么这种对应关系,就是多对多关系,最经典的应用就是权限控制;
首先,我们来看多对多关系的三张表,具体如下:
tpuser:用户表;tp_role:角色表;tp_access:中间表;
access 表包含了 user 和 role 表的关联 id,多对多模式;
在 User.php 的模型中,设置多对多关联,方法如下:
public function roles()
{
return $this->belongsToMany(‘Role’, ‘Access’);
}
在 roles 方法中,belongsToMany 为多对多关联,具体参数如下:
belongsToMany(‘关联模型’,’中间表’,[‘外键’,’关联键’]);
$this->belongsToMany(‘Role’, ‘Access’, ‘role_id’, ‘user_id’);
role.php 和 access.php 创建一个空模型即可,无须创建任何;
注意:Role 继承 Model 即可,而中间表需要继承 Pivot;
在 user.php 中,创建 many()方法,用于测试,查询方式如下:
public function many()
{
//得到一个用户:蜡笔小新
$user = _UserModel
::get(21);
//获取这个用户的所有角色
$roles = $user->roles;
//输出这个角色所具有的权限【十天精品课堂系列】
主讲:李炎恢
return
json($roles);
}
当我们要给一个用户创建一个角色时,用到多对多关联新增;
而关联新增后,不但会给 tp_role 新增一条数据,也会给 tp_access 新增一条;
$user->roles()->save([‘type’=>’测试管理员’]);
$user->roles()->saveAll([[…],[…]]);
一般来说,上面的这种新增方式,用于初始化角色比较合适;
也就是说,各种权限的角色,并不需要再新增了,都是初始制定好的;
那么,我们真正需要就是通过用户表新增到中间表关联即可;
$user->roles()->save(1);
或:
$user->roles()->save(Role::get(1));
$user->roles()->saveAll([1,2,3]);
或:
$user->roles()->attach(1);
$user->roles()->attach(2, [‘details’=>’测试详情’]);
除了新增,还有直接删除中间表数据的方法:
$user->roles()->detach(2);