Консоль Artisan

Вступление

Artisan — это интерфейс командной строки, входящий в комплект поставки Laravel. Он предоставляет ряд полезных команд, которые могут помочь вам в процессе создания приложения. Для просмотра списка всех доступных команд Artisan можно воспользоваться командой list:

php artisan list

Каждая команда также включает в себя экран справки, в котором отображаются и описываются доступные аргументы и опции команды. Для просмотра экрана справки имени команды предшествует help:

php artisan help migrate

Tinker (REPL)

Laravel Tinker — это мощный REPL для фреймворка Laravel, работающий на основе пакета PsySH.

Установка

Все приложения Laravel включают Tinker по умолчанию. Однако при необходимости вы можете установить его вручную с помощью Composer:

composer require laravel/tinker

Использование

Tinker позволяет взаимодействовать со всем приложением Laravel в командной строке, включая Eloquent ORM, задания, события и многое другое. Чтобы войти в среду Tinker, запустите команду tinker:

php artisan tinker

Вы можете опубликовать конфигурационный файл Tinker'а с помощью команды vendor:published:

php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"

Функция-помощник 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\User::class,
],

Написание команд

В дополнение к командам, предоставляемым Artisan, вы также можете создавать свои собственные пользовательские команды. Команды обычно хранятся в каталоге app/Console/Commands; однако, вы можете выбрать своё собственное место хранения, главное, чтобы ваши команды могли быть загружены Composer`ом.

Генерация команд

Для создания новой команды используйте Artisan-команду make:command. Эта команда создаст новый класс команды в каталоге app/Console/Commands. Не беспокойтесь, если этот каталог не существует в вашем приложении, так как он будет создан при первом запуске команды make:command. Сгенерированная команда будет включать набор свойств и методов по умолчанию, которые присутствуют во всех командах:

php artisan make:command SendEmails

Структура команды

После генерации команды у класса необходимо заполнить свойства signature и description, которые будут использоваться при отображении Вашей команды на экране list. Метод handle будет вызван при выполнении Вашей команды. Вы можете поместить логику Вашей команды в этот метод.

Для повторного использования кода, это хорошая практика, сохраняйте консольные команды легкими и позвольте им использовать сервисы приложений для выполнения своих задач. В примере ниже, обратите внимание, что мы вводим класс обслуживания, чтобы сделать "тяжелую задачу" отправки электронной почты.

Давайте рассмотрим пример команды. Обратите внимание, что мы можем ввести любые необходимые нам зависимости в метод handle команды. Service-контейнер Laravel автоматически внедрит все зависимости, которые указаны в сигнатуре этого метода:

<?php

namespace App\Console\Commands;

use App\DripEmailer;
use App\User;
use Illuminate\Console\Command;

class SendEmails extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'email:send {user}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Send drip e-mails to a user';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @param  \App\DripEmailer  $drip
     * @return mixed
     */
    public function handle(DripEmailer $drip)
    {
        $drip->send(User::find($this->argument('user')));
    }
}

Команды на функциях обратного вызова

Команды, основанные на функциях обратного вызова, представляют собой альтернативу определению консольных команд как классов. Точно так же, как маршрутные Closures являются альтернативой контроллерам, думайте о командах Closures как об альтернативе командным классам. В методе commands класс app/Console/Kernel.php загружает файл routes/console.php:

/**
 * Register the Closure based commands for the application.
 *
 * @return void
 */
protected function commands()
{
    require base_path('routes/console.php');
}

Несмотря на то, что этот файл не определяет HTTP-маршруты, он определяет консольные точки входа (routes) в приложение. Внутри этого файла вы можете определить все ваши маршруты, основанные на Closure, используя метод Artisan::command. Метод command принимает два аргумента: сигнатура команды и Closure, который получает аргументы и опции команд:

Artisan::command('build {project}', function ($project) {
    $this->info("Building {$project}!");
});

Функция обратного вызова привязана к базовому экземпляру команды, поэтому у вас есть полный доступ ко всем вспомогательным методам, к которым вы обычно можете получить доступ с помощью полного класса команд.

Type-Hinting Dependencies

В дополнение к получению аргументов и опций вашей команды, в коллбеке можно также указывать подсказки типов на дополнительные зависимости, которые вы хотели бы разрешить из сервис-контейнера:

use App\DripEmailer;
use App\User;

Artisan::command('email:send {user}', function (DripEmailer $drip, $user) {
    $drip->send(User::find($user));
});

Описание команды, основанной на коллбеке

При определении команды, основанной на Closure, вы можете использовать метод decribe для добавления описания к команде. Это описание будет отображаться при выполнении команд php artisan list или php artisan help:

Artisan::command('build {project}', function ($project) {
    $this->info("Building {$project}!");
})->describe('Build the project');

Определение входных данных

При написании консольных команд принято собирать входные данные от пользователя через аргументы или опции. Laravel делает очень удобным определение входа, который вы ожидаете от пользователя, используя свойство signature в ваших командах. Свойство signature позволяет определить имя, аргументы и опции для команды в едином, выразительном синтаксисе.

Аргументы

Все аргументы и опции, предоставленные пользователем, обернуты фигурными скобками. В следующем примере команда определяет один обязательный аргумент: user:

/**
 * The name and signature of the console command.
 *
 * @var string
 */
protected $signature = 'email:send {user}';

Вы также можете сделать аргументы необязательными и определить значения по умолчанию:

// Optional argument...
email:send {user?}

// Optional argument with default value...
email:send {user=foo}

Опции

Опции, как и аргументы, являются другой формой пользовательского ввода. Опции префиксуются двумя дефисами (--), когда они указываются в командной строке. Существует два типа опций: те, которые получают значение и те, которые не получают. Опции, которые не получают значения, служат булевым "переключателем". Рассмотрим пример такого типа опций:

/**
 * The name and signature of the console command.
 *
 * @var string
 */
protected $signature = 'email:send {user} {--queue}';

В этом примере при вызове команды может быть указан переключатель --queue. Если передан переключатель --queue, то значение опции будет true. В противном случае, значение будет false:

php artisan email:send 1 --queue

Опции со значениями

Далее давайте рассмотрим вариант, который ожидает значение. Если пользователь должен указать значение для опции, добавьте к имени опции знак =:

/**
 * The name and signature of the console command.
 *
 * @var string
 */
protected $signature = 'email:send {user} {--queue=}';

В этом примере, пользователь может передать значение для опции, подобное этому:

php artisan email:send 1 --queue=default

Вы можете присвоить опциям значения по умолчанию, указав его после названия опции. Если значение опции не будет передано пользователем, будет использовано значение по умолчанию:

email:send {user} {--queue=default}

Сокращения для опций

Чтобы назначить ярлык при определении опции, вы можете указать его перед именем опции и использовать разделитель | для отделения ярлыка от полного имени опции:

email:send {user} {--Q|queue}

Ввод массивов

Если нужно определить аргументы или опции ожидающие ввода массива, Вы можете использовать символ *. Сначала рассмотрим пример, который задает аргумент массива:

email:send {user*}

При вызове этого метода в командную строку могут быть переданы аргументы user. Например, следующая команда установит значение user в ['foo', 'bar']:

php artisan email:send foo bar

При определении опции, ожидающей ввода массива, каждое значение опции, передаваемое команде, должно иметь префикс с именем опции:

email:send {user} {--id=*}

php artisan email:send --id=1 --id=2

Описание аргументов и опций

Вы можете назначить описания входным аргументам и опциям, отделив параметр от описания двоеточием. Если вам нужно немного больше места для определения вашей команды, не стесняйтесь распространять определение на несколько строк:

/**
 * The name and signature of the console command.
 *
 * @var string
 */
protected $signature = 'email:send
                        {user : The ID of the user}
                        {--queue= : Whether the job should be queued}';

Ввод-вывод команды

Получение входных данных

Пока ваша команда выполняется, вам, очевидно, понадобится доступ к значениям аргументов и опций, принятых вашей командой. Для этого вы можете использовать методы argument и option:

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    $userId = $this->argument('user');

    //
}

Если вам нужно получить все аргументы в виде массива, вызовите метод arguments:

$arguments = $this->arguments();

Опции могут быть извлечены так же легко, как и аргументы, с помощью метода option. Чтобы получить все опции в виде массива, вызовите метод options:

// Retrieve a specific option...
$queueName = $this->option('queue');

// Retrieve all options...
$options = $this->options();

Если аргумент или опция не существует, то будет возвращено значение null.

Запрос входных данных

В дополнение к отображению вывода, Вы также можете попросить пользователя предоставить ввод во время выполнения Вашей команды. Метод ask покажет пользователю заданный вопрос, примет его ввод, а затем вернет ввод пользователя обратно Вашей команде:

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    $name = $this->ask('What is your name?');
}

Метод secret похож на ask, но ввод данных пользователем не будет виден во время набора в консоли. Этот метод полезен при запросе конфиденциальной информации, такой как пароль:

$password = $this->secret('What is the password?');

Запрос подтверждения

Если вам нужно запросить у пользователя простое подтверждение, вы можете воспользоваться методом confirm. По умолчанию этот метод возвращает false. Однако, если пользователь введет y или yes в ответ на запрос, метод вернет true.

if ($this->confirm('Do you wish to continue?')) {
    //
}

Автозавершение

Метод anticipate может быть использован для обеспечения автозавершения возможных вариантов выбора. Пользователь может выбрать любой ответ, независимо от подсказок автозавершения:

$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);

В качестве альтернативы, вы можете передать Closure как второй аргумент к методу anticipate. Closure будет вызываться каждый раз, когда пользователь вводит символ ввода. Closure должен принять строковый параметр, содержащий входной сигнал пользователя до сих пор, и вернуть массив опций для автозавершения:

$name = $this->anticipate('What is your name?', function ($input) {
    // Return auto-completion options...
});

Множественный выбор

Если вам нужно дать пользователю предопределенный набор вариантов, вы можете использовать метод 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 и error. Каждый из этих методов будет использовать соответствующие цвета ANSI. Например, давайте покажем пользователю некоторую общую информацию. Обычно, метод info будет отображаться в консоли в виде зеленого текста:

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    $this->info('Display this on the screen');
}

Для отображения сообщения об ошибке используйте метод error. Текст сообщения об ошибке обычно отображается красным цветом:

$this->error('Something went wrong!');

Если вы хотите отобразить обычный, не цветной консольный вывод, используйте метод line:

$this->line('Display this on the screen');

Табличный вывод

Метод table позволяет легко и корректно форматировать несколько строк/столбцов данных. Просто передайте методу заголовки и строки. Ширина и высота будут динамически рассчитываться на основе заданных данных:

$headers = ['Name', 'Email'];

$users = App\User::all(['name', 'email'])->toArray();

$this->table($headers, $users);

Индикатор прогресса

Для длительных задач может быть полезным отображение индикатора прогресса. Используя объект output, мы можем запускать, продвигать и останавливать индикатор прогресса. Сначала определите общее количество шагов, через которые будет проходить процесс. Затем, после обработки каждого элемента, передвиньте индикатор:

$users = App\User::all();

$bar = $this->output->createProgressBar(count($users));

$bar->start();

foreach ($users as $user) {
    $this->performTask($user);

    $bar->advance();
}

$bar->finish();

Для получения более подробной информации о дополнительных опциях обратитесь к документации компонента Symfony Progress Bar.

Регистрация команд

Из-за вызова метода load в методе commands консольного ядра, все команды в каталоге app/Console/Commands будут автоматически зарегистрированы в Artisan. Фактически, Вы можете совершать дополнительные вызовы метода load для сканирования других каталогов на наличие команд Artisan:

/**
 * Register the commands for the application.
 *
 * @return void
 */
protected function commands()
{
    $this->load(__DIR__.'/Commands');
    $this->load(__DIR__.'/MoreCommands');

    // ...
}

Вы также можете вручную зарегистрировать команде, добавив имя класса в свойство $commands файла app/Console/Kernel.php. Когда Artisan загрузится, все команды, перечисленные в этом свойстве, будут разрешены сервис-контейнером и зарегистрированы в Artisan:

protected $commands = [
    Commands\SendEmails::class
];

Программное выполнение команд

Иногда вы можете захотеть выполнить Artisan-команду за пределами CLI. Например, вы можете захотеть запустить Artisan-команду из маршрута или контроллера. Для этого можно использовать метод call фасада Artisan. Метод call принимает в качестве первого аргумента либо имя команды, либо класс, а в качестве второго аргумента — массив параметров команды. Возвращается код выхода:

Route::get('/foo', function () {
    $exitCode = Artisan::call('email:send', [
        'user' => 1, '--queue' => 'default'
    ]);

    //
});

Или же вы можете передать всю команду Artisan в метод call в виде строки:

Artisan::call('email:send 1 --queue=default');

Используя метод queue фасада Artisan, вы можете даже ставить команды Artisan в очередь, чтобы они обрабатывались в фоновом режиме вашими воркерами очереди. Перед использованием этого метода, убедитесь, что Вы настроили свою очередь и запустили слушателя очереди:

Route::get('/foo', function () {
    Artisan::queue('email:send', [
        'user' => 1, '--queue' => 'default'
    ]);

    //
});

Вы также можете указать соединение или очередь, в которую должна быть отправлена команда Artisan:

Artisan::queue('email:send', [
    'user' => 1, '--queue' => 'default'
])->onConnection('redis')->onQueue('commands');

Передача массивов

Если ваша команда определяет опцию, которая принимает массив, вы можете передать массив значений в этот параметр:

Route::get('/foo', function () {
    $exitCode = Artisan::call('email:send', [
        'user' => 1, '--id' => [5, 13]
    ]);
});

Передача булевых значений

Если вам нужно указать значение опции, которая не принимает строковые значения, например, флаг --force в команде migrate:refresh, вы должны передать true или false:

$exitCode = Artisan::call('migrate:refresh', [
    '--force' => true,
]);

Вызов команд из других команд

Иногда вам может понадобиться вызвать другие команды из существующей Artisan-команды. Вы можете сделать это, используя метод call. Этот метод call принимает имя команды и массив параметров команды:

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    $this->call('email:send', [
        'user' => 1, '--queue' => 'default'
    ]);

    //
}

Если вы хотите вызвать другую консольную команду и подавить весь ее вывод, вы можете использовать метод callSilent. Метод callSilent имеет такую же сигнатуру, как и метод call:

$this->callSilent('email:send', [
    'user' => 1, '--queue' => 'default'
]);

Настройка заготовок

Команды make консоли Artisan используются для создания различных классов, таких как контроллеры, задания, миграции и тесты. Эти классы генерируются с помощью "заготовок" файлов, которые заполняются значениями, основанными на вводимых вами данных. Однако, иногда Вы можете захотеть внести небольшие изменения в файлы, сгенерированные Artisan. Для этого вы можете использовать команду stub:published, чтобы опубликовать наиболее распространенные заготовки для настройки:

php artisan stub:publish

Опубликованные заготовки будут находиться в каталоге stubs в корне Вашего приложения. Любые изменения, которые вы сделаете в этих файлах, будут отражены при генерации соответствующих классов, используя команды Artisan make.

Last updated