CLI command basics
Add-ons can provide custom CLI commands that run through cmd.php, which is useful for maintenance scripts and data imports.
Creating a command
A command is a PHP class in your add-on's Cli/Command directory, such as src/addons/Vendor/AddOn/Cli/Command/Greet.php. XenForo scans this directory in every add-on, so no registration is required.
To scaffold the class, run xf-make:cli-command with development mode enabled:
php cmd.php xf-make:cli-command Vendor/AddOn:Greet --description="Greets the user with a message."
This creates the class with configure() and execute() stubs. The class extends XF\Cli\Command\AbstractCommand, which sets up XenForo's output styles:
<?php
namespace Vendor\AddOn\Cli\Command;
use XF\Cli\Command\AbstractCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class Greet extends AbstractCommand
{
// ...
}
Configuring the command
The configure() method defines the command's name, description, and any arguments or options. Prefix the command name to avoid clashes with other add-ons.
protected function configure(): void
{
$this
->setName('vendor-addon:greet')
->setDescription('Greets the user with a message.')
->addArgument(
'name',
InputArgument::REQUIRED,
'The name of the person to greet.'
)
->addOption(
'yell',
'y',
InputOption::VALUE_NONE,
'If set, the greeting will be in uppercase.'
);
}
| Method | Purpose |
|---|---|
setName() | Sets the name used to call the command. |
setDescription() | Sets the text shown in the command list. |
addArgument() | Defines a positional argument. |
addOption() | Defines an option, passed as --yell or -y. |
Arguments and options use Symfony's mode constants, such as InputArgument::REQUIRED and InputOption::VALUE_NONE.
Implementing the command
The execute() method runs when the command is called.
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument('name');
$yell = $input->getOption('yell');
$message = "Hello, $name!";
if ($yell)
{
$message = strtoupper($message);
}
$io->title('Greeting');
$io->table(['Field', 'Value'], [
['Name', $name],
['Yelling', $yell ? 'Yes' : 'No'],
]);
$io->success($message);
return Command::SUCCESS;
}
Return Command::SUCCESS on success, Command::FAILURE on failure, or Command::INVALID for invalid input. Use $io->error() to report failures.
Running the command
The command appears in the php cmd.php list as soon as the add-on exists, but the add-on must be active to run it.
php cmd.php
Pass --help to any command to see its arguments and options, for example php cmd.php vendor-addon:greet --help.
Input
Pass arguments and options after the command name, for example php cmd.php vendor-addon:greet TestName --yell. The execute() example reads them with $input->getArgument('name') and $input->getOption('yell').
See Console Input for argument and option modes, default values, and array inputs.
Output
Use SymfonyStyle so your output matches the built-in commands.
Run the command with the TestName argument:
php cmd.php vendor-addon:greet TestName
Greeting
========
--------- ----------
Field Value
--------- ----------
Name TestName
Yelling No
--------- ----------
[OK] Hello, TestName!
Passing --yell changes the output:
php cmd.php vendor-addon:greet TestName --yell
Greeting
========
--------- ----------
Field Value
--------- ----------
Name TestName
Yelling Yes
--------- ----------
[OK] HELLO, TESTNAME!
Life cycle
Symfony runs initialize(), then interact(), then execute(). Most commands only need execute(); use interact() to ask for missing values and initialize() for setup that must happen before input is validated.
Further reading
See the Symfony Console documentation for the full command API and console helpers.