Indexes and Foreign Keys

Indexes and Foreign Key Constraints

Index a column with ->unique(), ->index() or ->fullText(), or several with $table->index(['status', 'ordered_at']) or $table->primary([...]); names follow table, columns and type, as in products_sku_unique. constrained() infers categories from category_id; a self-reference names it: constrained('categories'). Foreign Keys's actions are cascadeOnDelete(), nullOnDelete(), restrictOnDelete() and cascadeOnUpdate(). There is no check() method, so the reviews migration adds its rating check with DB::statement() and raw ALTER TABLE.

The order_items table with its composite primary keyPHP
Schema::create('order_items', function (Blueprint $table) {
    $table->foreignId('order_id')->constrained()->cascadeOnDelete();
    $table->foreignId('product_id')->constrained();
    $table->unsignedSmallInteger('quantity');
    $table->decimal('unit_price', 8, 2);
    $table->primary(['order_id', 'product_id']);
});
Output
$ sudo mysql -E shop -e 'SHOW CREATE TABLE order_items'
*************************** 1. row ***************************
       Table: order_items
Create Table: CREATE TABLE `order_items` (
  `order_id` bigint unsigned NOT NULL,
  `product_id` bigint unsigned NOT NULL,
  `quantity` smallint unsigned NOT NULL,
  `unit_price` decimal(8,2) NOT NULL,
  PRIMARY KEY (`order_id`,`product_id`),
  KEY `order_items_product_id_foreign` (`product_id`),
  CONSTRAINT `order_items_order_id_foreign` FOREIGN KEY (`order_id`) REFERENCES `orders`
    (`id`) ON DELETE CASCADE,
  CONSTRAINT `order_items_product_id_foreign` FOREIGN KEY (`product_id`) REFERENCES `products`
    (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

Against MySQL's order_items the keys match; BIGINT, the collation, the cascade and the names differ. order_items_order_id_foreign replaces MySQL 524 's order_items_ibfk_1, so dropForeign(['order_id']) can rebuild the name from the column. InnoDB added the product_id index that every foreign key needs; order_id uses the primary key. The raw CHECK rejected a rating of 6 with error 3819.