Create make:custom commands in Laravel

Mar 4, 2022

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 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:

php artisan make:report MonthlyReport

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

<?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:

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

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

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:

php artisan make:report MyReport

And a new report will be created automatically.

If you liked this article follow me on Twitter, I post tips and other laravel content there.