Статьи

Повторное представление Symfony Console — CLI PHP для непосвященных!

Эта популярная статья была обновлена ​​24 мая 2017 года, чтобы дать более полное представление о существенном, современном инструменте.


«Компонент консоли облегчает создание красивых и тестируемых интерфейсов командной строки».

Вот как мы приветствуем, когда посещаем страницу инструментов Symfony Console .

Как разработчики программного обеспечения, мы часто чувствуем необходимость прибегнуть к инструментам командной строки. Эти виды инструментов полезны, когда нам нужно выполнить своего рода повторяющуюся задачу, такую ​​как миграция данных, выполнение импорта или создание заданий cron.

Векторное изображение терминала или консольного приложения

Инструмент Symfony Console предоставляет нам простую структуру для создания собственных инструментов командной строки.

В отличие от многих компонентов в Symfony, это автономный пакет, который используется такими, как Laravel ‘s Artisan и многими другими известными пакетами PHP.

Чтобы узнать об альтернативах Symfony Console, посмотрите наш пост сравнения: PHP Console Wars!

Установка

composer require symfony/console 

Необходимая информация о Композиторе здесь .

Создание новой команды

Чтобы создать новую команду, нам нужно убедиться, что наш файл будет исполняемым. Для этого давайте создадим console файл в корне нашего проекта. Этот файл будет нашим командным менеджером.

 touch console 

Теперь давайте удостоверимся, что файл исполняемый.

 chmod 755 console 

Затем, давайте удостоверимся, что наш файл имеет шебанг в начале. Шебанг — это последовательность символов (знак числа, за которым следует восклицательный знак), которая появляется в начале сценария. Когда присутствует shebang, exec() вместо этого запускает исполняемый файл, указанный после shebang. В нашем случае он будет работать как скрипт PHP.

После этого давайте определим наше консольное приложение. Первая итерация нашего менеджера команд будет выглядеть так:

 #!/usr/bin/env php <?php require_once __DIR__ . '/vendor/autoload.php'; use Symfony\Component\Console\Application; $app = new Application(); $app->run(); 

`

Давайте внимательнее посмотрим на вещи. Сначала мы автоматически загружаем все наши зависимости, затем импортируем пакет Application из компонента консоли. После этого мы создаем новый экземпляр приложения и запускаем его.

Если мы выполним наш скрипт с помощью ./console , мы должны получить следующее сообщение справки:
Команда 1

Это потому, что мы еще не зарегистрировали какие-либо команды, мы создали для них только базовую структуру.

Давайте создадим наш скрипт и зарегистрируем его в нашем недавно созданном диспетчере команд.

В этом конкретном примере мы реализуем две простые команды: одну для хеширования строк, а другую для подтверждения того, что хеш принадлежит данной строке.

Мы создадим папку /src в которую мы поместим наш класс Hash.php с содержимым:

 <?php namespace Hash; class Hash{ /** * Receives a string password and hashes it. * * @param string $password * @return string $hash */ public static function hash($password){ return password_hash($password, PASSWORD_DEFAULT); } /** * Verifies if an hash corresponds to the given password * * @param string $password * @param string $hash * @return boolean If the hash was generated from the password */ public static function checkHash($string, $hash){ if( password_verify( $string, $hash ) ){ return true; } return false; } } 

Пришло время создать нашу команду. Давайте создадим новый файл PHP с именем HashCommand.php .

Этот класс будет расширяться из класса Command Symfony и реализовывать методы configure и execute . Эти методы важны для нашей команды, так как они говорят ей, как выглядеть и вести себя.

Вот как выглядит готовая команда:

 <?php namespace Hash; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Hash\Hash; class HashCommand extends Command{ protected function configure(){ $this->setName("Hash:Hash") ->setDescription("Hashes a given string using Bcrypt.") ->addArgument('Password', InputArgument::REQUIRED, 'What do you wish to hash)'); } protected function execute(InputInterface $input, OutputInterface $output){ $hash = new Hash(); $input = $input->getArgument('Password'); $result = $hash->hash($input); $output->writeln('Your password hashed: ' . $result); } } 

В части configure метод setName — это то, как мы будем вызывать нашу команду, setDescription — описание нашей команды, а addArgument — это место, где мы говорим, что наша команда будет принимать один аргумент с именем Password , и что это необходимо.

В части execute мы обращаемся к аргументу через функцию getArgument , а затем используем наш класс Hash для его хеширования. Наконец, мы используем метод writeln для OutputInterface чтобы вывести наш результат на экран.

Если мы выполним нашу команду таким образом, мы увидим, что ничего не происходит. Это потому, что мы все еще пропускаем один очень важный шаг. Нам все еще нужно зарегистрировать нашу команду в console .

 #!/usr/bin/env php <?php require_once __DIR__ . '/vendor/autoload.php'; use Symfony\Component\Console\Application; use Hash\HashCommand; $app = new Application(); $app->add(new HashCommand()); $app->run(); 

С командой, зарегистрированной в нашей console , давайте запустим ее.

Если мы снова ./console команду ./console , мы увидим, что теперь у нас зарегистрирована новая команда.

Новый список команд

Давайте запустим это:

 ./console Hash:Hash Sitepoint 

И мы видим окончательный результат:

Выполнение команды

Хеш является результатом запуска метода PHP hash() в строке Sitepoint .

Для функции подтверждения хеша мы будем использовать тот же метод, но вместо одного у нас будет два аргумента. Одна будет строкой для подтверждения, а другая — хешем, который мы хотим проверить.

Мы будем создавать новый командный файл, прямо рядом с файлом HashCommand . Давайте назовем это ConfirmCommand .

 <?php namespace Hash; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Hash\Hash; class ConfirmCommand extends Command{ protected function configure(){ $this->setName("Hash:Confirm") ->setDescription("Confirms an Hash given the string.") ->addArgument('Password', InputArgument::REQUIRED, 'What password do you wish to confirm?)') ->addArgument('Hash', InputArgument::REQUIRED, 'What is the hashyou want to confirm?'); } protected function execute(InputInterface $input, OutputInterface $output){ $hash = new Hash(); $inputPassword = $input->getArgument('Password'); $inputHash = $input->getArgument('Hash'); $result = $hash->checkHash($inputPassword, $inputHash); if($result){ $output->writeln('The hash belongs to the password!'); return true; } $output->writeln('The hash does not belong to the password!'); } } 

Затем зарегистрируйте команду в console .

 #!/usr/bin/env php <?php require_once __DIR__ . '/vendor/autoload.php'; use Symfony\Component\Console\Application; use Hash\HashCommand; use Hash\ConfirmCommand; $app = new Application(); $app->add(new HashCommand()); $app->add(new ConfirmCommand()); $app->run(); 

тестирование

Когда дело доходит до тестирования, Symfony предоставляет нам несколько удобных инструментов. Наиболее полезным из них является класс CommandTester , поскольку он предоставляет специальные классы ввода и вывода для тестирования наших команд без необходимости использования командной строки.

Давайте используем класс CommandTester для реализации теста для нашей команды Hash:Hash .

Сначала давайте создадим папку /tests на том же уровне, что и наша папка /src .

Затем давайте создадим наш тестовый класс внутри него и назовем его HashCommandTest.php :

 <?php use Hash\HashCommand; use Symfony\Component\Console\Application; use Symfony\Component\Console\Tester\CommandTester; require_once './vendor/autoload.php'; class HashCommandTest extends \PHPUnit_Framework_TestCase{ public function testHashIsCorrect(){ $application = new Application(); $application->add(new HashCommand()); $command = $application->find('Hash:Hash'); $commandTester = new CommandTester($command); $commandTester->execute(array( 'command' => $command->getName(), 'Password' => 'Sitepoint' )); $this->assertRegExp('/Your password hashed:/', $commandTester->getDisplay()); } } 

Мы начинаем наш тест с загрузки нашей команды с помощью класса Application . Затем мы создаем новый CommandTester . С помощью CommandTester мы можем настроить способ вызова нашей команды. Последний шаг — просто сравнение результатов выполнения с getDisplay() результатом использования getDisplay() .

Метод getDisplay() содержит результат выполнения нашей команды, так же, как мы видим его в командной строке.

Вывод

Мы только что создали две разные команды, используя Symfony Console Component. Мы также увидели хороший способ тестирования этих команд. Я рекомендую вам взглянуть на различные опции и функции компонента и дать нам некоторые отзывы о ваших экспериментах в разделе комментариев ниже.

Хотели бы вы увидеть более продвинутые учебники о Symfony Console на SitePoint? Дайте нам знать!

Весь код, который мы написали в этой статье, доступен на Github .