annotate vendor/consolidation/annotated-command/src/CommandProcessor.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2 namespace Consolidation\AnnotatedCommand;
Chris@0 3
Chris@0 4 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ReplaceCommandHookDispatcher;
Chris@0 5 use Psr\Log\LoggerAwareInterface;
Chris@0 6 use Psr\Log\LoggerAwareTrait;
Chris@0 7 use Symfony\Component\Console\Input\InputInterface;
Chris@0 8 use Symfony\Component\Console\Output\OutputInterface;
Chris@0 9 use Symfony\Component\Console\Output\ConsoleOutputInterface;
Chris@0 10
Chris@0 11 use Consolidation\OutputFormatters\FormatterManager;
Chris@0 12 use Consolidation\OutputFormatters\Options\FormatterOptions;
Chris@0 13 use Consolidation\AnnotatedCommand\Hooks\HookManager;
Chris@0 14 use Consolidation\AnnotatedCommand\Options\PrepareFormatter;
Chris@0 15
Chris@0 16 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\InitializeHookDispatcher;
Chris@0 17 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\OptionsHookDispatcher;
Chris@0 18 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\InteractHookDispatcher;
Chris@0 19 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ValidateHookDispatcher;
Chris@0 20 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ProcessResultHookDispatcher;
Chris@0 21 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\StatusDeterminerHookDispatcher;
Chris@0 22 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ExtracterHookDispatcher;
Chris@0 23
Chris@0 24 /**
Chris@0 25 * Process a command, including hooks and other callbacks.
Chris@0 26 * There should only be one command processor per application.
Chris@0 27 * Provide your command processor to the AnnotatedCommandFactory
Chris@0 28 * via AnnotatedCommandFactory::setCommandProcessor().
Chris@0 29 */
Chris@0 30 class CommandProcessor implements LoggerAwareInterface
Chris@0 31 {
Chris@0 32 use LoggerAwareTrait;
Chris@0 33
Chris@17 34 /** @var HookManager */
Chris@0 35 protected $hookManager;
Chris@17 36 /** @var FormatterManager */
Chris@0 37 protected $formatterManager;
Chris@17 38 /** @var PrepareFormatterOptions[] */
Chris@0 39 protected $prepareOptionsList = [];
Chris@17 40 /** @var boolean */
Chris@0 41 protected $passExceptions;
Chris@17 42 /** @var ResultWriter */
Chris@17 43 protected $resultWriter;
Chris@17 44 /** @var ParameterInjection */
Chris@17 45 protected $parameterInjection;
Chris@0 46
Chris@0 47 public function __construct(HookManager $hookManager)
Chris@0 48 {
Chris@0 49 $this->hookManager = $hookManager;
Chris@0 50 }
Chris@0 51
Chris@0 52 /**
Chris@0 53 * Return the hook manager
Chris@0 54 * @return HookManager
Chris@0 55 */
Chris@0 56 public function hookManager()
Chris@0 57 {
Chris@0 58 return $this->hookManager;
Chris@0 59 }
Chris@0 60
Chris@17 61 public function resultWriter()
Chris@17 62 {
Chris@17 63 if (!$this->resultWriter) {
Chris@17 64 $this->setResultWriter(new ResultWriter());
Chris@17 65 }
Chris@17 66 return $this->resultWriter;
Chris@17 67 }
Chris@17 68
Chris@17 69 public function setResultWriter($resultWriter)
Chris@17 70 {
Chris@17 71 $this->resultWriter = $resultWriter;
Chris@17 72 }
Chris@17 73
Chris@17 74 public function parameterInjection()
Chris@17 75 {
Chris@17 76 if (!$this->parameterInjection) {
Chris@17 77 $this->setParameterInjection(new ParameterInjection());
Chris@17 78 }
Chris@17 79 return $this->parameterInjection;
Chris@17 80 }
Chris@17 81
Chris@17 82 public function setParameterInjection($parameterInjection)
Chris@17 83 {
Chris@17 84 $this->parameterInjection = $parameterInjection;
Chris@17 85 }
Chris@17 86
Chris@0 87 public function addPrepareFormatter(PrepareFormatter $preparer)
Chris@0 88 {
Chris@0 89 $this->prepareOptionsList[] = $preparer;
Chris@0 90 }
Chris@0 91
Chris@0 92 public function setFormatterManager(FormatterManager $formatterManager)
Chris@0 93 {
Chris@0 94 $this->formatterManager = $formatterManager;
Chris@17 95 $this->resultWriter()->setFormatterManager($formatterManager);
Chris@0 96 return $this;
Chris@0 97 }
Chris@0 98
Chris@0 99 public function setDisplayErrorFunction(callable $fn)
Chris@0 100 {
Chris@17 101 $this->resultWriter()->setDisplayErrorFunction($fn);
Chris@0 102 }
Chris@0 103
Chris@0 104 /**
Chris@0 105 * Set a mode to make the annotated command library re-throw
Chris@0 106 * any exception that it catches while processing a command.
Chris@0 107 *
Chris@0 108 * The default behavior in the current (2.x) branch is to catch
Chris@0 109 * the exception and replace it with a CommandError object that
Chris@0 110 * may be processed by the normal output processing passthrough.
Chris@0 111 *
Chris@0 112 * In the 3.x branch, exceptions will never be caught; they will
Chris@0 113 * be passed through, as if setPassExceptions(true) were called.
Chris@0 114 * This is the recommended behavior.
Chris@0 115 */
Chris@0 116 public function setPassExceptions($passExceptions)
Chris@0 117 {
Chris@0 118 $this->passExceptions = $passExceptions;
Chris@0 119 return $this;
Chris@0 120 }
Chris@0 121
Chris@0 122 public function commandErrorForException(\Exception $e)
Chris@0 123 {
Chris@0 124 if ($this->passExceptions) {
Chris@0 125 throw $e;
Chris@0 126 }
Chris@0 127 return new CommandError($e->getMessage(), $e->getCode());
Chris@0 128 }
Chris@0 129
Chris@0 130 /**
Chris@0 131 * Return the formatter manager
Chris@0 132 * @return FormatterManager
Chris@0 133 */
Chris@0 134 public function formatterManager()
Chris@0 135 {
Chris@0 136 return $this->formatterManager;
Chris@0 137 }
Chris@0 138
Chris@0 139 public function initializeHook(
Chris@0 140 InputInterface $input,
Chris@0 141 $names,
Chris@0 142 AnnotationData $annotationData
Chris@0 143 ) {
Chris@0 144 $initializeDispatcher = new InitializeHookDispatcher($this->hookManager(), $names);
Chris@0 145 return $initializeDispatcher->initialize($input, $annotationData);
Chris@0 146 }
Chris@0 147
Chris@0 148 public function optionsHook(
Chris@0 149 AnnotatedCommand $command,
Chris@0 150 $names,
Chris@0 151 AnnotationData $annotationData
Chris@0 152 ) {
Chris@0 153 $optionsDispatcher = new OptionsHookDispatcher($this->hookManager(), $names);
Chris@0 154 $optionsDispatcher->getOptions($command, $annotationData);
Chris@0 155 }
Chris@0 156
Chris@0 157 public function interact(
Chris@0 158 InputInterface $input,
Chris@0 159 OutputInterface $output,
Chris@0 160 $names,
Chris@0 161 AnnotationData $annotationData
Chris@0 162 ) {
Chris@0 163 $interactDispatcher = new InteractHookDispatcher($this->hookManager(), $names);
Chris@0 164 return $interactDispatcher->interact($input, $output, $annotationData);
Chris@0 165 }
Chris@0 166
Chris@0 167 public function process(
Chris@0 168 OutputInterface $output,
Chris@0 169 $names,
Chris@0 170 $commandCallback,
Chris@0 171 CommandData $commandData
Chris@0 172 ) {
Chris@0 173 $result = [];
Chris@0 174 try {
Chris@0 175 $result = $this->validateRunAndAlter(
Chris@0 176 $names,
Chris@0 177 $commandCallback,
Chris@0 178 $commandData
Chris@0 179 );
Chris@0 180 return $this->handleResults($output, $names, $result, $commandData);
Chris@0 181 } catch (\Exception $e) {
Chris@0 182 $result = $this->commandErrorForException($e);
Chris@0 183 return $this->handleResults($output, $names, $result, $commandData);
Chris@0 184 }
Chris@0 185 }
Chris@0 186
Chris@0 187 public function validateRunAndAlter(
Chris@0 188 $names,
Chris@0 189 $commandCallback,
Chris@0 190 CommandData $commandData
Chris@0 191 ) {
Chris@0 192 // Validators return any object to signal a validation error;
Chris@0 193 // if the return an array, it replaces the arguments.
Chris@0 194 $validateDispatcher = new ValidateHookDispatcher($this->hookManager(), $names);
Chris@0 195 $validated = $validateDispatcher->validate($commandData);
Chris@0 196 if (is_object($validated)) {
Chris@0 197 return $validated;
Chris@0 198 }
Chris@0 199
Chris@17 200 // Once we have validated the optins, create the formatter options.
Chris@17 201 $this->createFormatterOptions($commandData);
Chris@17 202
Chris@0 203 $replaceDispatcher = new ReplaceCommandHookDispatcher($this->hookManager(), $names);
Chris@0 204 if ($this->logger) {
Chris@0 205 $replaceDispatcher->setLogger($this->logger);
Chris@0 206 }
Chris@0 207 if ($replaceDispatcher->hasReplaceCommandHook()) {
Chris@0 208 $commandCallback = $replaceDispatcher->getReplacementCommand($commandData);
Chris@0 209 }
Chris@0 210
Chris@0 211 // Run the command, alter the results, and then handle output and status
Chris@0 212 $result = $this->runCommandCallback($commandCallback, $commandData);
Chris@0 213 return $this->processResults($names, $result, $commandData);
Chris@0 214 }
Chris@0 215
Chris@0 216 public function processResults($names, $result, CommandData $commandData)
Chris@0 217 {
Chris@0 218 $processDispatcher = new ProcessResultHookDispatcher($this->hookManager(), $names);
Chris@0 219 return $processDispatcher->process($result, $commandData);
Chris@0 220 }
Chris@0 221
Chris@0 222 /**
Chris@0 223 * Create a FormatterOptions object for use in writing the formatted output.
Chris@0 224 * @param CommandData $commandData
Chris@0 225 * @return FormatterOptions
Chris@0 226 */
Chris@0 227 protected function createFormatterOptions($commandData)
Chris@0 228 {
Chris@0 229 $options = $commandData->input()->getOptions();
Chris@0 230 $formatterOptions = new FormatterOptions($commandData->annotationData()->getArrayCopy(), $options);
Chris@0 231 foreach ($this->prepareOptionsList as $preparer) {
Chris@0 232 $preparer->prepare($commandData, $formatterOptions);
Chris@0 233 }
Chris@17 234 $commandData->setFormatterOptions($formatterOptions);
Chris@0 235 return $formatterOptions;
Chris@0 236 }
Chris@0 237
Chris@0 238 /**
Chris@17 239 * Handle the result output and status code calculation.
Chris@0 240 */
Chris@17 241 public function handleResults(OutputInterface $output, $names, $result, CommandData $commandData)
Chris@0 242 {
Chris@17 243 $statusCodeDispatcher = new StatusDeterminerHookDispatcher($this->hookManager(), $names);
Chris@17 244 $extractDispatcher = new ExtracterHookDispatcher($this->hookManager(), $names);
Chris@17 245
Chris@17 246 return $this->resultWriter()->handle($output, $result, $commandData, $statusCodeDispatcher, $extractDispatcher);
Chris@0 247 }
Chris@0 248
Chris@0 249 /**
Chris@17 250 * Run the main command callback
Chris@0 251 */
Chris@17 252 protected function runCommandCallback($commandCallback, CommandData $commandData)
Chris@17 253 {
Chris@17 254 $result = false;
Chris@17 255 try {
Chris@17 256 $args = $this->parameterInjection()->args($commandData);
Chris@17 257 $result = call_user_func_array($commandCallback, $args);
Chris@17 258 } catch (\Exception $e) {
Chris@17 259 $result = $this->commandErrorForException($e);
Chris@0 260 }
Chris@17 261 return $result;
Chris@0 262 }
Chris@0 263
Chris@17 264 public function injectIntoCommandData($commandData, $injectedClasses)
Chris@0 265 {
Chris@17 266 $this->parameterInjection()->injectIntoCommandData($commandData, $injectedClasses);
Chris@0 267 }
Chris@0 268 }