从命令行运行Zend Framework操作
我想运行一个Zend Framework操作来从命令行生成一些文件。 这是可能的,我需要对现有的使用ZF的Web项目做多less改变?
谢谢!
这实际上比你想象的要容易得多。 引导程序/应用程序组件和现有的configuration可以与CLI脚本一起使用,同时避免在HTTP请求中调用MVC堆栈和不必要的权重。 这是不使用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'));
然后,您可以像在MVC应用程序中那样继续使用ZF资源:
$db = $application->getBootstrap()->getResource('db'); $row = $db->fetchRow('SELECT * FROM something');
如果您希望为CLI脚本添加可configuration参数,请查看Zend_Console_Getopt
如果你发现你有一些通用的代码,你也可以在MVC应用程序中调用,那就把它包装在一个对象中,然后从MVC和命令行应用程序中调用这个对象的方法。 这是一般的良好做法。
UPDATE
如果你喜欢,你可以从https://github.com/akond/zf-cli获得所有这些代码适用于ZF 1.12。
虽然解决scheme#1是好的,有时候你想要更精细的东西。 特别是如果你期望有不止一个CLI脚本。 如果你允许我,我会提出另一个解决scheme。
首先,在你的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中为您的Web界面定义了自己的路由,那么在命令行模式下,您可能需要中和它们。
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 } }
Class 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
在这种情况下,将调用BackupController控制器中的cliAction方法。
class BackupController extends Zend_Controller_Action { function cliAction () { print "I'm here.\n"; } }
你甚至可以继续修改Application_Router_Cli类,这样就不会每次都采取“cli”动作,而是用户通过一个附加参数select的东西。
还有最后一件事。 为命令行界面定义自定义error handling程序,以便您不会在屏幕上看到任何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。 如果你偶然发现这个post,并使用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', ), ), ), ), ), ),
使用上面的configuration,你可以在你的Application模块下的IndexController.php中定义doCliAction。 从命令行运行它是蛋糕:
php index.php做cli
完成! 更平滑。
上面的akond的解决scheme是最好的轨道,但有一些微妙的,他的脚本可能可能不会在你的环境中工作。 考虑这些调整到他的答案:
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() ); } }
初始化错误可能会像上面写的那样error handling程序可能还没有实例化,除非你改变了默认configuration。
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'); } }
你也可能想从命令行中select多个参数,下面是一个基本的例子:
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
你会想要实现一个更强大的过滤/转义,但它是一个快速的构build块。 希望这可以帮助!
一个select是你可以通过对你用来调用期望的动作的URL执行wget来模糊它
你不能使用wget的-O选项来保存输出。 但是wget显然不是解决scheme。 优先使用CLI。
akond的想法很好,除了error error不是由错误控制器渲染的。
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中,注释掉echo和die声明
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
如果您的操作系统是Linux,您可以使用wget命令。 例如:
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
如果你不想保存输出