Artisan-like console for Nette:
- Symfony Console wired into DI via contributte/console
- package discovery: DI extensions of installed packages register themselves after
composer require make:*generators with overridable stubs
composer require rajtik76/nette-console
Attach discovery in Bootstrap, before the container is created:
use Rajtik\Console\Discovery\PackageDiscovery;
PackageDiscovery::fromComposer()->attach($this->configurator);Add an entry script, e.g. nette in the project root:
#!/usr/bin/env php
<?php declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
// debug mode recompiles the container on config changes; set NETTE_DEBUG=0 in production
$container = (new App\Bootstrap)->bootConsoleApplication(debugMode: getenv('NETTE_DEBUG') !== '0');
exit($container->getByType(Contributte\Console\Application::class)->run());php nette list
list and --version print a nette banner; console: name and console: version set the caption under it.
| Command | Description |
|---|---|
make:command <Name> |
Creates App\Console\<Name>Command. Mail/Report → App\Console\Mail\ReportCommand, terminal name app:report (--command to override, --force to overwrite). |
package:discover |
Lists extensions registered by discovery. |
cache:clear |
Deletes files in temp/cache (DI container, Latte, ...). |
Commands extend Rajtik\Console\Command\Command and return an ExitCode from handle();
the process exits with its numeric value (Success = 0, Failure = 1, Invalid = 2):
use Rajtik\Console\Command\Command;
use Rajtik\Console\Command\ExitCode;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand(name: 'app:send-report')]
final class SendReportCommand extends Command
{
protected function handle(InputInterface $input, OutputInterface $output): ExitCode
{
return ExitCode::Success;
}
}Any service extending Symfony\Component\Console\Command\Command is a command. Register
generated commands through search in services.neon:
search:
- in: %appDir%
classes:
- *CommandA package declares its extensions in composer.json using NEON entity syntax:
"extra": {
"nette": {
"extensions": {
"migrations": "Acme\\Migrations\\DI\\MigrationsExtension(%consoleMode%)"
}
}
}-
The container is recompiled after
composer install/update(production) and whenevervendor/composer/installed.jsonchanges (debug mode). -
An extension of the same name in the application's
extensions:section wins. -
Two packages claiming the same name fail the compilation.
-
Opt out in the root
composer.json:"extra": { "nette": { "dont-discover": ["acme/migrations"] } }
"*" disables discovery entirely.
netteConsole:
stubs: %rootDir%/stubs # application stubs override package ones (command.stub, ...)
commands:
namespace: App\Console
directory: %appDir%/ConsoleExtend Rajtik\Console\Command\GeneratorCommand and implement stubName(), defaultStubDirectory(),
targetFile() and replacements(). Stub placeholders use {{ key }}. After generating, the
DI container cache is invalidated so new classes found by search are registered on the next run.
composer run ci:check # PHPStan level 8 + Nette Tester