X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=vendor%2Fconsolidation%2Fannotated-command%2Fsrc%2FAnnotatedCommand.php;fp=vendor%2Fconsolidation%2Fannotated-command%2Fsrc%2FAnnotatedCommand.php;h=597d6a2fa97858e05dca42b66fdf77463070e8f5;hp=0000000000000000000000000000000000000000;hb=a2bd1bf0c2c1f1a17d188f4dc0726a45494cefae;hpb=57c063afa3f66b07c4bbddc2d6129a96d90f0aad diff --git a/vendor/consolidation/annotated-command/src/AnnotatedCommand.php b/vendor/consolidation/annotated-command/src/AnnotatedCommand.php new file mode 100644 index 000000000..597d6a2fa --- /dev/null +++ b/vendor/consolidation/annotated-command/src/AnnotatedCommand.php @@ -0,0 +1,437 @@ +getName(); + } + } + parent::__construct($name); + if ($commandInfo && $commandInfo->hasAnnotation('command')) { + $this->setCommandInfo($commandInfo); + $this->setCommandOptions($commandInfo); + } + } + + public function setCommandCallback($commandCallback) + { + $this->commandCallback = $commandCallback; + return $this; + } + + public function setCommandProcessor($commandProcessor) + { + $this->commandProcessor = $commandProcessor; + return $this; + } + + public function commandProcessor() + { + // If someone is using an AnnotatedCommand, and is NOT getting + // it from an AnnotatedCommandFactory OR not correctly injecting + // a command processor via setCommandProcessor() (ideally via the + // DI container), then we'll just give each annotated command its + // own command processor. This is not ideal; preferably, there would + // only be one instance of the command processor in the application. + if (!isset($this->commandProcessor)) { + $this->commandProcessor = new CommandProcessor(new HookManager()); + } + return $this->commandProcessor; + } + + public function getReturnType() + { + return $this->returnType; + } + + public function setReturnType($returnType) + { + $this->returnType = $returnType; + return $this; + } + + public function getAnnotationData() + { + return $this->annotationData; + } + + public function setAnnotationData($annotationData) + { + $this->annotationData = $annotationData; + return $this; + } + + public function getTopics() + { + return $this->topics; + } + + public function setTopics($topics) + { + $this->topics = $topics; + return $this; + } + + public function setCommandInfo($commandInfo) + { + $this->setDescription($commandInfo->getDescription()); + $this->setHelp($commandInfo->getHelp()); + $this->setAliases($commandInfo->getAliases()); + $this->setAnnotationData($commandInfo->getAnnotations()); + $this->setTopics($commandInfo->getTopics()); + foreach ($commandInfo->getExampleUsages() as $usage => $description) { + $this->addUsageOrExample($usage, $description); + } + $this->setCommandArguments($commandInfo); + $this->setReturnType($commandInfo->getReturnType()); + return $this; + } + + public function getExampleUsages() + { + return $this->examples; + } + + protected function addUsageOrExample($usage, $description) + { + $this->addUsage($usage); + if (!empty($description)) { + $this->examples[$usage] = $description; + } + } + + public function helpAlter(\DomDocument $originalDom) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($commandXML = $dom->createElement('command')); + $commandXML->setAttribute('id', $this->getName()); + $commandXML->setAttribute('name', $this->getName()); + + // Get the original element and its top-level elements. + $originalCommandXML = $this->getSingleElementByTagName($dom, $originalDom, 'command'); + $originalUsagesXML = $this->getSingleElementByTagName($dom, $originalCommandXML, 'usages'); + $originalDescriptionXML = $this->getSingleElementByTagName($dom, $originalCommandXML, 'description'); + $originalHelpXML = $this->getSingleElementByTagName($dom, $originalCommandXML, 'help'); + $originalArgumentsXML = $this->getSingleElementByTagName($dom, $originalCommandXML, 'arguments'); + $originalOptionsXML = $this->getSingleElementByTagName($dom, $originalCommandXML, 'options'); + + // Keep only the first of the elements + $newUsagesXML = $dom->createElement('usages'); + $firstUsageXML = $this->getSingleElementByTagName($dom, $originalUsagesXML, 'usage'); + $newUsagesXML->appendChild($firstUsageXML); + + // Create our own elements + $newExamplesXML = $dom->createElement('examples'); + foreach ($this->examples as $usage => $description) { + $newExamplesXML->appendChild($exampleXML = $dom->createElement('example')); + $exampleXML->appendChild($usageXML = $dom->createElement('usage', $usage)); + $exampleXML->appendChild($descriptionXML = $dom->createElement('description', $description)); + } + + // Create our own elements + $newAliasesXML = $dom->createElement('aliases'); + foreach ($this->getAliases() as $alias) { + $newAliasesXML->appendChild($dom->createElement('alias', $alias)); + } + + // Create our own elements + $newTopicsXML = $dom->createElement('topics'); + foreach ($this->getTopics() as $topic) { + $newTopicsXML->appendChild($topicXML = $dom->createElement('topic', $topic)); + } + + // Place the different elements into the element in the desired order + $commandXML->appendChild($newUsagesXML); + $commandXML->appendChild($newExamplesXML); + $commandXML->appendChild($originalDescriptionXML); + $commandXML->appendChild($originalArgumentsXML); + $commandXML->appendChild($originalOptionsXML); + $commandXML->appendChild($originalHelpXML); + $commandXML->appendChild($newAliasesXML); + $commandXML->appendChild($newTopicsXML); + + return $dom; + } + + protected function getSingleElementByTagName($dom, $parent, $tagName) + { + // There should always be exactly one '' element. + $elements = $parent->getElementsByTagName($tagName); + $result = $elements->item(0); + + $result = $dom->importNode($result, true); + + return $result; + } + + protected function setCommandArguments($commandInfo) + { + $this->setUsesInputInterface($commandInfo); + $this->setUsesOutputInterface($commandInfo); + $this->setCommandArgumentsFromParameters($commandInfo); + return $this; + } + + /** + * Check whether the first parameter is an InputInterface. + */ + protected function checkUsesInputInterface($params) + { + $firstParam = reset($params); + return $firstParam instanceof InputInterface; + } + + /** + * Determine whether this command wants to get its inputs + * via an InputInterface or via its command parameters + */ + protected function setUsesInputInterface($commandInfo) + { + $params = $commandInfo->getParameters(); + $this->usesInputInterface = $this->checkUsesInputInterface($params); + return $this; + } + + /** + * Determine whether this command wants to send its output directly + * to the provided OutputInterface, or whether it will returned + * structured output to be processed by the command processor. + */ + protected function setUsesOutputInterface($commandInfo) + { + $params = $commandInfo->getParameters(); + $index = $this->checkUsesInputInterface($params) ? 1 : 0; + $this->usesOutputInterface = + (count($params) > $index) && + ($params[$index] instanceof OutputInterface); + return $this; + } + + protected function setCommandArgumentsFromParameters($commandInfo) + { + $args = $commandInfo->arguments()->getValues(); + foreach ($args as $name => $defaultValue) { + $description = $commandInfo->arguments()->getDescription($name); + $hasDefault = $commandInfo->arguments()->hasDefault($name); + $parameterMode = $this->getCommandArgumentMode($hasDefault, $defaultValue); + $this->addArgument($name, $parameterMode, $description, $defaultValue); + } + return $this; + } + + protected function getCommandArgumentMode($hasDefault, $defaultValue) + { + if (!$hasDefault) { + return InputArgument::REQUIRED; + } + if (is_array($defaultValue)) { + return InputArgument::IS_ARRAY; + } + return InputArgument::OPTIONAL; + } + + public function setCommandOptions($commandInfo, $automaticOptions = []) + { + $inputOptions = $commandInfo->inputOptions(); + + $this->addOptions($inputOptions + $automaticOptions, $automaticOptions); + return $this; + } + + public function addOptions($inputOptions, $automaticOptions = []) + { + foreach ($inputOptions as $name => $inputOption) { + $description = $inputOption->getDescription(); + + if (empty($description) && isset($automaticOptions[$name])) { + $description = $automaticOptions[$name]->getDescription(); + $inputOption = static::inputOptionSetDescription($inputOption, $description); + } + $this->getDefinition()->addOption($inputOption); + } + } + + protected static function inputOptionSetDescription($inputOption, $description) + { + // Recover the 'mode' value, because Symfony is stubborn + $mode = 0; + if ($inputOption->isValueRequired()) { + $mode |= InputOption::VALUE_REQUIRED; + } + if ($inputOption->isValueOptional()) { + $mode |= InputOption::VALUE_OPTIONAL; + } + if ($inputOption->isArray()) { + $mode |= InputOption::VALUE_IS_ARRAY; + } + if (!$mode) { + $mode = InputOption::VALUE_NONE; + } + + $inputOption = new InputOption( + $inputOption->getName(), + $inputOption->getShortcut(), + $mode, + $description, + $inputOption->getDefault() + ); + return $inputOption; + } + + /** + * Returns all of the hook names that may be called for this command. + * + * @return array + */ + public function getNames() + { + return HookManager::getNames($this, $this->commandCallback); + } + + /** + * Add any options to this command that are defined by hook implementations + */ + public function optionsHook() + { + $this->commandProcessor()->optionsHook( + $this, + $this->getNames(), + $this->annotationData + ); + } + + public function optionsHookForHookAnnotations($commandInfoList) + { + foreach ($commandInfoList as $commandInfo) { + $inputOptions = $commandInfo->inputOptions(); + $this->addOptions($inputOptions); + foreach ($commandInfo->getExampleUsages() as $usage => $description) { + if (!in_array($usage, $this->getUsages())) { + $this->addUsageOrExample($usage, $description); + } + } + } + } + + /** + * {@inheritdoc} + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + $this->commandProcessor()->interact( + $input, + $output, + $this->getNames(), + $this->annotationData + ); + } + + protected function initialize(InputInterface $input, OutputInterface $output) + { + // Allow the hook manager a chance to provide configuration values, + // if there are any registered hooks to do that. + $this->commandProcessor()->initializeHook($input, $this->getNames(), $this->annotationData); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + // Validate, run, process, alter, handle results. + return $this->commandProcessor()->process( + $output, + $this->getNames(), + $this->commandCallback, + $this->createCommandData($input, $output) + ); + } + + /** + * This function is available for use by a class that may + * wish to extend this class rather than use annotations to + * define commands. Using this technique does allow for the + * use of annotations to define hooks. + */ + public function processResults(InputInterface $input, OutputInterface $output, $results) + { + $commandData = $this->createCommandData($input, $output); + $commandProcessor = $this->commandProcessor(); + $names = $this->getNames(); + $results = $commandProcessor->processResults( + $names, + $results, + $commandData + ); + return $commandProcessor->handleResults( + $output, + $names, + $results, + $commandData + ); + } + + protected function createCommandData(InputInterface $input, OutputInterface $output) + { + $commandData = new CommandData( + $this->annotationData, + $input, + $output + ); + + $commandData->setUseIOInterfaces( + $this->usesOutputInterface, + $this->usesInputInterface + ); + + return $commandData; + } +}