Seth Phat
Posted on August 20, 2022
Hi Laravel developers,
As you may know, Laravel's Eloquent provides you a fancy way to create a "getter" and transform/access the data as how you want. Example:
// App/Models/User
public function getFullNameAttribute(): string
{
return sprintf('%s %s', $this->first_name, $this->last_name);
}
// Seth Phat
$user->full_name;
Looks cool, isn't it?
But, you have to avoid it as soon as you can, here are the reasons.
1/ Conflicts between the table's columns
As the example above, we can't tell the different between an accessor and a table's column. It is too similar how we access the data.
When your projects grow, more and more features come to join, overusing the accessors will create a big pain in your codebase:
- You can't tell the different between the columns and the accessors in your code.
- Maintenance and tech debt will rise high.
- Confuse new people when they're reading the code, logic,...
- You have to open a SQL Manager (eg TablePlus) all the time to see what is it.
- ...
2/ Maintain phpDoc manually
The more accessors you have, the higher time to maintain the phpDoc of your Model class.
To make it IDE-friendly, code suggestions,... you have to add your accessors into the phpDoc of your class, example:
/**
* @property-read string $full_name // Accessor
* @property-read string $sex // Accessor
*/
Imagine you created 10 accessors, you have to add it 10 times. Or when you don't need it anymore, you need remove both the accessor and the doc attribute.
Not so fun, IKR?
3/ Hard to mock
When TDD comes to play, you want to write test. You want to mock your Eloquent model. The mocking process itself is a big pain.
Eloquent will check what attribute wanna access then return the data via __get()
magic method. And to mock:
$user = $this->createMock(User::class):
$user->expects($this->exactly(3))
->method('__get')
->willReturnOnConsecutiveCalls(
'Seth Phat', // full_name
'Male', // sex
// ... more and more
);
And I believe nobody would like that mocking process above. It is super hard to maintain.
So what should I use?
A good'ol getter method is simply perfect. IDE-friendly, no need to maintain phpDoc, super easy to mock:
public function getFullName(): string
{
return sprintf('%s %s', $this->first_name, $this->last_name);
}
Mock:
$user = $this->createMock(User::class):
$user->expects($this->once())
->method('getFullName')
->willReturn('Seth Phat');
// mock more...
With that mocking process, write test is totally enjoyable and easy to maintain.
Limitation
- Can't use
appends
&hidden
- Alternatively: you can use Laravel's Resource response and preferred to use this way instead of return a whole Eloquent Model
Final
That's my experience for this one. How about you guys?
Cheers!
Posted on August 20, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.