<?php namespace descartes; /** * Class to route console query */ class Console { /** * Check if a command explicitly ask for help * @param array $command : Command called * @param boolean : True if need help, false else */ private static function is_asking_for_help (array $command) : bool { return (isset($command[1]) && $command[1] == '--help'); } /** * Search name of controller to call and verify if it exist * @param array $command : Command called * @return string | bool : False if controller didn't exist. Name of controller if find */ private static function extract_controller (array $command) { //If we need help, we remove help flag if (self::is_asking_for_help($command)) { unset($command[1]); $command = array_values($command); } //If no controller found if (!isset($command[1])) { return false; } $controller = $command[1]; $controller = str_replace('/', '\\', $controller); $ends_with = mb_substr($controller, -4); if ($ends_with === '.php') { $controller = mb_substr($controller, 0, mb_strlen($controller) - 4); } if (!class_exists($controller)) { return false; } return $controller; } /** * Search name of the method to call, an verify it exist and is available * @param array $command : Command called * @param string $controller : Name of controller of the method * @return string | bool : False if method not found, not exist or not available, method name else */ private static function extract_method (array $command, string $controller) { //Remove help flag if needed if (self::is_asking_for_help($command)) { unset($command[1]); $command = array_values($command); } //If no method passed if (!isset($command[2])) { return false; } $method = $command[2]; if (!method_exists($controller, $method)) { return false; } return $method; } /** * Extract params from the command * @param array $command : La commande à analyser * @return mixed : Array of params (format name => value). * @return array | bool : An array with parameters in order we want theme to be passed to method. False if a need parameter is missing */ private static function extract_params (array $command, string $controller, string $method) { //Remove invocation, controller and method from command unset($command[0], $command[1], $command[2]); $command = array_values($command); $params = []; foreach ($command as $param) { $param = explode('=', $param, 2); $name = str_replace('--', '', $param[0]); $value = $param[1]; $params[$name] = $value; } $reflection = new \ReflectionMethod($controller, $method); $method_arguments = []; foreach ($reflection->getParameters() as $parameter) { if (!array_key_exists($parameter->getName(), $params) && !$parameter->isDefaultValueAvailable()) { return false; } if ($parameter->isDefaultValueAvailable()) { $method_arguments[$parameter->getName()] = $parameter->getDefaultValue(); } if (!array_key_exists($parameter->getName(), $params)) { continue; } //On ajoute la variable dans le tableau des arguments de la méthode $method_arguments[$parameter->getName()] = $params[$parameter->getName()]; } return $method_arguments; } /** * Generate help text * @param array $command : Called command * @param ?string $controller : Name of the controller we want help for, null if not given * @param ?string $method : Name of the method we want help for, null if not giver * @param boolean $missing_arguments : If there is required arguments missing, false by default * @param string : Le texte d'aide à afficher */ private static function generate_help_text (array $command, ?string $controller = null, ?string $method = null, bool $missing_arguments = false) : string { $retour = ''; $retour .= "Help : \n"; //Si pas de controlleur, on sort l'aide par défaut if (!$controller) { $retour .= "You havn't supplied a Controller to call. To see help of a Controller : " . $command[0] . " --help <name controller> <name method>\n"; return $retour; } if ($missing_arguments) { $retour .= "Some required arguments are missing. \n"; } if (!$method) { $retour .= 'Help of Controller ' . $controller . "\n" . "Methods : \n"; $reflection = new \ReflectionClass($controller); $reflection_methods = $reflection->getMethods(); } else { $reflection_methods = [new \ReflectionMethod($controller, $method)]; $retour .= 'Help of Controller ' . $controller . ' and method ' . $method . "\n"; } foreach ($reflection_methods as $reflection_method) { $retour .= " " . $reflection_method->getName(); foreach ($reflection_method->getParameters() as $parameter) { $retour .= ' --' . $parameter->getName() . "=<value" . ($parameter->isDefaultValueAvailable() ? ' (by default, ' . gettype($parameter->getDefaultValue()) . ':' . str_replace(PHP_EOL, '', print_r($parameter->getDefaultValue(), true)) . ')': '') . ">"; } $retour .= "\n"; } return $retour; } /** * This method call controller and method from command * @param array $command : Command to call * @param $args : Arguments to pass to Controller constructor * @return bool : False on error, true else */ public static function execute_command (array $command, ...$args) { $controller = self::extract_controller($command); if (!$controller) { echo self::generate_help_text($command); return true; } $method = self::extract_method($command, $controller); if (!$method) { echo self::generate_help_text($command, $controller); return true; } $params = self::extract_params($command, $controller, $method); if ($params === false) { echo self::generate_help_text($command, $controller, $method, true); return true; } $asking_for_help = self::is_asking_for_help($command); if ($asking_for_help) { echo self::generate_help_text($command, $controller, $method); return true; } $reflection = new \ReflectionClass($controller); $reflection_method = $reflection->getMethod($method); if (!$reflection_method->isStatic()) { $controller = new $controller(...$args); } return call_user_func_array([$controller, $method], $params); } }