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 }
|