{{TOC}} {{DOCVER 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11}} == Введение == Artisan - интерфейс командной строки, который поставляется с Laravel. Он содержит набор полезных команд, помогающих вам при разработке приложения. Для просмотра списка доступных команд используйте команду %%(sh)list%%: %%(sh) php artisan list %% Каждая команда имеет описание, в котором указаны её доступные аргументы и ключи. Для просмотра описания просто добавьте перед командой слово %%(sh)help%%: %%(sh) php artisan help migrate %% == Создание команд == В дополнение к стандартным командам Artisan вы можете также создавать свои собственные команды. Обычно команды хранятся в папке %%(t)app/Console/Commands%%, но вы можете поместить их в любое другое место, в котором их сможет найти и загрузить Composer. === Генерирование команд === %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) Для создания новой команды используйте Artisan-команду %%(sh)make:command%%. Эта команда создаст новый класс команды в папке %%(t)app/Console/Commands%%. Если этой папке не существует, она будет создана при первом запуске команды %%(sh)make:command%%. Сгенерированная команда будет содержать стандартный набор свойств и методов, присущих всем командам: %%(sh) php artisan make:command SendEmails ~%% Затем вам надо ((#регистрация зарегистрировать команду)), тогда она сможет быть запущена через командный интерфейс Artisan. %% %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Для создания новой команды можно использовать Artisan-команду %%(sh)make:console%%, которая создаст заглушку, с которой вы можете начать работать. %%(sh) php artisan make:console SendEmails ~%% Эта команда создаст класс в %%(t)app/Console/Commands/SendEmails.php%%. При создании команды может быть использован ключ %%(sh)--command%% для назначения имени команды в терминале: %%(sh) php artisan make:console SendEmails --command=emails:send ~%% %% === Структура команды === После генерирования команды, вам нужно заполнить свойства %%(t)signature%% и %%(t)description%% в её классе, которые используются при отображении вашей команды в списке команд (%%(sh)list%%). При вызове вашей команды будет вызван метод %%handle()%%. В него вы можете поместить необходимую вам логику. .(alert) Для улучшения кода, с точки зрения его повторного использования, полезно сохранять ваши консольные команды простыми и использовать в них сервисы самого приложения для выполнения их задач. Обратите внимание, что в приведённом примере мы внедряем класс сервиса для выполнения "трудоёмкой" задачи отправки писем. Давайте посмотрим на пример команды. Мы можем внедрить любые необходимые зависимости в конструкторе команды. ((/docs/v5/container Сервис-контейнер)) Laravel автоматически внедрит все указанные в конструкторе зависимости: %% drip = $drip; } /** * Выполнение консольной команды. * * @return mixed */ public function handle() { $this->drip->send(User::find($this->argument('user'))); } } %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) === Команды замыкания === Команды на основе замыканий являются альтернативой определению консольных команд в виде классов, подобно тому, как замыкания маршрутов являются альтернативой контроллерам. В методе %%commands()%% файла %%(t)app/Console/Kernel.php%% Laravel загружает файл %%(t)routes/console.php%%: ~%% /** * Регистрация команд на основе замыканий для приложения. * * @return void */ protected function commands() { require base_path('routes/console.php'); } ~%% Не смотря на то, что этот файл не определяет HTTP-маршруты, он определяет консольные входные точки (маршруты) в ваше приложение. В этом файле вы можете определить все свои маршруты на основе замыканий с помощью метода %%Artisan::command()%%. Метод %%command()%% принимает два аргумента: ((#определение сигнатуру команды)) и замыкание, которое получает аргументы и ключи команды: ~%% Artisan::command('build {project}', function ($project) { $this->info("Building {$project}!"); }); ~%% Замыкание привязано к лежащему в основе экземпляру команды, поэтому у вас есть полный доступ ко всем вспомогательным методам, которые обычно доступны вам в полном классе команды. **Указание типов зависимостей** Помимо получения аргументов и ключей вашей команды в замыканиях команд можно указывать типы дополнительных зависимостей, которые вам необходимо получить из ((//docs/v5/container сервис-контейнера)): ~%% use App\User; use App\DripEmailer; Artisan::command('email:send {user}', function (DripEmailer $drip, $user) { $drip->send(User::find($user)); }); ~%% **Описание команд замыканий** При определении команд на основе замыканий вы можете использовать метод %%describe()%% для добавления описания команды. Это описание будет выводится при выполнении команд %%(sh)php artisan list%% или %%(sh)php artisan help%%: ~%% Artisan::command('build {project}', function ($project) { $this->info("Building {$project}!"); })->describe('Build the project'); ~%% %% == Определение ожиданий ввода == При создании консольных команд часто необходимо получать ввод от пользователя через аргументы или ключи. В Laravel очень удобно определить ожидаемый от пользователя ввод, используя свойство %%(t)signature%% вашей команды. Это свойство позволяет задать имя, аргументы и ключи для команды в едином, выразительном, маршруто-подобном синтаксисе. === Аргументы === Все вводимые пользователем аргументы и ключи заключаются в фигурные скобки. В следующем примере команда определяет один **требуемый** аргумент %%(t)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%%, то его значение будет %%(t)true%%, иначе %%(t)false%%: %%(sh) php artisan email:send 1 --queue %% **Ключи со значениями** Теперь посмотрим на ключи, которые ожидают значения. Необходимость ввода значения для ключа задаётся при помощи знака равно (=): %% /** * Имя и аргументы консольной команды. * * @var string */ protected $signature = 'email:send {user} {--queue=}'; %% В этом примере пользователь может передать значение для ключа вот так: %%(sh) php artisan email:send 1 --queue=default %% Для ключей можно задать значение по умолчанию, указав его после имени ключа. Это значение будет использовано, если пользователь не укажет значение ключа: %%(sh) email:send {user} {--queue=default} %% **Сокращение ключа** Чтобы задать сокращение при определении ключа, вы можете указать его перед именем ключа и отделить его символом вертикальной черты (|): %%(sh) email:send {user} {--Q|queue} %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) === Ввод массивов === Если вы хотите указать, что аргументы или ключи будут принимать на вход массивы, используйте символ %%(t)*%%. Сначала посмотрим на пример указания аргумента массива: %%(sh) email:send {user*} ~%% При вызове этой команды в командную строку можно передать аргументы %%(t)user%% по порядку. Например, следующая команда установит значение %%(t)user%% равное %%(t)['foo', 'bar']%%: %%(sh) php artisan email:send foo bar ~%% При определении ключа, который будет принимать на вход массив, каждое передаваемое в команду значение ключа должно иметь префикс в виде имени ключа: %%(sh) email:send {user} {--id=*} php artisan email:send --id=1 --id=2 ~%% %% === Описание ввода === Вы можете задать описание для аргументов и ключей, отделив их двоеточием. Если вам необходимо немного больше места для определения вашей команды, вы можете разделить описание на несколько строк: %% /** * Имя и аргументы консольной команды. * * @var string */ protected $signature = 'email:send {user : ID пользователя} {--queue= : Ставить ли задачу в очередь}'; %% == Ввод/вывод команд == === Чтение ввода === Во время выполнения команды вам, конечно, потребуется доступ к аргументам и ключам, которые были переданы ей на вход. Для этого вы можете использовать методы %%argument()%% и %%option()%%. Для чтения значения аргумента используйте метод %%argument()%%: %% /** * Выполнение консольной команды. * * @return mixed */ public function handle() { $userId = $this->argument('user'); // } %% Если вам необходимо прочитать все аргументы в виде массива, вызовите метод %%arguments()%% (для версии 5.2 и ранее - метод %%argument()%% без аргументов): %% $arguments = $this->arguments(); %% Ключи можно прочитать так же легко, как аргументы, используя метод %%option()%%. Чтобы получить массив всех ключей, вызовите метод %%options()%% (для версии 5.2 и ранее - метод %%option()%% без аргументов): %% // Чтение конкретного ключа... $queueName = $this->option('queue'); // Чтение всех ключей... $options = $this->options(); %% Если аргумента или ключа не существует, будет возвращён %%null%%. === Запрос ввода === В дополнение к отображению вывода вы можете запросить у пользователя данные во время выполнения команды. Метод %%ask()%% выведет запрос, примет введённые данные, а затем вернёт их вашей команде: %% /** * Выполнение консольной команды. * * @return mixed */ public function handle() { $name = $this->ask('What is your name?'); } %% Метод %%secret()%% похож на метод %%ask()%%, но он не отображает вводимые пользователем данные в консоли. Этот метод полезен при запросе секретной информации, такой как пароль: %% $password = $this->secret('What is the password?'); %% **Запрос подтверждения** Для получения от пользователя простого подтверждения можно использовать метод %%confirm()%%. По умолчанию этот метод возвращает %%(t)false%%. Но если пользователь введёт %%(t)y%% или %%(t)yes%% в ответ на запрос, то метод вернёт %%(t)true%%: %% if ($this->confirm('Do you wish to continue?')) { // } %% **Автозаполнение** Метод %%anticipate()%% можно использовать для предоставления пользователю возможных вариантов для выбора. Независимо от наличия этих вариантов пользователь может указать свой вариант. %% $name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']); %% **Вопросы с несколькими вариантами ответов** Для предоставления пользователю определённого набора вариантов можно использовать метод %%choice()%%. Можно задать значение по умолчанию, на случай если вариант не выбран: %% $name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $default); %% === Вывод === Для вывода вы можете использовать методы %%line()%%, %%info()%%, %%comment()%%, %%question()%% и %%error()%%. Каждый из них будет использовать подходящие по смыслу цвета ANSI для отображении текста. Давайте для примера выведем информационное сообщение для пользователя. Обычно метод %%info()%% выводит в консоль текст зелёного цвета: %% /** * Выполнение консольной команды. * * @return mixed */ public function handle() { $this->info('Вывести это на экран'); } %% Для вывода сообщения об ошибке используйте метод %%error()%%. Он выводит в консоль текст красного цвета: %% $this->error('Что-то пошло не так!'); %% Для простого вывода текста в консоль без использования специальных цветов используйте метод %%line()%%: %% $this->line('Вывести это на экран'); %% **Табличный вывод** Метод %%table()%% позволяет легко форматировать несколько строк/столбцов данных. Просто передайте в него заголовки и строки. Ширина и высота будет динамически определена на основе переданных данных: %% $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(); %% Более подробная информация указана в ((https://symfony.com/doc/2.7/components/console/helpers/progressbar.html документации по индикаторам процесса Symfony)). %%(DOCNEW 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) **Указание имени среды для выполнения команды** Вы можете указать среду, которая будет использоваться при выполнении команды, с помощью ключа %%(sh)--env%%: %%(sh) php artisan migrate --env=local ~%% **Вывод вашей текущей версии Laravel** Вы также можете узнать версию текущей установки Laravel с помощью ключа %%(sh)--version%%: %%(sh) php artisan --version ~%% %% == Регистрация команд == Когда ваша команда написана, вам нужно зарегистрировать её в Artisan. Все команды регистрируются в файле %%(t)app/Console/Kernel.php%%. В нём вы найдёте список команд в свойстве %%(t)commands%%. Чтобы зарегистрировать свою команду, просто добавьте имя класса команды в этот список. Когда Artisan загружается, все перечисленные в этом свойстве команды будут включены в ((/docs/v5/container сервис-контейнер)) и зарегистрированы в Artisan: %% protected $commands = [ Commands\SendEmails::class ]; %% == Программное выполнение команд == Иногда необходимо выполнить команду извне командной строки. Например, когда вы хотите запустить команду из маршрута или контроллера. Для этого можно использовать метод %%call()%% фасада %%(t)Artisan%%. Этот метод принимает первым аргументом имя команды, а вторым - массив аргументов команды. Будет возвращён код выхода: %% Route::get('/foo', function () { $exitCode = Artisan::call('email:send', [ 'user' => 1, '--queue' => 'default' ]); // }); %% С помощью метода %%queue()%% можно даже поставить команды в очередь, тогда они будут обработаны в фоне с помощью ваших ((/docs/v5/queues обработчиков очереди)). Прежде чем использовать этот метод, убедитесь в том, что вы настроили вашу очередь, и что слушатель очереди запущен: %% Route::get('/foo', function () { Artisan::queue('email:send', [ 'user' => 1, '--queue' => 'default' ]); // }); %% Когда нужно указать значение ключа, который не принимает строковое значение, например, флаг %%(sh)--force%% команды %%(sh)migrate:refresh%%, вы можете передать значение %%(t)true%% или %%(t)false%%: %% $exitCode = Artisan::call('migrate:refresh', [ '--force' => true, ]); %% === Вызов команд из других команд === Иногда необходимо вызвать другую команду из своей. Для этого используйте метод %%call()%%. Он принимает имя команды и массив её аргументов: %% /** * Выполнение консольной команды. * * @return mixed */ public function handle() { $this->call('email:send', [ 'user' => 1, '--queue' => 'default' ]); // } %% Если вы хотите вызвать другую команду и запретить её вывод в консоль, используйте метод %%callSilent()%%. Этот метод принимает те же аргументы, что и метод %%call()%%: %% $this->callSilent('email:send', [ 'user' => 1, '--queue' => 'default' ]); %% == ((#планировщик)) Планирование команд Artisan == .(alert) Данный раздел статьи актуален только для версии 5.0 и был удален в версии 5.1. Раньше разработчикам приходилось создавать Cron-задачи для каждой консольной команды, которую они хотели запланировать. Это утомительно. Для планирования консольных команд теперь не ведётся контроль версий, и для добавления Cron-задач вам необходимо подключаться к серверу по SSH. Давайте упростим нам жизнь. Планировщик команд Laravel позволяет вам гибко и выразительно задавать план команд в самом Laravel, а на сервере нужна только одна Cron-задача. Ваш план команд хранится в файле %%(t)app/Console/Kernel.php%%. В этом классе вы найдёте метод %%schedule%%. Чтобы помочь вам разобраться, в метод включён простой пример. Вы можете добавлять в объект %%Schedule%% столько запланированных задач, сколько пожелаете. А на сервере вам надо добавить единственную Cron-задачу: %%(sh) * * * * * php /path/to/artisan schedule:run 1>> /dev/null 2>&1 %% Эта задача будет каждую минуту вызывать планировщик команд Laravel. А тот в свою очередь будет проверять имеющиеся в плане задачи и выполнять необходимые. Проще некуда! === Ещё примеры планирования === Давайте рассмотрим ещё несколько примеров планирования. **Планирование замыканий** %% $schedule->call(function() { // Выполнить какое-то задание... })->hourly(); %% **Планирование терминальных команд** %% $schedule->exec('composer self-update')->daily(); %% **Ручное Cron-выражение** %% $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(); %% **Защита от наложения задач** По умолчанию запланированные задачи будут запущены, даже если предыдущий экземпляр всё ещё запущен. Для предотвращения такого поведения используйте метод %%withoutOverlapping%%: %% $schedule->command('foo')->withoutOverlapping(); %% В этом примере команда %%(t)foo%% будет запускаться каждую минуту, если она уже не запущена. **Указание конкретных сред для запуска задач** %% $schedule->command('foo')->monthly()->environments('production'); %% **Указание необходимости запуска задачи даже в режиме техобслуживания** %% $schedule->command('foo')->monthly()->evenInMaintenanceMode(); %% **Запуск задачи только в случае возврата %%true%%** %% $schedule->command('foo')->monthly()->when(function() { return true; }); %% **Отправка вывода задачи на e-mail** %% $schedule->command('foo')->sendOutputTo($filePath)->emailOutputTo('foo@example.com'); %% .(alert) Необходимо отправить вывод в файл перед тем, как он сможет быть послан по e-mail. **Отправка вывода задачи в указанное место** %% $schedule->command('foo')->sendOutputTo($filePath); %% **Выполнить ping указанного URL после запуска задачи** %% $schedule->command('foo')->thenPing($url); %% Для использования функции %%thenPing($url)%% необходима HTTP-библиотека Guzzle. Вы можете добавить Guzzle 5 в свой проект, добавив следующую строку в файл %%composer.json%%: %%(conf) "guzzlehttp/guzzle": "~5.0" %%