Консоль Artisan
11.x
.
Почему это важно?
- Введение
- Tinker (REPL)
- Написание команд
- Генерация команд
- Структура команды
- Анонимные команды
- Определение вводимых данных
- Аргументы
- Параметры
- Массивы данных
- Описания вводимых данных
- Ввод/вывод команды
- Получение входных данных
- Запрос для ввода данных
- Вывод данных
- Регистрация команд
- Программное выполнение команд
- Вызов команд из других команд
- Обработка сигналов
- Настройка заготовок команд (stubs)
- События
Введение
Artisan – это интерфейс командной строки, входящий в состав Laravel. Он предлагает ряд полезных команд, которые помогут при создании приложения. Для просмотра списка всех доступных команд Artisan можно использовать команду list
:
php artisan list
Каждая команда также включает в себя экран «справки», который отображает и описывает доступные аргументы и параметры команды. Чтобы просмотреть экран справки, используйте help
перед именем команды:
php artisan help migrate
Laravel Sail
Если вы используете Laravel Sail в качестве локальной среды разработки, не забудьте использовать командную строку sail
для вызова команд Artisan. Sail выполнит ваши команды Artisan в контейнерах Docker вашего приложения:
./sail artisan list
Tinker (REPL)
Laravel Tinker – это мощный REPL для фреймворка Laravel, основанный на пакете PsySH.
Установка
Все приложения Laravel по умолчанию включают Tinker. Однако вы можете установить Tinker с помощью Composer, если вы ранее удалили его из своего приложения:
composer require laravel/tinker
Ищете графический интерфейс для взаимодействия с приложением Laravel? Зацените Tinkerwell!
Использование
Tinker позволяет взаимодействовать полностью со всем приложением Laravel из командной строки, включая модели Eloquent, задачи, события и многое другое. Чтобы войти в среду Tinker, выполните команду tinker
Artisan:
php artisan tinker
Вы можете опубликовать конфигурационный файл Tinker с помощью команды vendor:publish
:
php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"
Глобальный помощник
dispatch
и методdispatch
классаDispatchable
зависят от “garbage collection” для помещения задания в очередь. Следовательно, при использовании Tinker вы должны использоватьBus::dispatch
илиQueue::push
для отправки заданий.
Список разрешенных команд
Tinker использует список «разрешенных» команд, которые разрешено запускать Artisan в её среде. По умолчанию вы можете запускать команды clear-compiled
, down
, env
, inspire
, migrate
, optimize
и up
. Для добавления в этот список больше команд, добавьте их в массив commands
конфигурационного файла config/tinker.php
:
'commands' => [
// App\Console\Commands\ExampleCommand::class,
],
Черный список псевдонимов
Как правило, Tinker автоматически создает псевдонимы классов, когда вы взаимодействуете с ними в Tinker. Тем не менее вы можете запретить такое поведение для некоторых классов, перечислив их в массиве dont_alias
конфигурационного файла config/tinker.php
:
'dont_alias' => [
App\Models\User::class,
],
Написание команд
В дополнение к командам Artisan, вы можете создавать пользовательские команды. Команды обычно хранятся в каталоге app/Console/Commands
; однако вы можете выбрать другое месторасположение, если эти команды могут быть загружены менеджером Composer.
Генерация команд
Чтобы сгенерировать новую команду, используйте команду make:command
Artisan. Эта команда поместит новый класс команды в каталог app/Console/Commands
вашего приложения. Если этот каталог не существует в вашем приложении, то Laravel предварительно создаст его:
php artisan make:command SendEmails
Структура команды
После создания команды следует заполнить свойства класса $signature
и $description
. Эти свойства будут отображаться на экране при использовании команды list
. Свойство $signature
также позволяет определять вводимые данные. Метод handle
будет вызываться при выполнении команды. Вы можете разместить логику команды в этом методе.
Давайте рассмотрим пример команды. Обратите внимание, что мы можем запросить любые необходимые зависимости в методе handle
команды. Контейнер служб Laravel автоматически внедрит все зависимости, типы которых объявлены в этом методе:
<?php
namespace App\Console\Commands;
use App\Models\User;
use App\Support\DripEmailer;
use Illuminate\Console\Command;
class SendEmails extends Command
{
/**
* Имя и сигнатура консольной команды.
*
* @var string
*/
protected $signature = 'mail:send {user}';
/**
* Описание консольной команды.
*
* @var string
*/
protected $description = 'Send a marketing email to a user';
/**
* Создать новый экземпляр команды.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Выполнить консольную команду.
*
* @param \App\Support\DripEmailer $drip
* @return mixed
*/
public function handle(DripEmailer $drip)
{
$drip->send(User::find($this->argument('user')));
}
}
Хорошей практикой повторного использования кода считается создание «простых» консольных команд с делегированием своих задач службам приложения. В приведенном примере мы внедряем класс службы для выполнения «затратной» отправки электронных писем.
Анонимные команды
Анонимные команды обеспечивают альтернативу определению консольных команд в виде классов. Точно так же, как замыкания маршрутов являются альтернативой контроллерам. В рамках метода commands
файла app/Console/Kernel.php
Laravel загружает файл routes/console.php
:
/**
* Зарегистрировать команды, основанные на анонимных функциях.
*
* @return void
*/
protected function commands()
{
require base_path('routes/console.php');
}
Этот файл не определяет маршруты HTTP, он определяет точки входа (маршруты) для консольных команд в приложении. В этом файле с помощью метода Artisan::command
можно определить все анонимные консольные команды. Метод command
принимает два аргумента: сигнатуру команды и замыкание, которое получает аргументы и параметры команды:
Artisan::command('mail:send {user}', function ($user) {
$this->info("Sending email to: {$user}!");
});
Замыкание привязано к базовому экземпляру команды, поэтому у вас есть полный доступ ко всем вспомогательным методам, к которым вы обычно можете обращаться в команде, созданной с помощью класса.
Типизация зависимостей
Помимо получения аргументов и параметров, замыкание анонимной команды также принимает дополнительные зависимости из контейнера служб, необходимые для внедрения:
use App\Models\User;
use App\Support\DripEmailer;
Artisan::command('mail:send {user}', function (DripEmailer $drip, $user) {
$drip->send(User::find($user));
});
Описания анонимных команд
При определении анонимных команд, можно использовать метод purpose
для добавления описания команды. Это описание будет отображаться при запуске команд php artisan list
и php artisan help
:
Artisan::command('mail:send {user}', function ($user) {
// ...
})->purpose('Send a marketing email to a user');
Определение вводимых данных
При написании консольных команд обычно происходит сбор данных, получаемых от пользователя, с помощью аргументов или параметров. Laravel позволяет очень удобно определять входные данные, которые вы ожидаете от пользователя, используя свойство $signature
команды. Свойство $signature
позволяет определить имя, аргументы и параметры команды в едином выразительном синтаксисе, схожим с синтаксисом маршрутов.
Аргументы
Все предоставленные пользователем аргументы и параметры заключаются в фигурные скобки. В следующем примере команда определяет один обязательный аргумент user
:
/**
* Имя и сигнатура консольной команды.
*
* @var string
*/
protected $signature = 'mail:send {user}';
По желанию можно сделать аргументы необязательными или определить значения по умолчанию:
// Необязательный аргумент ...
mail:send {user?}
// Необязательный аргумент с заданным по умолчанию значением ...
mail:send {user=foo}
Параметры
Параметры, как и аргументы, являются разновидностью пользовательского ввода. Параметры должны иметь префикс в виде двух дефисов (--
), при использовании их в командной строке. Существует два типа параметров: получающие значение, и те, которые его не получают. Параметры, которые не получают значение, служат логическими «переключателями». Давайте рассмотрим пример такого варианта:
/**
* Имя и сигнатура консольной команды.
*
* @var string
*/
protected $signature = 'mail:send {user} {--queue}';
В этом примере при вызове команды Artisan может быть указан переключатель --queue
. Если переключатель --queue
передан, то значение этого параметра будет true
. В противном случае значение будет false
:
php artisan mail:send 1 --queue
Параметры со значениями
Давайте рассмотрим параметр, ожидающий значение. Если пользователь должен указать значение для параметра, то добавьте суффикс =
к имени параметра:
/**
* Имя и сигнатура консольной команды.
*
* @var string
*/
protected $signature = 'mail:send {user} {--queue=}';
В этом примере пользователь может передать значение для параметра. Если параметр не указан при вызове команды, то его значение будет null
:
php artisan mail:send 1 --queue=default
Параметру можно присвоить значение по умолчанию, указав его после имени. Если значение параметра не передано пользователем, то будет использовано значение по умолчанию:
mail:send {user} {--queue=default}
Псевдонимы параметров
Чтобы назначить псевдоним при определении параметра, вы можете указать его перед именем параметра и использовать символ разделителя |
для отделения псевдонима от полного имени параметра:
mail:send {user} {--Q|queue}
При вызове команды в терминале, псевдонимы параметров должны иметь префикс с одним дефисом
php artisan mail:send 1 -Q
Массивы данных
Чтобы определить, что аргументы или параметры ожидают массив данных, используйте метасимвол *
. Во-первых, давайте рассмотрим пример, в котором описывается аргумент как массив данных:
mail:send {user*}
При вызове этого метода аргументы user
могут передаваться по порядку в командную строку. Например, следующая команда установит значение user
как ['foo', 'bar']
:
php artisan mail:send foo bar
Метасимвол *
можно комбинировать с необязательным определением аргумента, чтобы разрешить ноль или более экземпляров аргумента:
mail:send {user?*}
Параметр со множеством значений
При определении параметра, ожидающего множество значений, каждое значение передаваемого команде параметра должно иметь префикс с именем параметра:
mail:send {user} {--id=*}
php artisan mail:send --id=1 --id=2
Описания вводимых данных
Вы можете назначить описания входным аргументам и параметрам, отделив имя аргумента от описания с помощью двоеточия. Если вам нужно немного больше места для определения вашей команды, то распределите определение на несколько строк:
/**
* Имя и сигнатура консольной команды.
*
* @var string
*/
protected $signature = 'mail:send
{user : The ID of the user}
{--queue : Whether the job should be queued}';
Ввод/вывод команды
Получение входных данных
Во время выполнения команды вам, вероятно, потребуется получить доступ к значениям аргументов и параметров, принятых командой. Для этого вы можете использовать методы argument
и option
. Если аргумент или параметр не существует, то будет возвращено значение null
.
/**
* Выполнить консольную команду.
*
* @return int
*/
public function handle()
{
$userId = $this->argument('user');
//
}
Если вам нужно получить все аргументы в виде массива, вызовите метод arguments
:
$arguments = $this->arguments();
Параметры могут быть получены так же легко, как и аргументы, используя метод option
. Чтобы получить все параметры в виде массива, вызовите метод options
:
// Получение определенного параметра ...
$queueName = $this->option('queue');
// Получение всех параметров в виде массива ...
$options = $this->options();
Запрос для ввода данных
Помимо отображения вывода, вы можете попросить пользователя предоставить данные во время выполнения вашей команды. Метод ask
отобразит пользователю указанный вопрос, примет его ввод, а затем вернет эти данные, полученные от пользователя, обратно в команду:
/**
* Выполнить консольную команду.
*
* @return mixed
*/
public function handle()
{
$name = $this->ask('What is your name?');
}
Метод secret
похож на ask
, но ввод пользователя не будет виден ему в консоли при вводе. Этот метод полезен при запросе конфиденциальной информации, например, пароля:
$password = $this->secret('What is the password?');
Запрос подтверждения
Если вам нужно получить от пользователя простое подтверждение «yes or no», то вы можете использовать метод confirm
. По умолчанию этот метод возвращает значение false
. Однако, если пользователь вводит y
или yes
в ответ на запрос, то метод возвращает true
.
if ($this->confirm('Do you wish to continue?')) {
//
}
По желанию можно указать, что запрос подтверждения должен по умолчанию возвращать true
, передав true
в качестве второго аргумента метода confirm
:
if ($this->confirm('Do you wish to continue?', true)) {
//
}
Автозавершение
Метод anticipate
используется для автоматического завершения возможных вариантов. Пользователь по-прежнему может дать любой ответ, независимо от подсказок автозавершения:
$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);
В качестве альтернативы, вы можете передать замыкание в качестве второго аргумента метода anticipate
. Замыкание будет вызываться каждый раз, когда пользователь вводит символ. Замыкание должно принимать строковый параметр, содержащий введенные пользователем данные, и возвращать массив вариантов для автозавершения:
$name = $this->anticipate('What is your address?', function ($input) {
// Вернуть варианты для автоматического завершения ...
});
Вопросы с множественным выбором
Если нужно предоставить пользователю предопределенный набор вариантов для выбора при задании вопроса, то используйте метод choice
. Вы можете установить индекс массива для возвращаемого по умолчанию значения, если не выбран ни один из вариантов, передав индекс в качестве третьего аргумента метода:
$name = $this->choice(
'What is your name?',
['Taylor', 'Dayle'],
$defaultIndex
);
Кроме того, метод choice
принимает необязательные четвертый и пятый аргументы для определения максимального количества попыток выбора действительного ответа и того, разрешен ли множественный выбор:
$name = $this->choice(
'What is your name?',
['Taylor', 'Dayle'],
$defaultIndex,
$maxAttempts = null,
$allowMultipleSelections = false
);
Вывод данных
Чтобы вывести в консоль, используйте методы line
, info
, comment
, question
, warn
и error
. Каждый из этих методов будет использовать соответствующие ANSI-цвета. Например, давайте покажем пользователю некоторую общую информацию. Обычно метод info
отображается в консоли в виде зеленого текста:
/**
* Выполнить консольную команду.
*
* @return mixed
*/
public function handle()
{
// ...
$this->info('The command was successful!');
}
Для отображения сообщения об ошибке используйте метод error
. Текст сообщения об ошибке обычно отображается красным цветом:
$this->error('Something went wrong!');
Вы можете использовать метод line
для отображения простого неокрашенного текста:
$this->line('Display this on the screen');
Вы можете использовать метод newLine
для отображения пустой строки:
// Вывести одну пустую строку ...
$this->newLine();
// Вывести три пустые строки ...
$this->newLine(3);
Таблицы
Метод table
упрощает корректное форматирование нескольких строк / столбцов данных. Все, что вам нужно сделать, это указать имена столбцов и данные для таблицы, и Laravel автоматически рассчитает подходящую ширину и высоту таблицы:
use App\Models\User;
$this->table(
['Name', 'Email'],
User::all(['name', 'email'])->toArray()
);
Индикаторы выполнения
Для длительно выполняемых задач было бы полезно показать индикатор выполнения, информирующий пользователя о том, насколько завершена задача. Используя метод withProgressBar
, Laravel будет отображать индикатор выполнения и продвигать его для каждой итерации на заданное повторяемое значение:
use App\Models\User;
$users = $this->withProgressBar(User::all(), function ($user) {
$this->performTask($user);
});
Иногда может потребоваться больший контроль над продвижением индикатора выполнения. Сначала определите общее количество шагов, через которые будет проходить процесс. Затем продвигайте индикатор выполнения после обработки каждого элемента:
$users = App\Models\User::all();
$bar = $this->output->createProgressBar(count($users));
$bar->start();
foreach ($users as $user) {
$this->performTask($user);
$bar->advance();
}
$bar->finish();
Для получения дополнительной информации ознакомьтесь с разделом документации компонента Symfony Progress Bar.
Регистрация команд
Все ваши консольные команды должны быть зарегистрированы в классе App\Console\Kernel
, который является «ядром консоли» вашего приложения. Внутри метода commands
этого класса вы увидите вызов метода load
ядра. Метод load
просканирует каталог app/Console/Commands
и автоматически зарегистрирует каждую содержащуюся в нем команду в Artisan. Фактически, вы можете делать дополнительные вызовы метода load
для сканирования других каталогов на наличие команд Artisan:
/**
* Зарегистрировать команды приложения.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
$this->load(__DIR__.'/../Domain/Orders/Commands');
// ...
}
Вы можете самостоятельно зарегистрировать команды, добавив название класса команды в свойство $commands
класса App\Console\Kernel
. Если это свойство еще не определено в вашем ядре, вы должны определить его вручную. При загрузке Artisan, все команды, перечисленные в этом свойстве будут доступны в контейнере служб и зарегистрированы в Artisan:
protected $commands = [
Commands\SendEmails::class
];
Программное выполнение команд
По желанию можно выполнить команду Artisan за пределами CLI. Например, вы можете запустить команду Artisan в маршруте или контроллере. Для этого можно использовать метод call
фасада Artisan
. Метод call
принимает в качестве первого аргумента либо имя сигнатуры команды, либо имя класса, а в качестве второго – массив параметров команды. Будет возвращен код выхода / возврата:
use Illuminate\Support\Facades\Artisan;
Route::post('/user/{user}/mail', function ($user) {
$exitCode = Artisan::call('mail:send', [
'user' => $user, '--queue' => 'default'
]);
//
});
Кроме того, вы можете передать методу call
команду полностью в виде строки:
Artisan::call('mail:send 1 --queue=default');
Передача массива значений
Если ваша команда определяет параметр, который принимает массив, то вы можете передать массив значений этому параметру:
use Illuminate\Support\Facades\Artisan;
Route::post('/mail', function () {
$exitCode = Artisan::call('mail:send', [
'--id' => [5, 13]
]);
});
Передача значений логического типа
Если необходимо указать значение параметра, который не принимает строковые значения, например флаг --force
в команде migrate:refresh
, то вы должны передать true
или false
как значение параметра:
$exitCode = Artisan::call('migrate:refresh', [
'--force' => true,
]);
Очереди команд Artisan
Используя метод queue
фасада Artisan
, вы можете даже поставить команды Artisan в очередь, чтобы они обрабатывались в фоновом режиме обработчиком очереди. Перед использованием этого метода убедитесь, что вы настроили очереди и был запущен слушатель очереди:
use Illuminate\Support\Facades\Artisan;
Route::post('/user/{user}/mail', function ($user) {
Artisan::queue('mail:send', [
'user' => $user, '--queue' => 'default'
]);
//
});
Используя методы onConnection
и onQueue
, вы также можете указать соединение или очередь, в которую должна быть отправлена команда Artisan:
Artisan::queue('mail:send', [
'user' => 1, '--queue' => 'default'
])->onConnection('redis')->onQueue('commands');
Вызов команд из других команд
По желанию можно вызвать другие команды из существующей команды Artisan. Вы можете сделать это с помощью метода call
. Метод call
принимает имя команды и массив аргументов / параметров команды:
/**
* Выполнить консольную команду.
*
* @return mixed
*/
public function handle()
{
$this->call('mail:send', [
'user' => 1, '--queue' => 'default'
]);
//
}
Если вы хотите вызвать другую консольную команду в тихом режиме, то используйте метод callSilently
. Метод callSilently
имеет ту же сигнатуру, что и метод call
:
$this->callSilently('mail:send', [
'user' => 1, '--queue' => 'default'
]);
Обработка сигналов
Компонент Symfony Console, на основе которого сделан Artisan, позволяет указать, какие сигналы процессов обрабатываются вашей командой. Например, Вы можете указать, что Ваша команда обрабатывает сигналы SIGINT
и SIGTERM
.
Чтобы воспользоваться этой фичей, имплементируйте Symfony\Component\Console\Command\SignalableCommandInterface
. Этот интерфейс требует наличия в классе методов getSubscribedSignals
и handleSignal
:
<?php
use Symfony\Component\Console\Command\SignalableCommandInterface;
class StartServer extends Command implements SignalableCommandInterface
{
// ...
/**
* Get the list of signals handled by the command.
*
* @return array
*/
public function getSubscribedSignals(): array
{
return [SIGINT, SIGTERM];
}
/**
* Handle an incoming signal.
*
* @param int $signal
* @return void
*/
public function handleSignal(int $signal): void
{
if ($signal === SIGINT) {
$this->stopServer();
return;
}
}
}
Метод getSubscribeSignals
должен возвращать массив сигналов, который ваша команда может обрабатывать, а метод handleSignal
принимает сигнал и может реагировать соответственно.
Настройка заготовок команд (stubs)
Команды make
консоли Artisan используются для создания различных классов, таких как контроллеры, задания, миграции и тесты. Эти классы создаются с помощью файлов «заготовок», которые заполняются значениями на основе ваших входных данных. Однако, иногда может потребоваться внести небольшие изменения в файлы, создаваемые с помощью Artisan. Для этого можно использовать команду stub:publish
, чтобы опубликовать наиболее распространенные заготовки для их дальнейшего изменения:
php artisan stub:publish
Опубликованные заготовки будут расположены в каталоге stubs
корня вашего приложения. Любые изменения, внесенные вами в эти заготовки, будут учтены при создании соответствующих классов с помощью команд make
Artisan.
События
Artisan запускает три события при выполнении команд: Illuminate\Console\Events\ArtisanStarting
, Illuminate\Console\Events\CommandStarting
, и Illuminate\Console\Events\CommandFinished
. Событие ArtisanStarting
выполняется сразу после запуска Artisan. Затем событие CommandStarting
выполняется непосредственно перед запуском команды. Наконец, событие CommandFinished
выполняется после завершения команды.