Łatwe rozszerzanie funkcjonalności komponentu Symfony2 Console dzięki Dependency Injection

Podczas pisania małego konsolowego programiku – konfiguratora ułatwiającego zarządzanie serwerami opartymi o nginx+PHP napkin (nginx and PHP configuration is neat), zaszła potrzeba zaimplementowania dodatkowej funkcjonalności Helpera formatującego wyjście konsolowe w komponencie Symfony Console.

Poniżej przedstawiam, jak w przystępny sposób zabrać się do takiego rozszerzania funkcjonalności.

Jeśli nie miałeś jeszcze styczności z Symfony2, to na wstępie pragnę gorąco polecić wstęp do komponentu Console Jakuba Zalasa oraz oficjalną dokumentację komponentu Console. Warto też spojrzeć na blog Umpirskiego.

A teraz do rzeczy. Standardowo, komponent Console ma dwa podstawowe sposoby wyświetlania i dwa sposoby formatowania/interakcji (w przypadku DialogHelpera) z wyjściem/wejściem standardowym (STD). Są nimi:

  • Wyjście bezpośrednie, opcjonalnie formatowane przez tagi:
    • $output->write(‘tekst niesformatowany <info>tekst zielony</info>’)
    • $output->writeln(‘tekst + zakończenie linii, formatowanie jak wyżej’)
  • Formatowanie przy użyciu helperów:
    • FormatterHelper() – generuje blok tekstowy lub sekcję, możliwe stylowanie całego bloku tagami jak wyżej
    • DialogHelper() – generuje interaktywny dialog z inputem

W wyściu bezpośrednim możemy oczywiście również pokolorować tekst dzięki OutputFormatterowi w następujący sposób:

$output->writeln('tekst niesformatowany');
$output->writeln('<info>tekst zielony</info>');
$output->writeln('<comment>tekst żółty</comment>');
$output->writeln('<fg=yellow;bg=white;cokolwiek=blink;other=bold>pogrubiony migający tekst żółty na białym tle</fg=yellow;bg=white;cokolwiek=blink;other=bold>');

Wykonując coś takiego otrzymamy:

Ostatni sposób nie jest niestety opisany w oficjalnej dokumentacji. 🙁

Przyjrzyjmy się jednak FormatterHelperowi, który ma bardzo przyjemne metody formatowania bloku.

$formatter = $this->getHelperSet()->get('formatter');
$output->writeln($formatter->formatBlock('jestem blokiem i nikt mi nie podskoczy!', 'error', true));

Argumenty Formattera to:

(string) tekst do sformatowania;
(string) format – czyli np. nasz powyższy ‘fg=yellow;bg=white;other=blink;other=bold’;
(bool) duży [true], czy mały blok (dodaje sformatowaną nową linię przed i po bloku)

Nie ma jednak prostego sposobu na wyświetlenie kilku bloków obok siebie. Takie coś byłoby przydatne wizualnie, gdybyśmy chcieli przedstawić użytkownikowi porównanie dwóch wartości (w moim wypadku starą i nową, która ma nadpisać tą starą). Z tego też powodu wziąłem się za napisanie własnego Helpera.

W tym celu rozszerzyłem klasę FormatterHelpera i dopisałem funkcję wyświetlającą sformatowane bloki obok siebie.
//
By użyć taką klasę możemy skorzystać z Dependency Injection, które Symfony2 oferuje nam w standardzie:

$this->setHelperSet(new ConsoleHelperHelperSet(
  array(
    new ConsoleHelperFormatterHelper(),
    new ConsoleHelperDialogHelper(),
    new XFormatterHelper()
  )));

$formatter = $this->getHelperSet()->get('xformatter');

I to wszystko! Już możemy korzystać z naszej nowo zbudowanej klasy:

$toFormat = array( 
    array('messages' => (array) 'stare ustawienie', 'style' => 'error'), 
    array('messages' => array('> >'), 'style' => 'fg=yellow;bg=black;other=blink;other=bold', 'large' => false), 
    array('messages' => (array) 'nowe ustawienie', 'style' => 'fg=black;bg=yellow;other=bold') 
); 

$output->writeln($formatter->formatMultipleBlocks($toFormat, ' ', true));

Metoda formatMultipleBlocks przyjmuje następujące argumenty:

(array) Dla każdego bloku zagnieżdżona asocjacyjna tablica z [‘messages’], [‘style’] i opcjonalnie [‘large’]. Jeśli wiadomość ma wiele linijek, również powinna być tablicą (dla każdej linijki nowy element).
(string) Klej – czym skleić bloki, najczęściej chcemy to zrobić spacją, taki też jest default
(bool) Bloki mają być duże (nadpisuje opcję z tablicy poszczególnych bloków)
(bool) Wyśrodkuj bloki w pionie
(bool) Przedłuż krótsze bloki, poprzez kopiowanie ostatniej linijki

Najaktualniejsza wersja XFormatterHelpera dostępna z GitHubowego Gist.

2 thoughts on “Łatwe rozszerzanie funkcjonalności komponentu Symfony2 Console dzięki Dependency Injection

  1. Dzięki 🙂
    Ja sam w zasadzie dopiero zaczynam zabawę z Symfony2, ale mówiąc szczerze z tego co widzę ma świetne możliwości.
    Szkoda tylko, że jest tak słabo udokumentowana (tzn. tam gdzie jest dokumentacja, jest ona bardzo dobra, ale niestety obejmuje jakieś 30% funkcjonalności).

Leave a Reply to Bazyli Brzóska Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.