Indexes — index(), unique(), primary(), fullText()
Concept
Foreign keys enforce referential integrity at the database level — ensuring that a column in one table always references a valid row in another table. Without foreign keys, orphaned records accumulate silently.
foreignId(string $column): Shorthand for unsignedBigInteger($column). Creates the column and associates it as a foreign key. Common pattern: $table->foreignId('user_id').
constrained(string $table = null, string $column = 'id'): Chain after foreignId(). If $table is omitted, it's inferred from the column name (user_id → users). Adds a foreign key constraint with a generated name.
references($column)->on($table): Verbose form: $table->foreign('user_id')->references('id')->on('users').
onDelete(string $action): What happens to child rows when the parent is deleted:
'cascade': Delete children when parent is deleted.'restrict'(default): Prevent parent deletion if children exist.'set null': Set the FK column to NULL (column must be nullable).'no action': Same as restrict (SQL standard).
onUpdate(string $action): Same actions for when the parent's PK updates (rare with integer PKs).
nullable(): Chain before constrained() to make the FK nullable: $table->foreignId('category_id')->nullable()->constrained().
cascadeOnDelete() / nullOnDelete(): Shorthand for onDelete('cascade') and onDelete('set null').
Dropping foreign keys:
dropForeign(string|array):$table->dropForeign('orders_user_id_foreign')or$table->dropForeign(['user_id']).
Code Example
<?php
Schema::create('orders', function (Blueprint $table) {
$table->id();
// Shorthand — infers table 'users' from column name 'user_id'
$table->foreignId('user_id')
->constrained()
->cascadeOnDelete(); // DELETE FROM users → cascade to orders
// Nullable FK (optional relationship)
$table->foreignId('coupon_id')
->nullable()
->constrained()
->nullOnDelete(); // DELETE FROM coupons → set coupon_id = NULL
// Explicit table/column
$table->foreignId('assigned_to')
->nullable()
->constrained('users', 'id')
->onDelete('set null');
$table->timestamps();
});
// Verbose form — for non-standard FK structures
Schema::create('order_items', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('order_id');
$table->unsignedBigInteger('product_id');
$table->integer('quantity');
$table->decimal('price', 10, 2);
$table->foreign('order_id')
->references('id')
->on('orders')
->onDelete('cascade')
->onUpdate('cascade');
$table->foreign('product_id')
->references('id')
->on('products')
->onDelete('restrict'); // can't delete product with order items
});
// Dropping foreign key (in down() or modification migration)
Schema::table('orders', function (Blueprint $table) {
$table->dropForeign(['user_id']); // auto-generates name: orders_user_id_foreign
$table->dropForeign('orders_coupon_id_foreign'); // by explicit name
$table->dropColumn('coupon_id'); // then drop the column
});
// Disable FK checks (needed for fresh migrations / seeding in specific orders)
Schema::disableForeignKeyConstraints();
DB::table('orders')->truncate();
Schema::enableForeignKeyConstraints();