
Artisan: як створити користувацькі команди make
05.02.2019 19:45 | Laravel
Досить зручно створювати класи з консолі. Та що робити у випадку, коли в artisan немає необхідних команд? Що ж, ніхто не заважає нам самим зробити своє життя простішим і комфортнішим.
Оскільки особисто я часто пишу трейти і інтерфейси, саме їх буду використовувати в якості прикладів.
Перш за все заглянемо під капот і поцікавимося, яким чином laravel генерує класи/файли каналів, подій, контролерів і т.д. Для цього зайдемо в директорію vendor/laravel/framework/src/Illuminate/Foundation/Console
, в якій виявимо цілу пачку класів команд. Переглянувши файли, назва яких включає make
ми зрозуміємо, що всі вони є нащадками класу GeneratorCommand
, в якому є практично все, що потрібно - створення директорій і файлів, побудова класів, заміна неймспейсів і багато іншого. Відмінно - особливо бруднити руки не доведеться. Також звернімо увагу на абстрактний метод getStub
:
/**
* Get the stub file for the generator.
*
* @return string
*/
abstract protected function getStub();
Цей метод ми зобов'язані реалізувати і вказати в ньому шлях до файлу, який буде використовуватися генератором. У тій же самій директорії також знайдемо теку з файлами-шаблонами. Наприклад, так виглядає шаблон model.stub
для моделі:
<?php
namespace DummyNamespace;
use Illuminate\Database\Eloquent\Model;
class DummyClass extends Model
{
//
}
Тобто нам залишається за наявними зразками реалізувати свої власні класи плюс під них написати шаблони. Виконуємо в консолі:
php artisan make:command TraitMakeCommand
В результаті буде створений файл app/Console/Commands/TraitMakeCommand.php
. Відкриваємо його і вставляємо наступний код:
<?php
namespace App\Console\Commands;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputArgument;
class TraitMakeCommand extends GeneratorCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $name = 'make:trait';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new trait';
/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Trait';
/**
* Replace the class name for the given stub.
*
* @param string $stub
* @param string $name
* @return string
*/
protected function replaceClass($stub, $name)
{
$stub = parent::replaceClass($stub, $name);
return str_replace('DummyTrait', $this->argument('name'), $stub);
}
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return __DIR__.'/../stubs/trait.stub';
}
/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace . '\Traits';
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the trait.'],
];
}
}
Хоча код говорить сам за себе, все ж поясню: у властивостях ми вказали назву і опис команди, а також тип "класу", який буде згенеровано. Сказали, що буде один обов'язковий аргумент - назва трейту (метод getArguments
); пояснили, де взяти шаблон (getStub
); дали вказівки щодо неймспейса (getDefaultNamespace
, це, до речі, означає, що якщо у нас немає директорії app/Traits
- вона буде створена); і попросили замінити DummyTrait
на ту назву, яку ми передамо як аргумент команди (replaceClass
). Тепер в app/Console
створимо каталог stubs, в якому помістимо шаблон trait.stub
. Ось його код:
<?php
namespace DummyNamespace;
trait DummyTrait
{
//
}
Чи потрібно щось ще? Ні, оскільки відповідно до офіційної документації всі команди, що знаходяться в app/Console/Commands
будуть автоматично зареєстровані в Artisan
. Перевірити, так це чи ні, можна виконавши:
php artisan list
і дійсно так! Серед усього іншого побачимо:
make:trait Create a new trait
Пробуємо:
php artisan make:trait Billable
...і знаходимо в app/Traits
файл Billable.php
з таким вмістом:
<?php
namespace App\Traits;
trait Billable
{
//
}
Що й треба було. Для контрактів (інтерфейсів) процедура аналогічна. Ось код файлу app/Console/Commands/ContractMakeComand.php
:
<?php
namespace App\Console\Commands;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputArgument;
class ContractMakeCommand extends GeneratorCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $name = 'make:contract';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new contract interface';
/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Contract';
/**
* Replace the class name for the given stub.
*
* @param string $stub
* @param string $name
* @return string
*/
protected function replaceClass($stub, $name)
{
$stub = parent::replaceClass($stub, $name);
return str_replace('DummyContract', $this->argument('name'), $stub);
}
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return __DIR__.'/../stubs/contract.stub';
}
/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace . '\Contracts';
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the contract.'],
];
}
}
і його шаблону:
<?php
namespace DummyNamespace;
interface DummyContract
{
//
}
Приклад команди:
php artisan make:contract Flyable
На цьому на сьогодні все. Успіхів!