从命令行运行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如果你不想保存输出