Running a Zend Framework Action from Command Line

Running a Zend Framework action from command line

It's actually much easier than you might think. The bootstrap/application components and your existing configs can be reused with CLI scripts, while avoiding the MVC stack and unnecessary weight that is invoked in a HTTP request. This is one advantage to not using wget.

Start your script as your would your 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'));

You can then proceed to use ZF resources just as you would in an MVC application:

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

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

If you wish to add configurable arguments to your CLI script, take a look at Zend_Console_Getopt

If you find that you have common code that you also call in MVC applications, look at wrapping it up in an object and calling that object's methods from both the MVC and the command line applications. This is general good practice.

How do you run an action in a controller using php cli?

You must to implement another entry point (e.g. cli.php). Below is main veersion of this file:

    <?php
// INI sets
ini_set('memory_limit', '1G');

// should be removed starting from PHP version >= 5.3.0
defined('__DIR__') || define('__DIR__', dirname(__FILE__));

// initialize the application path, library and autoloading
defined('APPLICATION_PATH') ||
define('APPLICATION_PATH', realpath(__DIR__ . '/../application'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
realpath(APPLICATION_PATH . '/../library/Janrain'),
realpath(APPLICATION_PATH . '/../application/modules/default/models'),
get_include_path(),
)));

// Set $_SERVER params
$_SERVER['DOCUMENT_ROOT'] = __DIR__;
$_SERVER['REMOTE_ADDR'] = '';
$_SERVER['HTTP_USER_AGENT'] = 'robot dusya';
$_SERVER['REQUEST_URI'] = '/en/';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';

require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();

// we need this custom namespace to load our custom class
$loader->registerNamespace('Nanocoding_');

// define application options and read params from CLI
$getopt = new Zend_Console_Getopt(array(
'action|a=s' => 'action to perform in format of "controller/action/param1/value1/param2/value2..."',
'env|e-s' => 'defines application environment (defaults to "production")',
'help|h' => 'displays usage information',
));

try {
$getopt->parse();
} catch (Zend_Console_Getopt_Exception $e) {
// Bad options passed: report usage
echo $e->getUsageMessage();
return false;
}

// show help message in case it was requested or params were incorrect (module, controller and action)
if ($getopt->getOption('h') || !$getopt->getOption('a')) {
echo $getopt->getUsageMessage();
return true;
}

// initialize values based on presence or absence of CLI options
$env = $getopt->getOption('e');
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (null === $env) ? 'production' : $env);

// initialize Zend_Application
$application = new Zend_Application (
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);

// bootstrap and retrive the frontController resource
$front = $application->getBootstrap()
->bootstrap('frontController')
->getResource('frontController');

// Get module list
$moduleList = array();
$modulePath = APPLICATION_PATH.'/modules/';
$dirList = scandir($modulePath);
foreach ($dirList as $dir) {
if (!is_dir($modulePath . $dir)) continue;
if ($dir[0] == '.') continue;
$moduleList[] = $dir;
}

// I like the idea to define request params separated by slash "/"
// for ex. "[module]/controller/action/param1/value1/param2/value2..."
$params = explode('/', $getopt->getOption('a'));
$requestParams = array();
foreach ($params as $i => $param) {
// Set module
if (!isset($requestParams['module'])) {
if (in_array($param, $moduleList))
$requestParams['module'] = $param;
else {
$requestParams['module'] = 'default';
$requestParams['controller'] = $param;
}
}
// Set controller
elseif (!isset($requestParams['controller']))
$requestParams['controller'] = $param;
// Set action
elseif (!isset($requestParams['action']))
$requestParams['action'] = $param;
// Set param
else {
if (isset($params[$i+1]))
$requestParams[$param] = $params[$i+1];
else
$requestParams[$param] = '';
$i++;
}
}
$request = new Zend_Controller_Request_Simple(
$requestParams['action'], $requestParams['controller'], $requestParams['module'], $requestParams
);

// set front controller options to make everything operational from CLI
$front->setRequest($request)
->setResponse(new Zend_Controller_Response_Cli())
->setRouter(new Nanocoding_Zend_Controller_Router_Cli())
->throwExceptions(true);

// lets bootstrap our application and enjoy!
$application->bootstrap()
->run();

How to run a script which uses ZendFramework library from CLI

this post has some the info you are looking for: Running a Zend Framework action from command line


Below you will find complete functional code that I wrote and use for cron jobs within my apps...

Need to do the following:

  1. pull required files in you cli file
  2. initialize the application and bootstrap resources. Here you can capture cli params and setup request object so it is dispatched properly.
  3. set controller directory
  4. run the application

Here is documentation on Zend_Console_Getopt that will help you understand how to work with cli params.

code for cli.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', 'development');

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/libraries'),
get_include_path(),
)));

// initialize application
require_once 'My/Application/Cron.php';
$application = new My_Application_Cron(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
$application->bootstrap();

//
Zend_Controller_Front::getInstance()->setControllerDirectory(APPLICATION_PATH . '/../scripts/controllers');

//
$application->run();

My_Application_Cron class code:

<?php

// because we are extending core application file we have to explicitly require it
// the autoloading occurs in the bootstrap which is part of this class
require_once 'Zend/Application.php';

class My_Application_Cron extends Zend_Application
{

protected $_cliRequest = null;

protected function _bootstrapCliRequest()
{
$this->_isCliBootstapped = true;

try {
$opts = array(
'help|h' => 'Displays usage information.',
'action|a=s' => 'Action to perform in format of module.controller.action',
'params|p=p' => 'URL-encoded parameter list',
//'verbose|v' => 'Verbose messages will be dumped to the default output.',
);
$opts = new Zend_Console_Getopt($opts);
$opts->setOption('ignoreCase', true)
->parse();

} catch (Zend_Console_Getopt_Exception $e) {
exit($e->getMessage() . "\n\n" . $e->getUsageMessage());
}

// See if help needed
if (isset($opts->h)) {
$prog = $_SERVER['argv'][0];
$msg = PHP_EOL
. $opts->getUsageMessage()
. PHP_EOL . PHP_EOL
. 'Examples:' . PHP_EOL
. "php $prog -a index.index'" . PHP_EOL
. "php $prog -a index.index -p 'fname=John&lname=Smith'" . PHP_EOL
. "php $prog -a index.index -p 'name=John+Smith'" . PHP_EOL
. "php $prog -a index.index -p 'name=John%20Smith'" . PHP_EOL
. PHP_EOL;

echo $msg;
exit;
}

// See if controller/action are set
if (isset($opts->a)) {
// Prepare necessary variables
$params = array();
$reqRoute = array_reverse(explode('.', $opts->a));
@list($action, $controller, $module) = $reqRoute;

// check if request parameters were sent
if ($opts->p) {
parse_str($opts->p, $params);
}

//
$this->_cliRequest = new Zend_Controller_Request_Simple($action, $controller, $module);
$this->_cliRequest->setParams($params);
}
}

public function bootstrap($resource = null)
{
$this->_bootstrapCliRequest();

return parent::bootstrap($resource);
}

public function run()
{
// make sure bootstrapCliRequest was executed prior to running the application
if (!($this->_cliRequest instanceof Zend_Controller_Request_Simple)) {
throw new Exception('application required "bootstrapCliRequest"');
}

// set front controller to support CLI
$this->getBootstrap()->getResource('frontcontroller')
->setRequest($this->_cliRequest)
->setResponse(new Zend_Controller_Response_Cli())
->setRouter(new Custom_Controller_Router_Cli())
->throwExceptions(true);

// run the application
parent::run();
}

}

To lean how to run the cli scipt simply type command below in terminal:

#> php /path/to/cli.php -h

Hopefully this will help you and others!

How to execute Zend Framework 3 action with zf-console?

The zend-mvc-console module does seem to be on the edge of deprecation. Just like you I was trying to implement zfcampus/zf-console. Since the mvc-console module seems to be (almost) deprecated, I suggest you use something different than (mvc) controllers for your console work. I used a class that can handle the call (in a way zf-console expects).

This is a dummy example I was working on for my project;

This is script that is called on the command line:


use Zend\Console\Console;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\Glob;
use ZF\Console\Application;
use ZF\Console\Dispatcher;

require_once __DIR__ . '/vendor/autoload.php'; // Composer autoloader

$configuration = [];
foreach (Glob::glob('config/{{*}}{{,*.local}}.php', Glob::GLOB_BRACE) as $file) {
$configuration = ArrayUtils::merge($configuration, include $file);
}

// Prepare the service manager
$smConfig = isset($config['service_manager']) ? $configuration['service_manager'] : [];
$smConfig = new \Zend\Mvc\Service\ServiceManagerConfig($smConfig);

$serviceManager = new ServiceManager();
$smConfig->configureServiceManager($serviceManager);
$serviceManager->setService('ApplicationConfig', $configuration);

// Load modules
$serviceManager->get('ModuleManager')->loadModules();

$routes = [
[
'name' => 'dumb',
'route' => '[--foo=]',
'description' => 'Some really cool feature',
'short_description' => 'Cool feature',
'options_descriptions' => [
'foo' => 'Lorem Ipsum',
],
'defaults' => [
'foo' => 'bar',
],
'handler' => function($route, $console) use ($serviceManager) {
$handler = new \Application\Command\DumbCommand();
return $handler($route, $console);
}
],
];

$config = $serviceManager->get('config');
$application = new Application(
$config['app'],
$config['version'],
$routes,
Console::getInstance(),
new Dispatcher()
);

$exit = $application->run();
exit($exit);

The handler function can use the service manager to inject any dependencies to the command handler:

'handler' => function($route, $console) use ($serviceManager) {
/** @var \Doctrine\ORM\EntityManager $entityManager */
$entityManager = $serviceManager->get(\Doctrine\ORM\EntityManager::class);
/** @var mixed $repository */
$contactRepository = $entityManager->getRepository(\Application\Entity\Contact::class);
$handler = new \Application\Command\DumbCommand($contactRepository);
return $handler($route, $console);
}

The command class is placed in a Command folder, it looks like:

<?php

namespace Application\Command;

use Application\Entity\Contact;
use Application\Repository\ContactRepository;
use Zend\Console\Adapter\AdapterInterface;
use ZF\Console\Route;

class DumbCommand
{
/** @var ContactRepository */
private $contactRepository;

public function __construct($contactRepository)
{
$this->contactRepository = $contactRepository;
}

/**
* @param Route $route
* @param AdapterInterface $console
* @throws \Doctrine\ORM\ORMException
*/
public function __invoke(Route $route, AdapterInterface $console)
{
$console->writeLine('Bob was here');
foreach ($this->contactRepository->findAll() as $item) {
/** @var Contact $item */
$console->writeLine($item->getFirstName() . ' was here');
}
}
}

(

Running a Zend_Application from the command line?

here's one way: http://webfractor.wordpress.com/2008/08/14/using-zend-framework-from-the-command-line/

if there is actually a web server in the mix, you could also of course trigger w/wget or lynx... wget --quiet http://server/app/doTheThing

PHP Command Line running, zend framework set up problem

I've been a ZF developer for several years, but was working on a pre- 1.5 version up until very recently (not by choice) I found it easiest to build a local version on my machine via ZendServer CE, then once all was running and stable, port it over to my dev server. Because I have full root permissions locally, I didn't run into any issues of naming/permissions as I walked through the initial tutorial of new features and initial setup.

Also, don't miss Akrabat's tutorial on getting started the ZF. It's very well written and in some cases easier to understand than the quickstart: http://akrabat.com/wp-content/uploads/Getting-Started-with-Zend-Framework.pdf

Runnig Zend Framework 2 action from console not working

Virtual host is not in stage when you run your app from console, because its not an HTTP request. It's a CLI request.

Define your APPLICATION_ENV variable in your ~/.bashrc file something like this:

export APPLICATION_ENV="development"

UPDATE: Don't forget to reload your profile file after editing:

source ~/.bashrc

Also, some systems (like ubuntu) uses different php.ini file for CLI. For example, on my personal server i have two php.ini files like follows:

/etc/php5/fpm/php.ini 
/etc/php5/cli/php.ini // This is CLI

The last thing is; write your action name in routing configuration dash-separated notCamelcased:

'action' => 'generateAll'  // WRONG
'action' => 'generate-all' // CORRECT

How can I create a Zend Framework controller/action url outside of controller?

Instead of sub-classing from Zend_Controller_Router_Abstract in Application_Router_Cli (as instructed in that tutorial), subclass from Zend_Controller_Router_Rewrite. This should give you the assemble() function and allow you to use the URL Helper as you would normally use it in a web context.

Zend Framework problem creating actions through command line

Did you create your project with the commandline tool as well? If not this is likeley the problem as using the tool requires an up-to-date .zfproject.xml file in the projects directory.

// example project sturcture

project-folder/
.zfproject.xml
application/
library/
public/


Related Topics



Leave a reply



Submit