CLI = Command-line Interface
A tool to be used in the context of a shell or commandline
Is often used to manipulate files or data streams (STDIN/STDOUT)
often have parameters to fine-tune behaviour or output
are essential in automating things, for example in CI/CD
TYPO3 uses the Symfony Console Component
Usually there is a 'console' script in which 'commands' can be registered to be executed (vendor/bin/typo3 in TYPO3)
the first parameter in that case is the command class to be called
Usually to be used to interact with the PHP application from the command line
declare(strict_types=1);
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class MytoolCommand extends Command
{
protected function configure(): void
{
$this->setDescription('that one task I need done regulary')
->setHelp('the help someone might need when using my command');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln('Hello World');
return 0;
}
}
services:
_defaults:
autowire: true
autoconfigure: true
public: true
Talk\Mytool\:
resource: '../Classes/*'
Talk\Mytool\Command\MytoolCommand:
tags:
- name: 'console.command'
command: 'my:tool'
description: 'My first CLI tool'
schedulable: false
declare(strict_types=1);
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator,
ContainerBuilder $containerBuilder): void
{
$services = $containerConfigurator->services();
$services->defaults()->public()
->autowire()->autoconfigure();
$services->load('Talk\\Mytool\\', __DIR__ . '/../Classes/');
$services->set(\Talk\Mytool\Command\MytoolCommand::class)
->tag('console.command', [
'priority'=>10,
'command'=>'my:tool',
'description'=>'My first CLI tool',
'schedulable'=>false,
]);
};
$input->getArgument('theargument');
$input->getOption('theoption');
$output
$output->writeln($message);
$output->write($message,OutputInterface::VERBOSITY_VERBOSE);
$message can be a string or an iterable
protected function configure(): void
{
$this->addArgument(
'message',
InputArgument::OPTIONAL,
'our message',
'default value'
);
}
protected function execute(InputInterface $input, OutputInterface $output):int
{
$msg = $input->getArgument('message');
}
when you use multiple arguments, the order they are defined is important!!
protected function configure(): void {
$this->addOption(
'twitterhandle',
'x',
InputOption::VALUE_REQUIRED,
'the twitter handle to use'
);
}
protected function execute(InputInterface $input, OutputInterface $output):int {
if($x = $input->getOption('twitterhandle')) {
$output->writeln($x);
}
}
be careful with InputOption::VALUE_OPTIONAL!!
There are some helpers which can attach to OutputInterface to format data or to enhance the output, for example Table or ProgressBar
Encapsulate Business logic in Services, and use LoggerAwareInterface and LoggerAwareTrait in those to communicate (free mapping to -v -vv -vvv)
class MyService implements LoggerAwareInterface {
use LoggerAwareTrait;
public function doSomething() {
$this->logger->error( 'there was an error');
$this->logger->warning('there was a warning');
$this->logger->info('this is some information -vv');
$this->logger->debug('this is debugging -vvv');
}
}
// function execute
$logger = new ConsoleLogger($output);
$service = GeneralUtility::makeInstance(MyService::class);
$service->setLogger($logger);
$service->doSomething();
There is no $TSFE and no $REQUEST available. The Site object's router will create you frontend-links even in CLI mode
There is no PageTS or Frontend TS available.
If you need configurable values in CLI, consider putting them in your site/config.yaml
or $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']
$site = GeneralUtility::makeInstance(SiteFinder::class)
->getSiteByPageId($pageID);
$uri = $site->getRouter()->generateUri($pageID, [
'tx_myext'=>[
'controller'=>'MyController',
'action'=>'detail',
'uid'=>$contentID,
'_language'=>0
]
], 'c123');
It will create a fully qualified URL including routeEnhancers
Generally speaking you can use Repositories and Models, but you should test it very well.
If you create or modify Models, persist them with
PersistenceManager directly!
Do small incremental updates,
otherwise the console seems 'frozen'
Other than that -> no $TSFE means no Extbase Context.
You can use Fluid (StandaloneView), but some ViewHelpers need a Controller context or TSFE
(for example the whole f:link and f:uri family)
Solution: write your own ViewHelper using SiteFinder and Site
Some ViewHelper might resolve a File to the full path instead of an URL
TEST!!
some CLI tools I wrote and maintain:
Twitter: @FoppelFB
Mastodon: @foppel@mastodon.cloud
fberger@sudhaus7.de
https://sudhaus7.de/
fberger@code711.de
https://code711.de/