溫馨提示:篇幅較長,閱讀需要5-10分鐘。
需求
一個比較完善的表中基本上都會有type
,status
欄位,來區分型別和狀態,現在的問題就是當api介面返回資料後,前端人員根本不知道你返回的type
或者status
欄位是什麼意思,之前的做法是用if
流程語句判斷,將status=1
手動轉換成“啟用”,status=2
轉換成“禁用”(剛入門的時候我就是這麼做的)。
這樣的話,是不是很複雜呢?既然複雜,那麼就改進它,我們可以加一個type_str
說明欄位,來說明type
中數字所表示的含義,同理,我們給status
配備一個status_str
。ok,解決辦法有了,但是如果直接加在資料庫的話,又很不方便,所以我們要借用一下helpers.php
。
實現步驟詳解
建立constants.php
這是一個自定義常量配置檔案,路徑在config/constants.php
,我們在裡面定義我們的常量:
<?php
return [
'APP_NAME' => 'my project',
'APP_URL'=> '你的域名',
'USER_TYPE' => [
1 => '代理商',
2 => '分銷商',
3 => '普通使用者',
],
大家可以看到,我定義了一個USER_TYPE
常量,為什麼叫這個名字呢,下面會解釋。
配置helpers.php檔案
首先建立我們的幫助類檔案並編輯,路徑為app/helpers.php
:
<?php
if (!function_exists('constants')) {
function constants(string $constName, $trans = false) {
$config = config('constants.' . strtoupper($constName));
if ($trans === false) {
return $config;
}
if ($trans === 'label') {
return array2label($config);
}
}
}
if (!function_exists('array2label')) {
function array2label(array $arr) {
$ret = [];
foreach ($arr as $key => $item) {
$ret[] = ['label' => $item, 'value' => $key];
}
return $ret;
}
}
來稍微解釋一下,我這裡定義了一個constants
函式,他的作用是當我們傳入引數時,透過config
輔助函式從constants
配置檔案裡面獲取相應的值,完整的流程會在最後說明。
將helpers.php加入到composer自動載入中
//將files新增到autoload中
"autoload": {
"files": [
"app/helpers.php",
],
"classmap": [
"app/Libraries",
"database/seeds",
"database/factories"
],
"psr-4": {
"App\\": "app/"
}
},
最後執行命令
composer dump-autoload
在模型Model中追加欄位
基本配置到這裡就差不多了,我們在model
中追加type_str
欄位。
protected $appends = ['type_str'];
然後給type_str
“賦值”,這裡不太懂的可以檢視文件 追加json值:
public function getTypeStrAttribute()
{
return array_get(constants( 'USER_TYPE'), $this->getAttribute('type'));
}
這裡呼叫了之前在helpers.php
中定義好的constants
函式,array_get
方法使用”.“號從巢狀陣列中獲取值,當然也不一定用array_get
,也可以用其他。
繼續完善,使用trait實現程式碼重用
到上一步,我們的需求基本上就實現了。但是,我一個專案裡大約有10多張表使用到了type
以及status
欄位,每個模型中都寫這麼一段程式碼,不太符合優雅的概念,所以完善過程中又使用到了trait
。
關於trait,它是為類似 PHP 的單繼承語言而準備的一種程式碼複用機制,具體可以參閱PHP文件。
建立trait檔案並編輯
路徑在app/Traits/TypeTrait.php
<?php
namespace App\Traits;
trait TypeTrait
{
public function getTypeStrAttribute()
{
return array_get(constants(class_basename(static::class) . '_TYPE'), $this->getAttribute('type'));
}
}
使用trait
回到我們Model模型,追加欄位不變,但是不用再進行“賦值”操作了,只需:
use TypeTrait;
protected $appends = ['type_str'];
還記得上面挖的坑為什麼要命名為USER_TYPE
嗎?就是為這裡做鋪墊的,仔細看TypeTrait.php
檔案,class_basename
的作用是返回給定類刪除名稱空間的類名,比如在uesr模型中它返回的就是user,這樣就方便我們程式碼的複用。
完整的步驟
可能有人看到這裡還是有些迷糊,你說了半天這到底是咋用的。讓我們一起走一遍流程(按照程式碼進行流程):
-
User控制器呼叫查詢方法,使用
toArray()
返回介面需要的欄位。 -
查詢的時候就透過User模型查詢資料,使用的同時就追加了type_str欄位,這個欄位不是資料表中有的,而是我們臨時新增上去的,所以我們需要定義它的值。
-
於是User模型呼叫了TypeTrait.php中的
getTypeStrAttribute()
方法,這個方法有三層巢狀:3.1 最裡面的是class_basename返回給定類刪除名稱空間的類名,如果我們是透過User模型呼叫的就是User,然後使用“.”拼接了字串,最後得到的是User_TYPE。
3.2 中間的一層,constants函式接收到了我們的引數“User_TYPE”,strtoupper將“User_TYPE“全部轉換為大寫字元,透過
config
在自定義常量配置檔案constants.php中取值,返回一個USER_TYPE陣列。3.3 回到
getTypeStrAttribute()
方法,最外面一層透過array_get匹配出type欄位相對應的說明文字並返回, -
這樣給追加欄位賦值就成功了。
結束語:一共用了兩個小時完成,修修改改了三遍,可能還是會有一些細小的紕漏,如果有什麼問題,歡迎評論指正,或者也可以糾錯改正!
本作品採用《CC 協議》,轉載必須註明作者和本文連結