Запуск действия Zend Framework из командной строки

Я хотел бы запустить действие Zend Framework для создания некоторых файлов из командной строки. Возможно ли это и сколько изменений мне нужно внести в мой существующий веб-проект, который использует ZF?

спасибо!

10 ответов


это на самом деле гораздо проще, чем вы думаете. Компоненты начальной загрузки / приложения и существующие конфигурации можно повторно использовать со сценариями CLI, избегая при этом стека MVC и ненужного веса, который вызывается в HTTP-запросе. Это одно из преимуществ не использовать wget.

Запустите свой скрипт, как ваш публичный индекс.на 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'));

затем вы можете использовать ресурсы ZF так же, как и в приложении MVC:

$db = $application->getBootstrap()->getResource('db');

$row = $db->fetchRow('SELECT * FROM something');

Если вы чтобы добавить настраиваемые аргументы в сценарий CLI, взгляните на Zend_Console_Getopt

Если вы обнаружите, что у вас есть общий код, который вы также вызываете в приложениях MVC, посмотрите на его обертывание в объекте и вызов методов этого объекта из приложений MVC и командной строки. Это вообще хорошая практика.


обновление

вы можете иметь весь этот код, адаптированный для ZF 1.12 из https://github.com/akond/zf-cli Если хотите.

в то время как решение № 1 в порядке, иногда вы хотите что-то более сложное. Особенно, если вы ожидаете иметь более одного сценария CLI. Если позволите, я предложу другое решение.

во-первых, в ушко.в 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 для вашего веб-интерфейса, вы, вероятно, захотите нейтрализовать их в режиме командной строки.

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

в этом случае будет вызван метод cliAction в контроллере BackupController.

class BackupController extends Zend_Controller_Action
{
    function cliAction ()
    {
        print "I'm here.\n";
    }
}

вы даже можете пойти вперед и изменить класс Application_Router_Cli, чтобы не "cli" действие принималось каждый раз, но что-то, что пользователь выбрал через дополнительный параметр.

и последнее. Определите пользовательский обработчик ошибок для интерфейса командной строки, чтобы вы не видели html-код на экране

In Загрузчик.в 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. Если вы наткнулись на этот пост и используете ZF2, это стало намного проще. Просто отредактируйте свой модуль.конфиг.маршруты 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',
                    ),
                ),
            ),
        ),    
    ),
),

используя конфигурацию выше, вы бы определили doCliAction в своем IndexController.php под вашим модулем приложения. Это не торт, из командной строки:

индекс php.php do cli

готово! Способ гладкой.


решение akond выше находится на лучшем пути, но есть некоторые тонкости, которые могут не работать в вашей среде. Рассмотрим эти хитрости к его ответу:

ушко.в 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() );
    }
}

ошибка Init, вероятно, будет рвать, как написано выше, обработчик ошибок, вероятно, еще не создан, если вы не изменили конфигурацию по умолчанию.

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

вы, вероятно, также хотите munge более одного параметра из командной строки, Вот простой пример:

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

вы захотите реализовать более надежную фильтрацию / экранирование, но это быстрый строительный блок. Надеюсь, это поможет!


один из вариантов заключается в том, что вы можете подделать его, выполнив wget по URL-адресу, который вы используете для вызова желаемого действия


вы не можете использовать опцию-O wget для сохранения вывода. Но wget явно не является решением. Предпочитайте использовать CLI вместо этого.


идея 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";
}

вы можете просто использовать PHP, как обычно из командной строки. Если вы вызываете скрипт из PHP и либо устанавливаете действие в своем скрипте, вы можете запустить все, что захотите.

Это было бы довольно просто. Его не совсем предполагаемое использование, однако это то, как он может работать, если вы хотите.

 php script.php 

читайте здесь:http://php.net/manual/en/features.commandline.php


вы можете использовать команду wget, если ваша ОС Linux. Например:

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 Если вы не хотите, чтобы сохранить вывод