Атрибуты модели 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;
}
Причина написания этой статьи заключалась в том, что у меня уже была ситуация, когда потребовалось некоторое время отладки, чтобы выяснить, что вызвало проблему в приложении, потому что я не был уверен, что касты не запускаются при использовании методов доступа.