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¶
New in version 12.4.8: The Symfony PHP attribute \Symfony\Component\Console\Attribute\AsCommand
is now accepted to register console commands.
See the section Use the PHP attribute to register commands
for more details.
Register the command in Configuration/Services.yaml
by adding the service
definition for your class as tag console.command
:
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.'
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
.
Note
Despite using autoconfigure: true
the commands
have to be explicitly defined in Configuration/Services.yaml
. 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 DoSomethingCommand
extending
\Symfony\Component\Console\Command\Command
.
<?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;
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::SUCCESS
orCommand::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¶
New in version 12.4.8.
CLI commands can be registered by setting the attribute
\Symfony\Component\Console\Attribute\AsCommand
on the command class.
When using this attribute there is no need to register the command in the
Services.yaml
file.
Note
Only the parameters command
, description
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.',
)]
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\Component\Console\Command\Command
,
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 wizardName
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->getArgument()
, the options with
$input->getOption()
, 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 SymfonyStyle
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
) {
$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