Подписывайтесь на наш Telegram канал и будьте в курсе всех событий.
Ищете работу? Мы поможем!
Ищете работу? Мы поможем!

Консоль Artisan

Вы просматриваете документ для прошлой версии.
Рассмотрите возможность обновления вашего проекта до актуальной версии 11.x. Почему это важно?

Введение

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 выполняется после завершения команды.