簡體   English   中英

從命令行運行Zend Framework操作

[英]Running a Zend Framework action from command line

我想從命令行運行Zend Framework操作來生成一些文件。 這是可能的,我需要對使用ZF的現有Web項目進行多少更改?

謝謝!

UPDATE

如果您願意,可以從https://github.com/akond/zf-cli獲取適用於ZF 1.12的所有代碼。

雖然解決方案#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";
        }
    }
}

它實際上比你想象的要容易得多。 可以使用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和命令行應用程序中調用該對象的方法。 這是一般的良好做法。

剛看到這個在我的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的解決方案是最好的,但是有一些細微之處可能是他的腳本在你的環境中不起作用。 考慮這些調整他的答案:

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() );
    }
}

如上所述,初始化錯誤可能是barf,除非您更改了默認配置,否則錯誤處理程序可能尚未實例化。

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

您需要實現更強大的過濾/轉義,但它是一個快速構建塊。 希望這可以幫助!

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";
    }
  }
}

並在Application_Router_Cli中,注釋echo和die語句

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 

請在此處閱讀: 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如果您不想保存輸出

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM