Laravel make custom class using console command

Laravel ships with built in console make commands to generate class files for controllers, models, migrations etc. For example creating a resourse controller, you can do :

php artisan make:controller CustomerController --resource

Depending in your project structure and design patterns, you might be using different classes like repositories, services etc. We can take advantage of console commands to save time and create it just like we created controller above.

File generation :

We firstly create a template file which is like a blueprint of how thw new class file will look like. This file is called stub file.

Then when command is run, we simply copy the stub to class.php and replace the dummyclass, dummynamespace etc with the new files class and namespace.

Above steps are made much simpler by GeneratorCommand class.

The GeneratorCommand class :

Laravel's make commands extend an abstract class GeneratorCommand. This class basically has all the methods which do making a directory, getting content of stub, replacing class & namespace, saving the new file and so on.

This is an abstract class which then extends the Illuminate command class.

Example :

Let's create a make command for generating Repository for a model.

  • Create the stub :

Create a directory called stubs in laravel project root. I really like non-php files outside the app folder, you can put the stubs in the location you prefer.

Create a new file inside stubs directory called Repository.stub. We are eliminating the repository specific functions as the goal is to focus on creating class file. You can add your repository functions inside the stub or maybe create a base class and extend stubs class from it.

<?php

namespace DummyNamespace;

use App\DummyModel;

class DummyRepository
{
    protected $model;
    /**
       * Instantiate reporitory
       * 
       * @param DummyModel $model
       */
    public function __construct(DummyModel $model)
    {
        $this->model = $model;
    }

    // Your methods for repository
}

The usual idea is whatever is to be replaced, we prefix it with Dummy.

  • Creating command :

Let's create command scaffolding from artisan :

php artisan make:command RepositoryMakeCommand

The make command classes are generally named in format WhatToCreateMakeCommand. If we had to create a service class, we could say ServiceMakeCommand.

We need to edit the RepositoryMakeCommand.php file which will be generated inside app/Console/Commands folder.

<?php

namespace App\Console\Commands;

use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Exception\InvalidArgumentException;

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

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Create a new model repository';

    /**
     * The type of class being generated.
     *
     * @var string
     */
    protected $type = 'Repository';

    /**
     * The name of class being generated.
     *
     * @var string
     */
    private $repositoryClass;

    /**
     * The name of class being generated.
     *
     * @var string
     */
    private $model;

    /**
     * Execute the console command.
     *
     * @return bool|null
     */
    public function fire(){

        $this->setRepositoryClass();

        $path = $this->getPath($this->repositoryClass);

        if ($this->alreadyExists($this->getNameInput())) {
            $this->error($this->type.' already exists!');

            return false;
        }

        $this->makeDirectory($path);

        $this->files->put($path, $this->buildClass($this->repositoryClass));

        $this->info($this->type.' created successfully.');

        $this->line("<info>Created Repository :</info> $this->repositoryClass");
    }

    /**
     * Set repository class name
     *
     * @return  void
     */
    private function setRepositoryClass()
    {
        $name = ucwords(strtolower($this->argument('name')));

        $this->model = $name;

        $modelClass = $this->parseName($name);

        $this->repositoryClass = $modelClass . 'Repository';

        return $this;
    }

    /**
     * Replace the class name for the given stub.
     *
     * @param  string  $stub
     * @param  string  $name
     * @return string
     */
    protected function replaceClass($stub, $name)
    {
        if(!$this->argument('name')){
            throw new InvalidArgumentException("Missing required argument model name");
        }

        $stub = parent::replaceClass($stub, $name);

        return str_replace('DummyModel', $this->model, $stub);
    }

    /**
     * 
     * Get the stub file for the generator.
     *
     * @return string
     */
    protected function getStub()
    {
        return  base_path('stubs/Repository.stub');
    }
    /**
     * Get the default namespace for the class.
     *
     * @param  string  $rootNamespace
     * @return string
     */
    protected function getDefaultNamespace($rootNamespace)
    {
        return $rootNamespace . '\Repo';
    }

    /**
     * Get the console command arguments.
     *
     * @return array
     */
    protected function getArguments()
    {
        return [
            ['name', InputArgument::REQUIRED, 'The name of the model class.'],
        ];
    }
}
  • Registering the command :

Finally we need to register this command to make available in artisan console. We can do that by adding it inside app/Console/Kernel.php.

Inside protected $commands = [] array add the class path :

\App\Console\Commands\RepositoryMakeCommand::class,
  • Using the command :
php artisan make:repository Customer

This will create a CustomerRepository.php inside app/Repo folder :

<?php

namespace App\Repo;

use App\Customer;

class CustomerRepository
{
    protected $model;
    /**
       * Instantiate reporitory
       * 
       * @param Customer $model
       */
    public function __construct(Customer $model)
    {
        $this->model = $model;
    }

    // Your methods for repository
}

You can extend this implementation as per your project structure needs. This indeed saves time in longer run and makes sure all generated classes have common blueprint structure.

 
 
By : Mihir Bhende Categories : laravel, php Tags : laravel, php, helpers, collections