Automating your service and repository patterns in Laravel with command generators
“Why spend 20 seconds doing something when you can spent 4 hours automating it,” goes the proverb. See any professional proverbists around any more? No, because they’ve all been automated. Also it’s fun.
Whatever your programming pattern in Laravel, chances are that the php artisan make:
x command is going to leave you high and dry on occasion. That’s why it can be useful to have your own commands available to cover those gaps. We’re going to go with the example of the “Service” pattern below.
Written By
Craig Riley
Craig is a full-stack developer who mainly deals in JavaScript and PHP. Frameworks include VueJS Laravel, Wordpress, Nuxt and Quasar. He also likes sysadmin stuff until it goes horribly wrong.
Setting up your command
We’ll skip the part where we guide you through a Laravel install, give you a 4,000 history of PHP and get to the point. Inside your app/Console
directory, there should be a directory called Commands
. If not, make one. Then, inside that, we’re going to create a file called MakeService.php
.
You can even use the php artisan make:command
command to automate your automation, although we’ll be changing most of the boilerplate code soon.
Instead of extending the normal Command
class, we’re going to change that. Make yours look like the below:
1<?php2
3namespace App\Console\Commands;4
5use Illuminate\Console\GeneratorCommand;6
7class MakeService extends GeneratorCommand8{9 /**10 * The name and signature of the console command.11 *12 * @var string13 */14 protected $signature = 'make:service';15
16 /**17 * The console command description.18 *19 * @var string20 */21 protected $description = 'Create a new service';22}23
You may have noticed that we deleted the handle()
method since we’re not going to be using, although if you have custom logic, you can leave it in. Just don’t forget to call parent::handle()
inside the method.
Overriding the default methods
The GeneratorCommand
command comes with a lot of methods that Laravel uses to know what to create, what to change and where to change it. We need to override a few of those with our child class.
All of the below should be added to your MakeService
class.
1 protected $type = 'Service';2
3 protected function getDefaultNamespace($rootNamespace)4 {5 return $rootNamespace . '\Services';6 }7
8 protected function getStub()9 {10 return base_path('stubs/service.stub');11 }12
13 protected function getPath($name)14 {15 $name = Str::replaceFirst($this->rootNamespace(), '', $name);16
17 return $this->laravel['path'] . '/' . str_replace('\\', '/', $name) . 'Service.php';18 }19
20 protected function replaceClass($stub, $name)21 {22 $name .= 'Service';23 $class = str_replace($this->getNamespace($name) . '\\', '', $name);24
25 // Do string replacement26 return str_replace('##service_name##', $class, $stub);27 }
Creating a stub
You may have noticed the getStub()
method above. This is reading a template file, and then creating a PHP file from that template. This doesn’t exist, so we need to create it. In our case, we’re doing that inside a stubs/service.stub
file from our project root.
There’s nothing special about this file extension. It’s just to ensure that our server doesn’t consider it a PHP file. The file itself is extremely simple:
<?php
namespace App\Services;
class ##service_name##{ //}
Running your new command
If you run php artisan list
, you’ll see that you now have an entry for make:service
on the list. We can now run php artisan make:service
and our friendly Artisan will ask us:
What should the service be named?
Artisan
Give your new service its naming ceremony (don’t write ‘Service’ at the end, we’ll do that automatically) et voila, inside your app/Services
folder will now reside a shiny new service for you to use.
What else can I do?
This is a very basic example, but it opens up a realm of possibilities for automating and standardising your workflow. In our case, we went on to create a facade for that service and then inject the accessor into a FacadeServiceProvider
so all of our new services were instantly registered and available as Facades.
If you override the handle
method as explained above, you can also call other Artisan commands as part of your own using the same input. For example:
1 public function handle()2 {3 parent::handle();4 if ($this->confirm('Do you want to create a facade for this service?')) {5 $name = $this->getNameInput();6 Artisan::call('make:facade ' . $name . ' \\\App\\\Services\\\\' . $name . "Service");7 }8 }
More Tutorials
Here are some more tutorials that we think might be helpful for you. Feel free to contact us if there's anything you might need
Easier Laravel polymorphic relationships with MorphMap
Polymorphic relationships are a hugely powerful way to make connections between tables in a Laravel application. Say you have tables called companies, users, & admins and all three needed to store addresses, without polymorphic relationships, we'd either have to forego standard two-way relationships in an addresses table and just use the ID, or we'd have to have three separate addresses tables, or even have all of our address fields on each of our three tables. All carry the weight of redundancy, repetition and unnecessary complexity.
Why you should be using backed enums in Laravel
Another year, another new "killer" feature for the poor, embattled software developer to learn rears its ugly head. Fortunately, enums only take a few minutes to learn and can be pretty useful for standardising database columns. Are they going to change the world? Probably not. Are they going to make a few problems slightly less problem-y? Quite possibly.
PHP Code Snippets Episode 2 - Use An Array To fill a Option Box
In this post I am going to show you how to take the values from an array and use them, in a form option box.
Passing through slots in Vue
If you're keeping your Vue component sizes small, there's a good chance you'll need to implement a wrapper component at some point. If you're only utilising the default slot for these, it can be as simple as putting a <slot /> tag inside your wrapper component. However, there's a bit more effort involved if you need to pass through named slots to your base component
How to Create a Simple Button Component in Figma
In this tutorial, we’ll create a simple button using Figma’s built-in component system.