annotate vendor/consolidation/annotated-command/src/CommandData.php @ 13:5fb285c0d0e3

Update Drupal core to 8.4.7 via Composer. Security update; I *think* we've been lucky to get away with this so far, as we don't support self-registration which seems to be used by the so-called "drupalgeddon 2" attack that 8.4.5 was vulnerable to.
author Chris Cannam
date Mon, 23 Apr 2018 09:33:26 +0100
parents 4c8ae668cc8c
children 129ea1e6d783
rev   line source
Chris@0 1 <?php
Chris@0 2 namespace Consolidation\AnnotatedCommand;
Chris@0 3
Chris@0 4 use Symfony\Component\Console\Input\ArgvInput;
Chris@0 5 use Symfony\Component\Console\Input\InputInterface;
Chris@0 6 use Symfony\Component\Console\Output\OutputInterface;
Chris@0 7
Chris@0 8 class CommandData
Chris@0 9 {
Chris@0 10 /** var AnnotationData */
Chris@0 11 protected $annotationData;
Chris@0 12 /** var InputInterface */
Chris@0 13 protected $input;
Chris@0 14 /** var OutputInterface */
Chris@0 15 protected $output;
Chris@0 16 /** var boolean */
Chris@0 17 protected $usesInputInterface;
Chris@0 18 /** var boolean */
Chris@0 19 protected $usesOutputInterface;
Chris@0 20 /** var boolean */
Chris@0 21 protected $includeOptionsInArgs;
Chris@0 22 /** var array */
Chris@0 23 protected $specialDefaults = [];
Chris@0 24
Chris@0 25 public function __construct(
Chris@0 26 AnnotationData $annotationData,
Chris@0 27 InputInterface $input,
Chris@0 28 OutputInterface $output,
Chris@0 29 $usesInputInterface = false,
Chris@0 30 $usesOutputInterface = false
Chris@0 31 ) {
Chris@0 32 $this->annotationData = $annotationData;
Chris@0 33 $this->input = $input;
Chris@0 34 $this->output = $output;
Chris@0 35 $this->usesInputInterface = false;
Chris@0 36 $this->usesOutputInterface = false;
Chris@0 37 $this->includeOptionsInArgs = true;
Chris@0 38 }
Chris@0 39
Chris@0 40 /**
Chris@0 41 * For internal use only; indicates that the function to be called
Chris@0 42 * should be passed an InputInterface &/or an OutputInterface.
Chris@0 43 * @param booean $usesInputInterface
Chris@0 44 * @param boolean $usesOutputInterface
Chris@0 45 * @return self
Chris@0 46 */
Chris@0 47 public function setUseIOInterfaces($usesInputInterface, $usesOutputInterface)
Chris@0 48 {
Chris@0 49 $this->usesInputInterface = $usesInputInterface;
Chris@0 50 $this->usesOutputInterface = $usesOutputInterface;
Chris@0 51 return $this;
Chris@0 52 }
Chris@0 53
Chris@0 54 /**
Chris@0 55 * For backwards-compatibility mode only: disable addition of
Chris@0 56 * options on the end of the arguments list.
Chris@0 57 */
Chris@0 58 public function setIncludeOptionsInArgs($includeOptionsInArgs)
Chris@0 59 {
Chris@0 60 $this->includeOptionsInArgs = $includeOptionsInArgs;
Chris@0 61 return $this;
Chris@0 62 }
Chris@0 63
Chris@0 64 public function annotationData()
Chris@0 65 {
Chris@0 66 return $this->annotationData;
Chris@0 67 }
Chris@0 68
Chris@0 69 public function input()
Chris@0 70 {
Chris@0 71 return $this->input;
Chris@0 72 }
Chris@0 73
Chris@0 74 public function output()
Chris@0 75 {
Chris@0 76 return $this->output;
Chris@0 77 }
Chris@0 78
Chris@0 79 public function arguments()
Chris@0 80 {
Chris@0 81 return $this->input->getArguments();
Chris@0 82 }
Chris@0 83
Chris@0 84 public function options()
Chris@0 85 {
Chris@0 86 // We cannot tell the difference between '--foo' (an option without
Chris@0 87 // a value) and the absence of '--foo' when the option has an optional
Chris@0 88 // value, and the current vallue of the option is 'null' using only
Chris@0 89 // the public methods of InputInterface. We'll try to figure out
Chris@0 90 // which is which by other means here.
Chris@0 91 $options = $this->getAdjustedOptions();
Chris@0 92
Chris@0 93 // Make two conversions here:
Chris@0 94 // --foo=0 wil convert $value from '0' to 'false' for binary options.
Chris@0 95 // --foo with $value of 'true' will be forced to 'false' if --no-foo exists.
Chris@0 96 foreach ($options as $option => $value) {
Chris@0 97 if ($this->shouldConvertOptionToFalse($options, $option, $value)) {
Chris@0 98 $options[$option] = false;
Chris@0 99 }
Chris@0 100 }
Chris@0 101
Chris@0 102 return $options;
Chris@0 103 }
Chris@0 104
Chris@0 105 /**
Chris@0 106 * Use 'hasParameterOption()' to attempt to disambiguate option states.
Chris@0 107 */
Chris@0 108 protected function getAdjustedOptions()
Chris@0 109 {
Chris@0 110 $options = $this->input->getOptions();
Chris@0 111
Chris@0 112 // If Input isn't an ArgvInput, then return the options as-is.
Chris@0 113 if (!$this->input instanceof ArgvInput) {
Chris@0 114 return $options;
Chris@0 115 }
Chris@0 116
Chris@0 117 // If we have an ArgvInput, then we can determine if options
Chris@0 118 // are missing from the command line. If the option value is
Chris@0 119 // missing from $input, then we will keep the value `null`.
Chris@0 120 // If it is present, but has no explicit value, then change it its
Chris@0 121 // value to `true`.
Chris@0 122 foreach ($options as $option => $value) {
Chris@0 123 if (($value === null) && ($this->input->hasParameterOption("--$option"))) {
Chris@0 124 $options[$option] = true;
Chris@0 125 }
Chris@0 126 }
Chris@0 127
Chris@0 128 return $options;
Chris@0 129 }
Chris@0 130
Chris@0 131 protected function shouldConvertOptionToFalse($options, $option, $value)
Chris@0 132 {
Chris@0 133 // If the value is 'true' (e.g. the option is '--foo'), then convert
Chris@0 134 // it to false if there is also an option '--no-foo'. n.b. if the
Chris@0 135 // commandline has '--foo=bar' then $value will not be 'true', and
Chris@0 136 // --no-foo will be ignored.
Chris@0 137 if ($value === true) {
Chris@0 138 // Check if the --no-* option exists. Note that none of the other
Chris@0 139 // alteration apply in the $value == true case, so we can exit early here.
Chris@0 140 $negation_key = 'no-' . $option;
Chris@0 141 return array_key_exists($negation_key, $options) && $options[$negation_key];
Chris@0 142 }
Chris@0 143
Chris@0 144 // If the option is '--foo=0', convert the '0' to 'false' when appropriate.
Chris@0 145 if ($value !== '0') {
Chris@0 146 return false;
Chris@0 147 }
Chris@0 148
Chris@0 149 // The '--foo=0' convertion is only applicable when the default value
Chris@0 150 // is not in the special defaults list. i.e. you get a literal '0'
Chris@0 151 // when your default is a string.
Chris@0 152 return in_array($option, $this->specialDefaults);
Chris@0 153 }
Chris@0 154
Chris@0 155 public function cacheSpecialDefaults($definition)
Chris@0 156 {
Chris@0 157 foreach ($definition->getOptions() as $option => $inputOption) {
Chris@0 158 $defaultValue = $inputOption->getDefault();
Chris@0 159 if (($defaultValue === null) || ($defaultValue === true)) {
Chris@0 160 $this->specialDefaults[] = $option;
Chris@0 161 }
Chris@0 162 }
Chris@0 163 }
Chris@0 164
Chris@0 165 public function getArgsWithoutAppName()
Chris@0 166 {
Chris@0 167 $args = $this->arguments();
Chris@0 168
Chris@0 169 // When called via the Application, the first argument
Chris@0 170 // will be the command name. The Application alters the
Chris@0 171 // input definition to match, adding a 'command' argument
Chris@0 172 // to the beginning.
Chris@13 173 if ($this->input->hasArgument('command')) {
Chris@13 174 array_shift($args);
Chris@13 175 }
Chris@0 176
Chris@0 177 if ($this->usesOutputInterface) {
Chris@0 178 array_unshift($args, $this->output());
Chris@0 179 }
Chris@0 180
Chris@0 181 if ($this->usesInputInterface) {
Chris@0 182 array_unshift($args, $this->input());
Chris@0 183 }
Chris@0 184
Chris@0 185 return $args;
Chris@0 186 }
Chris@0 187
Chris@0 188 public function getArgsAndOptions()
Chris@0 189 {
Chris@0 190 // Get passthrough args, and add the options on the end.
Chris@0 191 $args = $this->getArgsWithoutAppName();
Chris@0 192 if ($this->includeOptionsInArgs) {
Chris@0 193 $args['options'] = $this->options();
Chris@0 194 }
Chris@0 195 return $args;
Chris@0 196 }
Chris@0 197 }