When creating the foreign key migrations in Laravel, a short syntax is constrained(). With that, it's easy to make one mistake related to Column modifiers.
If you want that foreign key column to be nullable, which syntax is correct?
// Option A:$table->foreignId('user_id')->nullable()->constrained(); // Or, Option B:$table->foreignId('user_id')->constrained()->nullable();
Perhaps, you would say both?
Wrong.
On the official documentation page for the foreign keys, you may find this important sentence:
Any additional column modifiers must be called before the constrained method.
Yes, nullable() is one of the so-called column modifiers. So yeah, the correct way is nullable before constrained.
But wait, what happens if we put it the other way around?
Schema::create('tasks', function (Blueprint $table) { $table->id(); $table->string('name'); $table->foreignId('user_id')->constrained()->nullable(); //INCORRECT! $table->timestamps();});
Would it throw an error? Not quite.
In fact, the migration will actually succeed.
That's what makes this mistake so dangerous: you may not even notice it.
You will have an issue only when saving the data:
Task::create(['name' => 'Testing']); // Will throw this:Illuminate\Database\QueryException with message 'SQLSTATE[HY000]:General error: 1364 Field 'user_id' doesn't have a default value (SQL: insert into `tasks` (`name`, `updated_at`, `created_at`) values (Testing, 2022-10-05 11:48:05, 2022-10-05 11:48:05))'
So, be careful and don't forget to add nullable before constrained.
In fact, it's also applicable to any other column modifiers. A few typical examples:
-
->after('name')->constrained();and not->constrained()->after('name'); -
->default(1)->constrained();and not->constrained()->default(1); -
->comment('Some comment')->constrained();and not->constrained()->comment('Some comment');
is there a way can solve this? like using phpstan?