I posted a question about how to handle CLI for multiple applications and today I found the solution.
I have two applications and wanted a common cli to execute tasks from them.
- v1 -> path: apps/kapi/v1
- admin -> path: apps/kapi/admi
The solution I have uses docopt but it is not required.
Examples:
# Execute v1's MainTask::mainAction()
php cli.php v1 main main --env=local
# Execute admin's MailTask::specialAction($params)
php cli.php admin mail special param1 param2 param3 --env=local
Code as shown below:
<?php
// how to use composer with phalcon https://stackoverflow.com/a/25662855
$loader = require_once(__DIR__ . '/../vendor/autoload.php');
// namespace to module mapping
$moduleNamespaces = array(
'admin' => 'Kapi\Admin\Tasks',
'v1' => 'Kapi\V1\Tasks'
);
$doc = <<<DOC
Phalcon CLI.
Usage:
cli.php <module> <task> <action> [<params> ...] [--env=<env>]
cli.php (-h | --help)
Options:
-h --help Show this screen.
--env=<env> Set environment [default: local]
DOC;
$module = $task = $action = $env = '';
$params = array();
$docpot = new Docopt();
$args = $docpot->handle($doc);
foreach($args as $k => $v)
{
if ($k == '--env')
$env = $v;
else if (preg_match('/<(.*?)>/', $k, $match))
{
$k = array_pop($match);
$$k = $v;
}
}
// used in other places of application
define('APP_ENV', $env);
// build arguments for CLI
$arguments['module'] = $module;
$arguments['task'] = $task;
$arguments['action'] = $action;
$arguments['params'] = $params;
class Console extends \Phalcon\CLI\Console
{
public function __construct()
{
$loader = new \Phalcon\Loader();
$namespaces = require_once(__DIR__ . '/../boot/autoload_namespaces.php');
$loader->registerNamespaces($namespaces['base']);
// register the installed modules
$this->registerModules(array(
'v1' => array(
'className' => 'Kapi\V1\Module',
'path' => __DIR__ . '/../apps/kapi/v1/Module.php'
),
'admin' => array(
'className' => 'Kapi\Admin\Module',
'path' => __DIR__ . '/../apps/kapi/admin/Module.php'
),
));
$loader->register();
}
public function main()
{
$di = new \Phalcon\DI\FactoryDefault\CLI();
// registering a router
$di->set('router', function(){
$router = new \Phalcon\CLI\Router();
return $router;
});
// registering a dispatcher
$di->set('dispatcher', function () use($di) {
// obtain the standard eventsManager from the DI
$eventsManager = $di->getShared('eventsManager');
$eventsManager->attach("dispatch:beforeDispatchLoop", function($event, $dispatcher) {
$dispatcher->setActionName(\Phalcon\Text::camelize($dispatcher->getActionName()));
});
$dispatcher = new \Phalcon\CLI\Dispatcher();
// bind the EventsManager to the Dispatcher
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
$this->setDI($di);
}
}
$console = new Console();
$console->main();
$di = $console->getDI();
/** @var $dispatcher \Phalcon\CLI\Dispatcher */
$dispatcher = $di['dispatcher'];
// https://forum.phalcon.io/discussion/4573/cli-task-not-found-when-in-namespace#C15319
$dispatcher->setDefaultNamespace($moduleNamespaces[$module]);
$dispatcher->setNamespaceName($moduleNamespaces[$module]);
try {
$console->handle($arguments);
}
catch (\Phalcon\Exception $e) {
echo $e->getMessage();
}