interitty / console
Extension of the standard Symfony/Console by some other features that are specific for use in the Interitty projects.
Installs: 672
Dependents: 1
Suggesters: 0
Security: 0
Stars: 1
Forks: 0
pkg:composer/interitty/console
Requires
- php: ~8.4
- dg/composer-cleaner: ~2.2
- interitty/utils: ~1.0
- symfony/console: ~7.2
- symfony/lock: ~7.2
Requires (Dev)
- interitty/code-checker: ~1.0
- interitty/di: ~1.0
- interitty/phpunit: ~1.0
- nette/application: ~3.2
- nette/bootstrap: ~3.2
- nette/caching: ~3.3
README
Extension of the standard Symfony/Console by some other features that are specific for use in the Interitty projects.
Requirements
- PHP >= 8.4
Installation
The best way to install interitty/console is using Composer:
composer require interitty/console
Then register the extension in the Nette config file:
# app/config/config.neon
extensions:
console: Interitty\Console\Nette\DI\ConsoleExtension(%consoleMode%)
Features
The Interitty/Console provides some additional features to the standard Symfony/Console library.
Console output
The BaseCommand class provides write and writeError methods that allow writing to standard output respectively
to standard error output without the need to transmit the OutputInterface object to every method.
protected function foo(): void
{
// outputs multiple lines to the console (adding PHP_EOL at the end of each line)
$this->write([
'User Creator',
'============',
'',
]);
// the value returned by someMethod() can be an iterator (https://php.net/iterator)
// that generates and returns the messages with the 'yield' PHP keyword
$this->write($this->someMethod());
// outputs a message followed by a PHP_EOL
$this->write('Whoa!');
// outputs a message without adding a PHP_EOL at the end of the line
$this->write('You are about to ', false);
$this->write('create a user.', false);
// outputs a message to standard error output
$this->writeError('<error>big bada bum</error>');
}
This is possible thanks to stored InputInterface and OutputInterface objects that are accessible via
getInput, getOutput, and getErrorOutput methods.
Debug log timestamped
Especially when dealing with complicated situations, it can be helpful to know when an event occurred. For this case,
standard methods like write and writeError are extended with the option to turn on the timestamp at the beginning
of the message in "debug" mode.
Just turn on the static variable $isLogTimestamped in the command.
Exception processor
When the Exception or any Throwable object was thrown in the execute process, there is a standard
processException method that converts the exception message to a standard error output message. It also dumps a trace
log when the Debug verbosity mode is set.
Lazy-loading
The ConsoleExtension extension automatically binds all registered services of type Symfony\Component\Console\Command\Command
using a simple implementation LazyCommandLoader.
The value defined by the AsCommand attribute is used as the command name.
use Interitty\Console\BaseCommand;
use Symfony\Component\Console\Attribute\AsCommand;
#[AsCommand(name: 'app:dummy')]
class DummyCommand extends BaseCommand
{
}
However, many existing classes still need to start using this attribute. It may also be helpful to set the name to a different value. In these cases, using so-called tags when defining a service is possible.
services:
commands.dummy:
class: App\DummyCommand
tags: [console.command: app:dummy]
# or
tags: [console.command: {name: app:dummy}]
Long running prevention
Sometimes, the command may process a massive volume of data regularly. It is usually routinely run, for example, every 10 minutes, to react as quickly as possible to new data. Thanks to the "Exclusive command call lock" functionality, it is ensured that any further run is preemptively terminated with a log message. However, the first run may run for several days, and all possible related logs go into one file.
To avoid this, a processCheckLock function has been implemented which can optionally be called in the code to check
if the command was run yesterday.
protected function processExecute(): int
{
do {
// ... do something important
$this->processCheckLock();
} while (...);
return self::SUCCESS;
}
Exclusive command call lock
Usually, rerunning the same command leads to an unwanted and difficult-to-detect error. Therefore, a simple check
is implemented by default using the Symfony/Lock package, which can be simply
disabled if necessary using the static $isExclusive parameter.
use Interitty\Console\BaseCommand;
class NotExclusiveCommand extends BaseCommand
{
/** @var bool */
protected static bool $isExclusive = false;
}
Otherwise, when the same command is re-executed with the same parameters, a logical exception will occur with the text "The command is already running in another process".
ProgressBar factory
The factory method createProgressBar is available for easier access to the progress bar.
protected function processExecute(): int
{
$data = $this->getData();
$progressBar = $this->createProgressBar($data->count());
$progressBar->start();
foreach($data as $item) {
// Do some logic here
$progressBar->advance();
}
$progressBar->finish();
return self::SUCCESS;
}