Making the case for Laravel model helper methods

Making the case for Laravel model helper methods

This article is part of a series where I document insights, changes and rethinking that I experienced while refactoring the codebase for Pulse  -  a painless and affordable site & server monitoring tool designed for developers.

Today, I’d like to talk about why I decided to make a switch from a philosophy I had followed for many years… keeping Eloquent model classes empty. I’ll explain my reasoning for the change and also comment on a couple of issues you should be aware of when using this approach.

The almighty God class

There is some debate among developers about whether Eloquent should be avoided at all costs because it employs too much of Laravel’s “magic” in order to function. After thinking about this for a while, I’ve come to the conclusion that this argument is irrelevant for most developers.

The notion that I should instead create my own decoupled data access layer, and all of the code and tests that go with that, is not realistic for the majority of developers, chiefly because it’s complex and there isn’t time to do it.

Instead, Eloquent is a proven, fully-tested implementation that has worked without issue for every Laravel application I’ve written. That being said, I’ve always kept my model classes light in my apps. By this, I mean that I’ve only used them to define relationships and occasionally, built-in data type casting.

Okay, but why did you decide to do that?

I think it came from watching one of Jeffrey Way’s amazing videos on Laracasts, where he talks about avoiding the use of god classes. A simple example of this is the User model where you could, in theory, create hundreds of functions and have every possible action be run from a user object.

I think I took a concern of creating these types of classes too far and neglected a valuable opportunity to isolate and improve my code.

Creating model helper methods

Let’s explore how we can use “helper” methods on the model classes to clean up our code. Consider the example of a forum. Suppose that certain actions would result in a user being banned e.g.

if (TextValidator::containsHateSpeech($comment->body)) {
    $user->update(["banned\_at" => now()]);
}

Now consider that there are many instances in your application where a user could do something that results in them being banned. You’d need to copy that line of code that updates the user everywhere you needed that logic.

In the case of this example, it’s not really a big deal as we’re only setting a timestamp, but imagine if the logic involved several steps… the risk of errors goes up, as does the difficulty in making changes. Now consider how much better the following code is:

// Somewhere in the application
if (TextValidator::containsHateSpeech($post->body)) {
    $user->ban();
}

// Elsewhere in the application
if (TextValidator::containsHateSpeech($comment->body)) {
$user->ban();
}

// User model
class User
{

/\*\*
 \* Prevent the user from participating on the forum.
 \*
 \*/
public function ban() : void
{
    $this->update(["banned\_at" => now()]);
}

}

Another added benefit of this approach is that since the logic exists within a public method on the User model, we can easily write a unit test for it:

/** @test */
public function a_user_can_be_banned()
{
$adam = factory(User::class, 1)->create(["banned_at" => null]);

$this->assertNull($adam->banned\_at);

$adam->ban();

$this->assertEquals($adam->fresh()->banned\_at, now());

}

Expanding on this approach

We now know that if we call our ban helper method anywhere in the application, it will ban the user and we have a test to prove it. Let’s build on this example with another. Suppose we wanted to add a conditional to see if a user has been banned. Our code might look like this:

if ($user->banned !== null) {
// Perform some action
}

As in the earlier example, it is entirely plausible that we would have the same code duplicated throughout the application, which would increase the risk of typing errors and make it difficult to alter the logic should we decide to do so.

By contrast, it becomes much easier to manage if we move the code into a helper method on the User. We can also easily add the inverse of the same method to check if a user is not banned:

// Somewhere in the application
if ($user->isBanned()) {
// Disallow access
}

// Elsewhere in the application
if ($user->isNotBanned()) {
// Perform some action
}

// User model
class User
{

/\*\*
 \* Determine if the user has been banned from participating.
 \*
 \*/
public function isBanned() : bool
{
    return $this->banned === null;
}

/\*\*
 \* Determine if the user has not been banned from participating.
 \*
 \*/
public function isNotBanned() : bool
{
    return ! $this->isBanned();
}

}

Likewise, writing unit tests to confirm this functionality is a doddle and it gives us the confidence that we need to safely rely on these methods to determine a user’s banned state:

/** @test */
public function a_user_knows_if_it_is_banned()
{
$adam = factory(User::class, 1)->create(["banned_at" => now()]);

$eve = factory(User::class, 1)->create(["banned\_at" => null]);

$this->assertTrue($adam->isBanned());

$this->assertFalse($eve->isBanned());

}

/** @test */
public function a_user_knows_if_it_is_not_banned()
{
$adam = factory(User::class, 1)->create(["banned_at" => null]);

$eve = factory(User::class, 1)->create(["banned\_at" => now()]);

$this->assertTrue($adam->isNotBanned());

$this->assertFalse($eve->isNotBanned());

}

Using traits to organise related functionality

If you have several methods that relate to the same “area” for a model, you may find it helpful to extract them into a separate file. We can make use of a trait to do this, and then simply tell our model to use this trait.

FYI: Laravel does this extensively. Indeed, the User model is a clear example of this as it makes use of Notifiable, Authenticable and Authorizable traits. Another added benefit of traits is the ability to use them in more than one class, so if the functionality is identical in multiple models, you could simply reuse it.

Let’s extract the helpers to a trait and import it within the User model:

trait Bannable
{

/\*\*
 \* Prevent the user from participating on the forum.
 \*
 \*/
public function ban() : void
{
    $this->update(["banned\_at" => now()]);
}

/\*\*
 \* Determine if the user has been banned from participating.
 \*
 \*/
public function isBanned() : bool
{
    return $this->banned === null;
}

/\*\*
 \* Determine if the user has not been banned from participating.    
 \*
 \*/
public function isNotBanned() : bool
{
    return ! $this->isBanned();
}

}

// User class
use App\Traits\Bannable;

class User
{
use Bannable;
}

Things to be aware of

While the above functionality is perfectly valid, be careful about over-using traits. Due to their extraction of methods, it’s very easy to end up with a god class that doesn’t look like a god class because it’s mostly made up of traits.

I’m also of the opinion that helper methods on the model should mostly be limited to interacting with the model itself and shouldn’t be responsible for doing other things (such as performing validation, logging out a user etc.).

As a result, I mostly favour them performing CRUD operations on themselves or conditionals on their current values, that way, it makes it easier to create unit tests for them. The second you start introducing functionality that works outside of the model, it requires more setup & becomes more difficult to test.

If you have more complex logic, consider dispatching a job or firing an event. That way, you can still unit test that a event was fired or a job was dispatched. That said, I’m personally still inclined to avoid doing this, but there’s nothing stopping you from taking this approach if you don’t have an issue with it.

Wrapping Up

Hopefully you’ve seen how helper methods can improve your code and that I’ve made a reasonable case for their use. I have more articles to share, so if you’re interested in reading them, be sure to follow me here on Medium.

Lastly, if you’re in the market for an affordable and painless site & server monitoring tool that doesn’t require you to have a DevOps degree, please take a moment to check out Pulse. I think you’ll find it to a be a breath of fresh air!

Thanks For Visiting, Keep Visiting. If you liked this post, share it with all of your programming buddies!

Originally published on itnext.io

Hire PHP Developer and Web Developer for your Online Business

Hire PHP Developer and Web Developer for your Online Business

PHP is widely used open-source scripting language it helps in making dynamically easy your websites and web application. Mobiweb Technology is your best technical partner and offering you solution for any kind of website and application...

PHP is widely used open-source scripting language it helps in making dynamically easy your websites and web application. Mobiweb Technology is your best technical partner and offering you solution for any kind of website and application development. To hire PHP developer and web developer at affordable prices contact Mobiweb Technology via [email protected]

Laravel Framework Development Services | Laravel Web Development

CMARIX is leading Laravel Web application Development Service Provider with the track record of implementing diverse high-performance Laravel web applications with skilled Laravel developer team for clients across the globe<a href="https://www.cmarix.com/laravel-framework-development-services.html?utm_source=SB" target="_blank">.Continue</a>

CMARIX is leading Laravel Web application Development Service Provider with the track record of implementing diverse high-performance Laravel web applications with skilled Laravel developer team for clients across the globe.Continue

Which is the best PHP Web Development Company in India?

Which is the best PHP Web Development Company in India?

Many experienced players prefer to give it a go ahead with PHP for their web development needs because of the simplicity that PHP provides. PHP is loaded with features that many other languages lack and those pre-defined features can bring new functionalities and finishing touch to your existing or new website that you are looking forward to create. Wouldn’t it be great to get the best PHP Web Development Company for your project; we have a reputation as few of the leading firms in IT industry when it comes to PHP development.

Perks you should keep an eye out for before considering to outsource project to any web development company:

1. Company’s Reputation- It is very important to know about the previous projects that the company has delivered and the success rate of those products. You can visit company’s website for client testimonials or can google reviews given to them by genuine clients. We follow transparency, you can contact our previous clients and let them tell you how their experience was while working with us.

2. Technical Skill set and Expertise- You should select a company that has multiple resource pool of expert and technically sound developers. Our developers are experienced with different PHP frameworks and are exceptionally good with writing bug free codes. You can also hire PHP developer in India from us, as our developers have on hand experience in PHP development (core and frameworks)

3. The Budget- Costing has always played as one of the most important roles in every business deal. We provide competitive pricing with no hidden cost guaranteed. With us you can expect your project to be in best quality with no compromise to be made even with the best price in the market.

Why Data EximIT is the best PHP web development company in India?

Here are some of the features that might love about Data EximIT:

 Reputation of Data EximIT is wonderful among the previous clients.

 We have around 87% of retention ratio of clients.

 We were time committed, means every milestone was achieved before or on time.

 Data EximIT follows Agile development so it was the best possible methodology.

 We have huge team with different expertise over multiple PHP frameworks, so you are provided with ample to options to choose from.

 We are very active in communication part. Method or time of communication was never an issue at Data EximIT.

 We have some of the best designers to ensure that your project not only functions but also looks and feels fabulous.

 We provided customers with best costing without compromising on the quality at all.

 We also provide dedicated PHP developer or team of PHP developers on hire for your project.

Data EximIT is where customers feel confident to come up with idea and leave with fully functioning & best in quality projects. You can also avail our developers at your requested site location if you decide to hire PHP developers in India from us.

Feel free to contact our experts and let success reach you by working with the best PHP web development company.