* @package tao */ abstract class tao_scripts_Runner { // Adding container and logger. use \oat\oatbox\log\ContainerLoggerTrait; /** * Runner related dependencies will be reached under this offset. * (use different indexes for every single child!!!) */ const CONTAINER_INDEX = 'taoScriptsRunner'; // --- ASSOCIATIONS --- // --- ATTRIBUTES --- private $isCli; private $logOny; /** * Short description of attribute parameters * * @access protected * @var array */ protected $parameters = []; /** * Short description of attribute inputFormat * * @access protected * @var array */ protected $inputFormat = []; // --- OPERATIONS --- /** * Short description of method __construct * * @access public * @author firstname and lastname of author, * @param \Pimple\Container|array $inputFormat * @param array $options * @return mixed */ public function __construct($inputFormat = [], $options = []) { // Using the container if it's necessary with automatic dependency returning. $inputFormat = $this->initContainer($inputFormat, static::CONTAINER_INDEX); if (PHP_SAPI == 'cli' && !isset($options['argv'])) { $this->argv = $_SERVER['argv']; $this->isCli = true; } else { $this->argv = isset($options['argv']) ? $options['argv'] : []; $this->isCli = false; } if (isset($options['output_mode']) && $options['output_mode'] == 'log_only') { $this->logOny = true; } $this->out("* Running " . (isset($this->argv[0]) ? $this->argv[0] : __CLASS__), $options); $this->inputFormat = $inputFormat; //check if help is needed $helpParams = ['-h', 'help', '-help', '--help']; $help = array_intersect($helpParams, $this->argv); if (!empty($help)) { $this->help(); exit(0); } //validate the input parameters if (!$this->validateInput()) { $this->help(); $this->err("Scripts stopped!", true); } //script run loop $this->preRun(); $this->run(); $this->postRun(); $this->out('Execution of Script ' . (isset($this->argv[0]) ? $this->argv[0] : __CLASS__) . ' completed', $options); } /** * Short description of method validateInput * * @access private * @author firstname and lastname of author, * @return boolean */ private function validateInput() { $returnValue = (bool) false; $returnValue = true; /** * Parse the arguments from the command lines * and set them into the parameter variable. * All the current formats are allowed: * * php script.php -arg1 value1 -arg2 value2 * php script.php --arg1 value1 --arg2 value2 * php script.php -arg1=value1 -arg2=value2 * php script.php --arg1=value1 --arg2=value2 * php script.php value1 value2 //the key will be numeric * */ $i = 1; while ($i < count($this->argv)) { $arg = trim($this->argv[$i]); if (!empty($arg)) { // command -(-)arg1=value1 if (preg_match("/^[\-]{1,2}\w+=(.*)+$/", $arg)) { $sequence = explode('=', preg_replace("/^[\-]{1,}/", '', $arg)); if (count($sequence) >= 2) { $this->parameters[$sequence[0]] = $sequence[1]; } } // command -(-)arg1 value1 value2 elseif (preg_match("/^[\-]{1,2}\w+$/", $arg)) { $key = preg_replace("/^[\-]{1,}/", '', $arg); $this->parameters[$key] = ''; while (isset($this->argv[$i + 1]) && substr(trim($this->argv[$i + 1]), 0, 1) != '-') { $this->parameters[$key] .= trim($this->argv[++$i]) . ' '; } $this->parameters[$key] = substr($this->parameters[$key], 0, -1); } // command value1 value2 else { $this->parameters[$i] = $arg; } } $i++; } //replaces shortcuts by their original names if (isset($this->inputFormat['parameters'])) { foreach ($this->inputFormat['parameters'] as $parameter) { if (isset($parameter['shortcut'])) { $short = $parameter['shortcut']; $long = $parameter['name']; if (array_key_exists($short, $this->parameters) && !array_key_exists($long, $this->parameters)) { $this->parameters[$long] = $this->parameters[$short]; unset($this->parameters[$short]); } } } } //one we have the parameters, we can validate it if (isset($this->inputFormat['min'])) { $min = (int) $this->inputFormat['min']; $found = count($this->parameters); if ($found < $min) { $this->err("Invalid parameter count: $found parameters found ($min expected)"); $returnValue = false; } } if (isset($this->inputFormat['required']) && is_array($this->inputFormat['required']) && count($this->inputFormat['required'])) { $requireds = []; if (!is_array($this->inputFormat['required'][0])) { $requireds = [$this->inputFormat['required']]; } else { $requireds = $this->inputFormat['required']; } $found = false; foreach ($requireds as $required) { $matched = 0; foreach ($required as $parameter) { if (array_key_exists($parameter, $this->parameters)) { $matched++; } } if ($matched == count($required)) { $found = true; break; } } if (!$found) { $this->err("Unable to find required arguments"); $returnValue = false; } } if ($returnValue && isset($this->inputFormat['parameters'])) { foreach ($this->inputFormat['parameters'] as $parameter) { if (isset($this->parameters[$parameter['name']])) { $input = $this->parameters[$parameter['name']]; switch ($parameter['type']) { case 'file': if ( !is_file($input) || !file_exists($input) || !is_readable($input) ) { $this->err("Unable to access to the file: $input"); $returnValue = false; } break; case 'dir': if ( !is_dir($input) || !is_readable($input) ) { $this->err("Unable to access to the directory: $input"); $returnValue = false; } break; case 'path': if (!is_dir(dirname($input))) { $this->err("Wrong path given: $input"); $returnValue = false; } break; case 'int': case 'float': case 'double': if (!is_numeric($input)) { $this->err("$input is not a valid " . $parameter['type']); $returnValue = false; } break; case 'string': if (!is_string($input)) { $this->err("$input is not a valid " . $parameter['type']); $returnValue = false; } break; case 'boolean': if (!is_bool($input) && strtolower($input) != 'true' && strtolower($input) != 'false' && !empty($input)) { $this->err("$input is not a valid " . $parameter['type']); $returnValue = false; } else { if (is_bool($input)) { $this->parameters[$parameter['name']] = $input = settype($input, 'boolean'); } elseif (!empty($input)) { $this->parameters[$parameter['name']] = ((strtolower($input) == 'true') ? true : false); } else { $this->parameters[$parameter['name']] = true; } } break; } } } } return (bool) $returnValue; } /** * Short description of method preRun * * @access protected * @author firstname and lastname of author, * @return mixed */ protected function preRun() { } /** * Short description of method run * * @abstract * @access protected * @author firstname and lastname of author, * @return mixed */ abstract protected function run(); /** * Short description of method postRun * * @access protected * @author firstname and lastname of author, * @return mixed */ protected function postRun() { } /** * * @access * @author "Lionel Lecaque, " * @param unknown $message * @param unknown $options * @return Ambigous */ private function renderCliOutput($message, $options = []) { $returnValue = ''; if (isset($options['prefix'])) { $returnValue = $options['prefix']; } $colorized = false; isset($options['color']) ? $color = $options['color'] : $color = 'grey'; $color = trim(tao_helpers_Cli::getFgColor($color)); if (!empty($color) && substr(strtoupper(PHP_OS), 0, 3) != 'WIN') { $colorized = true; $returnValue .= "\033[{$color}m" ; } isset($options['background']) ? $bg = $options['background'] : $bg = ''; $bg = trim(tao_helpers_Cli::getBgColor($bg)); if (!empty($bg)) { $colorized = true; $returnValue .= "\033[{$bg}m"; } $returnValue .= $message; if (!isset($options['inline'])) { $returnValue .= "\n"; } if ($colorized) { $returnValue .= "\033[0m"; } return $returnValue; } /** * * @access private * @author "Lionel Lecaque, " * @param string $message * @param array $options * @return string */ private function renderHtmlOutput($message, $options = []) { $returnValue = ''; if (isset($options['prefix'])) { $returnValue = $options['prefix']; } isset($options['color']) ? $color = $options['color'] : $color = 'grey'; if (!empty($color)) { $colorized = true; $returnValue .= '
'; } $returnValue .= $message; if (!isset($options['inline'])) { $returnValue .= "
"; } if ($colorized) { $returnValue .= "
"; } return $returnValue; } /** * Short description of method out * * @access public * @author firstname and lastname of author, * @param string message * @param array options */ public function out($message, $options = []) { $returnValue = $this->isCli ? $this->renderCliOutput($message, $options) : $this->renderHtmlOutput($message, $options); if ($this->logOny) { //do nothing } else { echo $returnValue ; } common_Logger::i($message, ['SCRIPTS_RUNNER']); } /** * Short description of method err * * @access protected * @author firstname and lastname of author, * @param string message * @param boolean stopExec */ protected function err($message, $stopExec = false) { common_Logger::e($message); echo $this->out($message, ['color' => 'light_red']); if ($stopExec == true) { $this->handleError(new Exception($message, 1)); } } /** * Handles a fatal error situation. * * @param Exception $e * * @throws Exception */ protected function handleError(Exception $e) { if ($this->isCli) { $errorCode = $e->getCode(); exit((empty($errorCode)) ? 1 : $errorCode); //exit the program with an error } else { throw new Exception($e->getMessage()); } } /** * Short description of method help * * @access protected * @author firstname and lastname of author, * @return mixed */ protected function help() { $usage = "Usage:php {$this->argv[0]} [arguments]\n"; $usage .= "\nArguments list:\n"; foreach ($this->inputFormat['parameters'] as $parameter) { $line = ''; if (isset($parameter['required'])) { if ($parameter['required'] == true) { $line .= "Required"; } else { $line .= "Optional"; } } else { //$usage .= "\t"; } $line = str_pad($line, 15) . ' '; $line .= "--{$parameter['name']}"; if (isset($parameter['shortcut'])) { $line .= "|-{$parameter['shortcut']}"; } $line = str_pad($line, 39) . ' '; $line .= "{$parameter['description']}"; $usage .= $line . "\n"; } $this->out($usage, ['color' => 'light_blue']); } /** * Short description of method outVerbose * * @access public * @author firstname and lastname of author, * @param string message * @param array options * @return mixed */ public function outVerbose($message, $options = []) { common_Logger::i($message); if (isset($this->parameters['verbose']) && $this->parameters['verbose'] === true) { $this->out($message, $options); } } } /* end of abstract class tao_scripts_Runner */