代码之家  ›  专栏  ›  技术社区  ›  Ariod

从命令行运行Zend框架操作

  •  61
  • Ariod  · 技术社区  · 15 年前

    我想运行Zend框架操作从命令行生成一些文件。这可能吗?我需要对使用ZF的现有Web项目做多少更改?

    谢谢!

    10 回复  |  直到 12 年前
        1
  •  63
  •   David Snabel-Caunt    15 年前

    实际上比你想象的要容易得多。引导程序/应用程序组件和现有配置可以与CLI脚本一起重用,同时避免在HTTP请求中调用MVC堆栈和不必要的权重。这是不使用wget的一个优点。

    启动脚本就像启动public 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和命令行应用程序调用该对象的方法。这是一般的良好做法。

        2
  •  64
  •   akond    12 年前

    更新

    您可以将所有这些代码改编为ZF 1.12,从 https://github.com/akond/zf-cli 如果你喜欢的话。

    虽然解决方案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 ());
        }
    }
    

    这种方法将剥夺默认路由器的调度控制,而有利于我们自己的路由器应用程序_router_cli。

    顺便说一句,如果您已经在Web界面的initropes中定义了自己的路由,那么在命令行模式下,您可能希望中和它们。

    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(我假设您已经为application prefix打开了autoload)可能如下所示:

    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";
            }
        }
    }
    
        3
  •  7
  •   Saeven    12 年前

    刚刚在我的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',
                        ),
                    ),
                ),
            ),    
        ),
    ),
    

    使用上面的配置,您将在应用程序模块下的indexcontroller.php中定义docliaction。从命令行运行它是cake:

    php index.php do cli

    完成! 方法平滑。

        4
  •  6
  •   Saeven    13 年前

    Akond上面的解决方案是最好的,但也有一些微妙之处,可能他的脚本在您的环境中不起作用。考虑这些对他的答案的调整:

    引导程序

    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-error可能会像上面写的那样死机,除非您更改了默认配置,否则错误处理程序可能还没有实例化。

    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
    

    您将希望实现更健壮的过滤/转义,但这是一个快速构建块。希望这有帮助!

        5
  •  0
  •   marsbomber    15 年前

    一种选择是,您可以通过对用于调用所需操作的URL执行wget来篡改它。

        6
  •  0
  •   antoineg    14 年前

    不能使用wget的-o选项保存输出。但wget显然不是解决方案。更喜欢使用CLI。

        7
  •  0
  •   james tan    12 年前

    除了错误控制器没有呈现错误异常之外,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";
        }
      }
    }
    

    在应用程序路由器CLI中,对echo和die语句进行注释

    public function assemble($userParams, $name = null, $reset = false, $encode = true) {
    //echo "Not implemented\n";
    }
    
        8
  •  -1
  •   Layke    15 年前

    您可以像通常在命令行中那样使用PHP。如果您从PHP调用一个脚本,并在脚本中设置操作,那么您可以运行任何您想要的操作。

    真的很简单。 它并不是真正的预期用途,但是如果你想这样做的话,它是如何工作的。

    例如

     php script.php 
    

    在这里阅读: http://php.net/manual/en/features.commandline.php

        9
  •  -1
  •   Richard Knop    15 年前

    如果您的操作系统是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 
    }
    

    希望这有帮助。

        10
  •  -2
  •   hhs    13 年前

    我使用了wget命令

    wget http://example.com/module/controller/action -O /dev/null

    -O /dev/null 如果不想保存输出