Eloquent mutators & accessors are handy feature that can simplify your high level code and hide some data-related logic in the model.
However, it is pretty common to misuse them and soon regret it.
Let’s take a look and see where we can go wrong…
1 2 3 4 5 6 7 |
// User model public function getFullNameAttribute() { return $this->first_name.' '.$this->last_name; } |
So far, so good. It’s nice and easy, doesn’t seem to be a problem, and now we can we can easily output *full name* in view, or wherever we need:
1 2 3 |
<h1>Hello, {{ $user->full_name }}</h1> |
Now, imagine you follow this path, and keep adding accessors like this to you models, for sake of data presentation. As it becomes habit, we’re tempted to use accessors for all kind of stuff until one day we do this to, say, a *Product* model:
simple scenario – show product’s price:
1 2 3 |
<div class="product__price"><strong>{{ $product->price }}</strong></div> |
obviously we want it to be nice and well-formatted, so why not use an accessor:
1 2 3 4 5 6 7 |
// Product model public function getPriceAttribute($value) { return $this->currency->symbol.$value; // $99.99 } |
The price in our view is now formatted and we’re good to go for the next task, until we realize that BOOOM – we just broke our ecommerce site into pieces…
It’s likely, that somewhere in the app we have something between the lines of:
1 2 3 4 |
$vat = round($product->price * 0.23, 2) // 23.00 $gross = $product->price + $vat // 122.99 |
but now, all the (gross) prices became 0 so we’re in trouble, unless we spot the issue before our client (or we do things the right way, have tests yada yada yada, but that’s different story..):
1 2 3 4 5 6 |
$vat = round($product->price * 0.23, 2) // 0 // '$99.99' * 0.23 $gross = $product->price + $vat // 0 |
The moral of the story is, that data handling and its presentation should not go into the same bucket. And the model is that bucket – instead of creating accessors, traits or god knows what for this task, better use decorator (like) pattern where you can do all the necessary work for preparing your data to be displayed in your view, without touching actual values anywhere else.
This brings much more that just safety, for example you can easily handle translations, transformations and other tedious tasks, that definitely don’t belongs to the data handling layer.
If you’re looking for a ready-to-use package, that can do it for you, or simply would like to grasp the idea, go check this one: laravel-auto-presenter by Shawn McCool and friends