Refactoring #6: Improve Code Quality in Laravel using Rector
The promise is simple: you install and run the package, you get instant automated upgrades and refactorings.

Search for a command to run...
The promise is simple: you install and run the package, you get instant automated upgrades and refactorings.

No comments yet. Be the first to comment.
Testing is almost always difficult when developing applications that interact with external services, APIs, or complex features. One way to make testing easier is to use stub classes. Here's how I usually work with them. Quick intro on benefits Stubs...

We're upgrading from Laravel 9 to 10, and PHPUnit 9 to 10, and, if all goes well, we'll top it off by migrating to Pest, the latest version. To keep the positive vibes on I'll skip an upgrade from PHP 8.1 to 8.2, just because I don't want to restart ...

GitHub's 2000 minutes per month of free usage of GitHub Actions is usually enough to handle light workflows. However, as more tech is run automatically, we are forced to upgrade to a paid plan or optimize our workflows. Currently, I am running Rector...

A nice refactoring I've learned recently is to utilize types in conditionals. For years I’ve been doing if (!empty($posts)), but Rector, a tool to automatically refactor code, changed that to if ($posts === []). The main advantage of using $posts ===...

Laravel 10 is making the headlines these days. However, many apps are stuck in older versions, or at least still use the syntax and methods of older releases. One of the most significant changes introduced in Laravel 9 is the syntax for accessors and...

I recently discovered Rector and was completely blown away by its power and effectiveness. The promise is simple: you install and run the package, you get instant automated upgrades and refactorings.
Damn, that's bold, I thought as I dry ran it into one of my projects. While still reading their first page instructions at getrector.org, I decided to dive in and refactor a whole project overnight, to whatever extent possible.
I'm running a Laravel 8 project in a PHP 7.4 environment, and I started out with this simple configuration that handles simple code quality improvements:
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths([
__DIR__ . '/app'
]);
$rectorConfig->importNames();
$rectorConfig->sets([
LevelSetList::UP_TO_PHP_74,
SetList::CODE_QUALITY,
]);
};
Don't worry if you don't understand the code above, I didn't either half an hour ago 😂.
After running vendor/bin/rector --dry-run, I immediately saw these little upgrades that I was never going to do myself anyway.
/**
- *
- * @return \Illuminate\Broadcasting\Channel|array
- */
+ *
+ * @return Channel|array
+ */
public function broadcastOn()
This change is coming from the $rectorConfig->importNames(); configuration, and it's a lifesaver. Most coding standards prefer short class names, so auto-importing the classes in the whole project is a big big win.
public function user() {
- return $this->belongsTo('App\User');
+ return $this->belongsTo(User::class);
}
This is fantastic for old Laravel projects since most of them still use the string version to this day. It's a great upgrade because IDEs have much better support for the User::class version.
$schedule->command('dummy-command')
->daily()
- ->when(function () {
- return \Carbon\Carbon::now()->endOfWeek()->isToday();
- });
+ ->when(fn() => Carbon::now()->endOfWeek()->isToday());
I didn't even know that arrow functions were introduced in PHP 7.4, and I could have used them without any language upgrade. Now I get to utilize their power with a single rector command.
- $phone = str_replace(' ', '', $phone);
- return $phone;
+ return str_replace(' ', '', $phone);
This is another low-hanging fruit. The $phone variable here adds nothing to the quality of the code, so it can be safely removed.
- $this->order_count = $this->order_count + 1;
+ $this->order_count += 1;
This is an easy one as well. The short version is always better in my opinion.
if return statements- if ($user->company_id == $this->id) {
- return true;
- }
-
- return false;
+ return $user->company_id == $this->id;
I think you almost always want to do this, it's a beautiful one-liner that's easy to the eye and helps you grasp the logic quicker. If, however, it ruins your formatting in one of your files, where the existing way makes more sense, you can ignore this rule by adding a comment like this:
/** @noRector \Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector */.
public function setImageUrlsAttribute($value)
{
- $this->attributes['image_urls'] = json_encode($value);
+ $this->attributes['image_urls'] = json_encode($value, JSON_THROW_ON_ERROR);
}
This extra parameter makes it so that when encoding or decoding JSON goes wrong, it won't return null but it will throw an exception instead. I like this one, but I'm not entirely sure I'm ready to have this optimization in my code yet. Since this throws an exception, I'm a bit weary and will store this for later.
We can ignore certain rules by using this configuration.
compact usages into arrays $user= auth()->user();
$credits= $user->credits()->latest()->get();
- return view('user.credits', compact('user', 'credits'));
+ return view('user.credits', ['user' => $user, 'credits' => $credits]);
Today I learned that there's an opinion about using the compact() function that states it's not ideal, and maybe an antipattern. Not sure how I feel about this, but I'm keeping this refactoring and going with the flow. Nothing wrong with plain old arrays, right?
And many other small upgrades actually. Not to forget that this is coming from just the CODE_QUALITY rules that I imported in a single line above. There are 30+ other categories that I can't wait to use and see what they offer.
At this point I just run vendor/bin/rector, all tests are still passing, commit, push, and deploy. All is well in production now 😁.