Я хотел бы запустить действие Zend Framework для создания некоторых файлов из командной строки. Является ли это возможным и сколько изменений мне необходимо внести в мой существующий веб-проект, который использует ZF?
Благодаря!
На самом деле это намного проще, чем вы думаете. Компоненты bootstrap / application и ваши существующие конфигурации могут быть повторно использованы с помощью сценариев CLI, избегая стека MVC и ненужного веса, который вызывается в HTTP-запросе. Это одно из преимуществ использования wget.
Начните свой скрипт, как ваш общедоступный index.php:
<?php // Define path to application directory defined('APPLICATION_PATH') || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application')); // Define application environment defined('APPLICATION_ENV') || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production')); require_once 'Zend/Application.php'; $application = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/config.php' ); //only load resources we need for script, in this case db and mail $application->getBootstrap()->bootstrap(array('db', 'mail'));
Затем вы можете использовать ресурсы ZF так же, как и в приложении MVC:
$db = $application->getBootstrap()->getResource('db'); $row = $db->fetchRow('SELECT * FROM something');
Если вы хотите добавить настраиваемые аргументы в свой CLI-скрипт, взгляните на Zend_Console_Getopt
Если вы обнаружите, что у вас есть общий код, который вы также вызываете в приложениях MVC, посмотрите на его обертку в объекте и вызовите методы этого объекта как из MVC, так и из приложений командной строки. Это общая хорошая практика.
ОБНОВИТЬ
Хотя решение № 1 в порядке, иногда вам нужно что-то более сложное. Особенно, если вы ожидаете иметь не один сценарий CLI. Если вы позволите мне, я предлагаю другое решение.
Прежде всего, в вашем Bootstrap.php
protected function _initRouter () { if (PHP_SAPI == 'cli') { $this->bootstrap ('frontcontroller'); $front = $this->getResource('frontcontroller'); $front->setRouter (new Application_Router_Cli ()); $front->setRequest (new Zend_Controller_Request_Simple ()); } }
Этот метод лишит диспетчерский контроль от маршрутизатора по умолчанию в пользу нашего собственного маршрутизатора Application_Router_Cli.
Кстати, если вы определили свои собственные маршруты в _initRoutes для своего веб-интерфейса, вы, вероятно, захотите их нейтрализовать в режиме командной строки.
protected function _initRoutes () { $router = Zend_Controller_Front::getInstance ()->getRouter (); if ($router instanceof Zend_Controller_Router_Rewrite) { // put your web-interface routes here, so they do not interfere } }
Класс Application_Router_Cli (предположим, что вы включили автозагрузку для префикса приложения) может выглядеть так:
class Application_Router_Cli extends Zend_Controller_Router_Abstract { public function route (Zend_Controller_Request_Abstract $dispatcher) { $getopt = new Zend_Console_Getopt (array ()); $arguments = $getopt->getRemainingArgs (); if ($arguments) { $command = array_shift ($arguments); if (! preg_match ('~\W~', $command)) { $dispatcher->setControllerName ($command); $dispatcher->setActionName ('cli'); unset ($_SERVER ['argv'] [1]); return $dispatcher; } echo "Invalid command.\n", exit; } echo "No command given.\n", exit; } public function assemble ($userParams, $name = null, $reset = false, $encode = true) { echo "Not implemented\n", exit; } }
Теперь вы можете просто запустить свое приложение, выполнив
php index.php backup
В этом случае будет вызван метод cliAction в контроллере BackupController.
class BackupController extends Zend_Controller_Action { function cliAction () { print "I'm here.\n"; } }
Вы можете даже пойти дальше и изменить класс Application_Router_Cli, чтобы каждый раз не выполнялось действие «cli», а то, что пользователь выбрал с помощью дополнительного параметра.
И последнее. Определите настраиваемый обработчик ошибок для интерфейса командной строки, чтобы вы не увидели какой-либо код html на вашем экране.
В Bootstrap.php
protected function _initError () { $error = $frontcontroller->getPlugin ('Zend_Controller_Plugin_ErrorHandler'); $error->setErrorHandlerController ('index'); if (PHP_SAPI == 'cli') { $error->setErrorHandlerController ('error'); $error->setErrorHandlerAction ('cli'); } }
В ErrorController.php
function cliAction () { $this->_helper->viewRenderer->setNoRender (true); foreach ($this->_getParam ('error_handler') as $error) { if ($error instanceof Exception) { print $error->getMessage () . "\n"; } } }
Просто увидели, как этот человек помечается в моем CP. Если вы наткнулись на этот пост и используете ZF2, ему стало намного проще. Просто отредактируйте маршруты module.config.php следующим образом:
/** * Router */ 'router' => array( 'routes' => array( // .. these are your normal web routes, look further down ), ), /** * Console Routes */ 'console' => array( 'router' => array( 'routes' => array( /* Sample Route */ 'do-cli' => array( 'options' => array( 'route' => 'do cli', 'defaults' => array( 'controller' => 'Application\Controller\Index', 'action' => 'do-cli', ), ), ), ), ), ),
Используя приведенную выше конфигурацию, вы должны определить doCliAction в вашем IndexController.php в своем приложении. Запуск это торт, из командной строки:
php index.php do cli
Готово! Путь более плавный.
Решение akond выше находится на лучшем треке, но есть некоторые тонкости, которые могут его сценарий не работать в вашей среде. Рассмотрите эти настройки к его ответу:
Bootstrap.php
protected function _initRouter() { if( PHP_SAPI == 'cli' ) { $this->bootstrap( 'FrontController' ); $front = $this->getResource( 'FrontController' ); $front->setParam('disableOutputBuffering', true); $front->setRouter( new Application_Router_Cli() ); $front->setRequest( new Zend_Controller_Request_Simple() ); } }
Ошибка Init, вероятно, будет barf, как написано выше, обработчик ошибок, вероятно, еще не создан, если вы не изменили конфигурацию по умолчанию.
protected function _initError () { $this->bootstrap( 'FrontController' ); $front = $this->getResource( 'FrontController' ); $front->registerPlugin( new Zend_Controller_Plugin_ErrorHandler() ); $error = $front->getPlugin ('Zend_Controller_Plugin_ErrorHandler'); $error->setErrorHandlerController('index'); if (PHP_SAPI == 'cli') { $error->setErrorHandlerController ('error'); $error->setErrorHandlerAction ('cli'); } }
Вероятно, вы также захотите выполнить несколько команд из командной строки, вот пример:
class Application_Router_Cli extends Zend_Controller_Router_Abstract { public function route (Zend_Controller_Request_Abstract $dispatcher) { $getopt = new Zend_Console_Getopt (array ()); $arguments = $getopt->getRemainingArgs(); if ($arguments) { $command = array_shift( $arguments ); $action = array_shift( $arguments ); if(!preg_match ('~\W~', $command) ) { $dispatcher->setControllerName( $command ); $dispatcher->setActionName( $action ); $dispatcher->setParams( $arguments ); return $dispatcher; } echo "Invalid command.\n", exit; } echo "No command given.\n", exit; } public function assemble ($userParams, $name = null, $reset = false, $encode = true) { echo "Not implemented\n", exit; } }
Наконец, в вашем контроллере действие, которое вы вызываете, использует параметры, которые были потеряны путем удаления контроллера и действия с помощью маршрутизатора CLI:
public function echoAction() { // disable rendering as required $database_name = $this->getRequest()->getParam(0); $udata = array(); if( ($udata = $this->getRequest()->getParam( 1 )) ) $udata = explode( ",", $udata ); echo $database_name; var_dump( $udata ); }
Затем вы можете вызвать команду CLI с помощью:
php index.php Controller Action ....
Например, как указано выше:
php index.php Controller echo database123 this,becomes,an,array
Вы захотите реализовать более надежную фильтрацию / экранирование, но это быстрый строительный блок. Надеюсь это поможет!
Один из вариантов заключается в том, что вы можете выманить его, выполнив wget по URL-адресу, который используется для вызова желаемого действия
Вы не можете использовать опцию «o» для сохранения вывода. Но wget явно НЕ является решением. Предпочитаете вместо этого использовать CLI.
Идея akond отлично работает, за исключением исключения ошибки, которое не отображается контроллером ошибок.
public function cliAction() { $this->_helper->layout->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); foreach ($this->_getParam('error_handler') as $error) { if ($error instanceof Exception) { print "cli-error: " . $error->getMessage() . "\n"; } } }
и в Application_Router_Cli комментировать off echo and die statement
public function assemble($userParams, $name = null, $reset = false, $encode = true) { //echo "Not implemented\n"; }
Вы можете просто использовать PHP, как обычно из командной строки. Если вы вызываете скрипт из PHP и задаете действие в своем скрипте, вы можете запустить все, что захотите.
Это было бы очень просто. На самом деле это не предполагаемое использование, но так оно и могло работать, если бы вы этого хотели.
Например
php script.php
Читайте здесь: http://php.net/manual/en/features.commandline.php
Вы можете использовать команду wget, если ваша ОС – Linux. Например:
wget http://example.com/controller/action
См. http://linux.about.com/od/commands/l/blcmdl1_wget.htm
ОБНОВИТЬ:
Вы можете написать простой скрипт bash следующим образом:
if wget http://example.com/controller/action echo "Hello World!" > /home/wasdownloaded.txt else "crap, wget timed out, let's remove the file." rm /home/wasdownloaded.txt fi
Тогда вы можете сделать в PHP:
if (true === file_exists('/home/wasdownloaded.txt') { // to check that the }
Надеюсь это поможет.
Я использовал команду wget
wget http://example.com/module/controller/action -O /dev/null
-O /dev/null
если вы не хотите сохранять вывод