Tutorial
Create a console command from scratch
A console command is always situated in an extension. If you want to create one, kickstart a custom extension or use your sitepackage extension.
Creating a basic command
The extension kickstarter "Make" offers a convenient console command that creates a new command in an extension of your choice: Create a new console command with "Make". You can use "Make" to create a console command even if your extension was created by different means.
This command can be found in the Examples extension.
1. Register the command
Note
The Symfony PHP attribute \Symfony\
registers console commands.
See the section Use the PHP attribute to register commands
for more details.
Register the command in Configuration/
by adding the service
definition for your class as tag console.
:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
T3docs\Examples\:
resource: '../Classes/*'
exclude: '../Classes/Domain/Model/*'
T3docs\Examples\Command\DoSomethingCommand:
tags:
- name: console.command
command: 'examples:dosomething'
description: 'A command that does nothing and always succeeds.'
# Also an alias for the command can be configured
- name: console.command
command: 'examples:dosomethingalias'
alias: true
The following attributes are available:
command
- The name under which the command is available.
description
- Give a short description. It will be displayed in the list of commands and the help information of the command.
schedulable
- By default, a command can be used in the scheduler, too. This can be disabled by setting
schedulable
tofalse
. hidden
- A command can be hidden from the command list by setting
hidden
totrue
. alias
- A command can be made available under a different name. Set to
true
, if your command name is an alias.
Note
Despite using autoconfigure: true
the commands
have to be explicitly defined in Configuration/
. It
is recommended to always supply a description, otherwise there is
an empty space in the list of commands.
2. Create the command class
Create a class called Do
extending
\Symfony\
.
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project. [...]
*/
namespace T3docs\Examples\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
final class DoSomethingCommand extends Command
{
protected function configure(): void
{
$this->setHelp('This command does nothing. It always succeeds.');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
// Do awesome stuff
return Command::SUCCESS;
}
}
The following two methods should be overridden by your class:
configure
() - As the name would suggest, allows to configure the command. The method allows to add a help text and/or define arguments and options.
execute
() - Contains the logic when executing the command. Must
return an integer. It is considered best practice to
return the constants
Command::
orSUCCESS Command::
.FAILURE
See also
A detailed description and an example can be found in the Symfony Command Documentation.
3. Run the command
The above example can be run via command line:
vendor/bin/typo3 examples:dosomething
typo3/sysext/core/bin/typo3 examples:dosomething
The command will return without a message as it does nothing but stating it succeeded.
Note
If a newly created or changed command is not found, clear the cache:
vendor/bin/typo3 cache:flush
Use the PHP attribute to register commands
CLI commands can be registered by setting the attribute
\Symfony\
on the command class.
When using this attribute there is no need to register the command in the
Services.
file.
Note
Only the parameters command
, description
, aliases
and hidden
are
available. In order to overwrite the parameter schedulable
use the
registration via
Services.yaml.
By default, schedulable
is true.
The example above can also be registered this way:
<?php
declare(strict_types=1);
namespace T3docs\Examples\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand(
name: 'examples:dosomething',
description: 'A command that does nothing and always succeeds.',
aliases: ['examples:dosomethingalias'],
)]
class DoSomethingCommand extends Command
{
protected function configure(): void
{
$this->setHelp('This command does nothing. It always succeeds.');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
// Do awesome stuff
return Command::SUCCESS;
}
}
Create a command with arguments and interaction
Passing arguments
Since a command extends \Symfony\
,
it is possible to define arguments (ordered) and options (unordered) using the Symfony
command API. This is explained in depth on the following Symfony Documentation page:
Add an optional argument and an optional option to your command:
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
final class CreateWizardCommand extends Command
{
protected function configure(): void
{
$this
->setHelp('This command accepts arguments')
->addArgument(
'wizardName',
InputArgument::OPTIONAL,
'The wizard\'s name',
)
->addOption(
'brute-force',
'b',
InputOption::VALUE_NONE,
'Allow the "Wizard of Oz". You can use --brute-force or -b when running command',
);
}
}
This command takes one optional argument wizard
and one optional option,
which can be passed on the command line:
vendor/bin/typo3 examples:createwizard [-b] [wizardName]
typo3/sysext/core/bin/typo3 examples:createwizard [-b] [wizardName]
This argument can be retrieved with $input->get
, the options with
$input->get
, for example:
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use T3docs\Examples\Exception\InvalidWizardException;
final class CreateWizardCommand extends Command
{
protected function execute(
InputInterface $input,
OutputInterface $output,
): int {
$io = new SymfonyStyle($input, $output);
$wizardName = $input->getArgument('wizardName');
$bruteForce = (bool)$input->getOption('brute-force');
try {
$this->doMagic($io, $wizardName, $bruteForce);
} catch (InvalidWizardException) {
return Command::FAILURE;
}
return Command::SUCCESS;
}
}
User interaction on the console
You can create a Symfony
console user interface from the
$input
and $output
parameters to the execute
function:
use Symfony\Component\Console\Style\SymfonyStyle;
final class CreateWizardCommand extends Command
{
protected function execute(
InputInterface $input,
OutputInterface $output
): int {
$io = new SymfonyStyle($input, $output);
// do some user interaction
return Command::SUCCESS;
}
}
The $io
variable can then be used to generate output and prompt for
input:
use Symfony\Component\Console\Style\SymfonyStyle;
use T3docs\Examples\Exception\InvalidWizardException;
final class CreateWizardCommand extends Command
{
private function doMagic(
SymfonyStyle $io,
mixed $wizardName,
bool $bruteForce,
): void {
$io->comment('Trying to create wizard ' . $wizardName . '...');
if ($wizardName === null) {
$wizardName = (string)$io->ask(
'Enter the wizard\'s name (e.g. "Gandalf the Grey")',
'Lord Voldermort',
);
}
if (!$bruteForce && $wizardName === 'Oz') {
$io->error('The Wizard of Oz is not allowed. Use --brute-force to allow it.');
throw new InvalidWizardException();
}
$io->success('The wizard ' . $wizardName . ' was created');
}
}
Dependency injection in console commands
You can use dependency injection (DI) in console commands by constructor injection or method injection:
use Psr\Log\LoggerInterface;
use T3docs\Examples\Http\MeowInformationRequester;
final class MeowInformationCommand extends Command
{
public function __construct(
private readonly MeowInformationRequester $requester,
private readonly LoggerInterface $logger,
) {
parent::__construct();
}
}
Initialize backend user
A backend user can be initialized with this call inside execute
method:
use TYPO3\CMS\Core\Core\Bootstrap;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
final class DoBackendRelatedThingsCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
Bootstrap::initializeBackendAuthentication();
// Do backend related stuff
return Command::SUCCESS;
}
}
This is necessary when using DataHandler or other backend permission handling related tasks.
More information
- See implementation of existing command controllers in the Core:
typo3/
sysext/*/ Classes/ Command - Symfony Command Documentation
- Symfony Commands: Console Input (Arguments & Options)