在Laravel Eloquent模型中创建动态命名的mutators

8

我有一个日期字段列表,它们所有的mutators都具有相同的逻辑。我想把这个功能提取到一个trait中,以便将来只需要在模型中创建一个日期字段数组并使用trait即可。

像这样:

foreach( $dates as $date ) {
    $dateCamelCase = $this->dashesToUpperCase($date);
    $setDateFunctionName ='set'.$dateCamelCase.'Attribute';
    $this->{$setDateFunctionName} = function()  use($date) {
        $this->attributes[$date] = date( 'Y-m-d', strtotime( $date ));
    };
}

展示一些代码和你目前的尝试。 - Steve
我尝试的方法已经添加 - shaswa
1
@shaswa 你解决了吗?我遇到了类似的情况,正在尝试相同的方法。如果你解决了,请告诉我。 - Donkarnash
@Donkarnash:我还没有做到。由于时间紧迫,不得不为模型中的每个字段定义一个mutator。 - shaswa
1个回答

14

在回答您的具体问题之前,让我们先了解一下Eloquent mutators是如何工作的。

Eloquent mutator的工作原理

所有Eloquent Model派生类都有它们自己的__set()offsetSet()方法来调用setAttribute方法来设置属性值并在需要时进行转换。

在设置值之前,它会检查:

  • 自定义mutator方法
  • 日期字段
  • JSON可转换和字段

利用该过程

通过了解这一点,我们可以简单地利用该过程并用我们自己的自定义逻辑来超载它。以下是一个实现示例:

<?php

namespace App\Models\Concerns;

use Illuminate\Database\Eloquent\Concerns\HasAttributes;

trait MutatesDatesOrWhatever
{
    public function setAttribute($key, $value)
    {
        // Custom mutation logic goes here before falling back to framework's 
        // implementation. 
        //
        // In your case, you need to check for date fields and mutate them 
        // as you wish. I assume you have put your date field names in the 
        // `$dates` model property and so we can utilize Laravel's own 
        // `isDateAttribute()` method here.
        //
        if ($value && $this->isDateAttribute($key)) {
            $value = date('Y-m-d', strtotime($value));
        }

        // Handover the rest to Laravel's own setAttribute(), so that other
        // mutators will remain intact...
        return parent::setAttribute($key, $value);
    }
}

毋庸置疑,你的模型需要使用这个特性来启用功能。

你不会需要它

如果 变换日期格式 是你唯一需要使用 "动态命名变换器" 的用例,那么这并不是必需的。正如你已经注意到的,Eloquent的日期字段可以被 Laravel 本身重新格式化:

class Whatever extends Model 
{
    protected $dates = [
        'date_field_1', 
        'date_field_2', 
        // ...
    ];

    protected $dateFormat = 'Y-m-d';
}

所有列出的字段将按照$dateFormat的格式进行格式化。那么我们就不要重复造轮子了。


如果有人需要重复使用访问器/修改器,你可能会对Eloquent Mutators感兴趣。请访问https://github.com/topclaudy/eloquent-mutators了解更多信息。 - topclaudy
你可以在模型中定义类型转换,这样做简洁优雅:protected $casts = [ 'your_field' => 'datetime:d/m/Y H:i:s', ]; - manuel-84
创建多个动态变异器Trait会多次调用model parent :: setAttribute吗? - Manpreet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接