php zend-framework command-line

php - Ejecución de una acción de Zend Framework desde la línea de comandos



zend-framework command-line (10)

Me gustaría ejecutar una acción de Zend Framework para generar algunos archivos, desde la línea de comandos. ¿Es esto posible y cuánto cambio necesitaría hacer en mi proyecto web existente que está usando ZF?

¡Gracias!


Acabo de ver a este ser etiquetado en mi CP. Si te tropiezas con esta publicación y estás usando ZF2, se ha hecho MUCHO más fácil. Simplemente edite las rutas de su module.config.php de la siguiente manera:

/** * 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'', ), ), ), ), ), ),

Usando la configuración anterior, definiría doCliAction en su IndexController.php debajo de su módulo de Aplicación. Ejecutarlo es pastel, desde la línea de comando:

php index.php do cli

¡Hecho! Más suave.


En realidad es mucho más fácil de lo que piensas. Los componentes bootstrap / application y sus configuraciones existentes se pueden reutilizar con scripts CLI, mientras se evita la pila MVC y el peso innecesario que se invoca en una solicitud HTTP. Esta es una ventaja de no usar wget.

Comience su script como si fuera su index.php público:

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

A continuación, puede proceder a utilizar los recursos ZF tal como lo haría en una aplicación MVC:

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

Si desea agregar argumentos configurables a su script CLI, eche un vistazo a Zend_Console_Getopt

Si encuentra que tiene un código común al que también llama en aplicaciones MVC, mire cómo lo resume en un objeto y llama a los métodos de ese objeto desde las aplicaciones MVC y de línea de comando. Esta es una buena práctica general.


He usado el comando wget

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

-O /dev/null si no quieres guardar la salida


La solución anterior de akond está en la mejor pista, pero hay algunas sutilezas que pueden hacer que su script no funcione en su entorno. Considere estos ajustes a su respuesta:

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

Es probable que el error de inicialización barf como se describió anteriormente, el controlador de errores probablemente aún no esté instanciado a menos que haya cambiado la configuración predeterminada.

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

Probablemente, también quiera importar más de un parámetro de la línea de comando, aquí hay un ejemplo básico:

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

Por último, en su controlador, la acción que invoca utiliza los parámetros que quedaron huérfanos debido a la eliminación del controlador y la acción del enrutador 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 ); }

A continuación, puede invocar su comando CLI con:

php index.php Controller Action ....

Por ejemplo, como arriba:

php index.php Controller echo database123 this,becomes,an,array

Querrá implementar un filtrado / escape más robusto, pero es un bloque de construcción rápido. ¡Espero que esto ayude!


No puede usar la opción -O de wget para guardar la salida. Pero wget claramente NO es la solución. Prefiere usar CLI en su lugar.


Puede usar PHP como lo haría normalmente desde la línea de comando. Si llama un script desde PHP y establece la acción en su script, puede ejecutar lo que desee.

Sería bastante simple en realidad. No es realmente el uso previsto, sin embargo, así es como podría funcionar si quisieras.

Por ejemplo

php script.php

Lea aquí: http://php.net/manual/en/features.commandline.php


Puede usar el comando wget si su sistema operativo es Linux. Por ejemplo:

wget http://example.com/controller/action

Ver http://linux.about.com/od/commands/l/blcmdl1_wget.htm

ACTUALIZAR:

Podrías escribir un script bash simple como este:

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

Entonces puedes hacer en PHP:

if (true === file_exists(''/home/wasdownloaded.txt'') { // to check that the }

Espero que esto ayude.


Una opción es que podría cambiarla haciendo un wget en la URL que usa para invocar la acción deseable


la idea de akond funciona muy bien, excepto que la excepción de error no es representada por el controlador de errores.

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

y en Application_Router_Cli, comente el enunciado echo y die

public function assemble($userParams, $name = null, $reset = false, $encode = true) { //echo "Not implemented/n"; }


ACTUALIZAR

Puede tener todo este código adaptado para ZF 1.12 desde https://github.com/akond/zf-cli si lo desea.

Si bien la solución n. ° 1 está bien, a veces quieres algo más elaborado. Especialmente si espera tener más de una sola secuencia de comandos CLI. Si me lo permite, propondría otra solución.

Antes que nada, tenga en su 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 ()); } }

Este método privará al control de envío del enrutador predeterminado a favor de nuestro propio enrutador Application_Router_Cli.

Por cierto, si ha definido sus propias rutas en _initRoutes para su interfaz web, probablemente quiera neutralizarlas cuando esté en el modo de línea de comandos.

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

La clase Application_Router_Cli (supongo que tiene la carga automática activada para el prefijo de la aplicación) puede verse así:

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

Ahora puede simplemente ejecutar su aplicación ejecutando

php index.php backup

En este caso, se llamará al método cliAction en el controlador BackupController.

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

Incluso puede continuar y modificar la clase Application_Router_Cli para que no se tome acción "cli" cada vez, sino algo que el usuario haya elegido a través de un parámetro adicional.

Y una última cosa Defina el controlador de error personalizado para la interfaz de línea de comandos para que no vea ningún código html en su pantalla

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

En ErrorController.php

function cliAction () { $this->_helper->viewRenderer->setNoRender (true); foreach ($this->_getParam (''error_handler'') as $error) { if ($error instanceof Exception) { print $error->getMessage () . "/n"; } } }