PHPixie Console — это новый компонент позволяющий создавать, роутить и запускать консольные команды. Как и другие библиотеки фреймворка он может легко использоваться без самой PHPixie как более простая альтернатива аналогичной библиотеки из Symfony. В первую очередь это статься рассчитана на тех кто уже пользуется PHPixie и в ней будет короткое описание стандартных команд фреймворка, но в конце я так же приведу пример того как запустить PHPixie Console в отдельности.Апгрейд существующих проектов
Если у вас уже есть PHPixie проект, то для работы Console надо внести несколько простых изменений:
Опционально можно также скопировать стандартную архитектуру и демо-команду с обновленного скелета проекта:
Внимание, замените NamespacePlaceholder на неймспейс своего проекта (по умолчанию Project) и BundleNamePlaceholder на имя своего бандла (скорее всего это App).
После этого ваша структура будет такая-же как у свежего проекта.
- Скопируйте https://github.com/PHPixie/Project/blob/master/console в корень проекта. Если вы на линуксе то поставьте на этот файл права на исполнение (chmod +x console)
- Добавьте «phpixie/framework-bundle»: "~3.0" в composer.json
- Поключите бандл \PHPixie\FrameworkBundle и добавьте /*GeneratorPlaceholder*/
как тут: https://github.com/PHPixie/Project/blob/master/src/Project/Framework/Bundles.php
Опционально можно также скопировать стандартную архитектуру и демо-команду с обновленного скелета проекта:
- Console.php
- Console/Greet.php
- В 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 Dont 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();
Таким образом добавить консольные возможности можно в любой проект, все это с минимальными зависимостями и весьма интуитивно.
