This is because
public function creator() {
return $this->belongsTo('User'); // Looks for creator_id
}
and
public function file() {
return $this->hasOne('Asset'); // Looks for file_id
}
In your Asset.php try using
public function creator()
{
return $this->belongsTo('User', 'user_id');
}
Where user_id is your foreign key. I'm thinking that by calling the function creator laravel will look for creator_id column as the foreign key.
eriktisme said:
This is because
public function creator() { return $this->belongsTo('User'); // Looks for creator_id }
True. That is my question. Why doesn't this work when the inverse works.
and
public function file() { return $this->hasOne('Asset'); // Looks for file_id }
This is false. It looks for user_id in the assets table. Basically for an hasOne dynamic property, the property name can be anything, but for a belongsTo property it has to be the same as the model name. Why?
iWader said:
In your Asset.php try using
public function creator() { return $this->belongsTo('User', 'user_id'); }
Yes I know I can do that but that is not my question
Where user_id is your foreign key. I'm thinking that by calling the function creator laravel will look for creator_id column as the foreign key.
Well I guess it behaves that way because the function (and table column) is part of the model, rather than the related model.
I guess its one of those things thats personal preference as to how you like to setup your database schema.
Edit:
I see where you're coming from now. hasOne from the parent searches for the parent_id where as belongsTo looks for the function_id. Odd.
Let's have 3 models: 'Start', 'Middle' and 'End'. 'Start' has many 'Middle'-s, 'Middle' has many 'End'-s.
The foreign key of the Start-Middle relation is stored in the middles table.
The foreign key of the Middle-End relation is stored in the ends table.
By defining the Middle model as
class Middle extends Eloquent ...
public function start(){
return $this->belongsTo('Start');
}
public function ends(){
return $this->hasMany('End');
}
Laravel will asume that the middles table contains a column called 'start_id', and that the ends table contains a column named 'middle_id'.
If you change the relationship names into
class Middle extends Eloquent ...
public function previous(){
return $this->belongsTo('Start');
}
public function next(){
return $this->hasMany('End');
}
Laravel will assume that there is a 'previous_id' in the middles table, and still a 'middle_id' column in the ends table. It always assumes a 'model_name_id' column in the other table in case of a hasMany relationship.
If this answers your question, mark it as solved.
I appreciated the thorough response but it still hasn't answered my question of "why". In this code
public function previous(){
return $this->belongsTo('Start');
}
I see no reason why laravel can't assume the middles table has start_id instead of previous_id. I think it should assume the foreign key should be the snake case of the related object that was given. In this case it should be start_id
I found this in the source code
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relationships.
I just find this behavior inconsistent with the way hasOne() works
The following code in Eloquent\Model.php
if (is_null($foreignKey))
{
$foreignKey = snake_case($relation).'_id';
}
$instance = new $related;
can be refactored to
$instance = new $related;
$foreignKey = $foreignKey ?: $instance->getForeignKey();
and still maintain backward compatibility assuming most people use the same class name as the function name (which they would have had to if $foreignKey was empty)
Sign in to participate in this thread!
The Laravel portal for problem solving, knowledge sharing and community building.
The community