База даних: міграції
Вступ
Міграції - це наче контроль версій для вашої бази даних: вони дозволяють команді описувати та спільно використовувати схему бази даних застосунку. Якщо вам колись доводилося просити колегу вручну додати стовпець до своєї локальної схеми після того, як він підтягнув ваші зміни з репозиторію, - ви стикалися саме з тією проблемою, яку розв'язують міграції.
Фасад Schema в Laravel дає незалежну від бази даних підтримку створення таблиць і роботи з ними в усіх підтримуваних Laravel системах баз даних. Зазвичай міграції користуються цим фасадом, щоб створювати й змінювати таблиці та стовпці.
Створення міграцій
Щоб згенерувати міграцію, скористайтеся artisan-командою make:migration. Нова міграція потрапить до каталогу database/migrations. Назва кожного файлу міграції містить часову позначку, за якою Laravel визначає порядок міграцій:
php artisan make:migration create_flights_table
Laravel спробує вгадати за назвою міграції, як називається таблиця і чи створює міграція нову таблицю. Якщо Laravel зможе визначити назву таблиці з назви міграції, він заздалегідь підставить цю таблицю у згенерований файл. Інакше ви просто вкажете таблицю у файлі міграції вручну.
Якщо ви хочете задати власний шлях для згенерованої міграції, скористайтеся опцією --path під час виконання команди make:migration. Вказаний шлях має бути відносним до базового шляху вашого застосунку.
Заготовки міграцій можна налаштувати через публікацію заготовок.
Стискання міграцій
Розробляючи застосунок, ви з часом накопичуєте все більше міграцій. Через це каталог database/migrations може розростися до сотень файлів. За бажанням ви можете «стиснути» міграції в один SQL-файл. Для початку виконайте команду schema:dump:
php artisan schema:dump
# Dump the current database schema and prune all existing migrations...
php artisan schema:dump --prune
Коли ви виконуєте цю команду, Laravel запише файл «схеми» до каталогу database/schema вашого застосунку. Назва файлу схеми відповідатиме підключенню до бази даних. Тепер, коли ви спробуєте виконати міграції й жодної іншої міграції ще не виконано, Laravel спершу виконає SQL-запити з файлу схеми того підключення, яке ви використовуєте. А потім виконає всі решту міграцій, які не входили до дампу схеми.
Якщо тести вашого застосунку працюють з іншим підключенням до бази даних, ніж те, яким ви зазвичай користуєтеся локально, переконайтеся, що ви зробили дамп схеми і для цього підключення, - інакше тести не зможуть побудувати вашу базу. Це варто зробити після дампу того підключення, яким ви зазвичай користуєтеся під час локальної розробки:
php artisan schema:dump
php artisan schema:dump --database=testing --prune
Файл схеми бази даних варто закомітити в репозиторій, щоб нові розробники у вашій команді могли швидко створити початкову структуру бази даних застосунку.
Стискання міграцій доступне лише для баз даних MariaDB, MySQL, PostgreSQL і SQLite і використовує консольний клієнт бази даних.
Структура міграції
Клас міграції містить два методи: up і down. Метод up додає до бази даних нові таблиці, стовпці чи індекси, а метод down має скасовувати те, що зробив метод up.
В обох методах ви можете користуватися конструктором схеми Laravel, щоб виразно створювати та змінювати таблиці. Про всі методи конструктора Schema читайте в його документації. Наприклад, ця міграція створює таблицю flights:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::drop('flights');
}
};
Задання підключення для міграції
Якщо ваша міграція працюватиме не з підключенням до бази даних за замовчуванням, задайте властивість $connection вашої міграції:
/**
* The database connection that should be used by the migration.
*
* @var string
*/
protected $connection = 'pgsql';
/**
* Run the migrations.
*/
public function up(): void
{
// ...
}
Пропуск міграцій
Іноді міграція призначена для можливості, яка ще не активна, і ви поки не хочете її виконувати. У такому разі опишіть у міграції метод shouldRun. Якщо shouldRun повертає false, міграцію буде пропущено:
use App\Models\Flight;
use Laravel\Pennant\Feature;
/**
* Determine if this migration should run.
*/
public function shouldRun(): bool
{
return Feature::active(Flight::class);
}
Запуск міграцій
Щоб виконати всі міграції, які ще не виконано, запустіть artisan-команду migrate:
php artisan migrate
Якщо ви хочете побачити, які міграції вже виконано, а які ще очікують, скористайтеся artisan-командою migrate:status:
php artisan migrate:status
Якщо передати команді migrate опцію --step, кожна міграція виконається як окремий пакет, і згодом ви зможете відкотити окремі міграції командою migrate:rollback:
php artisan migrate --step
Якщо ви хочете побачити SQL-запити, які виконають міграції, не запускаючи їх насправді, передайте команді migrate прапорець --pretend:
php artisan migrate --pretend
Ізоляція виконання міграцій
Якщо ви розгортаєте застосунок на кількох серверах і виконуєте міграції в межах процесу розгортання, вам навряд чи потрібно, щоб два сервери одночасно намагалися міграцію виконати. Щоб цього не сталося, скористайтеся опцією isolated під час виклику команди migrate.
Коли передано опцію isolated, Laravel перед спробою виконати міграції отримає атомарне блокування через драйвер кешу вашого застосунку. Усі інші спроби запустити команду migrate, поки блокування тримається, не виконаються; проте команда все одно завершиться з кодом успішного виходу:
php artisan migrate --isolated
Щоб скористатися цією можливістю, ваш застосунок має використовувати драйвер кешу
memcached,redis,dynamodb,database,fileабоarrayяк драйвер за замовчуванням. Крім того, усі сервери повинні спілкуватися з одним центральним сервером кешу.
Примусовий запуск міграцій на продакшні
Деякі операції міграцій руйнівні, тобто через них ви можете втратити дані. Щоб убезпечити вас від запуску таких команд на продакшн-базі, Laravel запитає підтвердження, перш ніж їх виконати. Щоб виконати команди без запитання, скористайтеся прапорцем --force:
php artisan migrate --force
Відкат міграцій
Щоб відкотити останню операцію міграції, скористайтеся artisan-командою rollback. Вона відкочує останній «пакет» міграцій, який може містити кілька файлів:
php artisan migrate:rollback
Ви можете відкотити обмежену кількість міграцій, передавши команді rollback опцію step. Наприклад, ця команда відкотить останні п'ять міграцій:
php artisan migrate:rollback --step=5
Ви можете відкотити конкретний «пакет» міграцій, передавши команді rollback опцію batch, значення якої відповідає значенню batch у таблиці migrations вашої бази даних. Наприклад, ця команда відкотить усі міграції з пакета номер три:
php artisan migrate:rollback --batch=3
Якщо ви хочете побачити SQL-запити, які виконають міграції, не запускаючи їх насправді, передайте команді migrate:rollback прапорець --pretend:
php artisan migrate:rollback --pretend
Команда migrate:reset відкотить усі міграції вашого застосунку:
php artisan migrate:reset
Відкат і міграція однією командою
Команда migrate:refresh відкотить усі ваші міграції, а потім виконає команду migrate. Фактично вона перестворює всю вашу базу даних:
php artisan migrate:refresh
# Refresh the database and run all database seeds...
php artisan migrate:refresh --seed
Ви можете відкотити й повторно виконати обмежену кількість міграцій, передавши команді refresh опцію step. Наприклад, ця команда відкотить і виконає заново останні п'ять міграцій:
php artisan migrate:refresh --step=5
Видалення всіх таблиць і міграція
Команда migrate:fresh видалить із бази даних усі таблиці, а потім виконає команду migrate:
php artisan migrate:fresh
php artisan migrate:fresh --seed
За замовчуванням команда migrate:fresh видаляє таблиці лише з підключення за замовчуванням. Втім, опцією --database ви можете вказати, яке підключення слід міграціювати. Назва підключення має відповідати підключенню, описаному у файлі конфігурації database вашого застосунку:
php artisan migrate:fresh --database=admin
Команда
migrate:freshвидалить усі таблиці бази даних незалежно від їхнього префікса. Користуйтеся нею обережно, якщо розробляєте на базі даних, спільній з іншими застосунками.
Таблиці
Створення таблиць
Щоб створити нову таблицю, скористайтеся методом create фасаду Schema. Метод create приймає два аргументи: перший - назва таблиці, другий - замикання, яке отримує об'єкт Blueprint для опису нової таблиці:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->timestamps();
});
Створюючи таблицю, ви можете описувати її стовпці будь-якими методами стовпців конструктора схеми.
Перевірка існування таблиці чи стовпця
Перевірити, чи існує таблиця, стовпець або індекс, можна методами hasTable, hasColumn і hasIndex:
if (Schema::hasTable('users')) {
// The "users" table exists...
}
if (Schema::hasColumn('users', 'email')) {
// The "users" table exists and has an "email" column...
}
if (Schema::hasIndex('users', ['email'], 'unique')) {
// The "users" table exists and has a unique index on the "email" column...
}
Підключення до бази даних та опції таблиці
Якщо ви хочете виконати операцію зі схемою не на підключенні за замовчуванням, скористайтеся методом connection:
Schema::connection('sqlite')->create('users', function (Blueprint $table) {
$table->id();
});
Крім того, кілька інших властивостей і методів дозволяють задати інші аспекти створення таблиці. Властивістю engine можна вказати рушій сховища таблиці на MariaDB чи MySQL:
Schema::create('users', function (Blueprint $table) {
$table->engine('InnoDB');
// ...
});
Властивостями charset і collation можна задати кодування та порядок сортування для створюваної таблиці на MariaDB чи MySQL:
Schema::create('users', function (Blueprint $table) {
$table->charset('utf8mb4');
$table->collation('utf8mb4_unicode_ci');
// ...
});
Методом temporary можна вказати, що таблиця має бути «тимчасовою». Тимчасові таблиці видимі лише в межах сесії поточного підключення й автоматично видаляються, коли підключення закривається:
Schema::create('calculations', function (Blueprint $table) {
$table->temporary();
// ...
});
Якщо ви хочете додати до таблиці «коментар», викличте метод comment на екземплярі таблиці. Коментарі до таблиць наразі підтримують лише MariaDB, MySQL і PostgreSQL:
Schema::create('calculations', function (Blueprint $table) {
$table->comment('Business calculations');
// ...
});
Оновлення таблиць
Методом table фасаду Schema можна оновлювати наявні таблиці. Як і create, метод table приймає два аргументи: назву таблиці та замикання, яке отримує екземпляр Blueprint для додавання стовпців чи індексів:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});
Перейменування та видалення таблиць
Щоб перейменувати наявну таблицю, скористайтеся методом rename:
use Illuminate\Support\Facades\Schema;
Schema::rename($from, $to);
Щоб видалити наявну таблицю, скористайтеся методами drop або dropIfExists:
Schema::drop('users');
Schema::dropIfExists('users');
Перейменування таблиць із зовнішніми ключами
Перш ніж перейменовувати таблицю, переконайтеся, що всі обмеження зовнішніх ключів на ній мають у ваших файлах міграцій явну назву, а не ту, яку Laravel призначає за конвенцією. Інакше назва обмеження зовнішнього ключа посилатиметься на стару назву таблиці.
Стовпці
Створення стовпців
Методом table фасаду Schema можна оновлювати наявні таблиці. Як і create, метод table приймає два аргументи: назву таблиці та замикання, яке отримує екземпляр Illuminate\Database\Schema\Blueprint для додавання стовпців:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});
Доступні типи стовпців
Blueprint конструктора схеми має цілу низку методів, що відповідають різним типам стовпців, які ви можете додати до таблиць. Усі доступні методи перелічено в таблиці нижче:
Логічні типи
Рядкові та текстові типи
Числові типи
bigIncrements bigInteger decimal double float id increments integer mediumIncrements mediumInteger smallIncrements smallInteger tinyIncrements tinyInteger unsignedBigInteger unsignedInteger unsignedMediumInteger unsignedSmallInteger unsignedTinyInteger
Типи дати й часу
dateTime dateTimeTz date time timeTz timestamp timestamps timestampsTz softDeletes softDeletesTz year
Бінарні типи
Об'єктні типи та JSON
Типи UUID та ULID
Просторові типи
Типи для зв'язків
Спеціальні типи
bigIncrements()
Метод bigIncrements створює автоінкрементний стовпець, еквівалентний UNSIGNED BIGINT (первинний ключ):
$table->bigIncrements('id');
bigInteger()
Метод bigInteger створює стовпець, еквівалентний BIGINT:
$table->bigInteger('votes');
binary()
Метод binary створює стовпець, еквівалентний BLOB:
$table->binary('photo');
На MySQL, MariaDB чи SQL Server ви можете передати аргументи length і fixed, щоб створити стовпець, еквівалентний VARBINARY або BINARY:
$table->binary('data', length: 16); // VARBINARY(16)
$table->binary('data', length: 16, fixed: true); // BINARY(16)
boolean()
Метод boolean створює стовпець, еквівалентний BOOLEAN:
$table->boolean('confirmed');
char()
Метод char створює стовпець, еквівалентний CHAR, заданої довжини:
$table->char('name', length: 100);
dateTimeTz()
Метод dateTimeTz створює стовпець, еквівалентний DATETIME (з часовою зоною), з необов'язковою точністю дробових секунд:
$table->dateTimeTz('created_at', precision: 0);
dateTime()
Метод dateTime створює стовпець, еквівалентний DATETIME, з необов'язковою точністю дробових секунд:
$table->dateTime('created_at', precision: 0);
date()
Метод date створює стовпець, еквівалентний DATE:
$table->date('created_at');
decimal()
Метод decimal створює стовпець, еквівалентний DECIMAL, із заданою точністю (загальна кількість цифр) і масштабом (кількість цифр після коми):
$table->decimal('amount', total: 8, places: 2);
double()
Метод double створює стовпець, еквівалентний DOUBLE:
$table->double('amount');
enum()
Метод enum створює стовпець, еквівалентний ENUM, із заданими допустимими значеннями:
$table->enum('difficulty', ['easy', 'hard']);
Звісно, замість того щоб описувати масив допустимих значень вручну, ви можете скористатися методом Enum::cases():
use App\Enums\Difficulty;
$table->enum('difficulty', Difficulty::cases());
float()
Метод float створює стовпець, еквівалентний FLOAT, із заданою точністю:
$table->float('amount', precision: 53);
foreignId()
Метод foreignId створює стовпець, еквівалентний UNSIGNED BIGINT:
$table->foreignId('user_id');
foreignIdFor()
Метод foreignIdFor додає для заданого класу моделі стовпець, еквівалентний {column}_id. Тип стовпця буде UNSIGNED BIGINT, CHAR(36) або CHAR(26) - залежно від типу ключа моделі:
$table->foreignIdFor(User::class);
foreignUlid()
Метод foreignUlid створює стовпець, еквівалентний ULID:
$table->foreignUlid('user_id');
foreignUuid()
Метод foreignUuid створює стовпець, еквівалентний UUID:
$table->foreignUuid('user_id');
foreignUuidFor()
Метод foreignUuidFor додає для заданого класу моделі стовпець {column}_id, еквівалентний UUID:
$table->foreignUuidFor(User::class);
geography()
Метод geography створює стовпець, еквівалентний GEOGRAPHY, із заданим просторовим типом і SRID (Spatial Reference System Identifier):
$table->geography('coordinates', subtype: 'point', srid: 4326);
Підтримка просторових типів залежить від драйвера вашої бази даних. Звіряйтеся з документацією своєї бази. Якщо ваш застосунок працює з PostgreSQL, перед використанням методу
geographyпотрібно встановити розширення PostGIS.
geometry()
Метод geometry створює стовпець, еквівалентний GEOMETRY, із заданим просторовим типом і SRID (Spatial Reference System Identifier):
$table->geometry('positions', subtype: 'point', srid: 0);
Підтримка просторових типів залежить від драйвера вашої бази даних. Звіряйтеся з документацією своєї бази. Якщо ваш застосунок працює з PostgreSQL, перед використанням методу
geometryпотрібно встановити розширення PostGIS.
id()
Метод id - псевдонім методу bigIncrements. За замовчуванням він створює стовпець id; втім, ви можете передати назву стовпця, якщо хочете назвати його інакше:
$table->id();
increments()
Метод increments створює автоінкрементний стовпець, еквівалентний UNSIGNED INTEGER, як первинний ключ:
$table->increments('id');
integer()
Метод integer створює стовпець, еквівалентний INTEGER:
$table->integer('votes');
ipAddress()
Метод ipAddress створює стовпець, еквівалентний VARCHAR:
$table->ipAddress('visitor');
На PostgreSQL буде створено стовпець INET.
json()
Метод json створює стовпець, еквівалентний JSON:
$table->json('options');
На SQLite буде створено стовпець TEXT.
jsonb()
Метод jsonb створює стовпець, еквівалентний JSONB:
$table->jsonb('options');
На SQLite буде створено стовпець TEXT.
longText()
Метод longText створює стовпець, еквівалентний LONGTEXT:
$table->longText('description');
На MySQL чи MariaDB ви можете застосувати до стовпця кодування binary, щоб створити стовпець, еквівалентний LONGBLOB:
$table->longText('data')->charset('binary'); // LONGBLOB
macAddress()
Метод macAddress створює стовпець, призначений для зберігання MAC-адреси. Деякі системи баз даних, як-от PostgreSQL, мають для таких даних окремий тип стовпця. Інші використають стовпець, еквівалентний рядковому:
$table->macAddress('device');
mediumIncrements()
Метод mediumIncrements створює автоінкрементний стовпець, еквівалентний UNSIGNED MEDIUMINT, як первинний ключ:
$table->mediumIncrements('id');
mediumInteger()
Метод mediumInteger створює стовпець, еквівалентний MEDIUMINT:
$table->mediumInteger('votes');
mediumText()
Метод mediumText створює стовпець, еквівалентний MEDIUMTEXT:
$table->mediumText('description');
На MySQL чи MariaDB ви можете застосувати до стовпця кодування binary, щоб створити стовпець, еквівалентний MEDIUMBLOB:
$table->mediumText('data')->charset('binary'); // MEDIUMBLOB
morphs()
Метод morphs - це зручний метод, який додає стовпець {column}_type, еквівалентний VARCHAR, і стовпець {column}_id. Тип стовпця {column}_id буде UNSIGNED BIGINT, CHAR(36) або CHAR(26) - залежно від типу ключа моделі.
Цей метод призначений для опису стовпців, потрібних для поліморфного зв'язку Eloquent. У прикладі нижче буде створено стовпці taggable_type і taggable_id:
$table->morphs('taggable');
nullableMorphs()
Метод схожий на morphs, але створені стовпці будуть «nullable»:
$table->nullableMorphs('taggable');
nullableUlidMorphs()
Метод схожий на ulidMorphs, але створені стовпці будуть «nullable»:
$table->nullableUlidMorphs('taggable');
nullableUuidMorphs()
Метод схожий на uuidMorphs, але створені стовпці будуть «nullable»:
$table->nullableUuidMorphs('taggable');
rememberToken()
Метод rememberToken створює nullable-стовпець, еквівалентний VARCHAR(100), призначений для зберігання поточного токена автентифікації «запам'ятати мене»:
$table->rememberToken();
set()
Метод set створює стовпець, еквівалентний SET, із заданим списком допустимих значень:
$table->set('flavors', ['strawberry', 'vanilla']);
smallIncrements()
Метод smallIncrements створює автоінкрементний стовпець, еквівалентний UNSIGNED SMALLINT, як первинний ключ:
$table->smallIncrements('id');
smallInteger()
Метод smallInteger створює стовпець, еквівалентний SMALLINT:
$table->smallInteger('votes');
softDeletesTz()
Метод softDeletesTz додає nullable-стовпець deleted_at, еквівалентний TIMESTAMP (з часовою зоною), з необов'язковою точністю дробових секунд. Цей стовпець призначений для зберігання часової позначки deleted_at, потрібної для м'якого видалення (soft delete) в Eloquent:
$table->softDeletesTz('deleted_at', precision: 0);
softDeletes()
Метод softDeletes додає nullable-стовпець deleted_at, еквівалентний TIMESTAMP, з необов'язковою точністю дробових секунд. Цей стовпець призначений для зберігання часової позначки deleted_at, потрібної для м'якого видалення в Eloquent:
$table->softDeletes('deleted_at', precision: 0);
string()
Метод string створює стовпець, еквівалентний VARCHAR, заданої довжини:
$table->string('name', length: 100);
text()
Метод text створює стовпець, еквівалентний TEXT:
$table->text('description');
На MySQL чи MariaDB ви можете застосувати до стовпця кодування binary, щоб створити стовпець, еквівалентний BLOB:
$table->text('data')->charset('binary'); // BLOB
timeTz()
Метод timeTz створює стовпець, еквівалентний TIME (з часовою зоною), з необов'язковою точністю дробових секунд:
$table->timeTz('sunrise', precision: 0);
time()
Метод time створює стовпець, еквівалентний TIME, з необов'язковою точністю дробових секунд:
$table->time('sunrise', precision: 0);
timestampTz()
Метод timestampTz створює стовпець, еквівалентний TIMESTAMP (з часовою зоною), з необов'язковою точністю дробових секунд:
$table->timestampTz('added_at', precision: 0);
timestamp()
Метод timestamp створює стовпець, еквівалентний TIMESTAMP, з необов'язковою точністю дробових секунд:
$table->timestamp('added_at', precision: 0);
timestampsTz()
Метод timestampsTz створює стовпці created_at і updated_at, еквівалентні TIMESTAMP (з часовою зоною), з необов'язковою точністю дробових секунд:
$table->timestampsTz(precision: 0);
timestamps()
Метод timestamps створює стовпці created_at і updated_at, еквівалентні TIMESTAMP, з необов'язковою точністю дробових секунд:
$table->timestamps(precision: 0);
tinyIncrements()
Метод tinyIncrements створює автоінкрементний стовпець, еквівалентний UNSIGNED TINYINT, як первинний ключ:
$table->tinyIncrements('id');
tinyInteger()
Метод tinyInteger створює стовпець, еквівалентний TINYINT:
$table->tinyInteger('votes');
tinyText()
Метод tinyText створює стовпець, еквівалентний TINYTEXT:
$table->tinyText('notes');
На MySQL чи MariaDB ви можете застосувати до стовпця кодування binary, щоб створити стовпець, еквівалентний TINYBLOB:
$table->tinyText('data')->charset('binary'); // TINYBLOB
unsignedBigInteger()
Метод unsignedBigInteger створює стовпець, еквівалентний UNSIGNED BIGINT:
$table->unsignedBigInteger('votes');
unsignedInteger()
Метод unsignedInteger створює стовпець, еквівалентний UNSIGNED INTEGER:
$table->unsignedInteger('votes');
unsignedMediumInteger()
Метод unsignedMediumInteger створює стовпець, еквівалентний UNSIGNED MEDIUMINT:
$table->unsignedMediumInteger('votes');
unsignedSmallInteger()
Метод unsignedSmallInteger створює стовпець, еквівалентний UNSIGNED SMALLINT:
$table->unsignedSmallInteger('votes');
unsignedTinyInteger()
Метод unsignedTinyInteger створює стовпець, еквівалентний UNSIGNED TINYINT:
$table->unsignedTinyInteger('votes');
ulidMorphs()
Метод ulidMorphs - це зручний метод, який додає стовпець {column}_type, еквівалентний VARCHAR, і стовпець {column}_id, еквівалентний CHAR(26).
Цей метод призначений для опису стовпців, потрібних для поліморфного зв'язку Eloquent, що використовує ідентифікатори ULID. У прикладі нижче буде створено стовпці taggable_type і taggable_id:
$table->ulidMorphs('taggable');
uuidMorphs()
Метод uuidMorphs - це зручний метод, який додає стовпець {column}_type, еквівалентний VARCHAR, і стовпець {column}_id, еквівалентний CHAR(36).
Цей метод призначений для опису стовпців, потрібних для поліморфного зв'язку Eloquent, що використовує ідентифікатори UUID. У прикладі нижче буде створено стовпці taggable_type і taggable_id:
$table->uuidMorphs('taggable');
ulid()
Метод ulid створює стовпець, еквівалентний ULID:
$table->ulid('id');
uuid()
Метод uuid створює стовпець, еквівалентний UUID:
$table->uuid('id');
vector()
Метод vector створює стовпець, еквівалентний vector:
$table->vector('embedding', dimensions: 100);
На PostgreSQL розширення pgvector має бути завантажене, перш ніж можна створювати стовпці vector:
Schema::ensureVectorExtensionExists();
year()
Метод year створює стовпець, еквівалентний YEAR:
$table->year('birth_year');
Модифікатори стовпців
Крім перелічених вище типів, є кілька «модифікаторів» стовпців, якими ви можете скористатися, додаючи стовпець до таблиці. Наприклад, щоб зробити стовпець «nullable», викличте метод nullable:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});
У таблиці нижче наведено всі доступні модифікатори стовпців. Цей список не містить модифікаторів індексів:
| Модифікатор | Опис |
|---|---|
->after('column') |
Розмістити стовпець «після» іншого стовпця (MariaDB / MySQL). |
->autoIncrement() |
Зробити стовпці INTEGER автоінкрементними (первинний ключ). |
->charset('utf8mb4') |
Задати кодування для стовпця (MariaDB / MySQL). |
->collation('utf8mb4_unicode_ci') |
Задати порядок сортування для стовпця. |
->comment('my comment') |
Додати коментар до стовпця (MariaDB / MySQL / PostgreSQL). |
->default($value) |
Задати значення стовпця за замовчуванням. |
->first() |
Розмістити стовпець «першим» у таблиці (MariaDB / MySQL). |
->from($integer) |
Задати початкове значення автоінкрементного поля (MariaDB / MySQL / PostgreSQL). |
->instant() |
Додати або змінити стовпець миттєвою операцією (MySQL). |
->invisible() |
Зробити стовпець «невидимим» для запитів SELECT * (MariaDB / MySQL). |
->lock($mode) |
Задати режим блокування для операції зі стовпцем (MySQL). |
->nullable($value = true) |
Дозволити вставляти в стовпець значення NULL. |
->storedAs($expression) |
Створити збережений генерований стовпець (MariaDB / MySQL / PostgreSQL / SQLite). |
->unsigned() |
Зробити стовпці INTEGER типу UNSIGNED (MariaDB / MySQL). |
->useCurrent() |
Задати стовпцям TIMESTAMP значення за замовчуванням CURRENT_TIMESTAMP. |
->useCurrentOnUpdate() |
Задати стовпцям TIMESTAMP значення CURRENT_TIMESTAMP при оновленні запису (MariaDB / MySQL). |
->virtualAs($expression) |
Створити віртуальний генерований стовпець (MariaDB / MySQL / SQLite). |
->generatedAs($expression) |
Створити identity-стовпець із заданими опціями послідовності (PostgreSQL). |
->always() |
Задати перевагу значень послідовності над вхідними для identity-стовпця (PostgreSQL). |
Вирази за замовчуванням
Модифікатор default приймає значення або екземпляр Illuminate\Database\Query\Expression. Використання Expression не дасть Laravel узяти значення в лапки й дозволить скористатися специфічними для бази функціями. Особливо це стає в пригоді, коли потрібно задати значення за замовчуванням для стовпців JSON:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->json('movies')->default(new Expression('(JSON_ARRAY())'));
$table->timestamps();
});
}
};
Підтримка виразів за замовчуванням залежить від драйвера вашої бази даних, її версії та типу поля. Звіряйтеся з документацією своєї бази.
Порядок стовпців
На MariaDB чи MySQL методом after можна додавати стовпці після наявного стовпця в схемі:
$table->after('password', function (Blueprint $table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});
Миттєві операції зі стовпцями
На MySQL ви можете дописати до опису стовпця модифікатор instant, щоб вказати: стовпець слід додати чи змінити «миттєвим» алгоритмом MySQL. Цей алгоритм дозволяє виконати певні зміни схеми без повного перебудування таблиці, тож вони майже миттєві незалежно від її розміру:
$table->string('name')->nullable()->instant();
Миттєве додавання стовпців може лише дописувати стовпці в кінець таблиці, тому модифікатор instant не можна поєднувати з after чи first. Крім того, алгоритм підтримує не всі типи стовпців і не всі операції. Якщо запитана операція несумісна, MySQL видасть помилку.
Щоб дізнатися, які операції сумісні з миттєвою зміною стовпців, звіряйтеся з документацією MySQL.
Блокування DDL
На MySQL ви можете дописати модифікатор lock до опису стовпця, індексу чи зовнішнього ключа, щоб керувати блокуванням таблиці під час операцій зі схемою. MySQL підтримує кілька режимів блокування: none дозволяє одночасні читання й записи, shared дозволяє одночасні читання, але блокує записи, exclusive блокує будь-який одночасний доступ, а default дає MySQL самому обрати найдоречніший режим:
$table->string('name')->lock('none');
$table->index('email')->lock('shared');
Якщо запитаний режим блокування несумісний з операцією, MySQL видасть помилку. Модифікатор lock можна поєднувати з модифікатором instant, щоб додатково оптимізувати зміни схеми:
$table->string('name')->instant()->lock('none');
Зміна стовпців
Метод change дозволяє змінити тип і атрибути наявних стовпців. Наприклад, ви можете захотіти збільшити розмір стовпця string. Щоб побачити change у дії, збільшимо розмір стовпця name з 25 до 50. Для цього ми просто описуємо новий стан стовпця й викликаємо метод change:
Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->change();
});
Змінюючи стовпець, ви маєте явно вказати всі модифікатори, які хочете на ньому зберегти, - будь-який пропущений атрибут буде скинуто. Наприклад, щоб зберегти атрибути unsigned, default і comment, кожен модифікатор потрібно викликати явно:
Schema::table('users', function (Blueprint $table) {
$table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
});
Метод change не змінює індексів стовпця. Тому, змінюючи стовпець, ви можете скористатися модифікаторами індексів, щоб явно додати чи видалити індекс:
// Add an index...
$table->bigIncrements('id')->primary()->change();
// Drop an index...
$table->char('postal_code', 10)->unique(false)->change();
Перейменування стовпців
Щоб перейменувати стовпець, скористайтеся методом renameColumn конструктора схеми:
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});
Видалення стовпців
Щоб видалити стовпець, скористайтеся методом dropColumn конструктора схеми:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});
Ви можете видалити з таблиці кілька стовпців, передавши методу dropColumn масив їхніх назв:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});
Доступні псевдоніми команд
Laravel має кілька зручних методів для видалення поширених типів стовпців. Кожен із них описано в таблиці нижче:
| Команда | Опис |
|---|---|
$table->dropMorphs('morphable'); |
Видалити стовпці morphable_type і morphable_id. |
$table->dropRememberToken(); |
Видалити стовпець remember_token. |
$table->dropSoftDeletes(); |
Видалити стовпець deleted_at. |
$table->dropSoftDeletesTz(); |
Псевдонім методу dropSoftDeletes(). |
$table->dropTimestamps(); |
Видалити стовпці created_at і updated_at. |
$table->dropTimestampsTz(); |
Псевдонім методу dropTimestamps(). |
Індекси
Створення індексів
Конструктор схеми Laravel підтримує кілька типів індексів. У прикладі нижче створюється новий стовпець email і вказується, що його значення мають бути унікальними. Щоб створити індекс, ми дописуємо метод unique до опису стовпця:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});
Або ж ви можете створити індекс після опису стовпця. Для цього викличте метод unique на blueprint конструктора схеми. Цей метод приймає назву стовпця, який має отримати унікальний індекс:
$table->unique('email');
Ви можете навіть передати методу індексу масив стовпців, щоб створити складений (композитний) індекс:
$table->index(['account_id', 'created_at']);
Створюючи індекс, Laravel автоматично згенерує його назву на основі таблиці, назв стовпців і типу індексу, але ви можете передати другий аргумент, щоб задати назву самостійно:
$table->unique('email', 'unique_email');
Доступні типи індексів
Клас blueprint конструктора схеми Laravel має методи для створення кожного типу індексу, що його підтримує Laravel. Кожен метод індексу приймає необов'язковий другий аргумент - назву індексу. Якщо його не передати, назву буде утворено з назв таблиці й стовпців, використаних для індексу, а також типу індексу. Усі доступні методи індексів описано в таблиці нижче:
| Команда | Опис |
|---|---|
$table->primary('id'); |
Додає первинний ключ. |
$table->primary(['id', 'parent_id']); |
Додає композитні ключі. |
$table->unique('email'); |
Додає унікальний індекс. |
$table->index('state'); |
Додає індекс. |
$table->fullText('body'); |
Додає повнотекстовий індекс (MariaDB / MySQL / PostgreSQL). |
$table->fullText('body')->language('english'); |
Додає повнотекстовий індекс заданої мови (PostgreSQL). |
$table->spatialIndex('location'); |
Додає просторовий індекс (окрім SQLite). |
Створення індексу без блокування
За замовчуванням створення індексу на великій таблиці може заблокувати її й перекрити читання чи записи, поки індекс будується. На PostgreSQL або SQL Server ви можете дописати до опису індексу метод online, щоб створити індекс без блокування таблиці, - і ваш застосунок зможе далі читати й писати дані під час створення індексу:
$table->string('email')->unique()->online();
На PostgreSQL це додає до запиту створення індексу опцію CONCURRENTLY. На SQL Server - опцію WITH (online = on).
Перейменування індексів
Щоб перейменувати індекс, скористайтеся методом renameIndex blueprint конструктора схеми. Він приймає поточну назву індексу першим аргументом і бажану назву - другим:
$table->renameIndex('from', 'to')
Видалення індексів
Щоб видалити індекс, ви маєте вказати його назву. За замовчуванням Laravel автоматично призначає назву індексу на основі назви таблиці, назви проіндексованого стовпця й типу індексу. Ось кілька прикладів:
| Команда | Опис |
|---|---|
$table->dropPrimary('users_id_primary'); |
Видалити первинний ключ із таблиці «users». |
$table->dropUnique('users_email_unique'); |
Видалити унікальний індекс із таблиці «users». |
$table->dropIndex('geo_state_index'); |
Видалити базовий індекс із таблиці «geo». |
$table->dropFullText('posts_body_fulltext'); |
Видалити повнотекстовий індекс із таблиці «posts». |
$table->dropSpatialIndex('geo_location_spatialindex'); |
Видалити просторовий індекс із таблиці «geo» (окрім SQLite). |
Якщо ви передасте методу видалення індексу масив стовпців, назву індексу буде згенеровано за конвенцією на основі назви таблиці, стовпців і типу індексу:
Schema::table('geo', function (Blueprint $table) {
$table->dropIndex(['state']); // Drops index 'geo_state_index'
});
Обмеження зовнішніх ключів
Laravel також підтримує створення обмежень зовнішніх ключів, які забезпечують цілісність посилань на рівні бази даних. Наприклад, опишімо в таблиці posts стовпець user_id, що посилається на стовпець id таблиці users:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});
Оскільки такий синтаксис досить громіздкий, Laravel має додаткові, лаконічніші методи, які спираються на конвенції й роблять роботу приємнішою. Якщо створювати стовпець методом foreignId, приклад вище можна переписати так:
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained();
});
Метод foreignId створює стовпець, еквівалентний UNSIGNED BIGINT, а метод constrained за конвенціями визначає таблицю й стовпець, на які йде посилання. Якщо назва вашої таблиці не відповідає конвенціям Laravel, ви можете передати її методу constrained вручну. Крім того, можна задати й назву згенерованого індексу:
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained(
table: 'users', indexName: 'posts_user_id'
);
});
Ви також можете задати бажану дію для властивостей обмеження «on delete» і «on update»:
$table->foreignId('user_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');
Для цих дій є й альтернативний, виразніший синтаксис:
| Метод | Опис |
|---|---|
$table->cascadeOnUpdate(); |
Оновлення мають каскадуватися. |
$table->restrictOnUpdate(); |
Оновлення мають бути обмежені. |
$table->nullOnUpdate(); |
Оновлення мають задавати зовнішньому ключу null. |
$table->noActionOnUpdate(); |
Жодних дій при оновленні. |
$table->cascadeOnDelete(); |
Видалення мають каскадуватися. |
$table->restrictOnDelete(); |
Видалення мають бути обмежені. |
$table->nullOnDelete(); |
Видалення мають задавати зовнішньому ключу null. |
$table->noActionOnDelete(); |
Забороняє видалення, якщо є дочірні записи. |
Будь-які додаткові модифікатори стовпців слід викликати перед методом constrained:
$table->foreignId('user_id')
->nullable()
->constrained();
Видалення зовнішніх ключів
Щоб видалити зовнішній ключ, скористайтеся методом dropForeign, передавши аргументом назву обмеження, яке слід видалити. Обмеження зовнішніх ключів мають ту саму конвенцію назв, що й індекси. Іншими словами, назва обмеження зовнішнього ключа складається з назви таблиці та стовпців в обмеженні, після яких додається суфікс «_foreign»:
$table->dropForeign('posts_user_id_foreign');
Або ж ви можете передати методу dropForeign масив із назвою стовпця, що містить зовнішній ключ. Масив буде перетворено на назву обмеження за конвенціями Laravel:
$table->dropForeign(['user_id']);
Увімкнення та вимкнення обмежень зовнішніх ключів
Увімкнути або вимкнути обмеження зовнішніх ключів у ваших міграціях можна такими методами:
Schema::enableForeignKeyConstraints();
Schema::disableForeignKeyConstraints();
Schema::withoutForeignKeyConstraints(function () {
// Constraints disabled within this closure...
});
SQLite за замовчуванням вимикає обмеження зовнішніх ключів. Працюючи з SQLite, обов'язково увімкніть підтримку зовнішніх ключів у конфігурації бази даних, перш ніж намагатися створювати їх у міграціях.
Події
Для зручності кожна операція міграції надсилає подію. Усі наведені нижче події розширюють базовий клас Illuminate\Database\Events\MigrationEvent:
| Клас | Опис |
|---|---|
Illuminate\Database\Events\DatabaseRefreshed |
Команда migrate:refresh завершилася. |
Illuminate\Database\Events\MigrationsStarted |
Пакет міграцій ось-ось буде виконано. |
Illuminate\Database\Events\MigrationsEnded |
Пакет міграцій завершився. |
Illuminate\Database\Events\MigrationStarted |
Окрему міграцію ось-ось буде виконано. |
Illuminate\Database\Events\MigrationEnded |
Окрема міграція завершилася. |
Illuminate\Database\Events\NoPendingMigrations |
Команда міграції не знайшла міграцій в очікуванні. |
Illuminate\Database\Events\SchemaDumped |
Дамп схеми бази даних завершився. |
Illuminate\Database\Events\SchemaLoaded |
Наявний дамп схеми бази даних завантажено. |