Я хотел бы запустить действие Zend Framework для создания некоторых файлов из командной строки. Является ли это возможным и сколько изменений мне нужно сделать для моего существующего веб-проекта, который использует ZF?
Спасибо!
Я хотел бы запустить действие Zend Framework для создания некоторых файлов из командной строки. Является ли это возможным и сколько изменений мне нужно сделать для моего существующего веб-проекта, который использует ZF?
Спасибо!
На самом деле это намного проще, чем вы думаете. Компоненты 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, так и из приложений командной строки. Это общепринятая практика.
UPDATE
Хотя решение № 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";
}
}
}
Просто увидел, что в моем 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 выше находится на лучшем треке, но есть некоторые тонкости, которые могут его 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
Вы хотите реализовать более надежную фильтрацию/экранирование, но это быстрый строительный блок. Надеюсь, это поможет!
Один из вариантов заключается в том, что вы можете выманить его, выполнив wget по URL-адресу, который используется для вызова желаемого действия.
Вы не можете использовать -O вариант wget для сохранения вывода. Но 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, как обычно из командной строки. Если вы вызываете script из PHP и устанавливаете действие в script, вы можете запускать все, что хотите.
Это было бы очень просто. На самом деле это не предполагаемое использование, но так оно и может работать, если вы хотите.
Например
PHP скрипт.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
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
}
Надеюсь, что это поможет.
Я использовал команду wget
wget http://example.com/module/controller/action -O /dev/null
-O /dev/null
, если вы не хотите сохранять вывод