Консоль Artisan
- Введение
- Написание команд
- Определение входных ожиданий
- Командный ввод/вывод
- Регистрация команд
- Программное выполнение команд
- Обработка сигналов
- Настройка заглушки
- События
Введение
Artisan - это интерфейс командной строки, включенный в Laravel. Artisan существует в корне вашего приложения как скрипт artisan
и предоставляет ряд полезных команд, которые могут помочь вам при создании приложения. Чтобы просмотреть список всех доступных 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
{tip} Ищете графический интерфейс для взаимодействия с вашим приложением Laravel? Зацените Tinkerwell!
Применение
Tinker позволяет вам взаимодействовать со всем вашим приложением Laravel в командной строке, включая ваши модели Eloquent, задания, события и многое другое. Чтобы войти в среду Tinker, запустите Artisan-команду tinker
:
php artisan tinker
Вы можете опубликовать файл конфигурации Tinker с помощью команды vendor:publish
:
php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"
{note} Вспомогательная функция
dispatch
и методdispatch
в классеDispatchable
зависят от сборки мусора для помещения задания в очередь. Следовательно, при использовании tinker вы должны использоватьBus::dispatch
илиQueue::push
для отправки заданий.
Список разрешенных команд
Tinker использует список «разрешенных», чтобы определить, какие команды Artisan разрешено запускать в его оболочке. По умолчанию вы можете запускать команды clear-compiled
, down
, env
, inspire
, migrate
, optimize
и up
. Если вы хотите разрешить больше команд, вы можете добавить их в массив команд commands
в файле конфигурации tinker.php
:
'commands' => [ // App\Console\Commands\ExampleCommand::class,],
Классы, которые не должны иметь псевдонимов
Обычно Tinker автоматически присваивает классам псевдонимы, когда вы взаимодействуете с ними в Tinker. Однако вы можете никогда не использовать псевдонимы для некоторых классов. Вы можете сделать это, перечислив классы в массиве dont_alias
вашего конфигурационного файла tinker.php
:
'dont_alias' => [ App\Models\User::class,],
Написание команд
В дополнение к командам, предоставленным Artisan, вы можете создавать свои собственные пользовательские команды. Команды обычно хранятся в каталоге app/Console/Commands
; однако вы можете выбрать свое собственное место хранения, если ваши команды могут быть загружены с помощью Composer.
Генерация команд
Чтобы создать новую команду, вы можете использовать Artisan-команду make:command
. Эта команда создаст новый класс команды в каталоге app/Console/Commands
. Не беспокойтесь, если этот каталог не существует в вашем приложении - он будет создан при первом запуске Artisan-команды make:command
:
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}'; /** * The console command description. * * @var string */ protected $description = 'Send a marketing email to a user'; /** * Create a new command instance. * * @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'))); }}
{tip} Для более широкого повторного использования кода рекомендуется держать консольные команды легкими и позволять им доверять выполнение своих задач службам приложений. Обратите внимание, что в приведенном выше примере мы внедряем сервис класс, чтобы выполнить «тяжелую работу» по отправке электронных писем.
Замыкание команд
Команды на основе замыкания предоставляют альтернативу определению консольных команд как классов. Точно так же, как замыкание маршрута является альтернативой контроллерам, думайте о замыкании команд как об альтернативе классам команд. В методе commands
вашего файла app/Console/Kernel.php
Laravel загружает файл routes/console.php
:
/** * Register the closure based commands for the application. * * @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}';
В этом примере переключатель --queue
может быть указан при вызове команды Artisan. Если передан переключатель --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}
When invoking the command on your terminal, option shortcuts should be prefixed with a single hyphen:
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'); //}
Если вам нужно получить все аргументы в виде массива array
, вызовите метод arguments
:
$arguments = $this->arguments();
Параметры можно получить так же легко, как и аргументы, с помощью метода option
. Чтобы получить все параметры в виде массива, вызовите метод options
:
// Получить конкретный вариант...$queueName = $this->option('queue'); // Получить все параметры в виде массива...$options = $this->options();
Запрос ввода
В дополнение к отображению вывода вы также можете попросить пользователя ввести ввод во время выполнения вашей команды. Метод ask
предложит пользователю заданный вопрос, примет его ввод, а затем вернет введенные пользователем данные обратно вашей команде:
/** * Выполнение консольной команды. * * @return mixed */public function handle(){ $name = $this->ask('Как тебя зовут?');}
Метод secret
похож на метод ask
, но вводимые пользователем данные не будут видны им при вводе в консоли. Этот метод полезен при запросе конфиденциальной информации, такой как пароли:
$password = $this->secret('Какой пароль?');
Просить о подтверждении
Если вам нужно попросить пользователя дать простое подтверждение «да или нет», вы можете использовать метод confirm
. По умолчанию этот метод возвращает false
. Однако, если пользователь вводит y
или yes
в ответ на приглашение, метод вернет true
.
if ($this->confirm('Вы хотите продолжить?')) { //}
Если необходимо, вы можете указать, что запрос подтверждения должен по умолчанию возвращать true
, передав true
в качестве второго аргумента метода confirm
:
if ($this->confirm('Вы хотите продолжить?', true)) { //}
Автозаполнение
Метод anticipate
может использоваться для автоматического завершения возможных вариантов. Пользователь по-прежнему может дать любой ответ, независимо от подсказок автозаполнения:
$name = $this->anticipate('Как тебя зовут?', ['Тейлор', 'Дейл']);
В качестве альтернативы вы можете передать замыкание в качестве второго аргумента методу anticipate
. Замыкание будет вызываться каждый раз, когда пользователь вводит вводимый символ. Замыкание должно принимать строковый параметр, содержащий введенные пользователем данные, и возвращать массив параметров для автозаполнения:
$name = $this->anticipate('What is your address?', function ($input) { // Вернуть параметры автозаполнения...});
Вопросы с множественным выбором
Если вам нужно предоставить пользователю предопределенный набор вариантов выбора при задании вопроса, вы можете использовать метод choice
. Вы можете установить индекс массива для значения по умолчанию, которое будет возвращено, если не выбран ни один из вариантов, передав индекс в качестве третьего аргумента метода:
$name = $this->choice( 'Как тебя зовут?', ['Тейлор', 'Дейл'], $defaultIndex);
Кроме того, метод choice
принимает необязательные четвертый и пятый аргументы для определения максимального количества попыток выбора действительного ответа и того, разрешен ли множественный выбор:
$name = $this->choice( 'Как тебя зовут?', ['Тейлор', 'Дейл'], $defaultIndex, $maxAttempts = null, $allowMultipleSelections = false);
Запись вывода
Чтобы отправить вывод на консоль, вы можете использовать методы line
, info
, comment
, question
, warn
и error
. Каждый из этих методов будет использовать соответствующие цвета ANSI для своей цели. Например, покажем пользователю некоторую общую информацию. Обычно метод info
отображается в консоли в виде текста зеленого цвета:
/** * Выполнение консольной команды. * * @return mixed */public function handle(){ // ... $this->info('Команда выполнена успешно!');}
Чтобы отобразить сообщение об ошибке, используйте метод error
. Текст сообщения об ошибке обычно отображается красным цветом:
$this->error('Что-то пошло не так!');
Вы можете использовать метод 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();
{tip} Чтобы узнать о дополнительных параметрах, ознакомьтесь с документацией по компонентам индикатора выполнения Symfony.
Регистрация команд
Все ваши консольные команды зарегистрированы в классе вашего приложения App\Console\Kernel
, который является «консольным ядром» вашего приложения. В методе commands
этого класса вы увидите вызов метода ядра load
. Метод load
просканирует каталог app/Console/Commands
и автоматически зарегистрирует каждую содержащуюся в нем команду в Artisan. Вы даже можете выполнять дополнительные вызовы метода load
для сканирования других каталогов на предмет команд Artisan:
/** * Register the commands for the application. * * @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' ]); //});
В качестве альтернативы вы можете передать всю Artisan-команду методу 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
в своем классе команд Artisan. Этот интерфейс требует от вас определения двух методов: 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; } }}
Как и следовало ожидать, метод getSubscribedSignals
должен возвращать массив сигналов, которые может обработать ваша команда, в то время как метод handleSignal
принимает сигнал и может соответствующим образом реагировать.
Настройка заглушки
Команды консоли Artisan make
используются для создания различных классов, таких как контроллеры, задания, миграции и тесты. Эти классы создаются с помощью файлов-заглушек, которые заполняются значениями на основе ваших входных данных. Однако вы можете внести небольшие изменения в файлы, созданные Artisan. Для этого вы можете использовать команду stub:publish
, чтобы опубликовать наиболее распространенные заглушки в вашем приложении, чтобы вы могли их настраивать:
php artisan stub:publish
Опубликованные заглушки будут расположены в каталоге stubs
в корне вашего приложения. Любые изменения, внесенные вами в эти заглушки, будут отражены при создании соответствующих классов с помощью команд Artisan make
.
События
Artisan отправляет три события при запуске команд: Illuminate\Console\Events\ArtisanStarting
, Illuminate\Console\Events\CommandStarting
и Illuminate\Console\Events\CommandFinished
. Событие ArtisanStarting
отправляется сразу после запуска Artisan. Затем событие CommandStarting
отправляется непосредственно перед запуском команды. Наконец, событие CommandFinished
отправляется после завершения выполнения команды.