Как создать универсальный геттер / мутатор для datetime в Laravel?

Я создал один, и я подумал, что это работает:

<?php

namespace App\Traits;

use Carbon\Carbon;

trait FormatDates
{

    public function setAttribute($key, $value)
    {
        parent::setAttribute($key, $value);

        if (strtotime($value))
            $this->attributes[$key] = Carbon::parse($value);
    }
}

Но есть проблема при вызове связанных моделей. Например, если у вас есть модель Article и Tag, и вы хотите получить все теги, подобные этому:

$article->tags

это возвращается null из-за этого мутатора-геттера.

Как это исправить?


обновление 17.11.2017

Я нашел решение своей проблемы. Лучший способ представить дату в локали - использовать эту функцию:

\Carbon\Carbon::setToStringFormat("d.m.Y H:i");

просто создайте поставщика услуг или промежуточное программное обеспечение, и оно покажет все $ даты в нужном вам формате. Нет необходимости делать геттер.

2 ответа

Решение

Исходя из этого: https://laravel.com/api/5.5/Illuminate/Database/Eloquent/Concerns/HasAttributes.html

В описании сказано:

Получить простой атрибут (не отношения).

К счастью, под ним есть еще два метода, называемые getRelationValue и getRelationshipFromMethod, и он читает:

Получить отношения.

Получить значение отношения из метода.

соответственно.

И в вашем примере, похоже, вы называете отношение.

Я думаю, что вы должны учитывать это при выполнении вашего универсального геттера / мутатора.

ОБНОВИТЬ:

Если вы проверяете код, getAttribute также называет getRelationValue метод. Но это последнее средство функции; если ключ не является ни атрибутом, ни мутатором, ни методом класса.

Вот заглушка: https://github.com/laravel/framework/blob/5.5/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php

/**
 * Get an attribute from the model.
 *
 * @param  string  $key
 * @return mixed
 */
public function getAttribute($key)
{
    if (! $key) {
        return;
    }
    // If the attribute exists in the attribute array or has a "get" mutator we will
    // get the attribute's value. Otherwise, we will proceed as if the developers
    // are asking for a relationship's value. This covers both types of values.
    if (array_key_exists($key, $this->attributes) ||
        $this->hasGetMutator($key)) {
        return $this->getAttributeValue($key);
    }
    // Here we will determine if the model base class itself contains this given key
    // since we don't want to treat any of those methods as relationships because
    // they are all intended as helper methods and none of these are relations.
    if (method_exists(self::class, $key)) {
        return;
    }
    return $this->getRelationValue($key);
}

ДРУГОЕ ОБНОВЛЕНИЕ

Поскольку вы изменили свой вопрос:

Вы можете просто поставить имя атрибута $casts или же $dates массив (в вашей модели), поэтому Laravel автоматически преобразует его в Carbon экземпляр при доступе к нему, вот так:

class Article extends Model {
    ...
    protected $dates = ['some_date_attribute`];

или с $casts

    ...
    protected $casts = ['some_date_attributes' => 'date'];

Вы действительно можете избежать этого, это уже там!

На модели класса вы можете сделать:

protected $dates = ['nameOfTheDateOrTimestampTypeField','nameOfAnotherOne'];
Другие вопросы по тегам