命令行
- php think list - 查看所有可用的命令列表
- php think help [command] - 查看指定命令的帮助信息
- php think build - 生成运行时文件
- php think clear - 清空应用的缓存、日志等文件
- php think optimize - 优化应用的性能
- php think make:controller [module/]controller - 创建控制器文件
- php think make:model [module/]model - 创建模型文件
- php think make:view [module/]controller/view - 创建视图文件
- php think make:middleware [module/]middleware - 创建中间件文件
- php think make:validate [module/]validate - 创建验证器文件
- php think make:command [module/]command - 创建命令行文件
- php think make:bind [module/]bind - 创建路由绑定文件
- php think make:provider [module/]provider - 创建服务提供者文件
- php think make:event [module/]event - 创建事件文件
- php think make:listener [module/]listener - 创建事件监听器文件
- php think make:config [module/]config - 创建配置文件
- php think make:middlewaregroup [module/]middlewaregroup - 创建中间件分组文件
- php think make:exception [module/]exception - 创建异常处理文件
- php think route:list - 查看路由列表
- php think route:check - 检查路由是否正确
- php think route:cache - 生成路由缓存文件
- php think route:clear - 清除路由缓存文件
- php think migrate:status - 查看迁移状态
- php think migrate:run - 执行数据库迁移
- php think migrate:rollback - 回滚数据库迁移
- php think migrate:create [migration_name] - 创建数据库迁移
- php think seed:run - 执行种子数据
- php think seed:create [seed_name] - 创建种子数据
- php think queue:work - 启动队列工作进程
- php think queue:listen - 启动队列监听进程
- php think queue:restart - 重启队列监听进程
- php think queue:stop - 停止队列监听进程
- php think queue:flush - 清空队列任务
以上命令是ThinkPHP框架中常用的一些命令,可以帮助开发者提高开发效率。
卸载插件
composer remove thans/tp-jwt-auth
开启注解路由
composer require topthink/think-annotation
开启多应用
composer require topthink/think-multi-app
隐藏入口文件
location / { // …..省略部分代码
if (!-f $request_filename) {
rewrite ^(.*)$ /index.php?s=/$1 last;
}
}
tp6常用扩展
安装字符串操作扩展类库
composer require topthink/think-helper
以下类库都在\think\helper命名空间下
use think\\helper\\Str;
// 检查字符串中是否包含某些字符串
Str::contains($haystack, $needles)
// 检查字符串是否以某些字符串结尾
Str::endsWith($haystack, $needles)
// 获取指定长度的随机字母数字组合的字符串
Str::random($length = 16)
// 字符串转小写
Str::lower($value)
// 字符串转大写
Str::upper($value)
// 获取字符串的长度
Str::length($value)
// 截取字符串
Str::substr($string, $start, $length = null)
//驼峰转下划线
Str::snake($value, $delimiter = '_')
//下划线转驼峰(首字母小写)
Str::camel($value)
//下划线转驼峰(首字母大写)
Str::studly
//转为首字母大写的标题格式
Str::title($value)
数组扩展库
use think\\helper\\Arr;
判断能否当做数组一样访问
//数组返回真
//模型查询的结果也为真
Arr::accessible($value)
向数组添加一个元素,支持"点"分割
Arr::add($array, $key, $value)
//如下操作
$arr = [];
$arr = Arr::add($arr,'name.3.ss','thinkphp'); //本行结果$arr['name'][3]['ss'] = 'thinkphp'
Arr::add($arr,'name','thinkphp2');//本行不会产生影响,因为'name'已存在.
将数据集管理类转换为数组
Arr::collapse($array)
排列数组组合
$arr = Arr::crossJoin(['dd'],['ff'=>'gg'],[2],[['a'=>'mm','kk'],'5']);
//上面行没有什么意义,但是可以看到该函数的作用,数组索引被忽略,数组得值被全部组合
$arr = Arr::crossJoin(['a','b','c'],['aa','bb','cc','dd']);
//这一行可以看到组合的效果,返回一个二维数组,第二维每个数组是的给定值排列,比如(a,aa),(a,bb),(a,cc)...直到(c,dd)
助手函数
系统为一些常用的操作方法封装了助手函数,便于使用,包含如下:
助手函数 | 描述 |
---|---|
abort | 中断执行并发送HTTP状态码 |
app | 快速获取容器中的实例 支持依赖注入 |
bind | 快速绑定对象实例 |
cache | 缓存管理 |
class | _basename 获取类名(不包含命名空间) |
class | _uses_recursive 获取一个类里所有用到的trait |
config | 获取和设置配置参数 |
cookie | Cookie管理 |
download | 获取\think\response\File对象实例 |
dump | 浏览器友好的变量输出 |
env | 获取环境变量 |
event | 触发事件 |
halt | 变量调试输出并中断执行 |
input | 获取输入数据 支持默认值和过滤 |
invoke | 调用反射执行callable 支持依赖注入 |
json | JSON数据输出 |
jsonp | JSONP数据输出 |
lang | 获取语言变量值 |
parse_name | 字符串命名风格转换 |
redirect | 重定向输出 |
request | 获取当前Request对象 |
response | 实例化Response对象 |
session | Session管理 |
token | 生成表单令牌输出 |
trace | 记录日志信息 |
trait_uses_recursive | 获取一个trait里所有引用到的trait |
url | Url生成 |
validate | 实例化验证器 |
view | 渲染模板输出 |
display | 渲染内容输出 |
xml | XML数据输出 |
app_path | 当前应用目录 |
base_path | 应用基础目录 |
config_path | 应用配置目录 |
public_path | web根目录 |
root_path | 应用根目录 |
runtime_path | 应用运行时目录 |
可以在应用的公共函数文件中重写上面这些助手函数。
搜索器的特殊用法
控制器层
public function deviceList()
{
$keywords = $this->request->param('keywords', '');
$status = $this->request->param('status', null);
$list = deviceModel::withSearch(['keywords', 'status'], [
'keywords' => $keywords,
'status' => $status,
])->where('is_delete', 0)->order('sort desc,id desc')->paginate($this->limit);
return json(success($list));
}
model 层定义
public function searchKeywordsAttr($query, $value){
if ($value != '') {
$map1 = [
['name', '=', $value],
];
$map2 = [
['code', '=', $value],
];
$query->whereOr([ $map1, $map2 ]);
}
}
sql 语句
SELECT * FROM `equ_list` WHERE ( `name` = '设备8' ) OR ( `code` = '设备8' ) AND `status` = 1 AND `is_delete` = 0 ORDER BY `sort` DESC,`id` DESC LIMIT 0,10
有问题的
可以使用下列方法实现
方法1:
适合用原生sql
$query->whereRaw("`name`= '" . $value . "' or `code`= '" . $value . "' ");
方法2:
$where[] = ['login_name|true_name', 'like', '%'.$keywords.'%'];
$query->where($where)
SELECT * FROM `equ_list` WHERE ( `name` LIKE '%设备8%' OR `code` LIKE '%设备8%' ) AND `status` = 0 AND `is_delete` = 0 ORDER BY `sort` DESC,`id` DESC LIMIT 0,10
前后端分离,反向代理
前端nginx 不写死 后端接口地址,可以使用nginx代理来实现
假设 前端访问有个manage
目录
location /manage {
proxy_pass http://localhost:80; # 你可以根据需要修改这个值
proxy_set_header Host t.xxx.com; # 设置目标主机名
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
tp6 启动workerman
- 安装 Workerman
composer require topthink/think-worker
启动
php think worker:server
停止可以使用:Press Ctrl+C to stop
启动守护进程
php think worker:server -d
停止守护进程
php think stop
如果在Linux下面,同样支持reload
|restart
|stop
|status
操作
php think worker:server reload
如果需要自定义参数,可以在config/worker_server.php中进行配置,包括:
配置参数 | 描述 |
---|---|
protocol | 协议 |
host | 监听地址 |
port | 监听端口 |
socket | 完整的socket地址 |
并且支持workerman所有的参数(包括全局静态参数)。
也支持使用闭包方式定义相关事件回调。
配置文件
两个配置文件
worker 配置文件
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | Workerman设置 仅对 php think worker:gateway 指令有效
// +----------------------------------------------------------------------
return [
// 扩展自身需要的配置
'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
'host' => '0.0.0.0', // 监听地址
'port' => 2348, // 监听端口
'socket' => '', // 完整监听地址
'context' => [], // socket 上下文选项
'register_deploy' => true, // 是否需要部署register
'businessWorker_deploy' => true, // 是否需要部署businessWorker
'gateway_deploy' => true, // 是否需要部署gateway
// Register配置
'registerAddress' => '127.0.0.1:1236',
// Gateway配置
'name' => 'thinkphp',
'count' => 1,
'lanIp' => '127.0.0.1',
'startPort' => 2000,
'daemonize' => false,
'pingInterval' => 30,
'pingNotResponseLimit' => 0,
'pingData' => '{"type":"ping"}',
// BusinsessWorker配置
'businessWorker' => [
'name' => 'BusinessWorker',
'count' => 1,
'eventHandler' => '\think\worker\Events',
],
];
worker_server配置文件
<?php
return [
/* 'name' => 'thinkphp',
'count' => 4,
'onMessage' => function($connection, $data) {
$connection->send(json_encode($data));
},
'worker_class' => 'app\manage\http\Worker', // 自定义Workerman服务类名 支持数组定义多个服务*/
'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
'host' => '0.0.0.0', // 监听地址
'port' => 2346, // 监听端口
'socket' => '', // 完整监听地址
'context' => [], // socket 上下文选项
'worker_class' => 'app\manage\http\Worker', // 自定义Workerman服务类名 支持数组定义多个服务
];
worker 类
<?php
namespace app\manage\http;
use app\Request;
use function Sodium\add;
use think\facade\Log;
use think\worker\Server;
use think\facade\Db;
use Workerman\Connection\TcpConnection;
use Workerman\Lib\Timer;
define('HEARTBEAT_TIME', 20);// 心跳间隔
class Worker extends Server
{
protected $socket = 'websocket://0.0.0.0:2346';
protected static $heartbeat_time = 55; //心跳55,秒
public function index()
{
$file = $this->getFile("D:/file");
var_dump($file);
}
public function onConnect(TcpConnection $tcpConnection)
{
$work = new \Workerman\Worker();
echo $tcpConnection->id . '\n';
echo $tcpConnection->getLocalIp() . '\n';
}
public function onMessage(TcpConnection $connection, $data)
{
try {
$res_arr = [];
echo $data;
Log::info('====同步原始数据===');
Log::info($data);
$dataJson = json_decode($data, true);
$arr_data = [];
if (is_array($dataJson)){
if ($dataJson['code'] == 200) {
$data = $dataJson['data'];
$txt = $data['txt'];
$upload = $data['upload'];
$type = $data['type'];
switch ($type) {
case 'sfz':
if (!empty($txt)) {
$txt_arr = explode(',', $txt);
if (is_array($txt_arr)) {
$arr_data['name'] = trim($txt_arr[0]);
$arr_data['sex'] = trim($txt_arr[1]);
$arr_data['nation'] = trim($txt_arr[2]);
$arr_data['birthday'] = trim($txt_arr[3]);
$arr_data['address'] = trim($txt_arr[4]);
$arr_data['cardid'] = trim($txt_arr[5]);
$arr_data['issuing'] = trim($txt_arr[6]);
$arr_data['validperiod'] = trim($txt_arr[7]);
} else {
$arr_data['name'] = '';
$arr_data['cardid'] = '';
}
}
break;
case 'xxx':
break;
default:
}
$arr_data['type'] = $type;
$arr_data['upload'] = $upload;
if (empty($arr_data['name'])) {
$res_arr['code'] = 201;
$res_arr['msg'] = 'error';
$res_arr['data'] = '姓名不能为空';
} else {
$res_arr['code'] = 200;
$res_arr['msg'] = 'success';
$res_arr['data'] = $arr_data;
}
}
$connection->send(json_encode($res_arr));
}else{
$res_arr['code'] = 201;
$res_arr['msg'] = '数据无法解析';
$res_arr['data'] = $data;
$connection->send(json_encode($res_arr));
}
//$connection->send($tmpData);
} catch (\Exception $exception) {
Log::error($exception->getMessage());
}
}
private function savaUser(array $arr)
{
if (is_array($arr)){
if (empty(trim($arr['cardid']))){
$res_arr['code'] = 201;
$res_arr['msg'] = 'error';
$res_arr['data'] = '身份证号码不能为空';
return json_encode($res_arr);
}
}
}
// 向所有验证的用户推送数据
function broadcast($message)
{
//遍历全局数组,然后发送数据
foreach ($this->worker->uidConnections as $connection) {
$connection->send($message);
}
}
// 针对uid推送数据
function sendMessageByUid($uid, $message)
{
echo '=====' . $uid . '====';
//指定key,然后取出对应的value,然后发送数据
if (isset($this->worker->uidConnections[$uid])) {
$connection = $this->worker->uidConnections[$uid];
$connection->send($message);
}
}
public function onClose(TcpConnection $tcpConnection)
{
echo '链接断开:\n';
}
public function onWorkerStart($worker)
{
echo '========';
//查看是否有新的充值或提现订单,有就推送给所有用户
Timer::add(10, function () use ($worker) {
/* $file = $this->getFile("D:/file");
foreach ($worker->connections as $connection) {
$send['name'] = '系统信息';
$send['content'] = '这是一个定时任务信息';
$send['time'] = time();
$connection->send(json_encode($file));
}*/
});
}
function onWorkerReload(Worker $worker)
{
foreach ($worker->connections as $connection) {
$connection->send('worker reloading');
}
}
/**
* 获取文件列表
* @param string $dir 绝对路径
*/
public function getDir($dir)
{
$dirArray[] = NULL;
if (false != ($handle = opendir($dir))) {
$i = 0;
while (false !== ($file = readdir($handle))) {
//去掉"“.”、“..”以及带“.xxx”后缀的文件
if ($file != "." && $file != ".." && !strpos($file, '.')) {
$dirArray[$i] = $file;
$i++;
}
}
//关闭句柄
closedir($handle);
}
return $this->writeJson($dirArray); //用JSON输出数组,不然直接rerun会报错
}
//获取文件列表
public function getFile($dir)
{
$fileArray[] = NULL;
if (false != ($handle = opendir($dir))) {
$i = 0;
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != ".." && strpos($file, '.')) {
$fileArray[$i]['url'] = $dir . '/' . $file;
$fileArray[$i]['name'] = $file;
if ($i == 100) {
break;
}
$i++;
}
}
closedir($handle);
}
return $this->writeJson($fileArray);
}
public function writeJson($file)
{
return json_encode($file);
}
}
获取绝对路径
\think\facade\app::getRootPath() 根目录C:\www\tp6\
\think\facade\app::getAppPath() 应用路径 C:\www\tp6\app\index\
\think\facade\app::getConfigPath() 配置路径C:\www\tp6\config\
\think\facade\app::version() 核心版本
变量全局过滤 (用户请求)
- 变量全局过滤
你可以在app\Request.php 中设置filter全局过滤属性:
class Request extends \think\Request
{
protected $filter = ["trim","htmlspecialchars","addslashes","strip_tags"];
}
- 效果演示
令牌Token统一生成与验证
- 生成令牌
你可以在app\common.php 中添加生成令牌的方法:
/**
* 生成令牌
*/
function shopToken()
{
$data = request()->buildToken('__token__', 'sha1');
return '<input type="hidden" name="__token__" value="' . $data . '" class="token">';
}
- 在模板表单中使用:
<div class="layui-form-item">
{:shopToken()}
</div>
- 控制器验证
namespace app\controller;
use think\exception\ValidateException;
use app\BaseController;
class Index extends BaseController
{
public function index(Request $request)
{
$check = $this->request->checkToken('__token__', $this->request->param());
if (false === $check) {
throw new ValidateException('invalid token');
}
// ...
}
}
JWT-实现token用户身份验证机制
- 引入php-jwt包
composer require firebase/php-jwt
- 生成token
//生成token
public function createJwt($userId = 'zq')
{
$key = md5('zq8876!@!'); //jwt的签发密钥,验证token的时候需要用到
$time = time(); //签发时间
$expire = $time + 14400; //过期时间
$token = array(
"user_id" => $userId,
"iss" => "http://www.najingquan.com/",//签发组织
"aud" => "zhangqi", //签发作者
"iat" => $time,
"nbf" => $time,
"exp" => $expire
);
$jwt = JWTUtil::encode($token, $key);
return $jwt;
}
- 验证token
//校验jwt权限API
public function verifyJwt($jwt = '')
{
$key = md5('zq8876!@!');
try {
$jwtAuth = json_encode(JWTUtil::decode($jwt, $key, array('HS256')));
$authInfo = json_decode($jwtAuth, true);
$msg = [];
if (!empty($authInfo['user_id'])) {
$msg = [
'status' => 1001,
'msg' => 'Token验证通过'
];
} else {
$msg = [
'status' => 1002,
'msg' => 'Token验证不通过,用户不存在'
];
}
return $msg;
} catch (\Firebase\JWT\ExpiredException $e) {
echo json_encode([
'status' => 1003,
'msg' => 'Token过期'
]);
exit;
} catch (\Exception $e) {
echo json_encode([
'status' => 1002,
'msg' => 'Token无效'
]);
exit;
}
}
- 测试
生成token
验证token
数据库常用查询与更新(搜集)
use think\facade\Db;
$rs =Db::name('user')->where('id',1)->find(); 查询一条记录 name不含前缀
$rs =Db::table('ims_user')->where('sex', 2)->select(); 多条数据 table含前缀
$rs1 =Db::name('user')->where('id', 1)->value('name'); 查询某个字段值
$rs =Db::table('ims_user')->where('sex', 2)->column('name,id','id'); 返回name,i
d列,后面是key
$userId = Db::name('user')->insertGetId($data);//插入数据返回id
Db::name('user')
->limit(100)
->insertAll($data); 插入多条数据,分每次100
Db::name('user')
->where('id', 1)
->update(['name' => 'thinkphp']); 更新
Db::table('think_user')->delete(1);
Db::table('think_user')->delete([1,2,3]);
Db::table('think_user')->where('id',1)->delete();
Db::name('user')->delete(true);//清空数据
where('id',' >= like
where("id=:id and username=:name", ['id' => 1 , 'name' => 'thinkphp'])
field('id,title,content') 指定字段
limit(10,25) 第十条开始25条 单数字返回数据条数
page(1,10) 第一页十条
order(['id'=>'desc','sex'=>'desc']) 排序
group('user_id,test_time') 分组
count() max('id') min() avg() sum() 聚合函数
whereTime('birthday', '>=', '1970-10-1') 支持< =
whereTime('create_time','-2 hours') 查询2小时
whereBetweenTime('create_time', '2017-01-01', '2017-06-30') 查询时间段
whereYear('create_time') 今年 whereYear('create_time','2018') last year 去年
whereMonth('create_time') last month上月 2018-06 具体月份
whereWeek('create_time') last week 上周
whereDay('create_time')今天 yesterday昨天 2018-11-1具体
Db::query("select * from think_user where status=1"); 原生查询
Db::execute("update think_user set name='thinkphp' where status=1");//更新插入删除
Db::query("select * from think_user where id=? AND status=?", [8, 1]);//绑定
$list = Db::name('user')->where('status',1)->paginate(10); 分页每页10条
tp6消息队列
安装
切换到WEB根目录下面并执行下面的命令:
composer require topthink/think-queue
不要使用阿里云的composer镜像安装,使用阿里云的会出现各种的下载错误。包括安装ThinkPHP建议都不要使用阿里云的镜像。被坑多了。
使用了阿里云的使用命令解除镜象再安装;
composer config -g --unset repos.packagist
配置
配置文件位于 config/queue.php
使用redis作为消息队列
return [
'default' => 'redis',
'connections' => [
'sync' => [
'type' => 'sync',
],
'database' => [
'type' => 'database',
'queue' => 'default',
'table' => 'jobs',
'connection' => null,
],
'redis' => [
'type' => 'redis',
'queue' => 'default',//默认队列名称
'host' => '127.0.0.1',//Redis主机IP地址
'port' => 6379,//Redis端口
'password' => '',//Redis密码
'select' => 1,//Redis数据库
'timeout' => 0,//Redis连接超时时间
'persistent' => false,//是否长连接
],
],
'failed' => [
'type' => 'none',
'table' => 'failed_jobs',
],
];
创建消费类
在app目录下创建目录job,创建类文件
<?php
namespace app\job;
use think\facade\Log;
use think\queue\Job;
class Test
{
public function fire(Job $job, $data)
{
// 处理业务逻辑返回为true表示消费成功,则删除队列
if($this->test($job->attempts())){
// 删除队列
$job->delete();
}else{
// 判断执行失败次数,到达设置值后删除消息队列
if ($job->attempts() >= 10) {
Log::channel('qxsp')->info('到达规定次数删除了');
// 删除队列
$job->delete();
}else{
Log::channel('qxsp')->info('继续执行');
// 重庆消息队列,重要:如果没有这样设置,默认的是1失败后1分钟执行一次,这样设置的话达到失败后隔多久执行下一次。官方的坑研究了好久。
$job->release(120);
}
}
}
// 处理业务逻辑
public function test($data)
{
Log::channel('qxsp')->info($data);
return false;
}
}
创建任务类
Queue::push($job, $data = '', $queue = null) 和Queue::later($delay, $job, $data = '', $queue = null)
两个方法,前者是立即执行,后者是在$delay秒后执行
$job 是任务名
命名空间是app\job的,比如上面的例子一,写Job1类名即可
其他的需要些完整的类名,比如上面的例子二,需要写完整的类名app\lib\job\Job2
如果一个任务类里有多个小任务的话,如上面的例子二,需要用@+方法名app\lib\job\Job2@task1、app\lib\job\Job2@task2
$data 是你要传到任务里的参数
$queue 队列名,指定这个任务是在哪个队列上执行,同下面监控队列的时候指定的队列名,可不填
以下为上面消费类例子
public function index()
{
Queue::push('Test', date("h:i:sa"), 'wu');
}
监听任务并执行
在根目录下执行
使用该语句:修改消费类代码可以实时更新无需重启
php think queue:listen
使用该语句:修改消费类代码不会实时更新,需要重启才能生效
php think queue:work
关联模型,hasOne的使用
如果要关联多个hasOne,不能这样使用,这样会导致部分hasOne失效
AdmUser::with('role')->with(,'office')->with('department')->where('is_delete', 0)->paginate();
正确的用法把它放到数组里
AdmUser::with(['role','office','department'])->where('is_delete', 0)->paginate();
模型使用方法
public function role(){
return $this->hasOne('AdmRole', 'id','role_id');
}
public function department(){
return $this->hasOne('Category', 'id','dept_id');
}
public function office(){
return $this->hasOne('Office', 'id','office_id');
}
这样出来的是二维数组
如何想变成1维数组,可以使用bind
public function role(){
return $this->hasOne('AdmRole', 'id','role_id');
}
public function department(){
return $this->hasOne('Category', 'id','dept_id')->bind(['dept_name'=>'name']);
}
public function office(){
return $this->hasOne('Office', 'id','office_id')->bind(['office_name'=>'name']);
}
注意:
[‘dept_name’=>‘name’]
[‘别名’=>‘字段名’]
效果如下
给自定义类加门面
-
现在app下建 facade文件夹
. -
绑定类路径
<?php
namespace app\facade;
use think\Facade;
class Person extends Facade
{
protected static function getFacadeClass()
{
return 'app\model\Person';
}
}
调用
$persion = \app\facade\Person::getNameById($v['person_uid'],'truename');
关于scope的全局用法
// 定义全局的查询范围
protected $globalScope = ['is_delete'];
public function scopeIs_delete($query)
{
$query->where('is_delete',0);
}
注意点: 如何该字段有下划线 例如:is_delete
不能 scopeIsDelete
而是要 scopeIs_delete
可能是tp6系统小bug
这样在查询的时候就不需要每次加上
AdmUser::where('status',0)->select();
SELECT * FROM `adm_user` WHERE `status` = 0 AND `is_delete` = 0 LIMIT 0,10
消息队列
消息操作请移步 thinkphp6 基于redis 的消息队列 queue
实现sql 语句的 xxx and (xxx or xxx)
QeueuOrder::whereRaw("`admin_uid` is null or `admin_uid` = ''")->where('office_id',3);
结果:
SELECT * FROM `queue_order` WHERE ( `admin_uid` is null or `admin_uid` = '' ) AND `office_id` = 3
nginx 反向代理无效,页面出现404
伪静态惹的祸,详细教程请看
nginx
忽略插入时数据库不存在的字段
strict(false)
$res = \app\model\SysTemplate::strict(false)->insert($param);
如何给浏览器header 返回头加信息
public function response(){
header('Xxx:000000000000000000000000000000000000000000000');
return 1;
}
结果:
如何给浏览器加cookie
public function response(){
response()->cookie('eee','eee');
return 1;
}
结果:
校验
public $rule = [
'id' => 'require|number',
'project_source_id' => 'require|number',
'name' => 'require|max:200',
'status' => 'require|in:0,1',
];
/**
* 定义错误信息
* 格式:'字段名.规则名' => '错误信息'
*
* @var array
*/
protected $message = [
"id.require" => "项目ID不能为空",
"id.number" => "项目ID为整数",
"project_source_id.require" => "来源名称不能为空",
"project_source_id.number" => "来源ID为数值型",
"name.require" => "项目名称不能为空",
"name.max" => "项目名称最多不能超过200个字符",
"status.require" => "状态不能为空",
"status.in" => "状态错误",
];
protected $scene = [
'add' => ['project_source_id', 'status','name', 'createTime'],
'update' => ['id','project_source_id', 'status', 'name'],
'get' => ['id'],
'delete' => ['id']
];
使用
//验证参数
if ($projectValidate->scene('add')->check($params) === false) {
return printMsg(self::wl_min_code + 16, $projectValidate->getError());
}