Eloquent: Мутатори
Вступ
Аксесуари та мутатори дозволяють форматувати значення атрибутів Eloquent під час отримання або встановлення їх на екземплярах моделі. Наприклад, ви можете використовуватиШифрувач Laravelщоб зашифрувати значення, коли воно зберігається в базі даних, а потім автоматично розшифрувати атрибут при доступі до нього за моделлю Eloquent.
На додаток до спеціальних аксесуарів та мутаторів, Eloquent може також автоматично передавати поля датиВуглецьекземпляри або навітьперекинути текстові поля в JSON.
Аксесуари та мутатори
Визначення доступу
Щоб визначити аксесуар, створіть файлgetFooAttribute
метод на вашій моделі деFoo
- це "стовбурчаста" назва стовпця, до якого ви хочете отримати доступ. У цьому прикладі ми визначимо аксесуар дляfirst_name
атрибут. Eloquent автоматично намагається викликати аксесуар при спробі отримати значенняfirst_name
атрибут:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get the user's first name.
*
* @param string $value
* @return string
*/
public function getFirstNameAttribute($value)
{
return ucfirst($value);
}
}
Як бачите, вихідне значення стовпця передається користувачеві, що дозволяє маніпулювати та повертати значення. Щоб отримати доступ до значення доступу, ви можете отримати доступ доfirst_name
атрибут на екземплярі моделі:
$user = App\Models\User::find(1);
$firstName = $user->first_name;
Ви також можете використовувати засоби доступу для повернення нових, обчислених значень із існуючих атрибутів:
/**
* Get the user's full name.
*
* @return string
*/
public function getFullNameAttribute()
{
return "{$this->first_name} {$this->last_name}";
}
Якщо ви хочете, щоб ці обчислювані значення були додані до View масиву / JSON вашої моделі,вам потрібно буде їх додати.
Визначення мутатора
Щоб визначити мутатора, визначте asetFooAttribute
метод на вашій моделі деFoo
- це "стовбурчаста" назва стовпця, до якого ви хочете отримати доступ. Отже, знову давайте визначимо мутатора дляfirst_name
атрибут. Цей мутатор буде автоматично викликаний при спробі встановити значенняfirst_name
атрибут на моделі:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Set the user's first name.
*
* @param string $value
* @return void
*/
public function setFirstNameAttribute($value)
{
$this->attributes['first_name'] = strtolower($value);
}
}
Мутатор отримає значення, яке встановлюється в атрибуті, що дозволяє вам маніпулювати значенням і встановлювати маніпульоване значення на внутрішній внутрішній моделі Eloquent$attributes
майно. Так, наприклад, якщо ми намагаємося встановитиfirst_name
приписуватиSally
:
$user = App\Models\User::find(1);
$user->first_name = 'Sally';
У цьому прикладіsetFirstNameAttribute
функція буде викликана зі значеннямSally
. Потім мутатор застосуєstrtolower
функцію до імені та встановіть її результуюче значення у внутрішній$attributes
масив.
Мутатори дати
За замовчуванням Eloquent конвертує файлcreated_at
іupdated_at
columns to instances of Вуглець, що розширює PHPDateTime
класу та надає асортимент корисних методів. Ви можете додати додаткові атрибути дати, встановивши$dates
властивість вашої моделі:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = [
'seen_at',
];
}
Ви можете вимкнути за замовчуваннямcreated_at
іupdated_at
позначки часу, встановлюючи загальнодоступні$timestamps
властивість вашої моделі доfalse
.
Коли стовпець вважається датою, ви можете встановити його значення як позначку часу UNIX, рядок дати (Y-m-d
), рядок дати-часу або aDateTime
/Carbon
інстанції. Значення дати буде правильно перетворено та збережено у вашій базі даних:
$user = App\Models\User::find(1);
$user->deleted_at = now();
$user->save();
Як зазначалося вище, при отриманні атрибутів, перелічених у вашому$dates
власності, вони будуть автоматично передані вВуглецьекземплярів, що дозволяє використовувати будь-який із методів Carbon для своїх атрибутів:
$user = App\Models\User::find(1);
return $user->deleted_at->getTimestamp();
Формати дат
За замовчуванням мітки часу мають формат'Y-m-d H:i:s'
. Якщо вам потрібно налаштувати формат позначки часу, встановіть$dateFormat
властивість на вашій моделі. Ця властивість визначає спосіб зберігання атрибутів дати в базі даних:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
/**
* The storage format of the model's date columns.
*
* @var string
*/
protected $dateFormat = 'U';
}
Casting атрибутів
$casts
властивість на вашій моделі забезпечує зручний метод перетворення атрибутів у загальні типи даних.$casts
властивість має бути масивом, де ключ - це ім'я атрибута, що відтворюється, а значення - тип, до якого ви бажаєте привести стовпець. Підтримувані типи складання:integer
,real
,float
,double
,decimal:<digits>
,string
,boolean
,object
,array
,collection
,date
,datetime
,timestamp
,encrypted
,encrypted:object
,encrypted:array
, іencrypted:collection
. При відливі доdecimal
, ви повинні визначити кількість цифр (decimal:2
).
Щоб продемонструвати Casting атрибутів, давайте додамоis_admin
атрибут, який зберігається в нашій базі даних як ціле число (0
або1
) до логічного значення:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'is_admin' => 'boolean',
];
}
Теперis_admin
атрибут завжди буде передано до логічного значення, коли ви отримаєте до нього доступ, навіть якщо базове значення зберігається в базі даних як ціле число:
$user = App\Models\User::find(1);
if ($user->is_admin) {
//
}
Атрибути, які єnull
не буде кинутий. Крім того, ви ніколи не повинні визначати склад (або атрибут), який має те саме ім'я, що і зв'язок.
Спеціальні Casts
Laravel має безліч вбудованих, корисних типів Casts; однак, іноді вам може знадобитися визначити власні типи акторського складу. Ви можете досягти цього, визначивши клас, який реалізуєCastsAttributes
інтерфейс.
Класи, що реалізують цей інтерфейс, повинні визначати aget
іset
метод.get
Метод відповідає за перетворення вихідного значення з бази даних у додане значення, тоді якset
метод повинен перетворити значення відлиття у вихідне значення, яке можна зберегти в базі даних. Як приклад, ми повторно реалізуємо вбудованийjson
тип лиття як власний тип Casts:
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class Json implements CastsAttributes
{
/**
* Cast the given value.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return array
*/
public function get($model, $key, $value, $attributes)
{
return json_decode($value, true);
}
/**
* Prepare the given value for storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param array $value
* @param array $attributes
* @return string
*/
public function set($model, $key, $value, $attributes)
{
return json_encode($value);
}
}
Після того, як ви визначили власний тип лиття, ви можете додати його до атрибута моделі, використовуючи його назву класу:
<?php
namespace App\Models;
use App\Casts\Json;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'options' => Json::class,
];
}
Casting об’єкта значення
Ви не обмежуєтесь передачею значень до примітивних типів. Ви також можете передавати значення об'єктам. Визначення користувацьких приводів, які передають значення об'єктам, дуже схоже на приведення в примітивні типи; однак,set
Метод повинен повертати масив пар ключ / значення, який буде використовуватися для встановлення необроблених значень, що зберігаються в моделі.
Як приклад, ми визначимо власний клас лиття, який відтворює кілька значень моделі в одинAddress
об'єкт значення. Ми припустимоAddress
value має дві загальнодоступні властивості:lineOne
іlineTwo
:
<?php
namespace App\Casts;
use App\Models\Address as AddressModel;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use InvalidArgumentException;
class Address implements CastsAttributes
{
/**
* Cast the given value.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return \App\Models\Address
*/
public function get($model, $key, $value, $attributes)
{
return new AddressModel(
$attributes['address_line_one'],
$attributes['address_line_two']
);
}
/**
* Prepare the given value for storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param \App\Models\Address $value
* @param array $attributes
* @return array
*/
public function set($model, $key, $value, $attributes)
{
if (! $value instanceof AddressModel) {
throw new InvalidArgumentException('The given value is not an Address instance.');
}
return [
'address_line_one' => $value->lineOne,
'address_line_two' => $value->lineTwo,
];
}
}
Під час Broadcast до об'єктів значення всі зміни, внесені до об'єкта значення, будуть автоматично синхронізовані з моделлю перед збереженням моделі:
$user = App\Models\User::find(1);
$user->address->lineOne = 'Updated Address Value';
$user->save();
Якщо ви плануєте серіалізувати ваші Eloquent моделі, що містять об'єкти значень, у форматі JSON або масиви, вам слід застосуватиIlluminate\Contracts\Support\Arrayable
іJsonSerializable
інтерфейси на об'єкті значення.
Серіалізація масиву / JSON
Коли модель Eloquent перетворюється на масив або JSON за допомогоюtoArray
Метод, ваші користувацькі об'єкти значення додавання, як правило, будуть серіалізовані, доки вони реалізуютьIlluminate\Contracts\Support\Arrayable
іJsonSerializable
інтерфейси. Однак при використанні об'єктів значення, наданих сторонніми бібліотеками, можливо, у вас не буде можливості додавати ці інтерфейси до об'єкта.
Таким чином, ви можете вказати, що ваш власний клас приведення буде відповідати за серіалізацію об'єкта значення. Для цього у вашому користувацькому складі класу має бути реалізованоIlluminate\Contracts\Database\Eloquent\SerializesCastableAttributes
інтерфейс. Цей інтерфейс стверджує, що ваш клас повинен містити файлserialize
метод, який повинен повернути серіалізовану форму вашого об’єкта значення:
/**
* Get the serialized representation of the value.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return mixed
*/
public function serialize($model, string $key, $value, array $attributes)
{
return (string) $value;
}
Вхідний Casting
Іноді вам може знадобитися написати власний привід, який перетворює лише значення, встановлені в моделі, і не виконує жодних операцій, коли атрибути отримуються з моделі. Класичний приклад лише вхідного складу - це хешування. Тільки вхідні спеціальні зливки повинні реалізовуватиCastsInboundAttributes
інтерфейс, який вимагає лишеset
метод, який слід визначити.
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
class Hash implements CastsInboundAttributes
{
/**
* The hashing algorithm.
*
* @var string
*/
protected $algorithm;
/**
* Create a new cast class instance.
*
* @param string|null $algorithm
* @return void
*/
public function __construct($algorithm = null)
{
$this->algorithm = $algorithm;
}
/**
* Prepare the given value for storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param array $value
* @param array $attributes
* @return string
*/
public function set($model, $key, $value, $attributes)
{
return is_null($this->algorithm)
? bcrypt($value)
: hash($this->algorithm, $value);
}
}
Параметри лиття
Під час приєднання користувацького приведення до моделі параметри приведення можуть бути вказані, відокремлюючи їх від імені класу, використовуючи a:
символом та кількома параметрами, що розмежовують комами. Параметри передаються конструктору класу Casts:
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'secret' => Hash::class.':sha256',
];
Кастеблі
Замість того, щоб приєднувати спеціальний привід до вашої моделі, ви можете альтернативно приєднати клас, який реалізуєIlluminate\Contracts\Database\Eloquent\Castable
інтерфейс:
protected $casts = [
'address' => \App\Models\Address::class,
];
Об'єкти, що реалізуютьCastable
інтерфейс повинен визначати acastUsing
метод, який повертає ім'я класу спеціального класу заклинателя, який відповідає за Broadcast до та зCastable
клас:
<?php
namespace App\Models;
use Illuminate\Contracts\Database\Eloquent\Castable;
use App\Casts\Address as AddressCast;
class Address implements Castable
{
/**
* Get the name of the caster class to use when casting from / to this cast target.
*
* @param array $arguments
* @return string
*/
public static function castUsing(array $arguments)
{
return AddressCast::class;
}
}
При використанніCastable
класів, ви все ще можете наводити аргументи в$casts
визначення. Аргументи будуть передані безпосередньо до класу заклинача:
protected $casts = [
'address' => \App\Models\Address::class.':argument',
];
Масив та JSON-Casting
array
тип приведення особливо корисний при роботі зі стовпцями, які зберігаються як серіалізовані JSON. Наприклад, якщо у вашій базі даних є файлJSON
абоTEXT
тип поля, що містить серіалізований JSON, додаючиarray
прив'язка до цього атрибуту автоматично десеріалізує атрибут до масиву PHP, коли ви отримуєте доступ до нього на вашій Eloquentй моделі:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'options' => 'array',
];
}
Після визначення акторського складу ви можете отримати доступ доoptions
атрибут, і він буде автоматично десеріалізований з JSON у масив PHP. Коли ви встановлюєте значенняoptions
атрибут, даний масив буде автоматично серіалізований назад у JSON для зберігання:
$user = App\Models\User::find(1);
$options = $user->options;
$options['key'] = 'value';
$user->options = $options;
$user->save();
Щоб оновити одне поле атрибута JSON з більш стислим синтаксисом, ви можете використовувати файл->
оператор:
$user = App\Models\User::find(1);
$user->update(['options->key' => 'value']);
Дата Casting
При використанніdate
or datetime
тип касту, ви можете вказати формат дати. Цей формат буде використовуватися, колимодель серіалізується до масиву або JSON:
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'created_at' => 'datetime:Y-m-d',
];
Час запиту
Іноді вам може знадобитися застосувати закиди під час виконання запиту, наприклад, при виборі вихідного значення з таблиці. Наприклад, розглянемо такий запит:
use App\Models\Post;
use App\Models\User;
$users = User::select([
'users.*',
'last_posted_at' => Post::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id')
])->get();
last_posted_at
attribute on the results of this query will be a raw string. It would be convenient if we could apply a date
прив'язка до цього атрибута під час виконання запиту. Для цього ми можемо використовуватиwithCasts
метод:
$users = User::select([
'users.*',
'last_posted_at' => Post::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id')
])->withCasts([
'last_posted_at' => 'datetime'
])->get();