Create your own laravel make commands
Tags: laravel, php
Published: 2023-12-20 21:53:56


So for those of you who like to extend your laravel application. You may already know that you can [customize the default stubs](https://laravel.com/docs/10.x/artisan#stub-customization) of the `artisan make:*` commands by calling the command `artisan stub:publish` and customizing the files in the `stubs` folder.


So what I would really want is to create my own maker command for non-framework classes.
Let's say I usually use `Action`* classes in my laravel project. I would really want to have a command that would streamline the process of creating such classes. Example:

```
php artisan make:action SendSalaries
```

That would generate this class:

```php
<?php

namespace App\Actions;


class SendSalaries extends BaseAction
{
    public function run()
    {
        // TODO: Implement run() method.
    }
}
```

> Actions classes are a concept regularly used among laravel developers. See [freek.dev blog post](https://freek.dev/1371-refactoring-to-actions).



#### Implementation

Let's start by adding a new stub file `action.stub`:

```php
<?php

namespace {{ namespace }};


class {{ class }} extends BaseAction
{
    public function run()
    {
        // TODO: Implement run() method.
    }
}
```

Then we will need to create a new `make:action` command.

```
php artisan make:command ActionMakeCommand
```

And replace the base command class by the abstract command  `GeneratorCommand`. This class is used by the laravel framework to create make commands.

```php
use Illuminate\Console\GeneratorCommand;


class ActionMakeCommand extends GeneratorCommand
{
  ....

```

After that it's pretty straightforward. We'll need to make these little changes:
- Add the php attribute `#[AsCommand(name: 'make:action')]`.

```php
use Symfony\Component\Console\Attribute\AsCommand;

#[AsCommand(name: 'make:action')
class ActionMakeCommand extends GeneratorCommand
{
```

> Since version 9, the Laravel framework no longer [maintains support for PHP 7](https://laravel.com/docs/9.x/releases#support-policy).

- Implement the `getStub()` method so that it returns the action stub file.
```php
protected function getStub()
{
    return $this->resolveStubPath('/stubs/action.stub');
}

protected function resolveStubPath($stub)
{
    return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
        ? $customPath
        : __DIR__.$stub;
}
```
- Extend the `getDefaultNamespace` method in order to specify the target file location. Otherwise, the generated classes will be placed at the project's root.
```php
protected function getDefaultNamespace($rootNamespace)
{
    return $rootNamespace . '\Actions';
}
```

- Set property `$type` to 'Action'. This is intended for the console display.
```php
protected $type = 'Action';
```


#### What about generating a test class?

Simple ! We just have to include the `CreatesMatchingTest` trait:

```php
...
use Illuminate\Console\Concerns\CreatesMatchingTest;

class ActionMakeCommand extends GeneratorCommand
{
    use CreatesMatchingTest;
    ...
```
And add the `--test` option when calling the make command:
```
php artisan make:action --test CreateSubscription
```


#### What did we learn?
We've learned that alongside customizing default stubs in Laravel, crafting your own generator is remarkably straightforward. By developing a command that extends the `GeneratorCommand` and associating it with your cutomized stub file, the process becomes seamless.
Credit is due to the laravel team for doing a great job designing the command generator, enabling such ease and flexibility in customization.


*: For the sake of simplicity I've used an action as an example but generally there is no need to make a maker command for a plain class.


*\*\*: [Cover image](https://cyriak.co.uk/animation/projects/flying-lotus-putty-boy-strut/)*