PHP code example of nette / command-line

1. Go to this page and download the library: Download nette/command-line library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

nette / command-line example snippets


use Nette\CommandLine\Command;
use Nette\CommandLine\Parser;

$command = new Command('convert');
$command->addFlag('--verbose', 'Enable verbose mode', alias: '-v');
$command->addOption('--output', 'Output file', alias: '-o');
$command->addArgument('input', 'File to convert');

$args = (new Parser)->parse($command);

$args['--verbose'];  // true, or null if not used
$args['--output'];   // 'file.txt', or null if not used
$args['input'];      // 'photo.png'

$args = (new Parser)->parse($command, ['--verbose', '-o', 'out.txt', 'photo.png']);

$command->addFlag('--verbose', alias: '-v');
// --verbose  → true
// -v         → true
// (not used) → null

$command->addFlag('--color', negatable: true, default: true);
// --color     → true
// --no-color  → false
// (not used)  → true

$command->addOption('--output', alias: '-o');
// --output file.txt    → 'file.txt'
// --output=file.txt    → 'file.txt'
// -o file.txt          → 'file.txt'
// --output             → throws (the value is 

$command->addOption('--format', valueOptional: true);
// --format=json  → 'json'
// --format       → true
// --format json  → true, and json is an argument
// (not used)     → null

$command->addOption('--sort', valueOptional: true, enum: ['name', 'time']);
// --sort=time  → 'time'
// --sort time  → 'time'
// --sort       → true
// --sort src   → true, and src is an argument

$command->addArgument('input');
// file.txt    → 'file.txt'
// (not used)  → throws

$command->addArgument('output', optional: true);
// (not used)  → null

// script.php -- --weird  → input = '--weird'
// script.php -           → input = '-'
// script.php -1          → input = '-1'

$command->addOption('--format', default: 'json');
// --format xml  → 'xml'
// --format      → throws (the value is �� 'xml'
// --format      → true
// (not used)    → 'json'

$command->addOption('--format', enum: ['json', 'xml', 'csv']);
// --format yaml  → throws "Option --format: expects json, xml or csv, 'yaml' given."

enum Format: string
{
	case Json = 'json';
	case Xml = 'xml';
}

$command->addOption('--format', enum: Format::class, default: Format::Json);
// --format xml  → Format::Xml
// (not used)    → Format::Json

$command->addOption('--['src', 'lib']
// (not used)     → []

$command->addArgument('files', optional: true, repeatable: true);
// a.txt b.txt    → ['a.txt', 'b.txt']

use Nette\CommandLine\Normalizers;

$command->addOption('--count', normalizer: Normalizers::int(min: 1));
// --count 42   → 42
// --count abc  → throws "Option --count: expects an integer, 'abc' given."
// --count 0    → throws "Option --count: expects at least 1, 0 given."

$command->addOption('--config', normalizer: Normalizers::realPath());
// --config app.ini      → '/full/path/to/app.ini'
// --config missing.ini  → throws "Option --config: file path 'missing.ini' not found."

$realPath = Normalizers::realPath();
$command->addOption('--config', normalizer: fn($v) => $realPath("config/$v"));

use Nette\Schema\Expect;
use Nette\Schema\Processor;

$options = (new Processor)->process(Expect::structure([
	'--jobs' => Expect::string()->pattern('[1-9][0-9]*')->castTo('int')->default(8),
	'paths' => Expect::listOf('string'),
])->otherItems(), array_filter($args->toArray(), fn($value) => $value !== null));

$cli = new Command('dresscode');
$cli->addFlag('--help', 'Print this help', alias: '-h', standalone: true);
$cli->addOption('--config', 'Configuration file', alias: '-c', normalizer: Normalizers::realPath());

$check = $cli->addCommand('check', 'Report violations');
$check->addArgument('paths', 'Files or directories', optional: true, repeatable: true);
$check->addFlag('--generate-baseline', 'Write the violations into the baseline');

$explain = $cli->addCommand('explain', 'What a rule is for');
$explain->addArgument('rule', 'Name of the rule');

$args = (new Parser)->parse($cli);

if ($args['--help']) {
	(new HelpRenderer)->render($args->command);
	exit(0);
}

exit(match ($args->command) {
	$check => $app->check($args['paths'], $args['--generate-baseline']),
	$explain => $app->explain($args['rule']),
	$cli => $app->usage(),
});

$args = (new Parser)->parse($check, ['check', 'src', '--generate-baseline']);

$cli->addCommand('check', 'Report violations', handler: $checker->check(...))
	->addArgument('paths', 'Files or directories', optional: true, repeatable: true);

$args = (new Parser)->parse($cli);
if ($args['--help']) {
	(new HelpRenderer)->render($args->command);
	exit(0);
}

exit($args->run());

public function check(array $paths, ?string $config, ParseResult $args): int

use Nette\CommandLine\Attributes\{Command, Option};

final class ConfigCommand
{
	#[Command('Print the configuration')]
	public function config(
		ParseResult $args,
		#[Option('Print it for one file', valueName: 'path')]
		?string $file = null,
		#[Option('Output format')]
		Format $format = Format::Console,
	): int
	{
		...
	}
}

$cli->addCommandFrom((new ConfigCommand)->config(...));

$cli->addCommandsFrom(new ConfigCommand);

public static function parseJobs(string $value): int
{
	return Normalizers::int(min: 1)($value);
}

final readonly class RunOptions
{
	public function __construct(
		#[Argument('Files or directories', repeatable: true)]
		public array $paths = [],
		#[Option('Number of worker processes', valueName: 'n', normalizer: [self::class, 'parseJobs'])]
		public ?int $jobs = null,
	) {
	}
}

#[Command('Report violations')]
public function check(RunOptions $run): int

use Nette\CommandLine\HelpRenderer;

$command = new Command('convert', 'Converts files between formats.');
$command->addFlag('--verbose', 'Enable verbose mode', alias: '-v');
$command->addOption('--output', 'Output file', alias: '-o', valueName: 'file');
$command->addArgument('input', 'Input file');

(new HelpRenderer)->render($command);

$command = new Command('convert');
$command->addFlag('--help', alias: '-h', standalone: true);
$command->addFlag('--version', standalone: true);
$command->addArgument('input');  // 

use Nette\CommandLine\UsageException;

try {
	$args = (new Parser)->parse($cli);
	exit($args->run());
} catch (UsageException $e) {
	(new HelpRenderer)->renderError($e);
	exit(2);
}

function (Command $command, bool $stdin, array $paths): int {
	if ($stdin && $paths) {
		throw new UsageException('Paths cannot be combined with `--stdin`.', $command);
	}
	...
}

$console = new Console;
$console->writeLine('Error!', 'red');
$console->writeLine('White text on blue background', 'white/blue');
$console->writeLine($console->color('gray', 'Config  ') . $file); // a line of several colors is composed

$console = new Console(STDOUT, colorDepth: ColorDepth::None);  // or $console->setColorDepth(ColorDepth::None);
$console->hasColors();      // whether it colors
$console->getColorDepth();  // ColorDepth::None
$console->isTerminal();     // whether someone is watching: progress bars, prompts
$console->getWidth();       // columns of the terminal, 80 when it is not one

$console->writeLine('See ' . $console->link('https://nette.org/cli'));
$console->writeLine($console->link('https://nette.org/cli', 'the manual'));  // "the manual (https://…)" without colors

$console->write($console->hasColors() ? $output : Ansi::strip($output));

foreach ($files as $i => $file) {
	$console->setStatus(sprintf('%d/%d  %s', $i + 1, count($files), $file));
	$console->writeLine(check($file));  // erases the status and writes above it
}

$console->clearStatus();

use Nette\CommandLine\Ansi;

Ansi::measure($console->color('red', 'chyba'));   // 5, the escape sequences do not count
Ansi::pad($console->color('red', 'chyba'), 10);   // padded to 10 columns, not to 10 bytes
Ansi::truncate($path, 30, keepEnd: true);         // cuts the front, so the file name stays
Ansi::strip($text);                               // the text without any escape sequence

use Nette\CommandLine\Prompt;

$prompt = new Prompt($console);
if ($prompt->isInteractive()) {
	$answer = $prompt->choose('Apply this fix?', ['y', 'n', 'a', 'q'], default: 'n');  // Apply this fix? [y/N/a/q]
}

$answer = $prompt->choose('Choice', [
	's' => 'Skip this operation',
	'r' => 'Resume',
	'c' => 'Cancel deployment',
], default: 'r');