我想运行一个Zend框架的动作来生成一些文件,从命令行操作。这是否可能?如果是,我需要对我的现有Web项目进行多少更改才能使用ZF?
谢谢!
我想运行一个Zend框架的动作来生成一些文件,从命令行操作。这是否可能?如果是,我需要对我的现有Web项目进行多少更改才能使用ZF?
谢谢!
更新
虽然解决方案#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中为你的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
}
}
假设你已经开启了Application前缀的自动加载,那么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" 操作,而是使用用户通过额外参数选择的操作。
最后一件事。为命令行界面定义自定义错误处理程序,这样你就不会在屏幕上看到任何 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";
}
}
}
其实比您想象中的要简单得多。使用CLI脚本可以重复使用bootstrap/application组件和现有的配置,同时避免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'));
你可以像在MVC应用程序中一样使用ZF资源:
$db = $application->getBootstrap()->getResource('db');
$row = $db->fetchRow('SELECT * FROM something');
如果你想要在CLI脚本中添加可配置参数,请查看Zend_Console_Getopt。
如果你发现有些常用代码同时在MVC应用程序中也被调用,那么可以将其封装成一个对象,并从MVC和命令行应用程序中调用该对象的方法。这是一般的良好实践。
我在我的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',
),
),
),
),
),
),
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() );
}
}
初始化错误可能会像上面所述一样抛出,错误处理程序可能尚未实例化,除非您已更改默认配置。
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;
}
}
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 );
}
php index.php Controller Action ....
php index.php Controller echo database123 this,becomes,an,array
你需要实现更加强大的过滤/转义,但这是一个快速搭建的基础模块。希望这可以帮助你!
$front->setParam('disableOutputBuffering', true);
- jamesakond的想法很好,但错误异常没有被错误控制器呈现。
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";
}
}
}
public function assemble($userParams, $name = null, $reset = false, $encode = true) {
//echo "Not implemented\n";
}
一种选择是通过在调用所需操作的URL上执行wget来模拟它。
你不能使用wget的-O选项来保存输出。但是wget显然不是解决方案。最好使用CLI。
您可以像平常一样从命令行中使用PHP。如果您从PHP调用脚本并在脚本中设置操作,那么您可以运行任何您想要的内容。
这其实非常简单。虽然这不是预期的使用方式,但如果您想要这样做,它就可以工作。
例如:
php script.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
如果你不想保存输出
/library
中创建一个Application/router/Cli.php
吗? - beingalex