Philippe
Philippe

Reputation: 668

Laravel 4: prevent lazy load hasMany relation when foreign_key is null (optional relation)

I've got a hasMany relationship defined this way, in a Command Eloquent model:

public function rows()
{
   return $this->hasMany('\Acme\Models\Row')
}

In my case, rows can be linked to Commands, or not. So my Row migration file contains a nullable foreign key:

$table->integer('command_id')->unsigned()->nullable()->index();
$table->foreign('command_id')->references('id')->on('commands')->onDelete('set null');

Nothing really crazy.

I realize thought that if I instantiate a new Command object and call $command->rows, instead of an empty Collection, I get all the rows with a null command_id.

This is perfectly explained by the SQL generated by this $command->rows call:

select * from `rows` where `rows`.`command_id` is null

I think it's strange that Laravel choose to consider valid a null foreign key... What do you think: is this a bug? Am I missing something? What could be the best way to prevent this behavior?

Thanks.

Upvotes: 3

Views: 951

Answers (1)

Jarek Tkaczyk
Jarek Tkaczyk

Reputation: 81187

2 ways of handling this:

1 In order to prevent that behaviour, with your current setup, you need to add not null clause on the relation definition:

public function rows()
{
   return $this->hasMany('\Acme\Models\Row')->whereNotNull('rows.command_id');
}

2 You can also change your schema, so the foreign key is not nullable, but Rows without Command will have 0 value there.


Now, I think this is correct behaviour by all means. You are trying to fetch something, given null as prerequisite, so it finds those rows. This is unexpected in terms of business logic, but definitely not wrong.

Not mentioning that I can't think, why you would like to call relation on newly instantiated model, that clearly doesn't have any. Unless it's just curiosity.

Upvotes: 3

Related Questions