- Введение
- Написание команд
- Определение вводимых данных
- Ввод/вывод команды
- Регистрация команд
- Программное выполнение команд
- Обработка сигналов
- Настройка заготовок
- События
Artisan – это интерфейс командной строки, входящий в состав Laravel. Он предлагает ряд полезных команд, которые помогут при создании приложения. Для просмотра списка всех доступных команд Artisan можно использовать команду list
:
php artisan list
Каждая команда также включает в себя экран «справки», который отображает и описывает доступные аргументы и параметры команды. Чтобы просмотреть экран справки, используйте help
перед именем команды:
php artisan help migrate
Если вы используете Laravel Sail в качестве локальной среды разработки, не забудьте использовать командную строку sail
для вызова команд Artisan. Sail выполнит ваши команды Artisan в контейнерах Docker вашего приложения:
./vendor/bin/sail artisan list
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';
/**
* Выполнить консольную команду.
*
* @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');
Предупреждение
Чтобы использовать этот функционал, ваше приложение должно использовать в качестве драйвера кеша по умолчаниюmemcached
,redis
,dynamodb
,database
,file
,array
. Кроме того, все серверы должны обмениваться данными с одним и тем же сервером центрального кэша.
Иногда необходимо гарантировать, что только один экземпляр команды может выполняться одновременно. Для этого вы можете реализовать интерфейс Illuminate\Contracts\Console\Isolatable
в своем классе команд:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Isolatable;
class SendEmails extends Command implements Isolatable
{
// ...
}
Когда команда помечена как Isolatable
, Laravel автоматически добавит к команде параметр --isolated
. Когда команда вызывается с этим параметром, то Laravel гарантирует, что никакие другие экземпляры этой команды еще не запущены. Laravel достигает этого, пытаясь получить атомарную блокировку, используя драйвер кеша вашего приложения по умолчанию. Если запущены другие экземпляры команды, то команда не будет выполняться; однако, команда все равно завершится с успешным кодом выхода:
php artisan mail:send 1 --isolated
Если вы хотите указать код состояния выхода, который должна возвращать команда, если она не может быть выполнена, то вы можете указать желаемый код состояния с помощью опции isolated
:
php artisan mail:send 1 --isolated=12
По умолчанию время действия изоляционных блокировок истекает после завершения команды. Или, если команда прервана и не может быть завершена, блокировка истечет через один час. Однако вы можете настроить время истечения блокировки, определив метод isolationLockExpiresAt
в вашей команде:
/**
* Определить, когда истечет время действия блокировки изоляции команды.
*
* @return \DateTimeInterface|\DateInterval
*/
public function isolationLockExpiresAt()
{
return now()->addMinutes(5);
}
При написании консольных команд обычно происходит сбор данных, получаемых от пользователя, с помощью аргументов или параметров. 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
как массив со значениями 1
и 2
:
php artisan mail:send 1 2
Метасимвол *
можно комбинировать с необязательным определением аргумента, чтобы разрешить ноль или более экземпляров аргумента:
'mail:send {--id=*}'
При определении параметра, ожидающего множество значений, каждое значение передаваемого команде параметра должно иметь префикс с именем параметра:
'mail:send {user} {--id=*}'
Такую команду можно вызвать, передав несколько аргументов --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,
]);
Используя метод 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'
]);
Как вы, возможно, знаете, операционные системы позволяют отправлять сигналы запущенным процессам. Например, сигнал SIGTERM
— это то, как операционные системы запрашивают завершение программы. Если вы хотите прослушивать сигналы в консольных командах Artisan и выполнять код при их появлении, вы можете использовать метод trap
:
/**
* Выполнить консольную команду.
*
* @return mixed
*/
public function handle()
{
$this->trap(SIGTERM, fn () => $this->shouldKeepRunning = false);
while ($this->shouldKeepRunning) {
// ...
}
}
Чтобы прослушивать несколько сигналов одновременно, вы можете передать массив сигналов методу trap
:
$this->trap([SIGTERM, SIGQUIT], function ($signal) {
$this->shouldKeepRunning = false;
dump($signal); // SIGTERM / SIGQUIT
});
Команды 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
выполняется после завершения команды.