Введение
Artisan — интерфейс командной строки, который поставляется с Laravel. Он содержит набор полезных команд, помогающих вам при разработке приложения. Для просмотра списка доступных команд используйте команду shlist
:
shphp artisan list
Каждая команда имеет описание, в котором указаны её доступные аргументы и ключи. Для просмотра описания просто добавьте перед командой слово shhelp
:
shphp artisan help migrate
Создание команд
В дополнение к стандартным командам Artisan вы можете также создавать свои собственные команды. Обычно команды хранятся в папке app/Console/Commands, но вы можете поместить их в любое другое место, в котором их сможет найти и загрузить Composer.
Генерирование команд
добавлено в 5.3 ()
Для создания новой команды используйте Artisan-команду shmake:command
. Эта команда создаст новый класс команды в папке app/Console/Commands. Если этой папке не существует, она будет создана при первом запуске команды shmake:command
. Сгенерированная команда будет содержать стандартный набор свойств и методов, присущих всем командам:
shphp artisan make:command SendEmails
Затем вам надо зарегистрировать команду, тогда она сможет быть запущена через командный интерфейс Artisan.
добавлено в 5.2 () 5.1 () 5.0 ()
Для создания новой команды можно использовать Artisan-команду shmake:console
, которая создаст заглушку, с которой вы можете начать работать.
shphp artisan make:console SendEmails
Эта команда создаст класс в app/Console/Commands/SendEmails.php. При создании команды может быть использован ключ sh--command
для назначения имени команды в терминале:
shphp artisan make:console SendEmails --command=emails:send
Структура команды
После генерирования команды, вам нужно заполнить свойства signature и description в её классе, которые используются при отображении вашей команды в списке команд (shlist
). При вызове вашей команды будет вызван метод PHPhandle()
. В него вы можете поместить необходимую вам логику.
Для улучшения кода, с точки зрения его повторного использования, полезно сохранять ваши консольные команды простыми и использовать в них сервисы самого приложения для выполнения их задач. Обратите внимание, что в приведённом примере мы внедряем класс сервиса для выполнения «трудоёмкой» задачи отправки писем.
Давайте посмотрим на пример команды. Мы можем внедрить любые необходимые зависимости в конструкторе команды. Сервис-контейнер Laravel автоматически внедрит все указанные в конструкторе зависимости:
<?php
namespace App\Console\Commands;
use App\User;
use App\DripEmailer;
use Illuminate\Console\Command;
class SendEmails extends Command
{
/**
* Имя и аргументы консольной команды.
*
* @var string
*/
protected $signature = 'email:send {user}';
/**
* Описание консольной команды.
*
* @var string
*/
protected $description = 'Send drip e-mails to a user';
/**
* Служба "капельных" e-mail сообщений.
*
* @var DripEmailer
*/
protected $drip;
/**
* Создание нового экземпляра команды.
*
* @param DripEmailer $drip
* @return void
*/
public function __construct(DripEmailer $drip)
{
parent::__construct();
$this->drip = $drip;
}
/**
* Выполнение консольной команды.
*
* @return mixed
*/
public function handle()
{
$this->drip->send(User::find($this->argument('user')));
}
}
добавлено в 5.3 ()
Команды замыкания
Команды на основе замыканий являются альтернативой определению консольных команд в виде классов, подобно тому, как замыкания маршрутов являются альтернативой контроллерам. В методе PHPcommands()
файла app/Console/Kernel.php Laravel загружает файл routes/console.php:
/**
* Регистрация команд на основе замыканий для приложения.
*
* @return void
*/
protected function commands()
{
require base_path('routes/console.php');
}
Не смотря на то, что этот файл не определяет HTTP-маршруты, он определяет консольные входные точки (маршруты) в ваше приложение. В этом файле вы можете определить все свои маршруты на основе замыканий с помощью метода PHPArtisan::command()
. Метод PHPcommand()
принимает два аргумента: сигнатуру команды и замыкание, которое получает аргументы и ключи команды:
Artisan::command('build {project}', function ($project) {
$this->info("Building {$project}!");
});
Замыкание привязано к лежащему в основе экземпляру команды, поэтому у вас есть полный доступ ко всем вспомогательным методам, которые обычно доступны вам в полном классе команды.
Помимо получения аргументов и ключей вашей команды в замыканиях команд можно указывать типы дополнительных зависимостей, которые вам необходимо получить из сервис-контейнера:
use App\User;
use App\DripEmailer;
Artisan::command('email:send {user}', function (DripEmailer $drip, $user) {
$drip->send(User::find($user));
});
При определении команд на основе замыканий вы можете использовать метод PHPdescribe()
для добавления описания команды. Это описание будет выводится при выполнении команд shphp artisan list
или shphp artisan help
:
Artisan::command('build {project}', function ($project) {
$this->info("Building {$project}!");
})->describe('Build the project');
Определение ожиданий ввода
При создании консольных команд часто необходимо получать ввод от пользователя через аргументы или ключи. В Laravel очень удобно определить ожидаемый от пользователя ввод, используя свойство signature вашей команды. Это свойство позволяет задать имя, аргументы и ключи для команды в едином, выразительном, маршруто-подобном синтаксисе.
Аргументы
Все вводимые пользователем аргументы и ключи заключаются в фигурные скобки. В следующем примере команда определяет один требуемый аргумент user:
/**
* Имя и аргументы консольной команды.
*
* @var string
*/
protected $signature = 'email:send {user}';
Вы можете сделать аргумент необязательным и определить значения по умолчанию для аргументов:
// Необязательный аргумент...
email:send {user?}
// Необязательный аргумент со значением по умолчанию...
email:send {user=foo}
Ключи
Ключи, как и аргументы, являются формой пользовательского ввода. Они обозначаются префиксом из двух дефисов (—). Существует два типа ключей: принимающие значение и не принимающие. Ключи, которые не принимают значение, служат логическими «переключателями». Давайте посмотрим на такой тип ключей:
/**
* Имя и аргументы консольной команды.
*
* @var string
*/
protected $signature = 'email:send {user} {--queue}';
В этом примере при вызове Artisan-команды может быть указан ключ sh--queue
. Если будет передан ключ sh--queue
, то его значение будет true, иначе false:
shphp artisan email:send 1 --queue
Теперь посмотрим на ключи, которые ожидают значения. Необходимость ввода значения для ключа задаётся при помощи знака равно (=):
/**
* Имя и аргументы консольной команды.
*
* @var string
*/
protected $signature = 'email:send {user} {--queue=}';
В этом примере пользователь может передать значение для ключа вот так:
shphp artisan email:send 1 --queue=default
Для ключей можно задать значение по умолчанию, указав его после имени ключа. Это значение будет использовано, если пользователь не укажет значение ключа:
shemail:send {user} {--queue=default}
Чтобы задать сокращение при определении ключа, вы можете указать его перед именем ключа и отделить его символом вертикальной черты (|):
shemail:send {user} {--Q|queue}
Ввод массивов
Если вы хотите указать, что аргументы или ключи будут принимать на вход массивы, используйте символ *. Сначала посмотрим на пример указания аргумента массива:
shemail:send {user*}
При вызове этой команды в командную строку можно передать аргументы user по порядку. Например, следующая команда установит значение user равное ['foo', 'bar']:
shphp artisan email:send foo bar
При определении ключа, который будет принимать на вход массив, каждое передаваемое в команду значение ключа должно иметь префикс в виде имени ключа:
shemail:send {user} {--id=*} php artisan email:send --id=1 --id=2
Описание ввода
Вы можете задать описание для аргументов и ключей, отделив их двоеточием. Если вам необходимо немного больше места для определения вашей команды, вы можете разделить описание на несколько строк:
/**
* Имя и аргументы консольной команды.
*
* @var string
*/
protected $signature = 'email:send
{user : ID пользователя}
{--queue= : Ставить ли задачу в очередь}';
Ввод/вывод команд
Чтение ввода
Во время выполнения команды вам, конечно, потребуется доступ к аргументам и ключам, которые были переданы ей на вход. Для этого вы можете использовать методы PHPargument()
и PHPoption()
.
Для чтения значения аргумента используйте метод PHPargument()
:
/**
* Выполнение консольной команды.
*
* @return mixed
*/
public function handle()
{
$userId = $this->argument('user');
//
}
Если вам необходимо прочитать все аргументы в виде массива, вызовите метод PHParguments()
(для версии 5.2 и ранее — метод PHPargument()
без аргументов):
$arguments = $this->arguments();
Ключи можно прочитать так же легко, как аргументы, используя метод PHPoption()
. Чтобы получить массив всех ключей, вызовите метод PHPoptions()
(для версии 5.2 и ранее — метод PHPoption()
без аргументов):
// Чтение конкретного ключа...
$queueName = $this->option('queue');
// Чтение всех ключей...
$options = $this->options();
Если аргумента или ключа не существует, будет возвращён PHPnull
.
Запрос ввода
В дополнение к отображению вывода вы можете запросить у пользователя данные во время выполнения команды. Метод PHPask()
выведет запрос, примет введённые данные, а затем вернёт их вашей команде:
/**
* Выполнение консольной команды.
*
* @return mixed
*/
public function handle()
{
$name = $this->ask('What is your name?');
}
Метод PHPsecret()
похож на метод PHPask()
, но он не отображает вводимые пользователем данные в консоли. Этот метод полезен при запросе секретной информации, такой как пароль:
$password = $this->secret('What is the password?');
Для получения от пользователя простого подтверждения можно использовать метод PHPconfirm()
. По умолчанию этот метод возвращает false. Но если пользователь введёт y или yes в ответ на запрос, то метод вернёт true:
if ($this->confirm('Do you wish to continue?')) {
//
}
Метод PHPanticipate()
можно использовать для предоставления пользователю возможных вариантов для выбора. Независимо от наличия этих вариантов пользователь может указать свой вариант.
$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);
Вопросы с несколькими вариантами ответов
Для предоставления пользователю определённого набора вариантов можно использовать метод PHPchoice()
. Можно задать значение по умолчанию, на случай если вариант не выбран:
$name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $default);
Вывод
Для вывода вы можете использовать методы PHPline()
, PHPinfo()
, PHPcomment()
, PHPquestion()
и PHPerror()
. Каждый из них будет использовать подходящие по смыслу цвета ANSI для отображении текста. Давайте для примера выведем информационное сообщение для пользователя. Обычно метод PHPinfo()
выводит в консоль текст зелёного цвета:
/**
* Выполнение консольной команды.
*
* @return mixed
*/
public function handle()
{
$this->info('Вывести это на экран');
}
Для вывода сообщения об ошибке используйте метод PHPerror()
. Он выводит в консоль текст красного цвета:
$this->error('Что-то пошло не так!');
Для простого вывода текста в консоль без использования специальных цветов используйте метод PHPline()
:
$this->line('Вывести это на экран');
Метод PHPtable()
позволяет легко форматировать несколько строк/столбцов данных. Просто передайте в него заголовки и строки. Ширина и высота будет динамически определена на основе переданных данных:
$headers = ['Name', 'Email'];
$users = App\User::all(['name', 'email'])->toArray();
$this->table($headers, $users);
Для продолжительных задач бывает полезно вывести индикатор процесса. Используя объект вывода мы можем запустить, передвинуть и остановить индикатор. Сначала определите общее число шагов, по которым будет идти процесс. Затем передвигайте индикатор после выполнения каждого шага:
$users = App\User::all();
$bar = $this->output->createProgressBar(count($users));
foreach ($users as $user) {
$this->performTask($user);
$bar->advance();
}
$bar->finish();
Более подробная информация указана в документации по индикаторам процесса Symfony.
добавлено в 5.0 ()
Указание имени среды для выполнения команды
Вы можете указать среду, которая будет использоваться при выполнении команды, с помощью ключа sh--env
:
shphp artisan migrate --env=local
Вывод вашей текущей версии Laravel
Вы также можете узнать версию текущей установки Laravel с помощью ключа sh--version
:
shphp artisan --version
Регистрация команд
Когда ваша команда написана, вам нужно зарегистрировать её в Artisan. Все команды регистрируются в файле app/Console/Kernel.php. В нём вы найдёте список команд в свойстве commands. Чтобы зарегистрировать свою команду, просто добавьте имя класса команды в этот список. Когда Artisan загружается, все перечисленные в этом свойстве команды будут включены в сервис-контейнер и зарегистрированы в Artisan:
protected $commands = [
Commands\SendEmails::class
];
Программное выполнение команд
Иногда необходимо выполнить команду извне командной строки. Например, когда вы хотите запустить команду из маршрута или контроллера. Для этого можно использовать метод PHPcall()
фасада Artisan. Этот метод принимает первым аргументом имя команды, а вторым — массив аргументов команды. Будет возвращён код выхода:
Route::get('/foo', function () {
$exitCode = Artisan::call('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
});
С помощью метода PHPqueue()
можно даже поставить команды в очередь, тогда они будут обработаны в фоне с помощью ваших обработчиков очереди. Прежде чем использовать этот метод, убедитесь в том, что вы настроили вашу очередь, и что слушатель очереди запущен:
Route::get('/foo', function () {
Artisan::queue('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
});
Когда нужно указать значение ключа, который не принимает строковое значение, например, флаг sh--force
команды shmigrate:refresh
, вы можете передать значение true или false:
$exitCode = Artisan::call('migrate:refresh', [
'--force' => true,
]);
Вызов команд из других команд
Иногда необходимо вызвать другую команду из своей. Для этого используйте метод PHPcall()
. Он принимает имя команды и массив её аргументов:
/**
* Выполнение консольной команды.
*
* @return mixed
*/
public function handle()
{
$this->call('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
}
Если вы хотите вызвать другую команду и запретить её вывод в консоль, используйте метод PHPcallSilent()
. Этот метод принимает те же аргументы, что и метод PHPcall()
:
$this->callSilent('email:send', [
'user' => 1, '--queue' => 'default'
]);
Планирование команд Artisan
Данный раздел статьи актуален только для версии 5.0 и был
удален в версии 5.1.
Раньше разработчикам приходилось создавать Cron-задачи для каждой консольной команды, которую они хотели запланировать. Это утомительно. Для планирования консольных команд теперь не ведётся контроль версий, и для добавления Cron-задач вам необходимо подключаться к серверу по SSH. Давайте упростим нам жизнь. Планировщик команд Laravel позволяет вам гибко и выразительно задавать план команд в самом Laravel, а на сервере нужна только одна Cron-задача.
Ваш план команд хранится в файле app/Console/Kernel.php. В этом классе вы найдёте метод PHPschedule
. Чтобы помочь вам разобраться, в метод включён простой пример. Вы можете добавлять в объект PHPSchedule
столько запланированных задач, сколько пожелаете. А на сервере вам надо добавить единственную Cron-задачу:
sh* * * * * php /path/to/artisan schedule:run 1>> /dev/null 2>&1
Эта задача будет каждую минуту вызывать планировщик команд Laravel. А тот в свою очередь будет проверять имеющиеся в плане задачи и выполнять необходимые. Проще некуда!
Ещё примеры планирования
Давайте рассмотрим ещё несколько примеров планирования.
$schedule->call(function()
{
// Выполнить какое-то задание...
})->hourly();
Планирование терминальных команд
$schedule->exec('composer self-update')->daily();
$schedule->command('foo')->cron('* * * * *');
Выполнение команды каждые пять, десять или тридцать минут соответственно:
$schedule->command('foo')->everyFiveMinutes();
$schedule->command('foo')->everyTenMinutes();
$schedule->command('foo')->everyThirtyMinutes();
$schedule->command('foo')->daily();
Ежедневные задачи в указанное время (24-часовой формат)
$schedule->command('foo')->dailyAt('15:00');
Задачи, выполняемые дважды в день
$schedule->command('foo')->twiceDaily();
$schedule->command('foo')->weekdays();
$schedule->command('foo')->weekly();
// Планирование еженедельной задачи на конкретный день (0-6) и время...
$schedule->command('foo')->weeklyOn(1, '8:00');
$schedule->command('foo')->monthly();
Задачи, выполняемые в указанный день недели
$schedule->command('foo')->mondays();
$schedule->command('foo')->tuesdays();
$schedule->command('foo')->wednesdays();
$schedule->command('foo')->thursdays();
$schedule->command('foo')->fridays();
$schedule->command('foo')->saturdays();
$schedule->command('foo')->sundays();
По умолчанию запланированные задачи будут запущены, даже если предыдущий экземпляр всё ещё запущен. Для предотвращения такого поведения используйте метод PHPwithoutOverlapping
:
$schedule->command('foo')->withoutOverlapping();
В этом примере команда foo будет запускаться каждую минуту, если она уже не запущена.
Указание конкретных сред для запуска задач
$schedule->command('foo')->monthly()->environments('production');
Указание необходимости запуска задачи даже в режиме техобслуживания
$schedule->command('foo')->monthly()->evenInMaintenanceMode();
Запуск задачи только в случае возврата PHPtrue
$schedule->command('foo')->monthly()->when(function()
{
return true;
});
Отправка вывода задачи на e-mail
$schedule->command('foo')->sendOutputTo($filePath)->emailOutputTo('foo@example.com');
Необходимо отправить вывод в файл перед тем, как он сможет быть послан по e-mail.
Отправка вывода задачи в указанное место
$schedule->command('foo')->sendOutputTo($filePath);
Выполнить ping указанного URL после запуска задачи
$schedule->command('foo')->thenPing($url);
Для использования функции PHPthenPing($url)
необходима HTTP-библиотека Guzzle. Вы можете добавить Guzzle 5 в свой проект, добавив следующую строку в файл PHPcomposer.json
:
conf"guzzlehttp/guzzle": "~5.0"
Комментарии (1)
Подскажите, куда делась команда app:name? Запускаю на выполнение php artisan app:name Appname, но выдает сообщение:
«There are no commands defined in the “app” namespace.»