【发布时间】:2011-01-20 11:40:32
【问题描述】:
我想从命令行运行 Zend Framework 操作来生成一些文件。这可能吗?我需要对使用 ZF 的现有 Web 项目进行多少更改?
谢谢!
【问题讨论】:
标签: php zend-framework command-line
我想从命令行运行 Zend Framework 操作来生成一些文件。这可能吗?我需要对使用 ZF 的现有 Web 项目进行多少更改?
谢谢!
【问题讨论】:
标签: php zend-framework command-line
刚刚看到这个在我的 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',
),
),
),
),
),
),
使用上面的配置,您可以在 Application 模块下的 IndexController.php 中定义 doCliAction。从命令行运行它很简单:
php index.php做cli
完成! 更流畅。
【讨论】:
akond idea 效果很好,除了错误控制器没有呈现错误异常。
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 and die 语句
public function assemble($userParams, $name = null, $reset = false, $encode = true) {
//echo "Not implemented\n";
}
【讨论】:
更新
虽然解决方案 #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_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";
}
}
}
【讨论】:
/library 中创建一个Application/router/Cli.php 对吗?
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;
}
}
最后,在您的控制器中,您调用的操作使用因删除控制器和 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
您会想要实现更强大的过滤/转义,但是,它是一个快速构建块。希望这会有所帮助!
【讨论】:
$front->setParam('disableOutputBuffering', true);
我用过 wget 命令
wget http://example.com/module/controller/action -O /dev/null
-O /dev/null如果你不想保存输出
【讨论】:
您不能使用 wget 的 -O 选项来保存输出。但 wget 显然不是解决方案。更喜欢使用 CLI。
【讨论】:
如果您的操作系统是 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
}
希望这会有所帮助。
【讨论】:
实际上比您想象的要容易得多。引导程序/应用程序组件和您现有的配置可以通过 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 脚本添加可配置参数,请查看 Zend_Console_Getopt
如果您发现您有在 MVC 应用程序中也调用的公共代码,请查看将其包装在一个对象中并从 MVC 和命令行应用程序调用该对象的方法。这是一般的良好做法。
【讨论】:
您可以像往常一样从命令行使用 PHP。如果您从 PHP 调用脚本并在脚本中设置操作,那么您可以运行任何您想要的。
真的很简单。 它并不是真正的预期用途,但是如果您愿意,它可以这样工作。
例如
php script.php
【讨论】:
一种选择是您可以通过对用于调用所需操作的 URL 执行 wget 来伪造它
【讨论】: