Files
DomFramework/cli.php
2015-09-17 13:20:58 +00:00

321 lines
10 KiB
PHP

<?php
/** DomFramework
@package domframework
@author Dominique Fournier <dominique@fournier38.fr> */
/** Allow to interract with controllers and models from the CLI */
class cli
{
/** Run in CLI mode with parameters
Example of cli code :
#!/usr/bin/php5
<?php
require ("domframework/cli.php");
$cli = new cli;
$cli->run(); */
private $EXPERT = false;
public function __construct ()
{
// Catch the trigger_errors and display them politely
set_error_handler(array(&$this, "cliErrorHandler"));
}
/** The error handler for CLI : display error in STDERR */
public function cliErrorHandler ($errno, $errstr, $errfile, $errline)
{
if (!(error_reporting() & $errno))
{
// This error code is not included in error_reporting
return;
}
switch($errno)
{
case E_ERROR: $severity = "ERROR"; break;
case E_WARNING: $severity = "WARNING"; break;
case E_PARSE: $severity = "PARSE"; break;
case E_NOTICE: $severity = "NOTICE"; break;
case E_CORE_ERROR: $severity = "CORE_ERROR"; break;
case E_CORE_WARNING: $severity = "CORE_WARNING"; break;
case E_COMPILE_ERROR: $severity = "COMPILE_ERROR"; break;
case E_COMPILE_WARNING: $severity = "COMPILE_WARNING"; break;
case E_USER_ERROR: $severity = "USER_ERROR"; break;
case E_USER_WARNING: $severity = "USER_WARNING"; break;
case E_USER_NOTICE: $severity = "USER_NOTICE"; break;
case E_STRICT: $severity = "STRICT"; break;
case E_RECOVERABLE_ERROR: $severity = "RECOVERABLE_ERROR"; break;
case E_DEPRECATED: $severity = "DEPRECATED"; break;
case E_USER_DEPRECATED: $severity = "USER_DEPRECATED"; break;
}
file_put_contents ("php://stderr", sprintf ("%-17s", $severity)." ".
"$errstr [".basename ($errfile) .
":$errline]\n");
if ($this->EXPERT)
{
$e = new Exception;
file_put_contents ("php://stderr",
print_r ($e->getTraceAsString(), TRUE)."\n");
}
}
public function run ()
{
global $argv;
$launcher = $argv[0];
chdir (dirname ($argv[0])."/..");
array_shift ($argv);
if (isset ($argv[0]) && $argv[0] === "-h")
{
echo "Execute in CLI a controller or a model (in expert mode)\n";
echo " $launcher -h : display this help\n";
echo " $launcher -list : display controllers\n";
echo " $launcher -expert -list : display controllers and models\n";
echo " $launcher -listmethods <class> : \n";
echo " display the methods available the controller class\n";
echo " $launcher -expert -listmethods <class> :\n";
echo " display the methods available the model or controller class".
"\n";
echo " $launcher -listmethodsdetails <class> : \n";
echo " display the methods available the controller class\n";
echo " $launcher -expert -listmethodsdetails <class> :\n";
echo " display the methods available the model or controller class".
"\n";
echo " $launcher <class> <method> [args]\n";
echo " execute the method with the provided args\n";
echo " $launcher -expert <class> <method> [args]\n";
echo " execute the method with the provided args\n";
echo "You can replace ONE arg by a dash (-) to read from stdin\n";
echo "Arrays must be coded like key1=val1&key2=val2&key3=val3...\n";
exit;
}
$this->EXPERT = FALSE;
if (isset ($argv[0]) && $argv[0] === "-expert")
{
$this->EXPERT = TRUE;
array_shift ($argv);
}
// List the controllers and the models if the expert mode is activated
$files = glob ("controllers/*.php");
if ($this->EXPERT)
$files = array_merge ($files, glob ("models/*.php"));
if (count ($files) === 0 && $this->EXPERT === FALSE)
die ("No controllers available in ".getcwd()."\n");
if (count ($files) === 0 && $this->EXPERT === TRUE)
die ("No controllers/models available in ".getcwd()."\n");
foreach ($files as $file)
{
if (strpos ($file, "_"))
$classes[$file] = substr (strstr ($file, "_"), 1, -4);
else
$classes[$file] = str_replace ("/", "\\", substr ($file, 0, -4));
}
if (isset ($argv[0]) && $argv[0] === "-listonly")
{
// Lists the classes available in controllers and models if expert mode
// Don't do any presentation to be parseable (by bash completion by example)
echo implode ("\n", $classes)."\n";
exit;
}
if (isset ($argv[0]) && $argv[0] === "-list")
{
// Lists the classes available in controllers and models if expert mode
echo "List of classes available :\n";
echo " ".implode ("\n ", $classes)."\n";
echo "Usage : ".$launcher;
if ($this->EXPERT) echo " -expert";
echo " -listmethods <class>\n";
exit;
}
if (isset ($argv[0]) && $argv[0] === "-listmethods" ||
isset ($argv[0]) && $argv[0] === "-listmethodsdetails" ||
isset ($argv[0]) && $argv[0] === "-listmethodsonly")
{
// Lists the methods of a class
if (!isset ($argv[1]))
die ("Missing parameter 'class'\n");
$class = $argv[1];
if (!in_array ($class, $classes))
die ("Unknown class '$class'\n");
$classesNames = array_keys ($classes, $class);
$file = reset ($classesNames);
require_once ($file);
$refclass = new ReflectionClass ($class);
// Look at constructor parameters
// PARAMETERS MUST NOT BE OPTIONNAL
$constParams = "";
try
{
$r = new ReflectionMethod ($class, "__construct");
$params = $r->getParameters();
foreach ($params as $param)
{
$constParams .= " ";
$constParams .= " <";
$constParams .= $param->name;
$constParams .= ">";
}
}
catch (Exception $e)
{
// No constructor
}
// Look at methods
$methods = $refclass->getMethods();
if ($argv[0] !== "-listmethodsonly")
echo "List of methods available in the class '$class' :\n";
foreach ($methods as $key=>$method)
{
if ($method->name === "__construct")
continue;
if ($key > 0 && $argv[0] !== "-listmethodsonly")
echo "\n";
if ($argv[0] !== "-listmethodsonly")
echo " ";
echo $method->name.$constParams;
if ($argv[0] !== "-listmethodsonly")
{
$r = new ReflectionMethod ($class, $method->name);
$params = $r->getParameters();
foreach ($params as $param)
{
echo " ";
if ($param->isOptional())
echo "[";
else
echo " <";
echo $param->name;
if ($param->isOptional())
echo "]";
else
echo ">";
}
if ($argv[0] === "-listmethodsdetails")
{
echo "\n";
echo trim (substr ($method->getDocComment(), 3, -2));
}
}
echo "\n";
}
exit;
}
// Execution of the class->method
if (!isset ($argv[0]))
die ("No class to execute provided\n");
$class = $argv[0];
if (!in_array ($class, $classes))
die ("Unknown class '$class'\n");
array_shift ($argv);
$classesNames = array_keys ($classes, $class);
$file = reset ($classesNames);
require_once ($file);
if (!isset ($argv[0]))
die ("No method for class '$class' to execute\n");
$method = $argv[0];
array_shift ($argv);
$refclass = new ReflectionClass ($class);
$methods = $refclass->getMethods();
$found = FALSE;
foreach ($methods as $meth)
{
if ($meth->name === $method)
{
$found = TRUE;
break;
}
}
if ($found === FALSE)
die ("Method '$method' not available in class '$class'\n");
$min = 0; $max = 0;
$paramsConst = array ();
try
{
$r = new ReflectionMethod ($class, "__construct");
$paramsConst = $r->getParameters();
$min = $max = count ($paramsConst);
}
catch (Exception $e)
{
// No constructor available in class
}
$r = new ReflectionMethod ($class, $method);
$params = $r->getParameters();
foreach ($params as $param)
{
if (!$param->isOptional())
$min++;
$max++;
}
unset ($r);
if (count ($argv) < $min)
die ("Not enough parameters provided to method\n");
if (in_array ("-", $argv))
{
$tab = array_keys ($argv, "-");
$keyStdIn = reset ($tab);
$dataStdIn = file_get_contents ("php://stdin");
$argv[$keyStdIn] = $dataStdIn;
}
// Convert "toto=ror&ypyp=oo" arg to array("toto"=>"ror","ypyp"=>"oo")
// (Array management in CLI)
foreach ($argv as $key=>$arg)
{
// Don't modify the stdin
if (isset ($keyStdIn) && $key === $keyStdIn)
continue;
$pairs = explode('&', $arg);
foreach($pairs as $pair) {
@list ($name, $value) = explode ('=', $pair, 2);
if ($value === null)
{
$argv[$key] = $name;
}
else
{
if (! is_array ($argv[$key]))
$argv[$key] = array ();
$argv[$key][$name] = $value;
}
}
}
// Manage a parameter in the constructor of the class
$paramConst = array ();
if (count ($paramsConst) > 0)
{
$paramConst = array_slice ($argv, 0, count ($paramsConst));
$argv = array_slice ($argv, count ($paramsConst));
}
try
{
$classReflection = new ReflectionClass($class);
$r = $classReflection->newInstanceArgs($paramConst);
$r->auth["email"] = "cli";
$s = call_user_func_array(array($r, $method), $argv);
var_dump ($s);
}
catch (Exception $e)
{
file_put_contents("php://stderr", $e->getMessage()."\n");
if ($this->EXPERT)
file_put_contents ("php://stderr", $e->getTraceAsString()."\n");
}
exit;
}
}