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


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

спасибо!

10 61

10 ответов:

это на самом деле гораздо проще, чем вы думаете. Компоненты bootstrap / application и существующие конфигурации можно повторно использовать со сценариями 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 выше находится на лучшем треке, но есть некоторые тонкости, которые могут не работать в вашей среде. Рассмотрим эти хитрости к его ответу:

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

вы, вероятно, также хотите, чтобы 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, прокомментировать эхо и умереть заявление

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