如何优雅地使用帮助类文件 helpers.php

温馨提示:篇幅较长,阅读需要 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. 这样给追加字段赋值就成功了。

结束语:一共用了两个小时完成,修修改改了三遍,可能还是会有一些细小的纰漏,如果有什么问题,欢迎评论指正,或者也可以纠错改正!

本作品采用《CC 协议》,转载必须注明作者和本文链接
空舟湖上~      ——Jouzeyu
lochpure
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 3

了解一下这个。Laravel-Enum

5年前 评论
lochpure (楼主) 5年前

这种枚举,和模型高度关联,我是建议写在 model 里面做 const STATUS_MAP = [1=> 'xxx'] 这样。

不然绕来绕去,反而阅读的时候麻烦,人为增加代码复杂性。。

5年前 评论
839891627 (作者) 5年前
lochpure (楼主) 5年前
lochpure (楼主) 5年前
小丑路人 5年前

放 Model 里面,也挺好

file

5年前 评论
lochpure (楼主) 5年前