Консольные команды с PHPixie Console

от автора

image
PHPixie Console — это новый компонент позволяющий создавать, роутить и запускать консольные команды. Как и другие библиотеки фреймворка он может легко использоваться без самой PHPixie как более простая альтернатива аналогичной библиотеки из Symfony.

Апгрейд существующих проектов

Если у вас уже есть PHPixie проект, то для работы Console надо внести несколько простых изменений:

  1. Скопируйте https://github.com/PHPixie/Project/blob/master/console в корень проекта. Если вы на линуксе то поставьте на этот файл права на исполнение (chmod +x console)
  2. Добавьте «phpixie/framework-bundle»: "~3.0" в composer.json
  3. Поключите бандл \PHPixie\FrameworkBundle и добавьте /*GeneratorPlaceholder*/
    как тут: https://github.com/PHPixie/Project/blob/master/src/Project/Framework/Bundles.php

Опционально можно также скопировать дефолтную архитектуру и демо-команду с новоно скелета проекта:

  1. Console.php
  2. Console/Greet.php
  3. В Builder классе банда подключите класс консоли как тут: Builder.php

Внимание, замените NamespacePlaceholder на неймспейс своего проекта (по умолчанию Project) и BundleNamePlaceholder на имя своего бандла (скорее всего это App).

После этого ваша структура будет такая-же как у свежего проекта.

Использование

Запустите консоль чтобы увидеть список доступных команд:

cd your_project_directory/  ./console # или php ./console 

Результат будет примерно таким:

Available commands:  app:greet                     Greet the user framework:installWebAssets    Symlink or copy bundle web files to the projects web folder framework:generateBundle      Generate a new bundle help                          Print command list and usage 

Команда help покажет больше информации и список доступных параметров:

./console help framework:installWebAssets  framework:installWebAssets [ --copy ] Symlink or copy bundle web files to the projects web folder  Options: copy    Whether to copy web directories instead of symlinking them 

Стандартные команды

  • framework:installWebAssets — создает ярлыки в папке /web/bundles указующие на /web папки внутри бандлов, например /web/bundles/app -> /bundles/app/web. Это делается для того чтобы бандлы инсталлированные с помощью композера могли предоставить свои веб файлы. Флажок —copy скопирует файлы вместо создания ярлыков. Это удобно например для создания архива для CDN.
  • framework:generateBundle — генерирует и подключает новый бандл в проект. Больше не придется вручную создавать бандлы путем копирования существующего.

Добавление собственных команд

У вас в проекте уже добавлена простая команда app:greet. Работа с командами полностью аналогична добавлению HTTP процессоров, используя класс \Project\App\Console. Достаточно добавить имя команды в массив возвращаемый методом commandNames() и добавить метод build<command_name>Command.

В конструкторе команды вы можете задать описание и список параметров и аргументов:

namespace Project\App\Console;  class Greet extends \PHPixie\Console\Command\Implementation {     public function __construct($config)     {         // Описание         $config->description('Greet the user');          // Добавим параметр 'message'         $config->argument('message')             ->description("Message to display");          parent::__construct($config);     }      /**      * Этот метод вызывается при запуске команды.      * $argumentData и $optionData работают так же      * как HTTP $request->query() и $request->data()      */     public function run($argumentData, $optionData)     {         $message = $argumentData->get('message', "Have fun coding!");         $this->writeLine($message);     } } 

Аргументы и опции

Допустим мы хотим добавить следующую команду:

sqldump --user=root --skip-missing -f myDatabase users items 

Здесь myDatabase имя базы данных, а за ней список таблиц которые мы хотели бы забекапить. Это аргументы нашей команды. А user, skip-missing, и f опции. Заметьте что для аргументов важен порядок в котором они задаются, а для опций нет. Также короткие опции с одной буквы используют один знак вместо двух.

В коде это будет выглядеть вот так:

$config->option('user')      //Обязательная опция     ->required()      //Ее описание, будет показано при запуске команды 'help'     ->description("User to connect to the database with");  $config->option('skip-missing')     ->description("Don't throw an error if the tables are missing")      //Задать опцию как флажок.     //Опциям-флажкам не задается значение,     //взамен они устанавливаются в 'true' если они присутствуют.     ->flag();  $config->option('f')     ->flag()     ->description("Force database dump"); 

При описании аргументов надо помнить что задавать их надо в том порядке в котором они должны присутствовать в команде. В нашем случае аргумент database идеи перед tables:

$config->argument('database')     ->required()     ->description("Which database to dump the tables from");  $config->argument('tables')     ->description("Tables to dump")      // Принимает массив значений     // В команде может быть толко один такой аргумент,     // и логично что он должен быть последним     ->arrayOf(); 

Теперь при запуске help мы получим вот такой результат:

./console help app:sqldump  app:sqldump --user=VALUE [ -f ] [ --skip-missing ] DATABASE [ TABLES... ]  Options: user            User to connect to the database with f               Force database dump skip-missing    Don't throw an error if the tables are missing  Arguments: DATABASE  Which database to dump the tables from TABLES    Tables to dump 

При запуске команды методу run() передадутся опции и аргументы, откуда их можно получить аналогично как и в HTTP процессоре:

public function run($argumentData, $optionData) {     $database = $argumentData->get('database');      // С указанием дефолтного значения     $user = $optionData->get('user', 'phpixie'); } 

Ввод и вывод

Самый простой метод вывода в консоль это просто return-уть текст. Но если процесс должен работать долгое время и надо выводить промежуточный результат, то можно использовать дополнительные методы:

public function run($argumentData, $optionData) {     // Вывод текста     $this->write("Hello ");      // Вывод текста с новой строкой     $this->writeLine("World");      // Считать ввод пользователя с консоли     $str = $this->readLine();      // Если бросить CommandException то в консоли отобразится текст ошибки     // и сама команда возвратит не-нулевой статус код (полезно при работе с Bash).     throw new \PHPixie\Console\Exception\CommandException("Something bad happened"); } 

Дополнительно можно получить доступ к CLI контексту и работать уже с ним:

public function run($argumentData, $optionData) {     $context = $this->cliContext();      $inputStream = $cliContext->inputStream();     $outputStream = $cliContext->outputStream();     $errorStream = $cliContext->errorStream();      $outputStream->write("Hello");     $errorStream->writeLine("Something bad happened");     $context->setExitCode(1); // указать код статуса 

Код статуса пригодится при проверке удачно ли исполнилась команда извне, например из Bash:

if ./console app:somecommand ; then     echo "Command succeeded" else     echo "Command failed" fi 

Как я уже писал с самого начала, компонент можно легко использовать и без фреймворка:

class YourCommandRegistry extends \PHPixie\Console\Registry\Provider\Implementation  {     public function commandNames()     {          return ['greet'];     }      public function buildGreetCommand($config)     {          return new Greet($config);     } }  $slice = new \PHPixie\Slice(); $cli = new \PHPixie\CLI(); $registry = new YourCommandRegistry();  $console = new \PHPixie\Console($slice, $cli, $registry); $console->runCommand(); 

Таким образом добавить консольные возможности можно в любой проект, все это с минимальными зависимостями и весьма интуитивно.
ссылка на оригинал статьи https://habrahabr.ru/post/314314/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *