Создание динамически названных мутаторов в моделях Laravel Eloquent

У меня есть список полей даты, и все они имеют одинаковую логику в своих мутаторах. Я хотел бы извлечь эту функциональность из признака, чтобы в будущем все, что мне было нужно, - это создать массив полей даты в модели и использовать признак.

Что-то вроде этого:

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 ));
    };
}

1 ответ

Решение

Прежде чем ответить на ваш конкретный вопрос, давайте сначала посмотрим, как работают мутаторы Eloquent.

Как работают красноречивые мутаторы

Все красноречиво Model классы имеют свои __set() а также offsetSet() методы для вызова setAttribute метод, который заботится об установке значения атрибута и его изменении, если это необходимо.

Перед установкой значения он проверяет:

  • Пользовательские методы мутатора
  • Поля даты
  • JSON Castables и поля

Нажав на процесс

Поняв это, мы можем просто подключиться к процессу и перегрузить его нашей собственной логикой. Вот реализация:

<?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, Давайте не будем изобретать колесо тогда.

Другие вопросы по тегам