优雅且语义化的断言之—将模型属性断言变为模型方法断言

举个例子,断言直接裸露的写在控制器中

控制器的方法:neckbeard:

<?php
use App\Models\Order;
class  OrderController  extends  Controller
{
    public  function  applyRefund(Order $order, ApplyRefundRequest $request)  {
        // 1.断言 - 判断是否未支付
        if (! $order->paid_at) {
        throw new InvalidRequestException('该订单未支付,不可退款');
        }
        // 2.断言 - 判断订单是否已退款
        if ($order->refund_status !== Order::REFUND_STATUS_PENDING) {
        throw new InvalidRequestException('该订单已经申请过退款,请勿重复申请');
        }
        ...
    }
}

这样写不是不可以,也是正确的,但是存在三面问题::collision:

  1. 断言有点长,看起来不够优雅,控制器的代码应简约一点。
  2. 断言不具有语义化,阅读起来不能快速理解其含义。
  3. 后期代码需要批量修改,麻烦且容易出错。

针对以上问题我要做是以下两点::dizzy:

  1. 长的断言修改为方法,写入到模型中,控制器直接调用模型方法即可。(代码看起来简约且后期维护只需修改模型方法)
  2. 方法名使用快速可读,可理解其中含义的名称。

优化后的样子:star2:

模型中的方法:

<?php
namespace  App\Models;
class  Order  extends  Model
{
    // 退订状态
    const  REFUND_STATUS_PENDING  =  'pending';

    // 是否未付款
    public function isUnpaid()  :bool
    {
        return ! ($this->paid_at);
    }
    // 是否订单已退款
    public function isRefunded() :bool
    {
        return $this->refund_status !== self::REFUND_STATUS_PENDING;
    }
}

控制器中的调用:

<?php
use App\Models\Order;
class  OrderController  extends  Controller
{
    public  function  applyRefund(Order $order, ApplyRefundRequest $request)  {
        // 1.断言 - 判断是否未支付
        if ($order->isUnpaid()) {
            throw new InvalidRequestException('该订单未支付,不可退款');
        }
        // 2.断言 - 判断订单是否已退款
        if ($order->isRefunded()) {
            throw new InvalidRequestException('该订单已经申请退款,请勿重复申请');
        }
        ...
    }
}

完了么?并没有,咱们继续优化!!

模型中的方法:

<?php
namespace  App\Models;
class  Order  extends  Model
{
    // 退订状态
    const  REFUND_STATUS_PENDING  =  'pending';

    // 是否未付款
    public function isUnpaid()  :bool
    {
        return ! ($this->paid_at);
    }
    // 直接抛出异常 - paid_at 未支付时值为null 
    public function isUnpaidNotSupported()  :bool
    {
        return ! $this->isUnpaid() ?: throw new InvalidRequestException('该订单未支付,不可退款');
    }
    // 是否订单已退款
    public function isRefunded() :bool
    {
        return $this->refund_status !== self::REFUND_STATUS_PENDING;
    }
    // 直接抛出异常
    public function isRefundedNotSupported() :bool
    {
        return ! $this->isRefunded() ?: throw new InvalidRequestException('该订单已经申请退款,请勿重复申请');;
    }
}

控制器中的调用:

<?php
use App\Models\Order;
class  OrderController  extends  Controller
{
    public  function  applyRefund(Order $order, ApplyRefundRequest $request)  {
        // 1.断言 - 判断是否未支付
        $order->isUnpaidNotSupported()
        // 2.断言 - 判断订单是否已退款
        $order->isRefundedNotSupported()
        ...
    }
}

如此这样,控制器的判断看起来不那么蹩脚,读起来也很通顺,后期代码维护直接修改模型方法,且属性也可调整,挺好!以后都按照这种方式写具有可读可维护性的代码!赏心也悦目,哈哈!:kissing_heart: :kissing_heart:

还能再优化么?

  1. 我想还能优化,直接控制器无需断言。
  2. 将断言放入中间件中。
  3. 将断言放入请求类中,都可以,就看你要优化到那种程度了。
本作品采用《CC 协议》,转载必须注明作者和本文链接
Xiao Peng
laravel_peng
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 15

基超

1个月前 评论
laravel_peng (楼主) 1个月前

感觉没什么区别

1个月前 评论
laravel_peng (楼主) 1个月前
chowjiawei

file

这些方法已经有了 可以再来个 调用这些方法 然后直接有问题抛出异常的方法 命名为 没用符合条件就抛出异常

你的控制器就更节省代码了

1个月前 评论
laravel_peng (楼主) 1个月前

isOrFail 是不是更加优雅

1个月前 评论
laravel_peng (楼主) 1个月前
Mumujin

empty 暴露你的基础不好或者说数据库设计有问题。。。。

  1. 使用migations boolean
  2. cast 设置字段类型
  3. model 直接返回或根据表的类型直接生成 entry 并引入 example:

public function isRefunded() :bool
{
    return $this->refunded;
}

public function isRefundsNotSupported(): bool
{
    return $this->isRefunded ?: throw new InvalidRequestException('该订单已经申请退款,请勿重复申请');
}
  1. 订单检测可以直接创建一个order check 中间件或封装在OrderRequest
1个月前 评论
laravel_peng (楼主) 1个月前
laravel_peng (楼主) 1个月前
Mumujin (作者) 1个月前
Mumujin (作者) 1个月前
laravel_peng (楼主) 1个月前
laravel_peng (楼主) 1个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!