Кастомные CLI команды — IO7 Framework
Внимание
Данная статья документации написана нейросетью. Возможны некоторые расхождения и неточность информации!
Обзор
IO7 позволяет создавать собственные CLI команды. Пользовательские команды хранятся в app/Commands/ и регистрируются в app/Module.php.
Создание команды
Через make:command
$ php iocli make:command SendEmail
Команда создана: app/Commands/SendEmailCommand.php
Генерируется файл app/Commands/SendEmailCommand.php с базовой структурой.
Вручную
Создайте файл в app/Commands/ с пространством имён App\Commands и расширением IO\Console\Command.
Структура класса команды
<?php
namespace App\Commands;
use IO\Console\Command;
class SendEmailCommand extends Command
{
protected string $signature = 'email:send {user_id} {--queue} {--delay=}';
protected string $description = 'Отправить email пользователю';
public function handle(): int
{
$userId = $this->argument('user_id');
$queue = $this->option('queue');
$delay = $this->option('delay') ?? 0;
$this->info("Email отправлен пользователю {$userId}");
return 0;
}
}
Обязательные элементы
| Элемент | Описание |
|---|---|
namespace App\Commands | Пространство имён |
extends Command | Наследование от IO\Console\Command |
protected string $signature | Сигнатура команды |
protected string $description | Описание для справки |
public function handle(): int | Точка входа. Возвращает 0 — успех, 1 — ошибка |
Сигнатура
Свойство $signature определяет имя команды, аргументы и опции. Формат:
имя_команды {аргумент1} {аргумент2} {--опция=значение} {--флаг}
Элементы сигнатуры
| Формат | Тип | Описание | Пример |
|---|---|---|---|
{name} | string | Позиционный аргумент | {user_id} |
{--key=value} | string | Опция со значением по умолчанию | {--delay=0} |
{--flag} | bool | Булевый флаг (true/false) | {--once} |
{args?*} | string* | Переменное число аргументов | {args?*} |
Примеры сигнатур
app:version
migrate
make:migration {name}
serve {--host=127.0.0.1} {--port=8000}
queue:work {--queue=default} {--once}
command:run {name} {args?*}
Доступ к аргументам и опциям
Позиционные аргументы
$name = $this->argument('user_id');
Возвращает значение аргумента или null, если не передан.
Опции
$delay = $this->option('delay'); // строка или null
$once = $this->option('once'); // true или null
Имя передаётся без --. Для флагов возвращает true или null.
Вспомогательные методы
| Метод | Описание | Пример |
|---|---|---|
info($message) | Зелёный вывод (успех) | $this->info('Готово'); |
error($message) | Красный вывод (ошибка) | $this->error('Файл не найден'); |
line($message) | Обычный вывод | $this->line('Текст'); |
confirm($message) | Запрос подтверждения y/n | if ($this->confirm('Удалить?')) |
ask($question) | Запрос ввода строки | $name = $this->ask('Имя'); |
self::app() | Доступ к экземпляру App | $app = self::app(); |
Регистрация в Module.php
После создания команды зарегистрируйте её в app/Module.php:
<?php
namespace App;
class Module
{
public static function registerCommands(\IO\Console\Kernel $kernel): void
{
$kernel->register('email:send', \App\Commands\SendEmailCommand::class);
$kernel->register('report:generate', \App\Commands\GenerateReportCommand::class);
}
}
Параметры register()
| Параметр | Тип | Описание |
|---|---|---|
$name | string | Имя команды (то что в $signature) |
$commandClass | string | Полное имя класса с \ |
Порядок загрузки
Точка входа iocli загружает команды в таком порядке:
\IO\Module::registerCommands($kernel)— 31 встроенная команда фреймворка\App\Module::registerCommands($kernel)— пользовательские команды
Пользовательские команды могут перезаписать встроенные, если использовать одно имя.
Полные примеры
Пример 1: Простая команда
<?php
namespace App\Commands;
use IO\Console\Command;
class HelloCommand extends Command
{
protected string $signature = 'app:hello {name}';
protected string $description = 'Поздороваться';
public function handle(): int
{
$name = $this->argument('name');
if ($name === null) {
$this->error('Укажите имя');
return 1;
}
$this->info("Привет, {$name}!");
return 0;
}
}
// Module.php
$kernel->register('app:hello', \App\Commands\HelloCommand::class);
$ php iocli app:hello Мир
Привет, Мир!
Пример 2: Команда с опциями
<?php
namespace App\Commands;
use IO\Console\Command;
class MigrateFreshSeedCommand extends Command
{
protected string $signature = 'app:fresh-seed {--class=} {--force}';
protected string $description = 'Очистить базу и заполнить данными';
public function handle(): int
{
$class = $this->option('class');
$force = $this->option('force');
if (!$force && !$this->confirm('Все данные будут удалены. Продолжить?')) {
$this->line('Отменено');
return 0;
}
$this->info('Очистка базы...');
// ... логика очистки
if ($class) {
$this->info("Запуск сидера: {$class}");
} else {
$this->info('Запуск всех сидеров...');
}
$this->info('Готово');
return 0;
}
}
// Module.php
$kernel->register('app:fresh-seed', \App\Commands\MigrateFreshSeedCommand::class);
# С подтверждением
$ php iocli app:fresh-seed
Все данные будут удалены. Продолжить? (y/n): y
Очистка базы...
Запуск всех сидеров...
Готово
# Пропустить подтверждение и запустить конкретный сидер
$ php iocli app:fresh-seed --force --class=UserSeeder
Очистка базы...
Запуск сидера: UserSeeder
Готово
Пример 3: Команда с выводом таблицы
<?php
namespace App\Commands;
use IO\Console\Command;
class UsersListCommand extends Command
{
protected string $signature = 'app:users {--role=} {--limit=50}';
protected string $description = 'Показать список пользователей';
public function handle(): int
{
$role = $this->option('role');
$limit = (int) ($this->option('limit') ?? 50);
$app = self::app();
$conditions = [];
if ($role) {
$conditions['role'] = $role;
}
$users = $app->iodb->search('users', $conditions, $limit);
$this->line(str_repeat('-', 60));
$this->line(sprintf('%-8s %-25s %-20s', 'ID', 'Email', 'Роль'));
$this->line(str_repeat('-', 60));
foreach ($users as $user) {
$this->line(sprintf('%-8d %-25s %-20s',
$user['pkid'],
$user['email'],
$user['role'] ?? 'user'
));
}
$this->line(str_repeat('-', 60));
$this->info('Всего: ' . count($users));
return 0;
}
}
// Module.php
$kernel->register('app:users', \App\Commands\UsersListCommand::class);
$ php iocli app:users
------------------------------------------------------------
ID Email Роль
------------------------------------------------------------
1 admin@example.com admin
2 user@example.com user
------------------------------------------------------------
Всего: 2
$ php iocli app:users --role=admin --limit=10
Пример 4: Команда для генерации отчёта
<?php
namespace App\Commands;
use IO\Console\Command;
class ReportCommand extends Command
{
protected string $signature = 'report:generate {type} {--from=} {--to=} {--output=}';
protected string $description = 'Сгенерировать отчёт';
public function handle(): int
{
$type = $this->argument('name');
if ($type === null) {
$this->error('Укажите тип отчёта (sales, users, inventory)');
return 1;
}
$from = $this->option('from') ?? date('Y-m-01');
$to = $this->option('to') ?? date('Y-m-d');
$output = $this->option('output') ?? "reports/{$type}_" . date('Ymd') . '.csv';
$this->line("Генерация отчёта: {$type}");
$this->line("Период: {$from} — {$to}");
$this->line("Файл: {$output}");
$this->info("Отчёт создан: {$output}");
return 0;
}
}
// Module.php
$kernel->register('report:generate', \App\Commands\ReportCommand::class);
$ php iocli report:generate sales --from=2024-01-01 --to=2024-01-31 --output=sales_jan.csv
Генерация отчёта: sales
Период: 2024-01-01 — 2024-01-31
Файл: sales_jan.csv
Отчёт создан: sales_jan.csv
Запуск кастомных команд
Через имя команды (зарегистрированная команда)
$ php iocli app:hello Мир
Через command:run (по имени класса)
Команда command:run ищет класс в App\Commands\ по имени:
$ php iocli command:run SendEmail
# Ищет App\Commands\SendEmailCommand
$ php iocli command:run App\Commands\SendEmailCommand
# Полное имя класса
Порядок файлов
app/
├── Commands/
│ ├── SendEmailCommand.php
│ ├── GenerateReportCommand.php
│ └── UsersListCommand.php
├── Module.php ← registerCommands()
└── ...
Важные замечания
- Имя команды в
$signatureи в$kernel->register()должны совпадать. - Код возврата
handle():0— успех,1— ошибка. - Позиционные аргументы — индексный массив,
$argument('name')работает только если аргумент передан позиционно. - Опции с
=возвращают строку, флаги без=возвращаютtrueилиnull. - Перезапись встроенных команд: пользовательская команда с тем же именем перезапишет встроенную.