Расширение Artisan-команд Laravel
9 мая 2022 г.Я люблю [Laravel] (https://laravel.com/).
Как PHP-разработчик с опытом работы во всем, от WordPress до CodeIgniter, появление Laravel стало откровением. От дизайна до удобства использования — это абсолютно первоклассный фреймворк, обладающий невероятной мощью.
Тем не менее, иногда собственная самоуверенная структура Laravel может мешать тому, что может показаться довольно простым намерением, таким как добавление настраиваемых глобальных аргументов ко всем командам Artisan.
Что я имею в виду под «настраиваемыми глобальными аргументами»? Например, все Artisan-команды имеют
тот же набор аргументов и опций, которые можно использовать во время выполнения:
--raw Вывести необработанный список команд
--format=FORMAT Выходной формат (txt, xml, json или md) [по умолчанию: "txt"]
--short Пропустить описание аргументов команд
-h, --help Показать справку по данной команде. Если команда не указана, отобразите справку для команды list.
-q, --quiet Не выводить никаких сообщений
-V, --version Показать эту версию приложения
--ansi|--no-ansi Принудительно (или отключить --no-ansi) вывод ANSI
-n, --no-interaction Не задавать никаких интерактивных вопросов
--env[=ENV] Среда, в которой должна выполняться команда
-v|vv|vvv, --verbose Увеличить уровень детализации сообщений: 1 для обычного вывода, 2 для более подробного вывода и 3 для отладки
Но что, если бы мы захотели добавить наши собственные опции и аргументы?
Появилась дикая проблема!
Я всегда был довольно большим поклонником Heroku как за его мощность, так и за простоту использования — ладно, может быть, не так сильно в последнее время из-за того, как плохо они сообщил о своем последнем инциденте с безопасностью, но исторически я был фанатом.
Однако одним из самых неприятных недостатков Heroku является то, насколько ограничен планировщик. Своего рода недоработанный cron [планировщик Heroku] (https://devcenter.heroku.com/articles/scheduler) позволяет вам запускать любую команду с интервалом в 10 минут, 1 час или 1 день, что отчасти полезно, но также крайне недостаточно для многих различных типов работ.
Что, если мне нужно что-то запускать еженедельно, ежемесячно или даже ежегодно?
Планировщик говорит "нет".
Итак, чтобы обойти это (в типичном приложении Laravel), я традиционно добавлял в свои Artisan-команды дополнительный аргумент, который ограничивает выполнение в определенные дни. Например:
``` ударить
php artisan run:команда --day=пятница
Довольно простой дизайн, не так ли?
Он выполняет свою работу, но вряд ли масштабируется. Копирование тех же нескольких строк логики «if current day == --day, затем запустить, иначе вернуть 0» может стать довольно утомительным (не говоря уже о чем-то близком к DRY), поэтому я покопался в Artisan, чтобы лучше понять, как я могу добавить дополнительные глобальные параметры, которые можно применять ко всем командам, а не только к тем, которые я указываю.
Расширение Artisan
К счастью, Laravel, будучи объектно-ориентированным фреймворком, довольно легко расширяется. Проблема заключается не столько в расширении, сколько в том, чтобы правильно вписать указанное расширение в остальную часть приложения.
Тем не менее, прежде чем мы сможем на самом деле подключить что-либо, нам сначала нужно расширить класс Console\Application
и добавить наш собственный аргумент --day
. Для этого создайте новый файл с именем ./app/Console/Application.php
и вставьте в него следующий код:
```php
<?php
пространство имен App\Console;
используйте Illuminate\Console\Application как Artisan;
используйте Illuminate\Support\Str;
используйте Symfony\Component\Console\Input\InputInterface;
используйте Symfony\Component\Console\Input\InputOption;
используйте Symfony\Component\Console\Output\OutputInterface;
Приложение класса расширяет Artisan
- Запускает текущее приложение.
- @return int 0, если все прошло нормально, или код ошибки
публичная функция doRun (InputInterface $ input, OutputInterface $ output)
если ( !$this->checkDay($input)) {
$output->writeln(sprintf('
вернуть 0;
вернуть parent::doRun($input, $output);
защищенная функция getDefaultInputDefinition()
$definition = parent::getDefaultInputDefinition();
$definition->addOption(new InputOption('--day', null, InputOption::VALUE_OPTIONAL, "Выполнять команду только в указанный день недели"));
вернуть определение $;
общедоступная функция checkDay (InputInterface $ input)
$day = $input->getParameterOption('--day');
если (!$день) {
вернуть истину;
вернуть strtolower(now()->englishDayOfWeek) === strtolower($day);
То, что делает приведенный выше код, можно разбить на несколько частей:
- Он создает новый метод
checkDay()
, который получает наш настраиваемый глобальный параметр (--day
) и сверяет значение с текущим днем недели. Если два значения совпадают (или --day не указан), то checkDay() вернет true, иначе вернет false.
- Он расширяет метод
doRun()
и проверяет значениеcheckDay()
перед выполнением остальной части команды. ЕслиcheckDay()
возвращает false, команда немедленновернет 0
и напечатает комментарий, указывающий, что команду можно запустить только в указанный день.
- Наконец, поскольку мы хотим, чтобы любой, кто вводит
php artisan --help
, знал об этом новом аргументе, мы расширяемgetDefaultInputFunction()
и добавляем новое определение, указывающее, что--day
как существует, так и и как это работает.
Подключение
Итак, мы расширили наше консольное приложение, но если мы запустим php artisan --help
, наш новый аргумент --day
еще не появится. Это потому, что нам нужно сообщить Laravel о нашем новом классе, иначе он по умолчанию загрузит исходный класс Console\Application
.
Для этого откройте ./app/Console/Kernel.php
и добавьте следующую функцию в класс Kernel
:
```php
- Получить экземпляр приложения ремесленника.
- @return\Illuminate\Консоль\Приложение
защищенная функция getArtisan()
если (is_null($this->artisan)) {
return $this->artisan = (new \App\Console\Application($this->app, $this->events, $this->app->version()))->resolveCommands($this->commands) ;
вернуть $this->artisan;
Вышеупомянутая функция говорит Laravel загружать наш недавно определенный класс \App\Console\Application
при настройке Artisan, а не класс по умолчанию \Illuminate\Console\Application
. Поскольку мы расширили исходный класс Console\Application
, существующая функциональность по-прежнему будет поддерживаться, но с новыми функциями, которые мы только что добавили.
Теперь, если бы мы набрали php artisan --help
, мы бы увидели в ответе новый аргумент:
--raw Вывести необработанный список команд
--format=FORMAT Выходной формат (txt, xml, json или md) [по умолчанию: "txt"]
--short Пропустить описание аргументов команд
-h, --help Показать справку по данной команде. Если команда не указана, отобразите справку для команды list.
-q, --quiet Не выводить никаких сообщений
-V, --version Показать эту версию приложения
--ansi|--no-ansi Принудительно (или отключить --no-ansi) вывод ANSI
-n, --no-interaction Не задавать никаких интерактивных вопросов
--env[=ENV] Среда, в которой должна выполняться команда
--day[=DAY] Запускать команду только в указанный день недели
-v|vv|vvv, --verbose Увеличить уровень детализации сообщений: 1 для обычного вывода, 2 для более подробного вывода и 3 для отладки
Фин.
Вот и все!
В целом, это довольно простое изменение с некоторыми потенциально важными последствиями.
Также опубликовано на flower.codes
Оригинал