So...I just discovered a "gotcha" with Eloquent relationships that I wish I had known when I created my migrations and data files. So this would be good for other developers to know in advance as well. The essence of the problem has to do with the potential name conflict between an eloquent property and a relationship method. Here's a look at the problem I ran into:
1) I have a "states" table with the following columns: id (auto-numbered), name, abbreviation.
2) I have a "companies" table with the following columns: id, name, address, city, state, zip.
Notice that I didn't use a "state_id" column in my "companies" table. Instead, I insert the state abbreviation and label it as "state". I made this decision because I fairly often run queries directly against tables and I want to avoid having to type out the JOIN statement for a simple, 2-character field.
So that's all fine except when I want to create a relationship in my Company model that makes grammatical sense:
Unfortunately, the above statement displays nothing, even though the query it produces is fine. This is because there is a company property conflicting with a company method:
The simplest solution to this (without creating some awkward grammar) is to change the "state" column in the "companies" table to "state_abbreviation". That will remove the conflict between property and method.
A better solution would have been to start with a states table where the ID was the state abbreviation then have "state_id" in the companies table reference the state.id field. This is ideally how Laravel Eloquent likes to do things. Unfortunately, once you get far enough into a project, a change like that turns into a lot of code changes. So note to self for next time!
1) I have a "states" table with the following columns: id (auto-numbered), name, abbreviation.
2) I have a "companies" table with the following columns: id, name, address, city, state, zip.
Notice that I didn't use a "state_id" column in my "companies" table. Instead, I insert the state abbreviation and label it as "state". I made this decision because I fairly often run queries directly against tables and I want to avoid having to type out the JOIN statement for a simple, 2-character field.
So that's all fine except when I want to create a relationship in my Company model that makes grammatical sense:
public function state()...which yields the code:
{
return $this->belongsTo('App\State', 'state', 'abbreviation');
}
$company= Company::with('state')->find($id);...which can be referenced like so:
$company->state->name;
Unfortunately, the above statement displays nothing, even though the query it produces is fine. This is because there is a company property conflicting with a company method:
$company->state; // = 'MD'In other words, Eloquent isn't able to translate the property to a method when used as such.
$company->state->name // = NULL
The simplest solution to this (without creating some awkward grammar) is to change the "state" column in the "companies" table to "state_abbreviation". That will remove the conflict between property and method.
A better solution would have been to start with a states table where the ID was the state abbreviation then have "state_id" in the companies table reference the state.id field. This is ideally how Laravel Eloquent likes to do things. Unfortunately, once you get far enough into a project, a change like that turns into a lot of code changes. So note to self for next time!
Comments
Post a Comment