Под капотом: как работают атрибуты модели в Laravel

Атрибуты модели Laravel в основном представляют поля базы данных для данной модели. Когда данные извлекаются из базы данных, к ним можно получить доступ через модель, поскольку они были фактическими свойствами экземпляра модели: $model->database_column_name.

Однако атрибуты не являются реальными свойствами экземпляра, а хранятся в защищенном $attributes свойстве.

Доступ к атрибутам осуществляется с помощью метода _ _ get magic. Это позволяет делать с ними некоторые классные вещи, такие как мутации и кастинг.

Как работать с моделями можно посмотреьт в документации. Что я хотел бы показать, так это то, как эти вещи работают, а также некоторые хитрости и предостережения.

Трейт HasAttributes

Этот трейт заботится об обработке атрибутов модели, поэтому давайте посмотрим, что происходит при доступе к атрибуту модели:

  • Волшебный __get метод использует getAttribute метод для извлечения значения
  • Если запрошенный ключ существует в $attributes, он проверяет, существует ли он:
    • имеет аццессор (accessor)
    • определен ли как каст (cast)
    • определен ли как дата

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

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

Очевидно, что вы можете использовать castAttribute и asDateTime методы в вашем accessor. Я оставил здесь соответствующую часть кода:

public function getAttributeValue($key)
{
    $value = $this->getAttributeFromArray($key);

    // If the attribute has a get mutator, we will call that then return what
    // it returns as the value, which is useful for transforming values on
    // retrieval from the model to a form that is more useful for usage.
    if ($this->hasGetMutator($key)) {
        return $this->mutateAttribute($key, $value);
    }

    // If the attribute exists within the cast array, we will convert it to
    // an appropriate native PHP type dependant upon the associated value
    // given with the key in the pair. Dayle made this comment line up.
    if ($this->hasCast($key)) {
        return $this->castAttribute($key, $value);
    }

    // If the attribute is listed as a date, we will convert it to a DateTime
    // instance on retrieval, which makes it quite convenient to work with
    // date fields without having to create a mutator for each property.
    if (in_array($key, $this->getDates()) &&
        ! is_null($value)) {
        return $this->asDateTime($value);
    }

    return $value;
}

Сеттеры работают аналогично тому, как я описал выше для геттеров. Установка атрибута вызывает setAttribute метод с помощью магического метода __set.

Порядок исполнения аналогичен тому, что мы видели у геттеров:

  • вызовается мутатор, если он существует. То же самое правило применяется и здесь, Если у вас есть мутатор, вы должны позаботиться о типе casts самостоятельно, так как это не произойдет автоматически
  • приводим к дате, если она определена для данного атрибута
  • приводим к json, если это необходимо для атрибута
  • если ключ атрибута содержит‘ ->’, он автоматически установит правильное значение в базовом массиве атрибута

Вы можете увидеть соответствующий код здесь:

public function setAttribute($key, $value)
{
    // First we will check for the presence of a mutator for the set operation
    // which simply lets the developers tweak the attribute as it is set on
    // the model, such as "json_encoding" an listing of data for storage.
    if ($this->hasSetMutator($key)) {
        return $this->setMutatedAttributeValue($key, $value);
    }

    // If an attribute is listed as a "date", we'll convert it from a DateTime
    // instance into a form proper for storage on the database tables using
    // the connection grammar's date format. We will auto set the values.
    elseif ($value && $this->isDateAttribute($key)) {
        $value = $this->fromDateTime($value);
    }

    if ($this->isJsonCastable($key) && ! is_null($value)) {
        $value = $this->castAttributeAsJson($key, $value);
    }

    // If this attribute contains a JSON ->, we'll set the proper value in the
    // attribute's underlying array. This takes care of properly nesting an
    // attribute in the array's value in the case of deeply nested items.
    if (Str::contains($key, '->')) {
        return $this->fillJsonAttribute($key, $value);
    }

    $this->attributes[$key] = $value;

    return $this;
}

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

Рейтинг
( 6 оценок, среднее 5 из 5 )
Maxyc Webber/ автор статьи
Мне 35 лет. Опыт профессиональной разработки 15 лет. Занимаюсь разработкой и поддержкой корпоративных систем автоматизации бизнеса, а также высоконагруженными проектами. Мне нравится решать нестандартные проблемы бизнеса. Имею опыт формирования команд под проект, налаживания процесса разработки, коммуникации программистов и заказчиков. Есть опыт работы с зарубежными заказчиками (ОАЭ, Польша, Германия, Швейцария).
Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.