interitty / console
Extension of the standard Symfony/Console by some other features that are specific for use in the Interitty projects.
Requires
- php: ~8.3
- 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.3
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;
}