Create make:custom commands in Laravel
Tags: laravel, tutorial, php
Published: 2022-03-09 16:27:24

Laravel comes with a feature that allows us to scaffold some commonly used classes, like models, factories, notifications, etc. If we want to create a model, for example, we can do it by running:

```php
php artisan make:model MyModel
```

**But what if we could do this for our custom classes?** Instead of copying and pasting code, why don't we automate that process with a *simple command!*?. In this article, I'll show you how to do that exactly.

## Let's start at the end
Before we start, we need to think about what we are building. I want to make a command that creates an empty report class that extends a different imaginary `Report` class.
I would like to run a command like this:

```bash
php artisan make:report MonthlyReport
```

That would then create a class under `app/Reports/` with the following content:

```php
<?php

namespace App\Reports;

class MontlyReport extends Report
{
    public function generate()
    {
        // TODO: add code..
    }
}
```

Of course, your classes don't have to be exactly like mine, you can use what I'm going to show you to make a generator command that fits your needs.

## Generating a generator command
First, we need to create the command that will handle the generation of the classes. Make a new command with:

```bash
php artisan make:command MakeReport
```

I named my command `MakeReport` you can name it whatever you think fits better for your use case.

After that, we can find it under `app/Console/Commands/`. Open the file and change the extended class from `Command` to `GeneratorCommand`. 

While we are here, we should also change the signature to `make:report {name}` (replace "report" with your type).

```php
<?php

namespace App\Console\Commands;

use Illuminate\Console\GeneratorCommand;

class MakeReport extends GeneratorCommand
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'make:report {name}';
    ...
}
```

We'll come back to this command later. Before that, let's create the template for our class.

## Adding the class template
To create the template for our classes, we need to create a new folder under `app/Console/Commands` named `Stubs`. Inside this folder, we need to create a new text file that contains the template for our class. I made a file with the name `make-report.stub`, and in that file, I added the template for the class:

```
<?php

namespace App\Reports;

class DummyReport extends Report
{
    public function generate()
    {
        // TODO: add code..
    }
}
```

The `DummyReport` name for the class is just a placeholder for the real class name. You can set it to whatever you want, but remember what it is since we'll replace it in the next step.

## The generation logic
Now inside the get `MakeReport` command that we created earlier, I deleted every method and overwrote three new methods `getStub` `getDefaultNamespace` and `replaceClass`

```php
class MakeReport extends GeneratorCommand
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'make:report {name}';

    //...
    
    public function getStub()
    {
        return app_path() . '/Console/Commands/Stubs/make-report.stub';
    } 

    public function getDefaultNamespace($rootNamespace)
    {
        return $rootNamespace . '\Reports';
    }

    public function replaceClass($stub, $name)
    {
        $stub = parent::replaceClass($stub, $name);

        return str_replace("DummyReport", $this->argument('name'), $stub);
    }
}
``` 

In the first method, we define the path to our stub file. In the second one, we add the namespace of the generated command, in this case, it will be `App\Reports`. The namespace will be used to calculate the correct path of the new class. And in the last method, we replace the `DummyReport` class name with the actual class name sent as an argument to the command.

## The final result
And that is it. Now we have a command to generate our custom class by simply running this in the terminal:

```bash
php artisan make:report MyReport
```

And a new report will be created automatically.

If you liked this article **[follow me on Twitter](https://twitter.com/cosmeescobedo)**, I post tips and other laravel content there.