Запуск действия Zend Framework из командной строки
Я хотел бы запустить действие Zend Framework для создания некоторых файлов из командной строки. Является ли это возможным и сколько изменений мне нужно сделать для моего существующего веб-проекта, который использует ZF?
Спасибо!
Ответы
Ответ 1
На самом деле это намного проще, чем вы думаете. Компоненты bootstrap/application и ваши существующие конфигурации могут быть повторно использованы с помощью сценариев CLI, избегая стека MVC и ненужного веса, который вызывается в HTTP-запросе. Это одно из преимуществ использования wget.
Начните свой script, как ваш общедоступный 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 script, посмотрите Zend_Console_Getopt
Если вы обнаружите, что у вас есть общий код, который вы также вызываете в приложениях MVC, посмотрите на его обертку в объекте и вызовите эти методы объектов как из MVC, так и из приложений командной строки. Это общепринятая практика.
Ответ 2
UPDATE
Вы можете использовать весь этот код для ZF 1.12 от https://github.com/akond/zf-cli, если хотите.
Хотя решение № 1 в порядке, иногда вам нужно что-то более сложное.
Особенно, если вы ожидаете иметь не один CLI script.
Если вы позволите мне, я бы предложил другое решение.
Прежде всего, в вашем 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";
}
}
}
Ответ 3
Просто увидел, что в моем 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
Готово!
Путь более плавный.
Ответ 4
Решение akond выше находится на лучшем треке, но есть некоторые тонкости, которые могут его script не работать в вашей среде. Подумайте об этих настройках его ответа:
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
Вы хотите реализовать более надежную фильтрацию/экранирование, но это быстрый строительный блок. Надеюсь, это поможет!
Ответ 5
Один из вариантов заключается в том, что вы можете выманить его, выполнив wget по URL-адресу, который используется для вызова желаемого действия.
Ответ 6
Вы не можете использовать -O вариант wget для сохранения вывода. Но wget явно НЕ является решением. Предпочитаете использовать CLI вместо этого.
Ответ 7
Идея 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";
}
Ответ 8
Вы можете просто использовать PHP, как обычно из командной строки. Если вы вызываете script из PHP и устанавливаете действие в script, вы можете запускать все, что хотите.
Это было бы очень просто.
На самом деле это не предполагаемое использование, но так оно и может работать, если вы хотите.
Например
PHP скрипт.php
Читайте здесь: http://php.net/manual/en/features.commandline.php
Ответ 9
Вы можете использовать команду wget, если ваша ОС - Linux. Например:
wget http://example.com/controller/action
См. http://linux.about.com/od/commands/l/blcmdl1_wget.htm
UPDATE:
Вы можете написать простой bash script следующим образом:
if wget http://example.com/controller/action
echo "Hello World!" > /home/wasdownloaded.txt
else
"crap, wget timed out, let remove the file."
rm /home/wasdownloaded.txt
fi
Тогда вы можете сделать в PHP:
if (true === file_exists('/home/wasdownloaded.txt') {
// to check that the
}
Надеюсь, что это поможет.
Ответ 10
Я использовал команду wget
wget http://example.com/module/controller/action -O /dev/null
-O /dev/null
, если вы не хотите сохранять вывод