Запуск Zend Framework MVC из командной строки
Хочу поделиться своим решение по запуску Zend Framework MVC из командной строки. Я ставил цель получить возможность легко и быстро работать как с новым проектом, так и с уже готовым приложением, к тому же используя все возможности последних версий фреймворка (Zend_Application, resources loading). Скрипт будет работать с проектами, базирующимися на Zend Framework 1.8 и дальше.
Писал свои инструкции, предполагая, что вы следуете стандартной структуре размещения директорий для Zend Framework.
Создаем скрипт играющий роль точки входа для приложения.
$ touch ./scripts/zf-cli.php
Далее посмотрим код скрипта с подробными комментариями по коду:
// можно удалить строчку начиная с PHP старше версии >= 5.3.0 defined('__DIR__') || define('__DIR__', dirname(__FILE__)); // стандартный код инициализации (путь к приложению, библиотека классов и автозагрузка) defined('APPLICATION_PATH') || define('APPLICATION_PATH', realpath(__DIR__ . '/../application')); $paths = explode(PATH_SEPARATOR, get_include_path()); $paths[] = realpath(__DIR__.'/../library'); set_include_path(implode(PATH_SEPARATOR, $paths)); unset($paths); require_once 'Zend/Loader/Autoloader.php'; $loader = Zend_Loader_Autoloader::getInstance(); // нам нужен этод код регистритующий отдельное пространство имен для загрузки специального класса $loader->registerNamespace('Custom_'); // наброски скелета CLI приложения $getopt = new Zend_Console_Getopt(array( 'action|a=s' => 'action to perform in format of "module/controller/action"', 'env|e-s' => 'defines application environment (defaults to "production")', 'help|h' => 'displays usage information', )); try { $getopt->parse(); } catch (Zend_Console_Getopt_Exception $e) { // пользователь передал неверные параметры: показать инструкцию по использованию echo $e->getUsageMessage(); return false; } // покажем справку в случае запроса последней или параметры (модуль, контролер, действие) упущены if ( $getopt->getOption('h') || !$getopt->getOption('a')) { echo $getopt->getUsageMessage(); return true; } // инициализируем дополнительные параметры если они есть $env = $getopt->getOption('e'); defined('APPLICATION_ENV') || define('APPLICATION_ENV', (null === $env) ? 'production' : $env); // инициализируем обьект приложения Zend_Application $application = new Zend_Application ( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini' ); // начинаем загрузку приложения, загружаем и извлекаем ресурс FrontController-а $front = $application->getBootstrap() ->bootstrap('frontController') ->getResource('frontController'); // дальше начинается магия! // // мы будем использовать Zend_Controller_Request_Simple и немного дополнительного кода // чтоб компенсировать отсутствие в еко-системе Zend Framework решения // "Zend_Controller_Request_Cli" которое сейчас находиться на стадии Предложения (англ. Proposal): // http://framework.zend.com/wiki/display/ZFPROP/Zend_Controller_Request_Cli // // Мне нравиться идея задавать параметры MVC через "/" // например "module/controller/action" // // NOTE: в соответствии с имеющейся реализацией мы не можем пропускать // параметры module/controller/action // // TODO: добавить возможность пропуска параметров "module", "action" // и давать им значения по умолчанию "default" и "index" соответственно // // давайте разделим параметры полученые из CLI // и сформируем их в обьект запроса // // TODO: думаю в будущем этот функционал должен будет перемещен в маршрутизацию (Routing) // FIXME: пока мы не будем заниматься обработкой других параметров кроме module/controller/action // $params = array_reverse(explode('/', $getopt->getOption('a'))); $module = array_pop($params); $controller = array_pop($params); $action = array_pop($params); $request = new Zend_Controller_Request_Simple ($action, $controller, $module); // зададим параметры FrontController чтоб подружить его с интерфейсом командной строки $front->setRequest($request) ->setResponse(new Zend_Controller_Response_Cli()) ->setRouter(new Custom_Controller_Router_Cli()) // наш отдельный класс для маршрутизации ->throwExceptions(true); // давайте загрузим остальные ресурсы приложения и насладимся работой! $application->bootstrap() ->run();
Я думаю для людей знакомых с Zend Framewrk — этот код предельно прост. Вы заметили, что я использовал свой класс-заглушку для маршрутизации. Это костыль без которого запустится стандартная система маршрутизации, работающая с HTTP обьектами запроса, результатом работы которой будет вызов метода getRequestUri()
и соответственно сообщение PHP Fatal error: Call to undefined method Zend_Controller_Request_Simple::getRequestUri()
. Для обхода проблемы я использую свой клас-маршрутизатора, который просто не осуществляет этот вызов.
$ mkdir -p ./library/Custom/Controller/Router $ touch ./library/Custom/Controller/Router/Cli.php
Собственно наш маршрутизатор наследует Zend_Controller_Router_Abstract
и реализует интерфейс Zend_Controller_Router_Interface
используя методы-заглушки, поскольку при работе через командную строку маршрутизация очень простая и мы ее по сути уже сделали выше.
/** * Клас маршрутизатора-заглушки * его задача ничего не делать на этапе маршрутизации (все уже сделано до нас) */ class Custom_Controller_Router_Cli extends Zend_Controller_Router_Abstract implements Zend_Controller_Router_Interface { public function route(Zend_Controller_Request_Abstract $dispatcher){} public function assemble($userParams, $name = null, $reset = false, $encode = true){} public function getFrontController(){} public function setFrontController(Zend_Controller_Front $controller){} public function setParam($name, $value){} public function setParams(array $params){} public function getParam($name){} public function getParams(){} public function clearParams($name = null){} };
Да я знаю, что решение смотрится не елегантно и в будущем компенсирую это возможно осуществив свой вклад в развитие идеи выше упомянутого предложения.
Вот теперь мы можем запускать наше приложение с командной строки. Примеры команд:
# справка $ php ./scripts/zf-cli.php $ php ./scripts/zf-cli.php --help # запуск модуля, контролера и действия по умолчанию $ php ./scripts/zf-cli.php -a default/index/index # запуск модуля "blog", контролера "users", действия "list" используя настройки среды "development" $ php ./scripts/zf-cli.php -a blog/users/list -e development
Я рекомендую использовать отдельную среду (environment
) для запуска приложения с командной строки. Такой подход позволит в отдельном разделе конфигурационного файла исключить ненужные в работе из под CLI ресурсы, осуществить более тонкую настройку приложения.
Также следует подумать о системе предоставления прав доступа к модулям/контролерам/действиям. Мой беглый взгляд на проблему позволяет увидеть решение в направлении создания отдельной ACL роли с последующим разрешением доступа к отдельным модулям/контролерам, что предназначены для запуска из командной строки. Но я думаю это целая тема отдельной статьи.
Выводы
Работа с значениями запроса и маршрутизацией из под командной строки в Zend Framework всегда с ухищрениями. Я нашел кучу разных решений, но большинство из них создана народными умельцами и могут быть рассмотрены только как нестандартные подходы к решению. У нас все есче нет официального пути запуска каркаса MVC с командной строки в полном соответствии с идеологией Zend Framework. Обратите внимание на обсуждения проблемы по ссылке в низу, для детального ознакомления и понимания сложившейся ситуации. Кажеться что многообещающий компонент Zend_Controller_Request_Cli
можеш сдвинуть решение проблемы, но есче нет единой точки зрения о интерпретации параметров CLI при маршрутизации.
Конечно все в мире open source движеться добровольцами, и я думаю, что волонтерская активность (если такая будет) приведет к решению.
Ссылки на ресурсы
Вот вам ссылки на материалы из Интернета, которые мне показалить полезными при освещении этой темы.
Using Zend Framework from the Command Line — статья созданая есче 2008 году автором по имени «Jed», и собственно единственная статья на его блоге. За несколько лет автора достали коментарии и он сам неоднократно заявлял, что за это время статья устарела в плане использования новых возможностей Zend Framework. Статья вдохновила меня написать обновленую версию его решения;
Programmer’s Reference Guide — Zend_Console_Getopt — прекрасный компонент делающий жизнь разработчика CLI приложений легче;
Zend_Controller_Request_Cli Component Proposal — многообещающие предложение для решения проблемы работы с параметрами командной строки в Zend Framework, но дальше обсуждения дело не пошло.
Zend Framework Quick Start — последняя версия инстурции для разработчика «Quick Start» показывающая эталоное решение запуска скриптов из CLI в Zend framework (без MVC);
The Mysteries Of Asynchronous Processing With PHP — Part 2: Making Zend Framework Applications CLI Accessible — самая интересная статья, в которой описано очень хорошое решение.