查漏補缺
- 1、数据库(sql)
- 1.1 join语法后面可以追加where条件
- 1,2 将json字符串转化json数据
- 查询时间区间
- 1.3 多个子查询合并(array_merge)
- 1.4 查询语句防止sql注入 + 条件复杂组合查询 (whereRaw)
- 1.5 In/NotIn 的快捷语法 (whereIn,whereNotIn)
- 1,.6 獲取數據庫的綫程id(連接ID)的方法
- 1.7 tp插入操作的好用函数大全以及一些技巧 【合集】
- 1.8 Union的用法(以及和paginate搭配使用的一些坑)
- 1.9 在TP數據庫方法裏面使用數據庫字段作爲條件,而不是作爲普通字符串處理的方法【Db::raw】
- 1.10TP里面实现sql加括号的语法(使用闭包查询)
- 1.11在原生sql中拼上php的数组和日期的注意事项( 关键是使用php变量的时候要加上 "{}" 和一些字符串变量要手动拼接' ')
- 1.12 数据库操作中使用到MYSQL关键字(ignore,SQL_BUFFER_RESULT)
- 1.13 TP中使用is not null/is null的写法(三种)
- 1.14TP里面执行原生sql(Db::query)
- 1.15 使用模型执行子查询的方法(涉及模型可绕过表的关联关系执行sql)
- 2、thinkphp语法
- 2.1、快速獲取public的路徑值(常用)
- 2.2、array_column 【快速提取】 `js中類似函數:map`
- 2.3、array_slice:从数组中提取一段连续的元素的函数
- 2.4、array_diff函數
- 2.5、TP的閉包函數寫法(常用)
- 2.6、TP的initialize() 方法 以及__construct的理解 (重要)
- 2.7、獲取器寫法
- 在thinkphp的field方法裏面定義自定義字段(concat)
- 2.8、從數據庫直接查詢出來的為字段的值,而不是數組(value)
- 2.9、DB操作和模型操作的区别
- 2.11、解析配置文件(.ini) 【parse_ini_file】
- 2.12、读取配置文件
- 2.13、动态执行执行函数call_user_func_array
- 2.14、从数据库里面查出来的数据是否是为空的标准判断【findOrEmpty、isEmpty】
- 2.15、thinkphp在h5和js裏面使用模板語法(获取配置信息的方法)
- 2.16、复杂子查询【场景一个必要的查询条件,和两个非必要的模糊查询条件】
- 2.17、thinphp没有接管的文件里面引入vendor下载好的插件
- 2.18、thinkphp连接多个数据库
- 2.19、Db类或模型使用自定义条件进行查询(常用)
- 2.20、Db类或模型中中使用获取器
- 2.21、在h5標簽上使用tp的模板語法
- 2.22、 thinphp链式语法的原理
- 2.23、thinkphp使用流文件保存图片
- 2.24、注意实例化(new) 出来的对象的继承父类的变量和父类就没什么关系了
- 2.25、分库的时候用TP的连表语法进行连表操作
- 2.26php获取配置文件内容的操作大全
- 2.27、将stdclass转化为数组的方法
- 2.28、tp查询数据库获取对象之后,继续添加属性【each】
- 2.29、讓一個函數内部能夠執行另一個自定義的函數(常用,不用寫一堆判斷)call_user_func_array
- 2.30、跨库的表要单独开启事务(单独使用模型的stran)
- 2.31、将一个类的方法可以在调用的时候全部变成静态方法来调用(使用Facade类)
- 2.32、通過命名空間字符串來動態創建想要的實例一個實例(重要)
- 2.33 Tp的trait(模拟多继承)
- 3. php请求接口时查漏补缺
- 3、文件路徑
- 4、tp中間件
- 5、Session
- 6、thinkphp的路由
- 7、事件订阅
- 8、TP自定異常類
- 9、其他
1、数据库(sql)
1.1 join语法后面可以追加where条件
->join(' dt_order_meals c', ['b.userid=c.userid',"c.company='{$request->get('company')}'" ,"c.date='{$date}'"])
1,2 将json字符串转化json数据
->json(['pick_up'])
查询时间区间
->whereBetween('c.date', [$startDate, $endDate])
1.3 多个子查询合并(array_merge)
foreach($companyList as $item){ //多公司查询
$query = Db::table('dt_user')->alias('b')
->field('c.id,c.breakfast_scan,c.lunch_scan,c.dinner_scan,c.breakfast,c.lunch,
c.dinner,c.date,c.pick_up, c.uptime,b.name,b.company,b.userid')
->join('dt_order_meals c', ['b.userid=c.userid',"b.company='{$item}'"])
->leftjoin('dt_set_meal bf','c.breakfast = bf.id')
->leftjoin('dt_set_meal lun','c.lunch = lun.id')
->leftjoin('dt_set_meal din','c.dinner = din.id')
->json(['pick_up'])
->where($orderMealsModel->combineQueryCondition($search))
->where(function ($query) use ($dateInput) {
$startDate = $dateInput ? date('Y-m-d', strtotime($dateInput . ' -14 days')) : date('Y-m-d', strtotime('-14 days'));
$endDate = $dateInput ? date('Y-m-d', strtotime($dateInput . ' +14 days')) : date('Y-m-d', strtotime('+14 days'));
if(input('date') == ''){
$query->whereBetween('c.date', [$startDate, $endDate]);
}else{
$query->whereBetween('c.date', [input('date')[0],input('date')[1]]);
}
})
->where('c.company',$item)
->order(['c.date' => 'DESC','c.uptime'=> "DESC"])
->select();
if ($combinedQuery === null) {
$combinedQuery = $query;
} else {
$combinedQuery = array_merge($combinedQuery,$query);
}
}
$page = $request->get('page', 1);
$limit = $request->get('limit', 30);
$start = ($page - 1) * $limit;
$list = array_slice($combinedQuery, $start, $limit);
}
1.4 查询语句防止sql注入 + 条件复杂组合查询 (whereRaw)
//条件复杂组合查询
$time = time();
$whereOrRaw = "(send_time < {$time} AND user_type = 20 AND `json` LIKE '%{$no}%') or (send_time < {$time} AND user_type = 10)";
$list = Db::name('notice')->whereOrRaw($whereOrRaw)->paginate(10)->toArray();
//更加安全的变量注入查询
Db::table('think_user')
->whereRaw("id=:id and username=:name", ['id' => [1, \PDO::PARAM_INT] , 'name' => 'thinkphp'])
->select();
1.5 In/NotIn 的快捷语法 (whereIn,whereNotIn)
b::name('user')->whereIn('id','1,5,8')->select();
Db::name('user')->whereNotIn('id','1,5,8')->select();
1,.6 獲取數據庫的綫程id(連接ID)的方法
//获取线程id
Db::connect()->getConnection()->query('SELECT CONNECTION_ID() as thread_id')[0]['thread_id'];
1.7 tp插入操作的好用函数大全以及一些技巧 【合集】
// 过滤post数组中的非数据表字段数据【allowField】
$user->allowField(true)->save($_POST);
//插入成功后會返回你插入的那個對象,通常情況下會使用(->id)來獲取最新插入的主鍵
$pCharge = PlatformChargeModel::create($platformP);
$pid = $pCharge->id;
1.8 Union的用法(以及和paginate搭配使用的一些坑)
//(注意)thinkphp的union裏面接的是一個sql語句不是一個對象
->union
->unionAll('SELECT name FROM think_user_1')
1.9 在TP數據庫方法裏面使用數據庫字段作爲條件,而不是作爲普通字符串處理的方法【Db::raw】
//使用Db::raw來標識使用的是字段作爲條件
->where('e.crtime', 'between', [Db::raw('b.start_time'), Db::raw('b.end_time')])
1.10TP里面实现sql加括号的语法(使用闭包查询)
if(empty($where)) $whereOr = [['type' => 1],['type' => 2]];
$this->model
->where(function($query) use ($whereOr){
foreach($whereOr as $v) $query->whereOr($v);
})
//实际上出来的sql语句是:where (type = 1 or type = 2) =》 闭包查询的那一块就可以看作是一个括号
1.11在原生sql中拼上php的数组和日期的注意事项( 关键是使用php变量的时候要加上 “{}” 和一些字符串变量要手动拼接’ ')
//1、拼接上php数组
//把数组变成字符串
$activityIdList = array_unique(ActivityIgbPoint::where($whereParams)->column('activity_id'));
$activityIdStringList = array_map(function($id) {
return "'{$id}'";
}, $activityIdList);
$activityIdListString = implode(',', $activityIdStringList);
//然后原生sql就可以这样写:要加上"( )"符号
and b.activity_id in ({$activityIdListString})
//2、拼接上日期(注意要加上给时间加上'')
and c.crtime <= '{$effective_end_time}'
1.12 数据库操作中使用到MYSQL关键字(ignore,SQL_BUFFER_RESULT)
//其中ignore很常用(如果数据库中存在某个唯一约束导致报错,使用ignore则不会抛错,影响的行数为0)
Db::name('user')
->extra('IGNORE')
->insert(['name' => 'think']);
Db::name('user')
->extra('SQL_BUFFER_RESULT')
->select();
1.13 TP中使用is not null/is null的写法(三种)
//1、字符串写法
$data->where("pic is not null")->select();
//2、数组写法(exp写法,注意要搭配上Db::raw来一起使用)
$where[] = ['pic','is null/not null','']; //常用
//函数写法
->whereNotNull('name') / ->whereNull('name')
1.14TP里面执行原生sql(Db::query)
//sql里面有变量推荐使用Db::query的第二个参数把变量填进去(变量用"?"代替)
$sql = "SELECT * FROM `information_schema`.`columns` "
. "WHERE TABLE_SCHEMA = ? AND table_name = ? "
. "ORDER BY ORDINAL_POSITION";
$columnList = Db::query($sql, [$dbname, $table]);
1.15 使用模型执行子查询的方法(涉及模型可绕过表的关联关系执行sql)
//例如这个子查询语句
SELECT ROUND(SUM(b.paid_amt / b.exchange_rate), 2) AS total_amt, b.userid FROM
( SELECT `pd`.`userid`,`pd`.`paid_amt`,`pd`.`exchange_rate` FROM `wallet_order` `wo` LEFT JOIN `payment_details` `pd` ON `pd`.`order_id`=`wo`.`ig_orderid` WHERE `wo`.`status` IN (1,3) AND `pd`.`userid` = 100656 AND `payment_time` BETWEEN '2024-07-11 00:00:00' AND '2024-08-15 00:00:00' GROUP BY `wo`.`ig_orderid` ) b
GROUP BY `b`.`userid`
/**
涉及到一个使用模型的技巧
$paymentQuery是一个子查询语句
直接使用 table 方法来指定表名,实际上绕过了模型与表的映射关系
**/
WalletOrderModel::table($paymentQuery . ' b')
//所以上面的那句子查询语句可以这样写
//子查询语句
$paymentQuery = WalletOrderModel::alias('wo')
->leftjoin('payment_details pd', 'pd.order_id = wo.ig_orderid')
->where([['wo.status', 'in', [1, 3]]])
->where(['pd.userid' => $row['userid']])
->whereBetween('payment_time', [$activityData['start_time'], $activityData['end_time']])
->field('pd.userid, pd.paid_amt, pd.exchange_rate')
->group('wo.ig_orderid')
->buildSql();
//可以这样执行子查询语句 [模型::table(子查询语句 表别名)]
$paymentData = WalletOrderModel::table($paymentQuery . ' b')
->field('ROUND(SUM(b.paid_amt / b.exchange_rate), 2) AS total_amt, b.userid')
->group('b.userid')
->select()->toArray();
2、thinkphp语法
2.1、快速獲取public的路徑值(常用)
//使用app()->getRootPath()能快速獲取
$publicPath = app()->getRootPath() ."public"
2.2、array_column 【快速提取】
js中類似函數:map
array_column(操作的数组,提取出来的字段,新数组的key值)
$originalArray = [
['name' => 'John', 'age' => 30],
['name' => 'Alice', 'age' => 25],
['name' => 'Bob', 'age' => 35],
];
$names = array_column($originalArray, 'name');
=》 $names = ['John', 'Alice', 'Bob'];
//第二个参数不写则用回原数组的索引
$names = array_column($originalArray,null)
=》 $names = [0 => 'John', 1 => 'Alice', 2 => 'Bob'];
//写了第三个参数的话,第二个参数就为新数组的value,第三个参数为新数组的key
$controllerList = array_column($v,'controller','action');
$v = [
['controller' => 'Controller1', 'action' => 'Action1'],
['controller' => 'Controller2', 'action' => 'Action2'],
['controller' => 'Controller3', 'action' => 'Action3'],
];
$controllerList = [
'Action1' => 'Controller1',
'Action2' => 'Controller2',
];
//如果第二个参数不写,第三个参数写的话,那个这个参数就会作为新数组的key,原数组作为value
[
'John' => ['name' => 'John', 'age' => 30],
'Alice' => ['name' => 'Alice', 'age' => 25],
'Bob' => ['name' => 'Bob', 'age' => 35],
]
js中函數map也能類似做到這一點
const arrayOfObjects = [
{ name: 'John', age: 30 },
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 35 }
];
// 使用map函数提取'name'属性的值
const names = arrayOfObjects.map(obj => obj.name);
//上面這種寫法相當於省略了{} 和 return 關鍵詞的寫法: obj是參數,=>obj.name相當於return obj.name
console.log(names); // 输出: ["John", "Alice", "Bob"]
2.3、array_slice:从数组中提取一段连续的元素的函数
array_slice(數組,開始提取的位置,要提取的元素數量,是否保留原索引)
$array = [1, 2, 3, 4, 5];
$result = array_slice($array, 2);
// 不保留鍵名,提取从索引2开始到数组末尾的元素: [3, 4, 5]
$array = ['a' => 1, 'b' => 2, 'c' => 3];
$result = array_slice($array, 1, 2, true);
// 保留键名,提取从键'b'开始的2个元素: ['b' => 2, 'c' => 3]
2.4、array_diff函數
$array1 = [1, 2, 3, 4, 5];
$array2 = [3, 4, 5, 6, 7];
$diff = array_diff($array1, $array2);
//返回在 $array1 中存在但 $array2 中不存在的元素
print_r($diff); //Array( [0] => 1,[1] => 2)
2.5、TP的閉包函數寫法(常用)
//例子: (非常要注意的一點就是閉包函數如果想要使用外面的變量的話,必須要在use裏面寫上需要的變量)
//tip:如果想要利用閉包函數裏面處理外部數組的屬性的時候,記得加上引用"&"符號
array_walk($extraFields,function ($value,$key) use(&$item){
$item[$key] = $value;
});
2.6、TP的initialize() 方法 以及__construct的理解 (重要)
//注意:如果跑靜態類的靜態函數的話是不會經過__construct和initialize()的,即:
Aescbc::encrypt(time());
//注意:無論是實例化一個對象還是只是用接口的形式調用這個類裏面的方法都會跑initialize以及__construct
//但是我們這裏更推薦使用initialize,且在當前類中使用的話會覆蓋掉父類的initialize。所以要保留父類的initialize要這樣,另外一個靜態變量的賦值也是在這裏完成
private static $fuluApi = '';
private static $fuluSecretId = '';
private static $fuluSecretKey = '';
public function initialize(){
parent::initialize();
self::$fuluApi = config('fulu_api.url');
self::$fuluSecretId = config('fulu_api.secret_id');
self::$fuluSecretKey = config('fulu_api.secret_key');
}
2.7、獲取器寫法
例如給字段status
生成一個不存在的字段status_text
protect $append = ['status_text']
//命名規則 get+大駝峰+Attr
public function getStatusTextAttr($value,$data)
{
$status = [-1=>'删除',0=>'禁用',1=>'正常',2=>'待审核'];
return $status[$data['status']];
}
在thinkphp的field方法裏面定義自定義字段(concat)
CustomerFlowModel::alias('a')->field("concat(c.name,' (', c.currency, ': ', lpad(RIGHT(c.account, 4),10,'***'), ')') as account")
2.8、從數據庫直接查詢出來的為字段的值,而不是數組(value)
$originRoieLabel = UserModel::where(['userid' => $value['userid'], 'company' => $value['company']])->value('role');
2.9、DB操作和模型操作的区别
//DB操作返回是数组。模型直接操作返回是对象
UserModel::where(['userid'=>$userid])->select()->toArray();
//等效于上面那句话
Db::table('dt_user')->where(['userid'=>$userid])->select();
2.11、解析配置文件(.ini) 【parse_ini_file】
parse_ini_file() 函数解析一个配置文件(ini 文件),并以数组的形式返回其中的设置。
//解析.env配置文件
$env = parse_ini_file(ROOT_PATH . '.env', true);
$ENV_CONST = $env;
global $ENV_CONST;
//接下来就可以使用关联数组的形式来访问.env的变量了,例如
define('APP_ENV',$env['common.env']);
2.12、读取配置文件
//读取config里面app.php的配置信息,使用config方法
config('属性')
//读取.env文件里面的配置信息
use think\facade\Env;
Env::get('APP_HOST')
2.13、动态执行执行函数call_user_func_array
//method为传进来的函数名,[$userid,$password]为传进函数的参数
if(method_exists($this,$method)){
$userData = call_user_func_array([$this,$method],[$userid,$password]);
}
2.14、从数据库里面查出来的数据是否是为空的标准判断【findOrEmpty、isEmpty】
$userInfoRes = User::where(["userid"=>$userid])->findOrEmpty();
if($userInfoRes -> isEmpty()){
}
2.15、thinkphp在h5和js裏面使用模板語法(获取配置信息的方法)
//在js裏面獲取變量
var name =' ${name}'
//在h5端獲取系统變量
{$Think.env.source}
2.16、复杂子查询【场景一个必要的查询条件,和两个非必要的模糊查询条件】
//例如company一定要满足,然后两个字段是name,email是模糊查询的条件
$userList = UserModel::where('company', $company)
->where(function ($query) use ($parameter) {
$query->where('name', 'like', '%' . $parameter . '%')
->whereOr('email', 'like', '%' . $parameter . '%');
})
->field('mobile, name, avatar, userid, email')
->order('id DESC')
->select()
->toArray();
2.17、thinphp没有接管的文件里面引入vendor下载好的插件
1、先引入这个链接的绝对路径
2、然后就可以使用这个文件的命名空间了
2.18、thinkphp连接多个数据库
1.打开/application/database.php
2.在 return[] 中最后一行添加数据库配置代码
"db_text" => [
// 数据库类型
'type' => Env::get('database.type', 'mysql'),
// 服务器地址
'hostname' => Env::get('database.hostname', '127.0.0.7'),
// 数据库名
'database' => Env::get('database.database', 'text1'),
// 用户名
'username' => Env::get('database.username', 'root'),
// 密码
'password' => Env::get('database.password', 'rootpas'),
// 端口
'hostport' => Env::get('database.hostport', ''),
// 连接dsn
'dsn' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用 utf8mb4
'charset' => Env::get('database.charset', 'utf8mb4'),
// 数据库表前缀
'prefix' => Env::get('database.prefix', ''),
// 数据库调试模式
'debug' => Env::get('database.debug', false),
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 数据集返回类型
'resultset_type' => 'array',
// 自动写入时间戳字段
'auto_timestamp' => false,
// 时间字段取出后的默认时间格式,默认为Y-m-d H:i:s
'datetime_format' => false,
// 是否需要进行SQL性能分析
'sql_explain' => false,
],
3.查询text1数据库中user表数据
// 连接text1数据库
$db_text = Db::connect(config('database.db_text'));
// 查询user表数据
$user=$db_text->name('user')->field('name,phone,sex,age')->select();
2.19、Db类或模型使用自定义条件进行查询(常用)
//写法 where(function($query) user(要使用的变量){
// 判断
// })
obotConfigModel::where(function ($query) use($company) {
if (is_array($company) && count($company) > 0) {
$query->where('company', 'in', $company);
} else if (is_string($company) && !empty($company)) {
$query->where('company', $company);
} else {
$query->where('company', '<>', 'test');
}
})->where('status', 1)->field(['access_token', 'company', 'secret', 'pic_url', 'title'])
2.20、Db类或模型中中使用获取器
//withAttr里面的第二个参数就是获取器的用法
RobotConfigModel::->where('status', 1)->field(['access_token', 'company', 'secret', 'pic_url', 'title'])
->withAttr('access_token', function ($value) {
return \Encryption::aesDecrypt($value);
})
2.21、在h5標簽上使用tp的模板語法
<a class="tar_tool" target="_blank" v-if="'{$Think.env.oa_source}' == 'dtalk'"
href="https://osa.gamedreamer.com/osa/Service/User/frogotPassword"><i class="el-icon-unlock a-icon"></i>修改密碼
</a>
2.22、 thinphp链式语法的原理
前置函数都返回$this就可以了
2.23、thinkphp使用流文件保存图片
$image = imagecreatefromjpeg("captcha/$captcha-$num.jpg");
imagefilter($image, IMG_FILTER_PIXELATE, 1, true);
imagefilter($image, IMG_FILTER_MEAN_REMOVAL);
ob_start();
imagejpeg($image);
$contents = ob_get_contents();
ob_end_clean();
$dataUri = "data:image/jpeg;base64," . base64_encode($contents);
2.24、注意实例化(new) 出来的对象的继承父类的变量和父类就没什么关系了
并且继承了父类protected的变量改值最好用get,set来获取和修改
2.25、分库的时候用TP的连表语法进行连表操作
//对不同库的表在模型上指定好库的名字
class Admin extends Model
{
protected $table = 'app_video.ba_admin';
}
public function admin(): BelongsTo
{
return $this->belongsTo(Admin::class,'cruser');
}
2.26php获取配置文件内容的操作大全
//获取config文件夹的里面的某个文件的所有内容(因为是一个大的关联数组)
Config::get('文件名')
//获取里面的某一个属性
Config::get('文件名.属性名')
2.27、将stdclass转化为数组的方法
if(!function_exists('stdObject2Array')){
function stdObject2Array($json){
// stdClass 轉數組
return json_decode(json_encode($json),TRUE);
}
}
2.28、tp查询数据库获取对象之后,继续添加属性【each】
$chapterObj = (new TopicChapter())
->where('question_bank_id', '=', $questionBankId)
->where('is_deleted', '=', 0)
->where('chapter_type', '=', 1)
->order('sort ASC')
->field('id as chapter_id,chapter_name')
->select(); //或者是paginate,这里查出来的是一个对象
$chapterObj->each(function ($item) use ($questionBankId) {
$item->topic_num = (new \app\common\model\v2\Topic())->where(['question_bank_id' => $questionBankId, 'topic_chapter_id' => $item->chapter_id, 'parent_id' => 0, 'is_deleted' => 0, 'organization_id' => 3])->count('id');
});
2.29、讓一個函數内部能夠執行另一個自定義的函數(常用,不用寫一堆判斷)call_user_func_array
【内含is_callable的用法】
更加自定义的用法(使用完整命名空间)
//is_callable的使用(主要注意第二個參數的使用),【用於檢測一個類中的某個方法是否可執行】
參數:
第一個:要檢查的方法參數【兩種格式:1、'someFunction' 2、array($anObject, 'someMethod')】
第二個(bool): 第一個參數的格式: false => 第一種 true => 第二種
第三個(回調變量): 用來接收可調用的這個方法的名稱(一般不寫)
//執行外部類的方法
//failHandlerMethod這個就是$exampleObject這個類裏面的函數
$exampleObject = new ExampleClass();
$failHandler = array($exampleObject, 'failHandlerMethod');
//執行内部的方法
$failHandler = array($this, 'failHandlerMethod');
//這樣就可以傳進來什麽就執行什麽對象裏面的函數
public static function accountRecordAction($failHandler)
if (is_callable($failHandler,true)) {
call_user_func_array($failHandler, []); //注意这个第二个参数要是一个数组,不管你的方法只有一个参数还是有多个参数
}
2.30、跨库的表要单独开启事务(单独使用模型的stran)
//遇到跟Db类主连接不同的表需要开启事务,就要这样写
Db::startTrans();
OrderDetailsModel::startTrans();
//相对应回滚也要
Db::rollback();
OrderDetailsModel::rollback();
//提交
Db::commit();
OrderDetailsModel::commit();
2.31、将一个类的方法可以在调用的时候全部变成静态方法来调用(使用Facade类)
//使用Dict类之前多包一层(Dict里面的方法全部是普通方法不是静态方法)
class Dict extends Facade
{
protected static function getFacadeClass()
{
return '\app\admin\controller\common\Dict';
}
}
//然后用的时候就可以这样来用了
Dict::gameDict(),
Dict::activityDict()
2.32、通過命名空間字符串來動態創建想要的實例一個實例(重要)
protected $storageDrivers = ['aliyun','google','file'];
//可以根據不同的命名空間來動態創建想要的實例
public function useStorage($storageName='file',$options=[])
{
$storageName = strtolower($storageName);
if (!in_array($storageName,$this->storageDrivers)) {
throw new \exception\StrorageFileException('Storage driver not found');
}
$storageDriverName = ucwords(camelize($storageName.'_storage'));
//使用命名空間來new出一個實例
$storageDriver = 'storageFile\\driver\\' . $storageDriverName;
$sdObject = new $storageDriver($options);
// if($storageName != 'file' && !$sdObject->useful){
// throw new \exception\StrorageFileException("Storage {$storageName} driver is not useful");
// }
return $sdObject;
}
2.33 Tp的trait(模拟多继承)
/ **
可以像定义一个普通类一样定义一个trait类,里面可以包含正常的方法和属性
**/
trait IdentityAuth
{
public function userData($value = ''){
$authSession = session("AUTH_SESSION");
if(!$authSession){
returnRes("驗證失效,请先登录");
}
return !$value ? $authSession : ($value&&isset($authSession[$value]) ? $authSession[$value] : '');
}
//然后使用就直接use
class BaseCore extends BaseController
{
use IdentityAuth;
//调用IdentityAuth里面的方法就直接$this-> 方法名 即可
}
3. php请求接口时查漏补缺
如果接口需要请求头的content-type是application/json的时候
那么传过去的参数就得是json_encdoe(数组) ,将数据转化为json字符串
3、文件路徑
mvc模式下,視圖層調用靜態資源,"/"表示的是public
所以public下static的資源都是直接 /static就可以了
4、tp中間件
全局中間件注冊所在位置config/middleware.php
//下面所用的‘auth’就是這裏的別名
return [
// 默认中间件命名空间
'default_namespace' => 'app\\http\\middleware\\',
'auth' => app\http\middleware\Auth::class,
'checkpermission' => app\http\middleware\CheckPermissions::class,
];
//這個意思就是所有繼承了Base類的所有子類的autopush和login方法不受這個auth中間件的影響(except)
//相對的only參數
class Base extends Controller
{
protected $middleware = ['auth' => ['except' => ['autoPush','login'] ]];
//也可以指定是某一个控制器下的方法
protected $middleware = ['auth' => ['except' => ['controller1.autoPush','controller2.login'] ]];
}
5、Session
6、thinkphp的路由
1、bind方法
// 绑定当前的URL到 admin模块
Route::bind('admin');
// 绑定当前的URL到 admin模块的blog控制器
Route::bind('admin/blog');
// 绑定当前的URL到 admin模块的blog控制器的read操作
Route::bind('index/blog/read');
那么接下来访问这个方法从访问: < http://serverName/index/blog/read/id/5 >
简化为 : < http://serverName/read/id/5 >
// 绑定命名空间
Route::bind(':\app\index\controller');
2、group和prefix的理解
当有prefix的时候,
group分组写的路径实际就是浏览器实际访问的路径,这个路径可以不关联模块、控制器,而使用自己自定义的名字
这时候prefix写的参数才是要根据这个函数所在的模块、控制器的名字来写
3、中间件仅作用于某些特定的页面
/* 需要进行验权的方法 */
Route::group(function () {
Route::rule('index/index', 'index/index');
})->middleware(\app\middleware\JwtAuth::class);
、TP8使用路由注意事项
/ ** 每一个模块的路由文件要放在他指定的文件下面,访问的时候要额外带上应用的名称 ** /
├─app 应用目录
│ ├─app_name 应用目录
│ │ ├─common.php 函数文件
│ │ ├─controller 控制器目录
│ │ ├─model 模型目录
│ │ ├─view 视图目录
│ │ ├─config 配置目录
│ │ ├─route 路由目录
│ │ │ ├─route.php 路由定义
│ │ │ ├─api.php 路由定义
│ │ │ └─... 更多路由定义
7、事件订阅
快速回忆
【事件监听 => listen】
1、通常每个模块都有自己单独的事件类,通常写在common\event文件夹下
2、然后通过在模块下面的event.php文件下注册事件(如果没有就自己创建一个), 如下图
3、然后在需要执行监听类逻辑的控制器的方法下面这样写(如下),就可以执行监听类的逻辑
//发起请求前添加日志记录
Event::trigger('requestBefore', $this->request);
【事件订阅 => subscribe】
参考 :(https://blog.csdn.net/firstime_tzjz/article/details/126869156)
·
8、TP自定異常類
1、app.php配置文件配置
//1、首先要清楚config/app.php文件裏面有一個 “exception_handle”的屬性,可以自定義指定異常處理的handle類
'exception_handle' => '\exception\ExceptionHandle', (注意這個命名空間的前面多了一個“/”)
2、錯誤異常類書寫(有個traceLog的公用方法)
<?php
namespace exception;
use think\exception\Handle;
use think\facade\Response;
/**
* 自定义异常类
* Class ExceptionHandle
* @package exception
*/
class ExceptionHandle extends Handle
{
public $code;
public $message;
public $error;
public $errorMsg;
public $errorCode;
public $errorExtra;
/**
* @param \Exception $e
* @return \think\Response|\think\response\Json
*/
public function render(\Exception $e)
{
if ($e instanceof BaseException) {
$this->error = $e->error;
$this->errorMsg = $e->errorMsg;
$this->errorCode = $e->errorCode;
$this->code = $e->code;
$this->message = $e->message;
$this->errorExtra = $e->errorExtra;
if(!config('app_debug') && !request()->isAjax()) {
\Wflog::e('error:'.$this->errorMsg.',code:'.$this->errorCode.',extra:'.json_encode($this->errorExtra).','.config('http_exception_template'));
return view(config('http_exception_template'), ['code'=>$this->code,'msg'=>$this->errorMsg]);
}
} else {
if(config('app_debug') && !request()->isAjax()) {
return parent::render($e);
}
$this->code = 500;
$this->error = 1;
$this->errorMsg = APP_ENV == 'production' ? '服务错误' : '[服务错误]'.$e->getMessage();
$this->errorCode = 9999;
$this->message = $this->errorMsg;
$this->errorExtra = [];
$this->recordErrorLog($e);
}
$result = [
'errorMsg' => $this->errorMsg,
'errorCode' => $this->errorCode,
'errorExtra' => $this->errorExtra,
'code' => $this->code,
'message' => $this->message,
'error' => $this->error,
];
return json($result);
}
/**
* @param \Exception $e
*/
private function recordErrorLog(\Exception $e)
{
// Log::record($e->getMessage(), 'error');
traceLog($e);
}
}
traceLog方法
if(!function_exists('traceLog')){
function traceLog($e){
$msg = $e->getMessage();
$trace = true;
if(is_json($msg)){
$msgArr = json2Array($msg);
if(isset($msgArr['code']) && isset($msgArr['message'])){
$trace = false;
}
}
if($trace){
\Wflog::e('[Throw Error]Error:'.$e->getMessage());
\Wflog::e('[Throw Error]Line:'.$e->getLine());
\Wflog::e('[Throw Error]File:'.$e->getFile());
$trace = $e->getTrace();
foreach($trace as $key=>$item){
if($key == 0) continue;
$line = isset($item['line']) ? $item['line'] : '';
$class = isset($item['class']) ? $item['class'] : '';
$type = isset($item['type']) ? $item['type'] : '';
$function = isset($item['function']) ? $item['function'] : '';
$file = isset($item['file']) ? $item['file'] : '';
$str = $line.'|'.$class.$type.$function.'|'.$file;
\Wflog::e('[Throw Error]Trace:'.$str);
}
}
}
}
9、其他
不用實例化直接鏈式寫法 (直接括號框住)
(new BreakfastPush())->getRobotConfig($item)->setTitle()->push();
TP用模型優雅寫完數據庫的插入(通過模型)
$platformAccount = new PlatformAccountModel();
//关键的一步,给这个对象加上这些属性
array_walk($param, function ($value, $key) use ($platformAccount){
$platformAccount->$key = $value;
});
//或者可以這樣寫(模型對象->data(數組))
$platformExAmountLog->data([
'account' => $platformExAmount->account,
'type' => $params['type'],
'event' => $params['event'],
'amount' => $params['amount'],
'balance' => $balance,
'crtime' => $time,
'creator' => Session::get('AUTH_SESSION.username'),
'fixedamount' => $params['amount'],
'remark' => Dict::getEvent($params['event']) . ': ' . ($params['type']? '收入' : '支出') . "金額:" . $params['amount']
]);
//其實這個模型對象打印出來實際只會顯示上面賦值數據的一個普通的關聯數組
if ($platformAccount->save()){
return json(['code' => 1 ,'msg' => '新增成功']);
}