Laravel - 很多用于使用 Blade 渲染视图的访问器(Mutators)

Ali*_*ice 6 php model view laravel laravel-blade

我有一个 Laravel 7 项目,需要在显示之前将大量数据从模型转换为视图。

我想过使用Laravel Accessors并直接在我的blade.php 文件中使用它们。
但是当我处理完一个简单的 html 表时,我查看了我的代码,我认为访问器太多了,甚至其中一些访问器的名称难以阅读。

刀片视图

@foreach($races as $race)
<tr>
    <td>{{ $race->display_dates }}</td>
    <td>{{ $race->display_name }}</td>
    <td>{{ $race->type->name }}</td>
    <td>{{ $race->display_price }}</td>
    <td>{{ $race->display_places }}</td>
    <td>{{ $race->online_registration_is_open ? 'Yes' : 'No' }}</td>
</tr>
@endforeach
Run Code Online (Sandbox Code Playgroud)

控制器

public function show(Group $group)
{
    $races = $group->races;
    $races->loadMissing('type'); // Eager loading
    return view('races', compact('races'));
}
Run Code Online (Sandbox Code Playgroud)

模型

// Accessors
public function getOnlineRegistrationIsOpenAttribute()
{
    if (!$this->online_registration_ends_at && !$this->online_registration_starts_at) return false;
    if ($this->online_registration_ends_at < now()) return false;
    if ($this->online_registration_starts_at > now()) return false;
    return true;
}

public function getNumberOfParticipantsAttribute()
{
    return $this->in_team === true
        ? $this->teams()->count()
        : $this->participants()->count();
}

// Accessors mainly used for displaying purpose
public function getDisplayPlacesAttribute()
{
    if ($this->online_registration_ends_at < now()) {
        return "Closed registration";
    }
    if ($this->online_registration_starts_at > now()) {
        return "Opening date: " . $this->online_registration_starts_at;
    }
    return "$this->number_of_participants / $this->max_participants";
}

public function getDisplayPriceAttribute()
{
    $text = $this->online_registration_price / 100;
    $text .= " €";
    return $text;
}

public function getDisplayDatesAttribute()
{
    $text = $this->starts_at->toDateString();
    if ($this->ends_at) { $text .= " - " . $this->ends_at->toDateString(); }
    return $text;
}

public function getDisplayNameAttribute()
{
    $text = $this->name;
    if ($this->length) { $text .= " $this->length m"; }
    if ($this->elevation) { $text .= " ($this->elevation m)"; }
    return $text;
}
Run Code Online (Sandbox Code Playgroud)

这段代码正在运行,但我认为它有很多缺点:可读性、错误是可能的,例如,如果name我在getDisplayNameAttribute这里创建访问器时关联的数据库表有一个列。
这只是一个开始,我想其他视图我还需要 30-40 个访问器......此外,我需要多次使用其中的一些,例如getDisplayNameAttribute可以在常规页面和管理页面中使用(也许更多)。

我还查看了JsonResourceViewComposer,JsonResource似乎有APIs一段时间ViewComposer似乎特别适用于Views.

我还考虑过在访问器前添加类似acc_减少现有 db 列错误的内容:

public function getAccDisplayNameAttribute() { ... };
Run Code Online (Sandbox Code Playgroud)

但我真的不认为这是一个解决方案,我什至不确定我在做什么是对还是错。我还通过互联网搜索了最佳实践,但没有成功。

小智 3

您可以创建一个专门处理转换的类。然后,您可以在模型构造函数中加载此类的实例。\n如果您愿意,您还可以使访问器类使用 PHP magic getter。

\n\n

附件类

\n\n
class RaceAccessors {\n    // The related model instance\n    private $model;\n\n    // Already generated results to avoid some recalculations\n    private $attributes = [];\n\n    function __construct($model)\n    {\n        $this->model = $model;\n    }\n\n    // Magic getters\n    public function __get($key)\n    {\n        // If already called once, just return the result\n        if (array_key_exists($key, $this->attributes)) {\n            return $this->attributes[$key];\n        }\n\n        // Otherwise, if a method with this attribute name exists\n        // Execute it and store the result in the attributes array\n        if (method_exists(self::class, $key)) {\n            $this->attributes[$key] = $this->$key($value);\n        }\n\n        // Then return the attribute value\n        return $this->attributes[$key];\n    }\n\n    // An example of accessor \n    public function price()\n    {\n        $text = $this->model->online_registration_price  / 100;\n        $text .= " \xe2\x82\xac";\n        return $text;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

模型类

\n\n
class Race {\n    // The Accessors class instance\n    public $accessors;\n\n    function __construct()\n    {\n        $this->accessors = new \\App\\Accessors\\RaceAccessors($this);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

看法

\n\n
@foreach($races as $race)\n<tr>\n    <td>{{ $race->accessors->price }}</td>\n    [...]\n</tr>\n@endforeach\n
Run Code Online (Sandbox Code Playgroud)\n\n

我没有在这里为变量设置类型$model,因为您可以将相同的accessors class类型用于需要以与此访问器类相同的方式转换某些字段的其他模型。

\n\n

例如,价格访问器可以适用于 Race(在您的情况下),但它也可以适用于其他模型,这样您就可以想象创建许多模型使用的访问器组,而无需更改太多代码来处理它。

\n