name = $name; $this->data = $data; $this->configure(); } public function getContextInfo() { return null; } public function setShell(Shell $shell) { $this->shell = $shell; } public function getShell() { return $this->shell; } public function setParent(Context $parent=null) { $this->parent = $parent; } public function getParent() { return $this->parent; } public function getRoot() { if (!$this->parent) { return $this; } $node = $this; while ($parent = $node->getParent()) { $node = $parent; } return $parent; } protected function configure() { // Override this to do setup stuff $this->findCommands(); } protected function findCommands() { $refl = new \ReflectionClass(get_called_class()); foreach ($refl->getMethods() as $method) { $docblock = $method->getDocComment(); $lines = array_map(function ($line) { return trim($line, "*/ \t"); }, explode("\n", $docblock)); $info = []; foreach ($lines as $line) { if (preg_match("/^@(command|help|args|global)\\s*(.*)$/", $line, $match)) { list($void,$key,$value) = $match; $info[$key] = $value; } if (count($info)>0) { $cmdName = array_key_exists("command",$info)?$info["command"]:$method->getName(); $this->addCommand($cmdName, [$this, $method->getName()], $info); } } } } public function addCommand($command, callable $handler, array $info=[]) { $this->commands[$command] = $handler; $this->commandInfo[$command] = $info; ksort($this->commands); } public function setCommandHelp($command, $help) { if (!array_key_exists($command, $this->commandInfo)) { return; } $this->commandInfo[$command]['help'] = $help; } public function addCommands(array $commands) { foreach ($commands as $command=>$handler) { // Make it easier to connect commands direct to local functions if (is_string($handler) && is_callable([$this,$handler])) { $handler = [ $this,$handler ]; } // Add the command to the command list $this->addCommand($command, $handler); } } public function hasCommand($command) { return array_key_exists($command, $this->commands); } public function getCommand($command) { return $this->commands[$command]; } public function getCommandHelp() { $ret = []; foreach ($this->commands as $command=>$handler) { $info = $this->commandInfo[$command]; $args = array_key_exists("args",$info)?$info['args']:""; $help = array_key_exists("help",$info)?$info['help']:""; $ret[trim("{$command} {$args}")] = $help; } return $ret; } public function isCommandGlobal($command) { if (strpos($command," ")!==false) { list($command, $void) = explode(" ",$command,2); } $info = $this->commandInfo[$command]; return array_key_exists('global', $info); } /** * Catch-all handler for commands not defined in context, globally or builtin. * Override this function and return true if the command is handled ok. * * @param string $command The command to execute * @param string[] $args The arguments to the command * @return bool True if the command was handled */ public function execute($command, ...$args) { return false; } /** * Get the name of the context * */ public function getName() { return $this->name; } public function __get($key) { if (!array_key_exists($key,$this->data)) { return false; } return $this->data[$key]; } public function __set($key,$value) { $this->data[$key] = $value; } public function __isset($key) { return array_key_exists($key); } public function __unset($key) { unset($this->data[$key]); } public function getData() { return $this->data; } }