【问题标题】:Is it acceptable to return HTML from an accessor?从访问器返回 HTML 是否可以接受?
【发布时间】:2019-11-17 15:37:57
【问题描述】:

我正在使用 Laravel 框架。我尽可能使用模型返回可在整个应用程序中使用的通用属性。

我的部分应用程序跟踪网站的响应时间(首字节时间/TTFB)。在我的Website 模型中,我将响应时间“评分”为“好”、“差”和“平均”。所以,我有一个返回这个的访问器。很简单,很好的做法:

/**
 * Accessor for TTFB grade (good, bad, average).
 * 
 * @return String
 */
public function getAverageTtfbGradeAttribute()
{
    if($this->average_ttfb < 0.5) {
        $grade = 'good';
    } elseif($this->average_ttfb >= 0.5 && $this->average_ttfb < 1.2) {
        $grade = 'average';
    } else {
        $grade = 'bad';
    }

    return $grade;
}

我想在整个应用程序中显示 TTFB/响应时间,但我希望它根据成绩着色。我创建了另一个依赖于第一个访问器的访问器:

/**
 * Accessor for TTFB with a colour
 * 
 * @return String
 */
public function getAverageTtfbColoredAttribute()
{
    $str = '<span class="';

    if($this->averageTtfbGrade == 'good') {
        $str.= 'text-success';
    } elseif($this->averageTtfbGrade == 'average') {
        $str.= 'text-warning';
    } else {
        $str.= 'text-danger';
    }

    $str.= '">' . $this->average_ttfb .'s</span>';

    return $str;
}

要使用它,我只需要使用$website-&gt;averageTtfbColored。效果很好。

我的问题是,这是好还是坏的做法?我的理解是,无论是在控制器、模型还是应用程序的任何其他部分中,HTML 都不应该成为业务逻辑的一部分。但是,如果我遵循这个逻辑,那么我最终会在视图中使用 if 语句,这些语句将在我的应用程序的许多地方重复 - 这违反了 DRY 原则。

这里的最佳做法是什么?我是不是想多了?

【问题讨论】:

  • 逻辑是写在控制器中的,模型负责数据检索和大写字符串等基本操作。视图应该以最少的 if 条件显示数据。这是我遵循的模式,不知道是不是你所期望的。
  • 这就是胖控制器、瘦模型之间的区别,反之亦然。这不是真正的问题。我可以将这个逻辑从模型移动到控制器,但是问题已经从视图移动到控制器,然后我有 2 个问题;控制器中的 HTML 并且重复了很多次。有了我现在所拥有的,我在一个模型中就有了这个逻辑,它在整个应用程序中都使用了,但只写了一次。唯一的缺点是它包含 HTML,这通常是禁忌。我想真正的问题是这个用例是否是一个可接受的例外
  • @ImmortalDude 我不同意你的观点。模型层(与 MVC 中的模型相反)应该包含业务逻辑,视图层应该处理表示,控制器尽可能瘦。胖控制器是一种常见的反模式,它使应用程序难以维护和测试。
  • @MatthewDaly as opposed to models in MVC 我正在遵循那个确切的模式,我不反对你的模式,只是我遵循你不遵循的模式,只是我的意见,并不难以 mvc 模式编写代码的核心“方式”
  • @ImmortalDude 模型层与框架提供的模型类不同,例如 Eloquent。 MVC 中的 M 不仅包含 Eloquent 之类的东西,还包含任何其他业务逻辑,例如,如果您的应用程序发送推送通知,则该功能应该包装在服务类中。将这种功能转移到控制器是导致难以测试的臃肿、重复代码的秘诀,并且在过去一直困扰着我。如果控制器方法的长度超过 10 行左右,则应始终考虑将部分功能移至模型层。

标签: php laravel dry


【解决方案1】:

这违反了 MVC 模式,因为您的模型现在也是部分视图。我建议您创建一些小的子视图/组件,例如 /resources/views/components/averageTtfd.blade,然后在整个应用程序中使用它们。

【讨论】:

  • 这可行。让整个视图输出一个包含在跨度中的单个数字似乎有点矫枉过正,但我​​想它比在模型中更干净。谢谢
  • 这可能有点矫枉过正,但这是保持代码结构化的小小代价。
【解决方案2】:

我认为逻辑上任何生成 HTML 的东西都是视图层的一部分,因此并不真正属于模型。

不过,您说得对,它也不应该在视图层中重复。替代方法包括:

  • 创建一个局部渲染项目
  • 创建帮助函数以返回正确的值
  • 创建一个视图模型来处理这个逻辑

后一个选项是最复杂的,并且 Laravel 没有原生包含,但是周围有第三方实现。

【讨论】:

    【解决方案3】:

    您在模型上获取值的逻辑是完全正确的,它被称为富实体,但您的应用程序可能并不总是在 http 上运行,这意味着 html 代码在模型上没有意义,您可以轻松创建一个专门用于此目的的刀片模板。

    其他一些小建议。使用提前返回并避免 else/elseif

    【讨论】:

      猜你喜欢
      • 2012-10-03
      • 2012-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-19
      相关资源
      最近更新 更多