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.