Версія фреймворка: 8.x

Eloquent: Початок роботи

Вступ

Eloquent ORM, що входить до складу Laravel, забезпечує чудову, просту реалізацію ActiveRecord для роботи з вашою базою даних. Кожна таблиця бази даних має відповідну "Модель", яка використовується для взаємодії з цією таблицею. Моделі дозволяють запитувати дані у ваших таблицях, а також вставляти нові записи до таблиці.

Перед початком роботи обов’язково налаштуйте підключення до бази даних уconfig/database.php. Щоб отримати додаткову інформацію про налаштування бази даних, ознайомтесь із цимдокументація.

Визначення моделей

Для початку давайте створимо Eloquent модель. Моделі зазвичай живуть вapp\Modelsкаталог, але ви можете вільно розміщувати їх у будь-якому місці, яке можна автоматично завантажити відповідно до вашогоcomposer.jsonфайл. Всі моделі Eloquent розширюютьсяIlluminate\Database\Eloquent\Modelклас.

Найпростіший спосіб створити екземпляр моделі - використовуватиmake:modelartisan командування:

php artisan make:model Flight

Якщо ви хочете створити файлміграція баз данихколи ви генеруєте модель, ви можете використовувати--migrationабо-mваріант:

php artisan make:model Flight --migration

php artisan make:model Flight -m

Ви можете генерувати різні інші типи класів під час створення моделі, такі як Factory, сівалки та контролери. Крім того, ці параметри можна комбінувати для створення декількох класів одночасно:

php artisan make:model Flight --factory
php artisan make:model Flight -f

php artisan make:model Flight --seed
php artisan make:model Flight -s

php artisan make:model Flight --controller
php artisan make:model Flight -c

php artisan make:model Flight -mfsc

Eloquent модельні конвенції

Тепер давайте розглянемо прикладFlightмодель, яку ми будемо використовувати для отримання та збереження інформації з нашогоflightsтаблиця бази даних:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    //
}

Назви таблиць

Зверніть увагу, що ми не говорили Eloquent, яку таблицю використовувати для нашоїFlightмодель. За домовленістю, "змієний випадок", множинне ім'я класу буде використовуватися як ім'я таблиці, якщо інше ім'я не вказано явно. Отже, у цьому випадку Eloquent припуститьFlightмодель зберігає записи вflightsтаблиці, тоді як anAirTrafficControllerмодель буде зберігати записи вair_traffic_controllersтаблиця.

Ви можете вручну вказати назву таблиці, визначивши atableвластивість на вашій моделі:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'my_flights';
}

Первинні ключі

Eloquent також припустить, що кожна таблиця має стовпець первинного ключа з іменемid. Ви можете визначити захищений$primaryKeyвластивість замінити цю конвенцію:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * The primary key associated with the table.
     *
     * @var string
     */
    protected $primaryKey = 'flight_id';
}

Крім того, Eloquent припускає, що первинний ключ - це ціле число, що збільшується, а це означає, що за замовчуванням первинний ключ буде автоматично переданий доint. Якщо ви хочете використовувати первинний ключ, що не збільшується або не числовий, ви повинні встановити загальнодоступний$incrementingвластивість на вашій моделі доfalse:

<?php

class Flight extends Model
{
    /**
     * Indicates if the IDs are auto-incrementing.
     *
     * @var bool
     */
    public $incrementing = false;
}

Якщо ваш первинний ключ не є цілим числом, вам слід встановити захищений$keyTypeвластивість на вашій моделі доstring:

<?php

class Flight extends Model
{
    /**
     * The "type" of the auto-incrementing ID.
     *
     * @var string
     */
    protected $keyType = 'string';
}

Мітки часу

За замовчуванням Eloquent очікуєcreated_atіupdated_atстовпців, які існують у ваших таблицях. Якщо ви не хочете, щоб ці стовпці автоматично керувалися Eloquent, встановіть$timestampsвластивість на вашій моделі доfalse:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public $timestamps = false;
}

Якщо вам потрібно налаштувати формат міток часу, встановіть$dateFormatвластивість на вашій моделі. Ця властивість визначає, як атрибути дати зберігаються в базі даних, а також їх формат, коли модель серіалізована до масиву або JSON:

<?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';
}

Якщо вам потрібно налаштувати імена стовпців, що використовуються для зберігання міток часу, ви можете встановитиCREATED_ATіUPDATED_ATконстанти у вашій моделі:

<?php

class Flight extends Model
{
    const CREATED_AT = 'creation_date';
    const UPDATED_AT = 'last_update';
}

Підключення до бази даних

За замовчуванням усі моделі Eloquent будуть використовувати підключення до бази даних за замовчуванням, налаштоване для вашої програми. Якщо ви хочете вказати інше з'єднання для моделі, використовуйте$connectionвластивість:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * The connection name for the model.
     *
     * @var string
     */
    protected $connection = 'connection-name';
}

Значення атрибута за замовчуванням

Якщо ви хочете визначити значення за замовчуванням для деяких атрибутів вашої моделі, ви можете визначити$attributesвластивість на вашій моделі:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * The model's default values for attributes.
     *
     * @var array
     */
    protected $attributes = [
        'delayed' => false,
    ];
}

Отримання моделей

Після того, як ви створили модель івідповідну таблицю бази даних, ви готові розпочати отримання даних із вашої бази даних. Подумайте про кожну Eloquent модель як про потужнуконструктор запитівщо дозволяє вільно запитувати таблицю бази даних, пов’язану з моделлю. Наприклад:

<?php

$flights = App\Models\Flight::all();

foreach ($flights as $flight) {
    echo $flight->name;
}

Додавання додаткових обмежень

Eloquentallметод поверне всі результати в таблиці моделі. Оскільки кожна Eloquent модель виконує функціїконструктор запитів, Ви також можете додати обмеження до запитів, а потім використовуватиgetспосіб отримання результатів:

$flights = App\Models\Flight::where('active', 1)
               ->orderBy('name', 'desc')
               ->take(10)
               ->get();
Оскільки Eloquent моделі створюють запити, вам слід переглянути всі методи, доступні вконструктор запитів. Ви можете використовувати будь-який із цих методів у своїх Eloquent запитах.

Освіжаючі моделі

Ви можете оновити моделі за допомогоюfreshіrefreshметоди.freshметод знову отримає модель із бази даних. На існуючий екземпляр моделі це не вплине:

$flight = App\Models\Flight::where('number', 'FR 900')->first();

$freshFlight = $flight->fresh();

refreshметод повторно гідратує існуючу модель, використовуючи свіжі дані з бази даних. Крім того, оновлять також усі його завантажені зв'язки:

$flight = App\Models\Flight::where('number', 'FR 900')->first();

$flight->number = 'FR 456';

$flight->refresh();

$flight->number; // "FR 900"

Колекції

Для Eloquent методів типуallіgetякі отримують кілька результатів, екземплярIlluminate\Database\Eloquent\Collectionбуде повернено.Collectionклас забезпечуєрізноманітні корисні методидля роботи з вашими Eloquent результатами:

$flights = $flights->reject(function ($flight) {
    return $flight->cancelled;
});

Ви також можете прокрутити колекцію як масив:

foreach ($flights as $flight) {
    echo $flight->name;
}

Результати Chunking

Якщо вам потрібно обробити тисячі Eloquent записів, використовуйтеchunkкоманди.chunkметод отримає "шматок" Eloquent моделей, подаючи їх заданомуClosureдля переробки. Використанняchunkметод збереже пам'ять при роботі з великими наборами результатів:

Flight::chunk(200, function ($flights) {
    foreach ($flights as $flight) {
        //
    }
});

Першим аргументом, що передається методу, є кількість записів, які ви хочете отримати за "шматок". Закриття, передане як другий аргумент, буде викликатися для кожного фрагмента, який отримується з бази даних. Буде виконано запит до бази даних, щоб отримати кожен шматок записів, переданих до Закриття.

Якщо ви фільтруєте результатиchunkметод, заснований на стовпці, який ви також будете оновлювати, переглядаючи результати, вам слід використовуватиchunkByIdметод. Використанняchunkметод у цих сценаріях може призвести до несподіваних і суперечливих результатів:

Flight::where('departed', true)->chunkById(200, function ($flights) {
    $flights->each->update(['departed' => false]);
});

Використання курсорів

cursorМетод дозволяє переглядати записи бази даних за допомогою курсору, який виконуватиме лише один запит. При обробці великих обсягів даних файлcursorметод може бути використаний для значного зменшення використання пам'яті:

foreach (Flight::where('foo', 'bar')->cursor() as $flight) {
    //
}

cursorповертаєIlluminate\Support\LazyCollectionекземпляр.Lazy колекціїдозволяють використовувати багато методів збирання, доступних у типових колекціях Laravel, одночасно завантажуючи в пам’ять лише одну модель:

$users = App\Models\User::cursor()->filter(function ($user) {
    return $user->id > 500;
});

foreach ($users as $user) {
    echo $user->id;
}

Розширені підзапити

Вибір підзапиту

Eloquent також пропонує розширену підтримку підзапитів, яка дозволяє витягувати інформацію з відповідних таблиць в одному запиті. Наприклад, уявімо, що у нас є таблиця польотуdestinationsі таблицяflightsдо пунктів призначення.flightsтаблиця міститьarrived_atграфа, яка вказує, коли рейс прибув у пункт призначення.

Використовуючи функціональність підзапиту, доступну дляselectіaddSelectметоди, ми можемо вибрати всіdestinationsі назва рейсу, який нещодавно прибув у цей пункт призначення за допомогою одного запиту:

use App\Models\Destination;
use App\Models\Flight;

return Destination::addSelect(['last_flight' => Flight::select('name')
    ->whereColumn('destination_id', 'destinations.id')
    ->orderBy('arrived_at', 'desc')
    ->limit(1)
])->get();

Впорядкування підзапитів

Крім того, запит будівельникаorderByфункція підтримує підзапити. Ми можемо використовувати цю функцію для сортування всіх пунктів призначення на основі того, коли останній рейс прибув у цей пункт призначення. Знову ж таки, це можна зробити під час виконання одного запиту до бази даних:

return Destination::orderByDesc(
    Flight::select('arrived_at')
        ->whereColumn('destination_id', 'destinations.id')
        ->orderBy('arrived_at', 'desc')
        ->limit(1)
)->get();

Отримання одиночних моделей / агрегатів

На додаток до отримання всіх записів для даної таблиці, ви також можете отримати окремі записи за допомогоюfind,first, абоfirstWhere. Замість повернення колекції моделей ці методи повертають один екземпляр моделі:

// Retrieve a model by its primary key...
$flight = App\Models\Flight::find(1);

// Retrieve the first model matching the query constraints...
$flight = App\Models\Flight::where('active', 1)->first();

// Shorthand for retrieving the first model matching the query constraints...
$flight = App\Models\Flight::firstWhere('active', 1);

Ви також можете зателефонувати доfindметод з масивом первинних ключів, який поверне колекцію відповідних записів:

$flights = App\Models\Flight::find([1, 2, 3]);

Іноді вам може знадобитися отримати перший результат запиту або виконати якусь іншу дію, якщо результатів не знайдено.firstOrметод поверне перший знайдений результат або, якщо результатів не знайдено, виконає заданий зворотний виклик. Результат зворотного виклику буде вважатися результатомfirstOrметод:

$model = App\Models\Flight::where('legs', '>', 100)->firstOr(function () {
        // ...
});

firstOrметод також приймає масив стовпців для отримання:

$model = App\Models\Flight::where('legs', '>', 100)
            ->firstOr(['id', 'legs'], function () {
                // ...
            });

Не знайдено винятків

Іноді, можливо, ви захочете створити виняток, якщо модель не знайдено. Це особливо корисно в маршрутах або контролерах.findOrFailіfirstOrFailметоди отримують перший результат запиту; однак, якщо результату не знайдено, символIlluminate\Database\Eloquent\ModelNotFoundExceptionбуде кинуто:

$model = App\Models\Flight::findOrFail(1);

$model = App\Models\Flight::where('legs', '>', 100)->firstOrFail();

Якщо виняток не вловлюється, a404Відповідь HTTP автоматично надсилається назад користувачеві. Для повернення не потрібно писати явні чеки404відповіді при використанні цих методів:

Route::get('/api/flights/{id}', function ($id) {
    return App\Models\Flight::findOrFail($id);
});

Отримання агрегатів

Ви також можете використовуватиcount,sum,max, і іншіагреговані методинаданіконструктор запитів. Ці методи повертають відповідне скалярне значення замість повного екземпляра моделі:

$count = App\Models\Flight::where('active', 1)->count();

$max = App\Models\Flight::where('active', 1)->max('price');

Вставка та оновлення моделей

Вставки

Щоб створити новий запис у базі даних, створіть новий екземпляр моделі, встановіть атрибути на моделі, а потім викликайтеsaveметод:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Flight;
use Illuminate\Http\Request;

class FlightController extends Controller
{
    /**
     * Create a new flight instance.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Validate the request...

        $flight = new Flight;

        $flight->name = $request->name;

        $flight->save();
    }
}

У цьому прикладі ми призначаємоnameз вхідного HTTP-запиту наnameатрибутApp\Models\Flightекземпляр моделі. Коли ми телефонуємо доsaveметод, запис буде вставлений у базу даних.created_atіupdated_atпозначки часу будуть автоматично встановлені, колиsaveметод, тому немає необхідності встановлювати їх вручну.

Оновлення

saveметод також може бути використаний для оновлення моделей, які вже існують у базі даних. Щоб оновити модель, вам слід отримати її, встановити будь-які атрибути, які ви хочете оновити, а потім зателефонувати доsaveметод. Знову ж такиupdated_atпозначка часу буде автоматично оновлена, тому немає необхідності встановлювати її значення вручну:

$flight = App\Models\Flight::find(1);

$flight->name = 'New Flight Name';

$flight->save();

Масові оновлення

Оновлення також можна виконати для будь-якої кількості моделей, які відповідають даному запиту. У цьому прикладі всі рейси, які єactiveі матиdestinationзSan Diegoбуде позначено як відкладене:

App\Models\Flight::where('active', 1)
          ->where('destination', 'San Diego')
          ->update(['delayed' => 1]);

updateметод очікує масив пар стовпців і значень, що представляють стовпці, які слід оновити.

Під час масового оновлення через Eloquent,saving,saved,updating, іupdatedподії моделей не запускатимуться для оновлених моделей. Це тому, що моделі фактично ніколи не отримуються під час масового оновлення.

Вивчення змін атрибутів

Eloquent забезпечуєisDirty,isClean, іwasChangedметоди для вивчення внутрішнього стану вашої моделі та визначення того, як змінилися її атрибути в порівнянні з початковим завантаженням.

isDirtyМетод визначає, чи були змінені будь-які атрибути після завантаження моделі. Ви можете передати конкретну назву атрибута, щоб визначити, чи певний атрибут забруднений.isCleanметод протилежнийisDirtyа також приймає необов'язковий аргумент атрибута:

$user = User::create([
    'first_name' => 'Taylor',
    'last_name' => 'Otwell',
    'title' => 'Developer',
]);

$user->title = 'Painter';

$user->isDirty(); // true
$user->isDirty('title'); // true
$user->isDirty('first_name'); // false

$user->isClean(); // false
$user->isClean('title'); // false
$user->isClean('first_name'); // true

$user->save();

$user->isDirty(); // false
$user->isClean(); // true

wasChangedМетод визначає, чи були змінені будь-які атрибути, коли модель востаннє зберігалась у межах поточного циклу запиту. Ви також можете передати ім'я атрибута, щоб побачити, чи було змінено певний атрибут:

$user = User::create([
    'first_name' => 'Taylor',
    'last_name' => 'Otwell',
    'title' => 'Developer',
]);

$user->title = 'Painter';
$user->save();

$user->wasChanged(); // true
$user->wasChanged('title'); // true
$user->wasChanged('first_name'); // false

getOriginalМетод повертає масив, що містить вихідні атрибути моделі, незалежно від будь-яких змін після завантаження моделі. Ви можете передати конкретну назву атрибута, щоб отримати вихідне значення певного атрибута:

$user = User::find(1);

$user->name; // John
$user->email; // john@example.com

$user->name = "Jack";
$user->name; // Jack

$user->getOriginal('name'); // John
$user->getOriginal(); // Array of original attributes...

Масове призначення

Ви також можете використовуватиcreateметод збереження нової моделі в один рядок. Вставлений примірник моделі буде повернено вам із методу. Однак перед цим вам потрібно буде вказати абоfillableабоguardedатрибут на моделі, оскільки всі моделі Eloquent за замовчуванням захищають від масового призначення.

Уразливість масового призначення виникає, коли користувач передає несподіваний параметр HTTP через запит, і цей параметр змінює стовпець у вашій базі даних, якого ви не очікували. Наприклад, зловмисний користувач може надіслати файлis_adminпараметру через HTTP-запит, який потім передається у вашу модельcreateметод, що дозволяє користувачеві перейти до адміністратора.

Отже, для початку слід визначити, які атрибути моделі ви хочете зробити масовим присвоюваним. Ви можете зробити це за допомогою$fillableвластивість на моделі. Наприклад, давайте зробимоnameатрибут нашогоFlightмодель, яка може призначатися:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name'];
}

Після того, як ми зробили атрибути масовими, їх можна призначити, ми можемо використовуватиcreateметод для вставки нового запису в базу даних.createметод повертає збережений примірник моделі:

$flight = App\Models\Flight::create(['name' => 'Flight 10']);

Якщо у вас вже є екземпляр моделі, ви можете використовуватиfillметод, щоб заповнити його масивом атрибутів:

$flight->fill(['name' => 'Flight 22']);

Масове призначення та стовпці JSON

При призначенні стовпців JSON у коді вашої моделі повинен бути вказаний ключ, що призначається масі кожного стовпця$fillableмасив. З міркувань безпеки Laravel не підтримує оновлення вкладених атрибутів JSON під час використанняguardedвластивість:

/**
 * The attributes that are mass assignable.
 *
 * @var array
 */
$fillable = [
    'options->enabled',
];

Дозвіл масового призначення

Якщо ви хочете зробити всі атрибути масовими, можна визначити,$guardedвластивість як порожній масив:

/**
 * The attributes that aren't mass assignable.
 *
 * @var array
 */
protected $guarded = [];

Інші методи створення

firstOrCreate/firstOrNew

Існує ще два методи, які ви можете використовувати для створення моделей шляхом масового присвоєння атрибутів:firstOrCreateіfirstOrNew.firstOrCreateметод спробує знайти запис бази даних за допомогою заданих пар стовпець / значення. Якщо модель не вдається знайти в базі даних, буде вставлено запис із атрибутами з першого параметра, а також із необов’язковим другим параметром.

firstOrNewметод, якfirstOrCreateспробує знайти запис у базі даних, що відповідає заданим атрибутам. Однак, якщо модель не знайдено, буде повернено новий екземпляр моделі. Зверніть увагу, що модель повернутаfirstOrNewще не збережено в базі даних. Вам потрібно буде зателефонуватиsaveвручну, щоб зберегти його:

// Retrieve flight by name, or create it if it doesn't exist...
$flight = App\Models\Flight::firstOrCreate(['name' => 'Flight 10']);

// Retrieve flight by name, or create it with the name, delayed, and arrival_time attributes...
$flight = App\Models\Flight::firstOrCreate(
    ['name' => 'Flight 10'],
    ['delayed' => 1, 'arrival_time' => '11:30']
);

// Retrieve by name, or instantiate...
$flight = App\Models\Flight::firstOrNew(['name' => 'Flight 10']);

// Retrieve by name, or instantiate with the name, delayed, and arrival_time attributes...
$flight = App\Models\Flight::firstOrNew(
    ['name' => 'Flight 10'],
    ['delayed' => 1, 'arrival_time' => '11:30']
);

updateOrCreate

Ви також можете зіткнутися з ситуаціями, коли ви хочете оновити існуючу модель або створити нову модель, якщо такої немає. Laravel пропонуєupdateOrCreateметод зробити це за один крок. ПодобаєтьсяfirstOrCreateметод,updateOrCreateмодель зберігається, тому дзвонити не потрібноsave():

// If there's a flight from Oakland to San Diego, set the price to $99...
// If no matching model exists, create one...
$flight = App\Models\Flight::updateOrCreate(
    ['departure' => 'Oakland', 'destination' => 'San Diego'],
    ['price' => 99, 'discounted' => 1]
);

Якщо ви хочете виконати кілька "виправлень" в одному запиті, тоді вам слід використовуватиupsertзамість цього. Перший аргумент методу складається зі значень, які потрібно вставити або оновити, тоді як другий аргумент містить перелік стовпців (колонок), які однозначно ідентифікують записи в асоційованій таблиці. Третім і остаточним аргументом методу є масив стовпців, який слід оновити, якщо відповідний запис уже існує в базі даних.upsertметод автоматично встановитьcreated_atіupdated_atмітки часу, якщо на моделі ввімкнено мітки часу:

App\Models\Flight::upsert([
    ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
    ['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);
Для всіх баз даних, крім SQL Server, потрібні стовпці у другому аргументіupsertметод, щоб мати "первинний" або "унікальний" індекс.

Видалення моделей

Щоб видалити модель, зателефонуйте наdeleteметод на екземплярі моделі:

$flight = App\Models\Flight::find(1);

$flight->delete();

Видалення існуючої моделі за ключем

У наведеному вище прикладі ми отримуємо модель із бази даних перед викликомdeleteметод. Однак, якщо ви знаєте первинний ключ моделі, ви можете видалити модель без явного отримання, зателефонувавши доdestroyметод. На додаток до одного первинного ключа як аргументу,destroyметод приймає кілька первинних ключів, масив первинних ключів або aколекціяпервинних ключів:

App\Models\Flight::destroy(1);

App\Models\Flight::destroy(1, 2, 3);

App\Models\Flight::destroy([1, 2, 3]);

App\Models\Flight::destroy(collect([1, 2, 3]));
destroyметод завантажує кожну модель окремо і викликаєdeleteметод на них, так щоdeletingіdeletedподії звільняються.

Видалення моделей за запитом

Ви також можете запустити оператор видалення на наборі моделей. У цьому прикладі ми видалимо всі рейси, позначені як неактивні. Як і масові оновлення, масові видалення не запускатимуть події моделі для моделей, які видаляються:

$deletedRows = App\Models\Flight::where('active', 0)->delete();
При виконанні оператора масового видалення за допомогою Eloquent,deletingіdeletedподії моделі не запускатимуться для видалених моделей. Це тому, що моделі фактично ніколи не отримуються під час виконання оператора delete.

М'яке видалення

На додаток до того, що фактично видаляє записи з вашої бази даних, Eloquent також може «м'яко видаляти» моделі. Коли моделі видаляються м’яко, вони насправді не видаляються з вашої бази даних. Натомість adeleted_atатрибут встановлюється на моделі і вставляється в базу даних. Якщо модель має ненульове значенняdeleted_atзначення, модель була видалена м'яко. Щоб увімкнути плавне видалення для моделі, використовуйтеIlluminate\Database\Eloquent\SoftDeletesриса на моделі:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Flight extends Model
{
    use SoftDeletes;
}
TheSoftDeletesриса автоматично додастьdeleted_atатрибут доDateTime/Carbonекземпляр для вас.

Слід також додатиdeleted_atстовпець до таблиці бази даних. Laravelьконструктор схеммістить допоміжний метод для створення цього стовпця:

public function up()
{
    Schema::table('flights', function (Blueprint $table) {
        $table->softDeletes();
    });
}

public function down()
{
    Schema::table('flights', function (Blueprint $table) {
        $table->dropSoftDeletes();
    });
}

Тепер, коли ви телефонуєте наdeleteметод на моделі,deleted_atу стовпці буде встановлено поточну дату та час. При запиті до моделі, яка використовує м’яке видалення, м’яко видалені моделі автоматично виключаються з усіх результатів запиту.

Щоб визначити, чи було видалено даний екземпляр моделі м'яким способом, використовуйтеtrashedметод:

if ($flight->trashed()) {
    //
}

Запит на видалені програми

У тому числі програми з м'яким видаленням

Як зазначалося вище, м'яко видалені моделі будуть автоматично виключені з результатів запиту. Однак ви можете змусити м'яко видалені моделі з'являтися у наборі результатів за допомогоюwithTrashedметод за запитом:

$flights = App\Models\Flight::withTrashed()
                ->where('account_id', 1)
                ->get();

withTrashedметод також може бути використаний назв'язкизапит:

$flight->history()->withTrashed()->get();

Отримання лише програм, які видалено з м’яким програмним забезпеченням

onlyTrashedметод отримаєлишем'яко видалені моделі:

$flights = App\Models\Flight::onlyTrashed()
                ->where('airline_id', 1)
                ->get();

Відновлення видалених моделей

Іноді вам може знадобитися "видалити" м'яко видалену модель. Щоб відновити м'яку видалену модель у активний стан, використовуйтеrestoreметод на екземплярі моделі:

$flight->restore();

Ви також можете використовуватиrestoreметод у запиті для швидкого відновлення декількох моделей. Знову ж таки, як і інші "масові" операції, це не буде запускати жодні події моделей для моделей, які відновляються:

App\Models\Flight::withTrashed()
        ->where('airline_id', 1)
        ->restore();

ПодобаєтьсяwithTrashedметод,restoreметод також може бути використаний назв'язки:

$flight->history()->restore();

Постійне видалення моделей

Іноді вам може знадобитися справді видалити модель зі своєї бази даних. Щоб назавжди видалити з бази даних програмне забезпечення, що видаляється, використовуйтеforceDeleteметод:

// Force deleting a single model instance...
$flight->forceDelete();

// Force deleting all related models...
$flight->history()->forceDelete();

Реплікаційні моделі

Ви можете створити незбережену копію екземпляра моделі за допомогоюreplicateметод. Це особливо корисно, коли у вас є екземпляри моделей, які мають багато однакових атрибутів:

$shipping = App\Models\Address::create([
    'type' => 'shipping',
    'line_1' => '123 Example Street',
    'city' => 'Victorville',
    'state' => 'CA',
    'postcode' => '90001',
]);

$billing = $shipping->replicate()->fill([
    'type' => 'billing'
]);

$billing->save();

Scopes запитів

Глобальні Scopes

Глобальні Scopes дозволяють додавати обмеження до всіх запитів для даної моделі. Власного Laravelм'яке видаленняфункціональність використовує глобальні Scopes застосування, щоб витягувати з бази даних лише "не видалені" моделі. Написання власних глобальних масштабів може забезпечити зручний і простий спосіб переконатися, що кожен запит для даної моделі отримує певні обмеження.

Написання глобальних масштабів

Написати глобальну сферу просто. Визначте клас, який реалізуєIlluminate\Database\Eloquent\Scopeінтерфейс. Цей інтерфейс вимагає реалізації одного методу:apply.applyметод може додатиwhereобмеження на запит за необхідності:

<?php

namespace App\Scopes;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class AgeScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('age', '>', 200);
    }
}
Якщо ваша глобальна область додає стовпці до пункту select запиту, вам слід використовуватиaddSelectметод замістьselect. Це запобіжить ненавмисній заміні існуючого запиту вибору запиту.

Застосування глобальних сфер

Щоб призначити модель глобальному обсягу, слід замінити дану модельbootedметод і використовуватиaddGlobalScopeметод:

<?php

namespace App\Models;

use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted()
    {
        static::addGlobalScope(new AgeScope);
    }
}

Після додавання Scopes, запит доUser::all()створить наступний SQL:

select * from `users` where `age` > 200

Анонімні глобальні Scopes

Eloquent також дозволяє визначати глобальні Scopes застосування за допомогою Closures, що особливо корисно для простих областей застосування, які не вимагають окремого класу:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted()
    {
        static::addGlobalScope('age', function (Builder $builder) {
            $builder->where('age', '>', 200);
        });
    }
}

Видалення глобальних масштабів

Якщо ви хочете видалити глобальний обсяг для даного запиту, ви можете використовуватиwithoutGlobalScopeметод. Метод приймає ім'я класу глобальної Scopes дії як єдиний аргумент:

User::withoutGlobalScope(AgeScope::class)->get();

Або якщо ви визначили глобальний обсяг за допомогою Закриття:

User::withoutGlobalScope('age')->get();

Якщо ви хочете видалити кілька або навіть усі глобальні Scopes, ви можете скористатисяwithoutGlobalScopesметод:

// Remove all of the global scopes...
User::withoutGlobalScopes()->get();

// Remove some of the global scopes...
User::withoutGlobalScopes([
    FirstScope::class, SecondScope::class
])->get();

Місцеві Scopes застосування

Локальні Scopes дозволяють вам визначити загальні набори обмежень, які ви можете легко використовувати повторно у своїй програмі. Наприклад, можливо, вам доведеться часто отримувати всіх користувачів, які вважаються "популярними". Щоб визначити область, додайте до методу Eloquentї моделі префіксscope.

Scopes завжди повинні повертати екземпляр конструктора запитів:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * Scope a query to only include popular users.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePopular($query)
    {
        return $query->where('votes', '>', 100);
    }

    /**
     * Scope a query to only include active users.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }
}

Використання локального обсягу

Після того, як область визначена, ви можете викликати методи Scopes при запиті моделі. Однак ви не повинні включатиscopeпрефікс при виклику методу. Ви навіть можете прив'язувати дзвінки до різних областей, наприклад:

$users = App\Models\User::popular()->active()->orderBy('created_at')->get();

Поєднання декількох Eloquent модельних областей черезorоператор запиту може вимагати використання зворотних викликів Closure:

$users = App\Models\User::popular()->orWhere(function (Builder $query) {
    $query->active();
})->get();

Однак, оскільки це може бути громіздким, Laravel забезпечує "вищий порядок"orWhereметод, який дозволяє вільно зв’язати ці Scopes дії без використання Закриття:

$users = App\Models\User::popular()->orWhere->active()->get();

Динамічні Scopes

Іноді вам може знадобитися визначити область, яка приймає параметри. Для початку просто додайте додаткові параметри до Scopes застосування. Параметри Scopes слід визначати після$queryпараметр:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * Scope a query to only include users of a given type.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @param  mixed  $type
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeOfType($query, $type)
    {
        return $query->where('type', $type);
    }
}

Тепер ви можете передавати параметри під час виклику Scopes:

$users = App\Models\User::ofType('admin')->get();

Порівняння моделей

Іноді може знадобитися визначити, чи є дві моделі "однаковими".isметод може бути використаний для швидкої перевірки того, що дві моделі мають однаковий підключення первинного ключа, таблиці та бази даних:

if ($post->is($anotherPost)) {
    //
}

isметод також доступний при використанніbelongsTo,hasOne,morphTo, іmorphOneзв'язки. Цей метод особливо корисний, коли ви хочете порівняти пов’язану модель, не видаючи запит на отримання цієї моделі:

if ($post->author()->is($user)) {
    //
}

Події

Eloquent моделі запускають декілька подій, що дозволяє зачепити такі моменти в життєвому циклі моделі:retrieved,creating,created,updating,updated,saving,saved,deleting,deleted,restoring,restored,replicating. Події дозволяють легко виконувати код кожного разу, коли певний клас моделі зберігається або оновлюється в базі даних. Кожна подія отримує екземпляр моделі через її конструктор.

retrievedподія спрацює, коли існуюча модель буде отримана з бази даних. Коли нова модель зберігається вперше, файлcreatingіcreatedподії відбуватимуться.updating/updatedподії запускатимуться, коли існуючу модель буде змінено таsaveметод називається.saving/savedподії запускатимуться під час створення або оновлення моделі.

Під час масового оновлення або видалення через Eloquent,saved,updated,deleting, іdeletedподії моделі не будуть запускатись для моделей, що зазнали впливу. Це пов’язано з тим, що моделі фактично ніколи не отримуються під час масового оновлення чи видалення.

Для початку визначте a$dispatchesEventsвластивість на вашій Eloquentй моделі, яке відображає різні точки життєвого циклу моделі Eloquentго до вашого власногоурокові заходи:

<?php

namespace App\Models;

use App\Events\UserDeleted;
use App\Events\UserSaved;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The event map for the model.
     *
     * @var array
     */
    protected $dispatchesEvents = [
        'saved' => UserSaved::class,
        'deleted' => UserDeleted::class,
    ];
}

Після визначення та відображення ваших Eloquent подій ви можете скористатися нимиListeners подійдля обробки подій.

Використання замикань

Замість використання власних класів подій ви можете зареєструвати закриття, які виконуються під час запуску різних модельних подій. Як правило, ви повинні реєструвати ці закриття вbootedметод вашої моделі:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted()
    {
        static::created(function ($user) {
            //
        });
    }
}

Якщо потрібно, ви можете використовуватианонімні прослуховувачі подій у черзіпри реєстрації модельних подій. Це дасть вказівку Laravel виконати прослуховувач події моделі за допомогоючерга:

use function Illuminate\Events\queueable;

static::created(queueable(function ($user) {
    //
}));

Observers(Спостерігачі)

Визначення Observers(Спостерігачі)в

Якщо ви слухаєте багато подій за даною моделлю, ви можете використовувати Observers(Спостерігачі)в, щоб згрупувати всіх своїх Listeners в один клас. Класи Observers(Спостерігачі)в мають імена методів, що відображають Eloquent події, які ви хочете послухати. Кожен із цих методів отримує модель як єдиний аргумент.make:observerКоманда ремісників - це найпростіший спосіб створити новий клас Observers(Спостерігачі)в:

php artisan make:observer UserObserver --model=User

Ця команда помістить нового спостерігача у вашApp/Observersкаталог. Якщо цього каталогу не існує, Artisan створить його для вас. Ваш свіжий спостерігач буде виглядати наступним чином:

<?php

namespace App\Observers;

use App\Models\User;

class UserObserver
{
    /**
     * Handle the User "created" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function created(User $user)
    {
        //
    }

    /**
     * Handle the User "updated" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function updated(User $user)
    {
        //
    }

    /**
     * Handle the User "deleted" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function deleted(User $user)
    {
        //
    }

    /**
     * Handle the User "forceDeleted" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function forceDeleted(User $user)
    {
        //
    }
}

Щоб зареєструвати спостерігача, використовуйтеobserveметод на моделі, яку ви хочете спостерігати. Ви можете зареєструвати Observers(Спостерігачі)в уbootметоду одного з ваших постачальників послуг. У цьому прикладі ми зареєструємо спостерігача вAppServiceProvider:

<?php

namespace App\Providers;

use App\Observers\UserObserver;
use App\Models\User;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        User::observe(UserObserver::class);
    }
}

Muting подій

Можливо, ви часом захочете тимчасово "вимкнути звук" усіх подій, які запускає модель. Ви можете досягти цього за допомогоюwithoutEventsметод.withoutEventsметод приймає Закриття як єдиний аргумент. Будь-який код, виконаний в рамках цього Закриття, не запускатиме події моделі. Наприклад, наступне завантажить і видалить файлApp\Models\Userекземпляр без запуску будь-яких модельних подій. Будь-яке значення, повернене даним Закриттям, буде поверненеwithoutEventsметод:

use App\Models\User;

$user = User::withoutEvents(function () use () {
    User::findOrFail(1)->delete();

    return User::find(2);
});

Збереження єдиної моделі без подій

Іноді вам може знадобитися "зберегти" дану модель, не викликаючи жодних подій. Ви можете досягти цього за допомогоюsaveQuietlyметод:

$user = User::findOrFail(1);

$user->name = 'Victoria Faith';

$user->saveQuietly();