thinkphp-响应输出和重定向、验证器定义、验证规则和错误信息
响应操作
响应输出,有好几种:包括return、json()和view()等等;默认输出方式是以html 格式输出,如果你发起json 请求,则输出json
而背后是response 对象,可以用response()输出达到相同的效果
return response($data);
使用response()方法可以设置第二参数,状态码,或调用code()方法;
return response($data, 201);
return response($data)->code(202);
// 常用的304 缓存 404找不到页面
使用json()、view()方法和response()返回的数据类型不同,效果一样;
return json($data, 201);
return json($data)->code(202);
不但可以设置状态码,还可以设置header()头文件信息;
return json($data)->code(202)
->header(['Cache-control' => 'no-cache,must-revalidate']);
// 从浏览器的检查-网络-标头 中可以看到添加的响应头
重定向
使用redirect()方法可以实现页面重定向,需要return 执行;
return redirect('http://www.baidu.com');
站内重定向,直接输入路由地址或相对地址即可,第二参数状态码;
// 站内重定向 比如要跳转到这个链接http://localhost/xuexi/tp6/public/address/index
return redirect('/xuexi/tp6/public/address/index');
// 其中必须从/xuexi开始,否则重定向链接就是错误的
// 最简单方法 用url包含一下,无论是路由或者绝对路径 都可以
return redirect( url('address/index') );
注意!以后用地址都要用url方法。保证正确,自动识别
return redirect('ds/5'); // 跳转到路由
return redirect('/xuexi/tp6/address/details/id/5', 201);
附加session 信息,并跳转重定向;
首先需要开启session,在app/middleware.php,中
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
\think\middleware\SessionInit::class 解开这个注释即可
];
然后在controller/Address.php中的Index方法:
echo session('name');
实现跳转到address/index,并携带session
return redirect( url('address/index') )->with('name', 'mr 5');
重定向还提供了,记住上一次的url,和跳转到上一次url 的功能;
学习框架,建议多看看源码部分,这里的remember还是通过session实现的。
redirect( url('address/index') )->remember();
echo session('redirect_url');
可以发现,打印出的结果:/xuexi/tp6/public/rely/get/id/5
首先在控制器中,执行跳转到address/index
// ?flag判断session中是否有flag这个值
if(session('?flag')) {
return '死机警告';
} else {
return redirect( url('address/index') )->remember();
}
其次在address控制器中,引导页面呈现address/index,并显示返回按钮,当点击返回时候,通过back方法回到初始的记录页面
public function index()
{
// echo session('redirect_url');
// return 'index';
$url = url('address/back');
return '<a href="'.$url.'">返回<a>';
}
public function back()
{
// restore() 跳转到上一次的url
// redirect必须需要一个参数,实际上这里用不到默认给一个值
// return redirect(1)->restore();
// with('flag', 1)随便写的 目的是为了方式一直不断的来回重定向导致死机
return redirect(1)->with('flag', 1)->restore();
}
注意这里有个问题,6.1.4版本中,如果传入:redirect(’1‘),那么会报错address中没有1这个方法,如果为空,那么则没任何反应。经过验证,不要传入字符串'1',要传入数字1,正确方式:redirect(1)
验证器
验证器定义
验证器的使用,我们必须先定义它,系统提供了一条命令直接生成想要的类;
php think make:validate User
D:\phpstudy\phpstudy_pro\WWW\xuexi\tp6>php think make:validate User
Validate:app\validate\User created successfully.
创建成功后,会创建一个app/validate文件夹(文件夹与model和controller同级)
里面默认生成一个app/validate/User.php文件 以下为默认的内容:
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
/**
* 定义验证规则
* 格式:'字段名' => ['规则1','规则2'...]
*
* @var array
*/
protected $rule = [];
/**
* 定义错误信息
* 格式:'字段名.规则名' => '错误信息'
*
* @var array
*/
protected $message = [];
}
比如,我们定义一个如下的验证规则,针对user表
class User extends Validate
{
/**
* 定义验证规则
* 格式:'字段名' => ['规则1','规则2'...]
*
* @var array
*/
protected $rule = [
// 这里的名称不一定要与数据库一模一样 可以自己写自己的
'name' => 'require|max:20', //对应表中username字段,不得为空,不得大于20 位
'price' => 'number|between:1,100', //必须是数值,1-100 之间
'email' => 'email' //邮箱格式要正确
];
/**
* 定义错误信息
* 格式:'字段名.规则名' => '错误信息'
*
* @var array
*/
protected $message = [
'name.require' => '姓名不得为空',
'name.max' => '姓名不得大于20 位',
'price.number' => '价格必须是数字',
'price.between' => '价格必须1-100 之间',
'email' => '邮箱的格式错误'
];
}
如果不设置$message 定义的话,将提示默认的错误信息;
验证器定义好了之后,我们需要进行调用测试,创建一个app/controller/Verify.php 控制器;
namespace app\controller;
use think\exception\ValidateException;
class Verify
{
public function index()
{
try {
} catch(ValidateException $e) {
}
}
}
ValidateException $e 这个就是固定格式。
比如,下面就实现了一个基本的验证:
namespace app\controller;
use app\validate\User;
use think\exception\ValidateException;
class Verify
{
public function index()
{
try {
// 使用助手函数,直接放一个验证类进去
validate(User::class)->check([
'name' => '蜡笔小新',
'price' => 90,
'email' => 'xiaoxin@163.com'
]);
} catch(ValidateException $e) {
dump($e->getError());
}
}
}
如果这里规则中设置了姓名不能为空
validate(User::class)->check([
'name' => '',
'price' => 90,
'email' => 'xiaoxin@163.com'
]);
这样页面会直接输出你定义的错误报错信息:姓名不能为空。
默认情况下,出现一个错误就会停止后面字段的验证,我们也可以设置批量验证(将错误信息一起验证出来);
validate(User::class)->batch(true)...
validate(User::class)->batch(true)->check([
'name' => '',
'price' => 120,
'email' => 'xiaoxin163.com'
]);
注意,batch不能写在check后面,必须写在check前面!
设置好后,再执行,会返回一个错误提示的结果数组:
array:3 [
"name" => "姓名不得为空"
"price" => "价格必须1-100 之间"
"email" => "邮箱的格式错误"
]
系统提供了常用的规则让开发者直接使用,也可以自行定义独有的特殊规则;
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
/**
* 定义验证规则
* 格式:'字段名' => ['规则1','规则2'...]
*
* @var array
*/
protected $rule = [
// 这里的名称不一定要与数据库一模一样 可以自己写自己的
'name' => 'require|max:20|checkName:wubin.work', //对应表中username字段,不得为空,不得大于20 位
'price' => 'number|between:1,100', //必须是数值,1-100 之间
'email' => 'email' //邮箱格式要正确
];
/**
* 定义错误信息
* 格式:'字段名.规则名' => '错误信息'
*
* @var array
*/
protected $message = [
'name.require' => '姓名不得为空',
'name.max' => '姓名不得大于20 位',
'price.number' => '价格必须是数字',
'price.between' => '价格必须1-100 之间',
'email' => '邮箱的格式错误'
];
// 自定义规则 支持5个参数,$value, $rule最重要
protected function checkName($value, $rule)
{
dump($value);
dump($rule);
}
}
控制器中
validate(User::class)->batch(true)->check([
'name' => '蜡笔小新',
'price' => 100,
'email' => 'xiaoxin@163.com'
]);
最终,打印出来:
"蜡笔小新" // $value
"wubin.work" // $rule
比如,自定义wubin.work这个名字不允许注册
<?php
declare (strict_types = 1);
namespace app\validate;
use think\Validate;
class User extends Validate
{
/**
* 定义验证规则
* 格式:'字段名' => ['规则1','规则2'...]
*
* @var array
*/
protected $rule = [
// 这里的名称不一定要与数据库一模一样 可以自己写自己的
'name' => 'require|max:20|checkName:wubin.work', //对应表中username字段,不得为空,不得大于20 位
'price' => 'number|between:1,100', //必须是数值,1-100 之间
'email' => 'email' //邮箱格式要正确
];
/**
* 定义错误信息
* 格式:'字段名.规则名' => '错误信息'
*
* @var array
*/
protected $message = [
'name.require' => '姓名不得为空',
'name.max' => '姓名不得大于20 位',
'price.number' => '价格必须是数字',
'price.between' => '价格必须1-100 之间',
'email' => '邮箱的格式错误'
];
// 自定义规则 支持5个参数,$value, $rule最重要
protected function checkName($value, $rule)
{
// 通过了就返回true
return $value != $rule ? true : '非法名称,不得注册';
}
}
这时如果我提交的是非法称谓:
validate(User::class)->batch(true)->check([
'name' => 'wubin.work',
'price' => 100,
'email' => 'xiaoxin@163.com'
]);
那么就会输出:
array:1 [
"name" => "非法名称,不得注册"
]
对于自定义规则中,一共可以有五个参数,我们分别了解一下;
protected function checkName($value, $rule, $data, $field, $title)
{
dump($data); //所有数据信息 做一些深度比较
dump($field); //当前字段名 到底是哪个字段再用验证器
dump($title); //字段描述,没有就是字段名
}
按照本例,最终结果
^ array:3 [
"name" => "wubin.work"
"price" => 100
"email" => "xiaoxin@163.com"
] // $data
^ "name" // $field
^ "name" // $title
默认情况下,field与title都是一样的,但是,如果我们对验证的规则做如下修改 name|用户名
protected $rule = [
'name|用户名' => 'require|max:20|checkName:wubin.work', //对应表中username字段,不得为空,不得大于20 位
];
此时打印出结果,此时title即为用户名,而field还是name
那么这个主要的用处是什么呢?比如,我修改一下验证的内容
validate(User::class)->batch(true)->check([
'name' => ''
]);
此时,会输出提示
^ array:1 [▼
"name" => "用户名不能为空"
]
如果不设置name|用户名,那么这里的提示就是name不能为空。所以title参数主要服务于默认的提示的。
验证规则
在上面验证器定义的时候,我们采用的字符串模式,也支持数组模式
protected $rule = [
'name' => [
'require',
'max' => 10,
'checkName' => '李炎恢'
],
'price' => [
'number',
'between' => '1,100'
],
'email' => 'email'
];
数组模式在验证规则很多很乱的情况下,更容易管理,可读性更高;
如果你想使用独立验证,就是手动调用验证类,而不是调用User.php 验证类;这种调用方式,一般来说,就是独立、唯一,并不共享的调用方式;就是不用单独创建验证类文件,而是直接在控制器中进行数据的验证。
<?php
namespace app\controller;
// 使用门面模式引入验证类
use think\facade\Validate;
class Verify
{
public function rule()
{
// 这里不使用try-catch
// 实现独立验证规则
$validate = Validate::rule([
'name' => 'require|max:20',
'price' => 'number|between:1,100',
'email' => 'email'
]);
// 对数据进行验证
$result = $validate->check([
'name' => '',
'price' => 100,
'email' => 'xiaoxin@163.com'
]);
// 如果没有结果 那么输出错误信息
if(!$result) {
dump($validate->getError());
}
}
}
同样的这里如果有错误,默认只输出遇到的第一个错误,如果要显示全部的错误。
独立验证默认也是返回一条错误信息,如果要批量返回所有错误使用batch();
$result = $validate->batch(true)->check([
'name' => '',
'price' => 100,
'email' => 'xiaoxin163.com'
]);
独立验支持对象化的定义方式,但不支持在属性方式的定义;
$validate = Validate::rule([
'name' => ValidateRule::isRequire()->max(20),
'price' => ValidateRule::isNumber()->between([1, 100]),
'email' => ValidateRule::isEmail()
]);
// 对数据进行验证
$result = $validate->batch(true)->check([
'name' => '',
'price' => 145,
'email' => 'xiaoxin163.com'
]);
// 如果没有结果 那么输出错误信息
if(!$result) {
dump($validate->getError());
}
注意:这里的'price'=>ValidateRule::isNumber()->between('1, 100','价格在1-100之间') 也可以不用数组方式,使用字符串方式'1, 100'
独立验证的自定义错误提示,可以在方法的第二参数,参数一是规则,参数二是错误提示
$validate = Validate::rule([
'name' => ValidateRule::isRequire()->max(20),
'price' => ValidateRule::isNumber()->between([1, 100], '价格在1-100之间'),
'email' => ValidateRule::isEmail(null, '邮箱格式不正确')
]);
根据参考的源代码,isEmail等第一个参数默认都是Null,所以当无参可传的时候,可以传一个Null进行占位。
也可以独立使用message()方法,来设置相关错误信息;
$validate = Validate::rule([
'name' => ValidateRule::isRequire()->max(20),
'price' => ValidateRule::isNumber()->between([1, 100], '价格在1-100之间'),
'email' => ValidateRule::isEmail(null, '邮箱格式不正确')
]);
// 使用message方法 对错误信息单独定义
$validate->message([
'name.require' => '姓名不得为空',
'name.max' => '姓名不得大于20 位',
]);
错误信息也可以传入一个数组,给出错误代码以及错误信息
$validate->message([
'name.require' => ['code'=>1001, 'msg'=>'姓名不得为空'],
'name.max' => '姓名不得大于20 位',
]);
array:3 [
"name" => array:2 [
"code" => 1001
"msg" => "姓名不得为空"
]
"price" => "价格在1-100之间"
"email" => "邮箱格式不正确"
]
独立验支持闭包的自定义方式,但这种方式会不支持字段的多规则;(就是设置闭包后,上面的规则会被覆盖掉)
$validate = Validate::rule([
'name' => ValidateRule::isRequire()->max(20),
'price' => ValidateRule::isNumber()->between([1, 100], '价格在1-100之间'),
'email' => ValidateRule::isEmail(null, '邮箱格式不正确')
]);
$validate = Validate::rule([
'name' => function() {}
]);
结果只是如下,可见其他price email字段的验证规则也都被覆盖了
array:1 [
"name" => null
]
如果这样写,下面的闭包函数定义的规则,会把上面的规则全部(所有字段的验证规则)都覆盖掉!如果不想覆盖之前定义的方法,那么就要使用->rule
$validate = Validate::rule([
'name' => ValidateRule::isRequire()->max(20),
'price' => ValidateRule::isNumber()->between([1, 100], '价格在1-100之间'),
'email' => ValidateRule::isEmail(null, '邮箱格式不正确')
]);
$validate = $validate->rule([
'name' => function() {}
]);
最终结果
array:3 [
"name" => null
"price" => "价格在1-100之间"
"email" => "邮箱格式不正确"
]
这里可以发现,其name字段规则被覆盖掉了!,所以它是不支持多字段的。
$validate = Validate::rule([
'name' => ValidateRule::isRequire()->max(20),
'price' => ValidateRule::isNumber()->between([1, 100], '价格在1-100之间'),
'email' => ValidateRule::isEmail(null, '邮箱格式不正确')
]);
$validate = $validate->rule([
'name' => function ($value) {
return $value != '' ? true : '姓名不得为空';
},
'price'=> function ($value) {
return $value > 0 ? true : '价格不得小于零';
}
]);