如何巧妙 / 優雅地使用幫助類檔案 helpers.php

Jouzeyu發表於2019-11-05

溫馨提示:篇幅較長,閱讀需要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,這樣就方便我們程式碼的複用。

完整的步驟

可能有人看到這裡還是有些迷糊,你說了半天這到底是咋用的。讓我們一起走一遍流程(按照程式碼進行流程):

  1. User控制器呼叫查詢方法,使用toArray()返回介面需要的欄位。

  2. 查詢的時候就通過User模型查詢資料,使用的同時就追加了type_str欄位,這個欄位不是資料表中有的,而是我們臨時新增上去的,所以我們需要定義它的值。

  3. 於是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欄位相對應的說明文字並返回,

  4. 這樣給追加欄位賦值就成功了。

結束語:一共用了兩個小時完成,修修改改了三遍,可能還是會有一些細小的紕漏,如果有什麼問題,歡迎評論指正,或者也可以糾錯改正!

一個有些偏執的人
     ——Jouzeyu

相關文章