Модификаторы колонок
Что это
Модификаторы — методы после колонки. Меняют поведение.
$table->string('email')->unique()->nullable();
unique и nullable — модификаторы.
Nullable
По умолчанию — NOT NULL. nullable() разрешает NULL.
$table->string('bio')->nullable();
$table->timestamp('published_at')->nullable();
$table->foreignId('category_id')->nullable()->constrained();
Когда: необязательные поля.
Default
Значение по умолчанию:
$table->integer('views')->default(0);
$table->boolean('active')->default(true);
$table->string('status')->default('draft');
$table->json('meta')->default('{}');
$table->timestamp('created_at')->useCurrent();
useCurrent — текущее время.
Unique
Уникальный индекс:
$table->string('email')->unique();
$table->string('slug')->unique();
Составной:
$table->unique(['user_id', 'slug']);
Своё имя:
$table->unique('email', 'users_email_unique');
Index
Обычный индекс:
$table->string('status')->index();
$table->index('created_at');
$table->index(['status', 'created_at']);
Своё имя:
$table->index('status', 'posts_status_idx');
Primary
Первичный ключ:
$table->primary('id');
$table->primary(['user_id', 'role_id']); // составной
Обычно — через $table->id().
Auto-increment
$table->integer('id')->autoIncrement();
Или через $table->id() / increments().
Unsigned
Числа без отрицательных:
$table->integer('count')->unsigned();
$table->bigInteger('views')->unsigned();
В Laravel 11 — все числа по умолчанию unsigned при foreignId.
Comment
Комментарий к колонке:
$table->string('status')->comment('draft|published|archived');
Полезно для документации схемы.
After / Before
Позиция колонки (MySQL):
$table->string('status')->after('title');
$table->string('slug')->before('body');
⚠️ Работает только в MySQL. В PostgreSQL и SQLite — игнорируется.
Collation
Кодировка:
$table->string('title')->collation('utf8mb4_unicode_ci');
Charset
MySQL:
$table->string('title')->charset('utf8mb4');
Virtual / Stored
Виртуальные колонки (генерируемые):
$table->string('full_name')->virtualAs('CONCAT(first_name, " ", last_name)');
$table->integer('total')->storedAs('price * quantity');
virtualAs — вычисляется на лету.
storedAs — сохраняется в БД.
Использование:
$user->full_name; // вычисленное значение
Fulltext
Полнотекстовый поиск (MySQL, PostgreSQL):
$table->fullText('body');
Запрос:
Post::whereFullText('body', 'laravel')->get();
Spatial
Геоданные:
$table->geometry('location')->spatialIndex();
$table->point('location');
Invisible (MySQL 8+)**
Скрытая колонка:
$table->string('internal')->invisible();
Не показывается в SELECT *.
Chained
Модификаторы цепочкой:
$table->string('email')
->unique()
->nullable()
->comment('Email пользователя');
Порядок — не важен, но читаемость лучше соблюдать.
Полный пример
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')
->constrained()
->cascadeOnDelete();
$table->string('title');
$table->string('slug')
->unique()
->comment('URL-slug для поста');
$table->text('body');
$table->string('status')
->default('draft')
->index();
$table->integer('views')
->default(0)
->unsigned();
$table->boolean('featured')
->default(false);
$table->json('meta')
->nullable();
$table->timestamp('published_at')
->nullable()
->index();
$table->timestamps();
$table->softDeletes();
$table->unique(['user_id', 'slug']);
$table->index(['status', 'published_at']);
});
Практика
Создай таблицу products:
id— автоинкремент.name— строка, обязательно.slug— строка, уникальная.price— decimal(10,2), обязательно.stock— integer, default 0.is_active— boolean, default true.description— text, nullable.meta— json, nullable.created_at,updated_at.deleted_at— soft delete.
Проверь через php artisan db:show --table=products.
Частые ошибки
1. Модификатор без колонки:
$table->unique(); // ошибка
// Правильно:
$table->unique('email');
2. after на PostgreSQL:
$table->string('x')->after('y'); // игнорируется
3. Забыли nullable для foreignId:
$table->foreignId('category_id'); // NOT NULL
// Если категория может быть null:
$table->foreignId('category_id')->nullable();
4. default('') для NULL:
$table->string('bio')->default(''); // пустая строка
// Для NULL:
$table->string('bio')->nullable();
5. unique на больших текстовых:
$table->text('body')->unique(); // MySQL: индекс слишком длинный
Решение: уникальность на короткое поле (slug).
Итог
nullable()— может быть NULL.default()— значение по умолчанию.unique(),index()— индексы.primary()— PK.unsigned()— без отрицательных.comment()— комментарий.after(),before()— позиция (MySQL).virtualAs,storedAs— вычисляемые.fullText,spatialIndex— спец-индексы.
Дальше — внешние ключи.