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.
Fajny wpis. Nie wgłębiałem się zanadto w “formatery” i nie zdawałem sobie nawet sprawy z możliwości jakie oferują 🙂
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).