Jak jednoduše použít Symfony\Console
ve vašich Nette projektech. Jak vytvořit vlastní command, jak ho zaregistrovat a nakonec spustit. S tímhle vším vám pomůže Contributte\Console
.
Symfony\Console
je v PHP světě poměrně rozšířený a známý nástroj. Napsala se celá řada příkazů pro práci s databází, generování obsahu, nespočet cronu a dalšího. A protože nechcem znovu vynálezat kolo, ukážeme si jak ji jednoduše vložíme do Nette projektu.
Spustit command z příkazové řádky se hodí např. při vývoji, kdy chceme vytvořit nové migrace, vymazat databázi, smazat cache, přidat uživatele apod. Taktéž se hodí při spouštění dlouhotrvajících scriptů, např. při počítání různých statistik, generování PDF. Svoje využití najdou commandy i při cron jobech. Obecně se dá řici, že commandy nám pomáháji ovládat aplikaci přes malé jednoduché příkazy, kterým lze předat nějaké argumenty (arguments), případně doladit přes atributy (options).
console foo:bar <argument> --option <baz> --option2
Rád bych vám ukázal tyto 3 způsoby integrace:
- stará dobrá
kdyby/console
- čistě přes
symfony/console
- integrace přes
contributte/console
Stará dobrá Kdyby\Console
Kdyby\Console
je tu s námi už delší dobu, určitě spadá mezi nejpoužívanější balíčky do Nette vůbec. Je to parádní práce z dílny Filipa Procházky
V čem vidím problém, je konkurence a také, že se z Kdyby\Console
stal poněkud větší baliček než by mohl být. Když chtěl někdo do teď integrovat symfony/console
do Nette, šáhl v 99% po Kdyby
balíčku. To znamená, že kdyby to Filip netáhnul dál, postupně by balíček stárnul. To že jsem balíček označil jako větší moloch, není myšleno hanlivě. Díky tomu můžeme dnes pohodlně zavolat php www/index.php
a uvidíme nám známou consoli. Kvůli této pohodlnosti, je tam však celkem dost kódu, který považujicí spíše za nadbytečný. Kdyby přetěžuje váš router a vkládá tam routu, která se volá v případě že aplikace beží v CLI modu.
Do nedávna nebyla žádná jiná implementace Symfonydo Nette, což mi škoda. Člověk by měl mít na výběr z více možností, než si napíše vlastní (;-D).
Dnes tu proto máme contributte/console.
Čistá symfony/console
integrace
Není nic jednoduššího než bez dalších závislostí přidat symfony console do Nette napřímo.
Nainstalujeme symfony console do našeho projektu.
composer require symfony/console
Dále musíme zaregistrovat Symfony\Component\Console\Application
jako službu v našem configu. Můžeme definovat i jméno a verzi, nicméně, není to uplně důležité. V dalším kroku přidáme ukázkový command App\Commands\TestCommand
.
services:
console.application:
class: Symfony\Component\Console\Application
setup:
# Configuration =================
- setName('My CLI')
- setVersion('1.0')
# Commands ======================
- add(App\Commands\TestCommand())
Poslední částí je spouštěcí script, který vytvoříme do bin/console
.
#!/usr/bin/env php
<?php
/** @var Nette\DI\Container $container */
$container = require __DIR__ . '/../app/bootstrap.php';
// Run symfony application.
$app = $container->getByType(Symfony\Component\Console\Application::class);
// Ensure exit codes
exit($app->run());
Snadné, rychlé, téměr bez práce. Má to pár nevýhod a to, že commandy nejsou registrované a volané tzn. lazy a také, že každý command musíme ručně přidat do Symfony\Component\Console\Application
.
Chtěl jsem skloubit Kdybyspolu s jednoduchým a přímočarým řešením. A tak vznikl balíček contributte.
Integrace pomocí contributte/console
Tento balíček vznikl jako alternativa ke Kdyby, jde ale jiným minimalistickým směrem. Stejně jako Filip, který se věnoval/věnuje údržbe Kdyby několik let, taktěž moje balíčky mají long-term-support.
Pomocí composeru nainstalujeme balíček.
composer require contributte/console
Registrace do Nette aplikace je přes CompilerExtension
.
extensions:
console: Contributte\Console\DI\ConsoleExtension
Konfigurovat lze všemožné parametry a to např.
console:
name: Acme Project
version: 1.0
catchExceptions: true / false
autoExit: true / false
url: https://contributte.com
helperSet: @customHelperSet
helpers:
- App\Console\MyHelper
Pro přidání vlastní commandu stačí vytvořit novou třídu s předkem Contributte\Console\Command\AbstractCommand
.
namespace App\Console;
use Contributte\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
final class FooCommand extends AbstractCommand
{
/**
* Configure command
*
* @return void
*/
protected function configure()
{
$this->setName('foo');
$this->setDescription('Example command');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
// Some magic..
}
}
A poté zaregistrovat jako službu.
services:
- App\Console\FooCommand
Hlavní rozdíl oproti Kdybyje, že tento balíček nemodifikuje router, takže vám zavolání php www/index.php
nespustí console.
Je nutné proto vytvořit entrypoint do bin/console
.
#!/usr/bin/env php
<?php
/** @var Nette\DI\Container $container */
$container = require __DIR__ . '/../app/bootstrap.php';
// Get application from DI container.
$application = $container->getByType(Contributte\Console\Application::class);
// Run application.
exit($application->run());
A také mu nastavit práva na spouštění, chmod +x bin/console
. Vyvolat consoli je už snadné.
bin/console
Acme Project
Usage:
command [options] [arguments]
Options:
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
-e, --env=ENV Forced environment name (production, development, test)
--no-sandbox Disable commands which depends on "Sandbox".
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
help Displays help for a command
list Lists commands
foo Example command.
Hooray! :+1:
Budu rád pokud vyzkoušíte contributte/console
nebo nějaký jiný balíček z rodiny Contributte, třeba contributte/event-dispatcher pro snadnou integraci Symfony/Events.