Completed
Push — master ( 2b1385...7c6a84 )
by Thomas
07:21
created

InputDefinition   C

Complexity

Total Complexity 66

Size/Duplication

Total Lines 426
Duplicated Lines 5.87 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 66
c 1
b 0
f 0
lcom 1
cbo 5
dl 25
loc 426
rs 5.7475

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like InputDefinition often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use InputDefinition, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Symfony\Component\Console\Input;
13
14
use Symfony\Component\Console\Descriptor\TextDescriptor;
15
use Symfony\Component\Console\Descriptor\XmlDescriptor;
16
use Symfony\Component\Console\Output\BufferedOutput;
17
18
/**
19
 * A InputDefinition represents a set of valid command line arguments and options.
20
 *
21
 * Usage:
22
 *
23
 *     $definition = new InputDefinition(array(
24
 *       new InputArgument('name', InputArgument::REQUIRED),
25
 *       new InputOption('foo', 'f', InputOption::VALUE_REQUIRED),
26
 *     ));
27
 *
28
 * @author Fabien Potencier <[email protected]>
29
 */
30
class InputDefinition
31
{
32
    private $arguments;
33
    private $requiredCount;
34
    private $hasAnArrayArgument = false;
35
    private $hasOptional;
36
    private $options;
37
    private $shortcuts;
38
39
    /**
40
     * Constructor.
41
     *
42
     * @param array $definition An array of InputArgument and InputOption instance
43
     */
44
    public function __construct(array $definition = array())
45
    {
46
        $this->setDefinition($definition);
47
    }
48
49
    /**
50
     * Sets the definition of the input.
51
     *
52
     * @param array $definition The definition array
53
     */
54
    public function setDefinition(array $definition)
55
    {
56
        $arguments = array();
57
        $options = array();
58
        foreach ($definition as $item) {
59
            if ($item instanceof InputOption) {
60
                $options[] = $item;
61
            } else {
62
                $arguments[] = $item;
63
            }
64
        }
65
66
        $this->setArguments($arguments);
67
        $this->setOptions($options);
68
    }
69
70
    /**
71
     * Sets the InputArgument objects.
72
     *
73
     * @param InputArgument[] $arguments An array of InputArgument objects
74
     */
75
    public function setArguments($arguments = array())
76
    {
77
        $this->arguments = array();
78
        $this->requiredCount = 0;
79
        $this->hasOptional = false;
80
        $this->hasAnArrayArgument = false;
81
        $this->addArguments($arguments);
82
    }
83
84
    /**
85
     * Adds an array of InputArgument objects.
86
     *
87
     * @param InputArgument[] $arguments An array of InputArgument objects
88
     */
89
    public function addArguments($arguments = array())
90
    {
91
        if (null !== $arguments) {
92
            foreach ($arguments as $argument) {
93
                $this->addArgument($argument);
94
            }
95
        }
96
    }
97
98
    /**
99
     * Adds an InputArgument object.
100
     *
101
     * @param InputArgument $argument An InputArgument object
102
     *
103
     * @throws \LogicException When incorrect argument is given
104
     */
105
    public function addArgument(InputArgument $argument)
106
    {
107
        if (isset($this->arguments[$argument->getName()])) {
108
            throw new \LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
109
        }
110
111
        if ($this->hasAnArrayArgument) {
112
            throw new \LogicException('Cannot add an argument after an array argument.');
113
        }
114
115
        if ($argument->isRequired() && $this->hasOptional) {
116
            throw new \LogicException('Cannot add a required argument after an optional one.');
117
        }
118
119
        if ($argument->isArray()) {
120
            $this->hasAnArrayArgument = true;
121
        }
122
123
        if ($argument->isRequired()) {
124
            ++$this->requiredCount;
125
        } else {
126
            $this->hasOptional = true;
127
        }
128
129
        $this->arguments[$argument->getName()] = $argument;
130
    }
131
132
    /**
133
     * Returns an InputArgument by name or by position.
134
     *
135
     * @param string|int $name The InputArgument name or position
136
     *
137
     * @return InputArgument An InputArgument object
138
     *
139
     * @throws \InvalidArgumentException When argument given doesn't exist
140
     */
141
    public function getArgument($name)
142
    {
143
        if (!$this->hasArgument($name)) {
144
            throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
145
        }
146
147
        $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
148
149
        return $arguments[$name];
150
    }
151
152
    /**
153
     * Returns true if an InputArgument object exists by name or position.
154
     *
155
     * @param string|int $name The InputArgument name or position
156
     *
157
     * @return bool true if the InputArgument object exists, false otherwise
158
     */
159
    public function hasArgument($name)
160
    {
161
        $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
162
163
        return isset($arguments[$name]);
164
    }
165
166
    /**
167
     * Gets the array of InputArgument objects.
168
     *
169
     * @return InputArgument[] An array of InputArgument objects
170
     */
171
    public function getArguments()
172
    {
173
        return $this->arguments;
174
    }
175
176
    /**
177
     * Returns the number of InputArguments.
178
     *
179
     * @return int The number of InputArguments
180
     */
181
    public function getArgumentCount()
182
    {
183
        return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);
184
    }
185
186
    /**
187
     * Returns the number of required InputArguments.
188
     *
189
     * @return int The number of required InputArguments
190
     */
191
    public function getArgumentRequiredCount()
192
    {
193
        return $this->requiredCount;
194
    }
195
196
    /**
197
     * Gets the default values.
198
     *
199
     * @return array An array of default values
200
     */
201
    public function getArgumentDefaults()
202
    {
203
        $values = array();
204
        foreach ($this->arguments as $argument) {
205
            $values[$argument->getName()] = $argument->getDefault();
206
        }
207
208
        return $values;
209
    }
210
211
    /**
212
     * Sets the InputOption objects.
213
     *
214
     * @param InputOption[] $options An array of InputOption objects
215
     */
216
    public function setOptions($options = array())
217
    {
218
        $this->options = array();
219
        $this->shortcuts = array();
220
        $this->addOptions($options);
221
    }
222
223
    /**
224
     * Adds an array of InputOption objects.
225
     *
226
     * @param InputOption[] $options An array of InputOption objects
227
     */
228
    public function addOptions($options = array())
229
    {
230
        foreach ($options as $option) {
231
            $this->addOption($option);
232
        }
233
    }
234
235
    /**
236
     * Adds an InputOption object.
237
     *
238
     * @param InputOption $option An InputOption object
239
     *
240
     * @throws \LogicException When option given already exist
241
     */
242
    public function addOption(InputOption $option)
243
    {
244
        if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
245
            throw new \LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
246
        }
247
248
        if ($option->getShortcut()) {
249
            foreach (explode('|', $option->getShortcut()) as $shortcut) {
250
                if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) {
251
                    throw new \LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut));
252
                }
253
            }
254
        }
255
256
        $this->options[$option->getName()] = $option;
257
        if ($option->getShortcut()) {
258
            foreach (explode('|', $option->getShortcut()) as $shortcut) {
259
                $this->shortcuts[$shortcut] = $option->getName();
260
            }
261
        }
262
    }
263
264
    /**
265
     * Returns an InputOption by name.
266
     *
267
     * @param string $name The InputOption name
268
     *
269
     * @return InputOption A InputOption object
270
     *
271
     * @throws \InvalidArgumentException When option given doesn't exist
272
     */
273
    public function getOption($name)
274
    {
275
        if (!$this->hasOption($name)) {
276
            throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
277
        }
278
279
        return $this->options[$name];
280
    }
281
282
    /**
283
     * Returns true if an InputOption object exists by name.
284
     *
285
     * @param string $name The InputOption name
286
     *
287
     * @return bool true if the InputOption object exists, false otherwise
288
     */
289
    public function hasOption($name)
290
    {
291
        return isset($this->options[$name]);
292
    }
293
294
    /**
295
     * Gets the array of InputOption objects.
296
     *
297
     * @return InputOption[] An array of InputOption objects
298
     */
299
    public function getOptions()
300
    {
301
        return $this->options;
302
    }
303
304
    /**
305
     * Returns true if an InputOption object exists by shortcut.
306
     *
307
     * @param string $name The InputOption shortcut
308
     *
309
     * @return bool true if the InputOption object exists, false otherwise
310
     */
311
    public function hasShortcut($name)
312
    {
313
        return isset($this->shortcuts[$name]);
314
    }
315
316
    /**
317
     * Gets an InputOption by shortcut.
318
     *
319
     * @param string $shortcut the Shortcut name
320
     *
321
     * @return InputOption An InputOption object
322
     */
323
    public function getOptionForShortcut($shortcut)
324
    {
325
        return $this->getOption($this->shortcutToName($shortcut));
326
    }
327
328
    /**
329
     * Gets an array of default values.
330
     *
331
     * @return array An array of all default values
332
     */
333
    public function getOptionDefaults()
334
    {
335
        $values = array();
336
        foreach ($this->options as $option) {
337
            $values[$option->getName()] = $option->getDefault();
338
        }
339
340
        return $values;
341
    }
342
343
    /**
344
     * Returns the InputOption name given a shortcut.
345
     *
346
     * @param string $shortcut The shortcut
347
     *
348
     * @return string The InputOption name
349
     *
350
     * @throws \InvalidArgumentException When option given does not exist
351
     */
352
    private function shortcutToName($shortcut)
353
    {
354
        if (!isset($this->shortcuts[$shortcut])) {
355
            throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
356
        }
357
358
        return $this->shortcuts[$shortcut];
359
    }
360
361
    /**
362
     * Gets the synopsis.
363
     *
364
     * @param bool $short Whether to return the short version (with options folded) or not
365
     *
366
     * @return string The synopsis
367
     */
368
    public function getSynopsis($short = false)
369
    {
370
        $elements = array();
371
372
        if ($short && $this->getOptions()) {
373
            $elements[] = '[options]';
374
        } elseif (!$short) {
375
            foreach ($this->getOptions() as $option) {
376
                $value = '';
377
                if ($option->acceptValue()) {
378
                    $value = sprintf(
379
                        ' %s%s%s',
380
                        $option->isValueOptional() ? '[' : '',
381
                        strtoupper($option->getName()),
382
                        $option->isValueOptional() ? ']' : ''
383
                    );
384
                }
385
386
                $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
387
                $elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value);
388
            }
389
        }
390
391
        if (count($elements) && $this->getArguments()) {
392
            $elements[] = '[--]';
393
        }
394
395
        foreach ($this->getArguments() as $argument) {
396
            $element = '<'.$argument->getName().'>';
397
            if (!$argument->isRequired()) {
398
                $element = '['.$element.']';
399
            } elseif ($argument->isArray()) {
400
                $element = $element.' ('.$element.')';
401
            }
402
403
            if ($argument->isArray()) {
404
                $element .= '...';
405
            }
406
407
            $elements[] = $element;
408
        }
409
410
        return implode(' ', $elements);
411
    }
412
413
    /**
414
     * Returns a textual representation of the InputDefinition.
415
     *
416
     * @return string A string representing the InputDefinition
417
     *
418
     * @deprecated since version 2.3, to be removed in 3.0.
419
     */
420
    public function asText()
421
    {
422
        @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
423
424
        $descriptor = new TextDescriptor();
425
        $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
426
        $descriptor->describe($output, $this, array('raw_output' => true));
427
428
        return $output->fetch();
429
    }
430
431
    /**
432
     * Returns an XML representation of the InputDefinition.
433
     *
434
     * @param bool $asDom Whether to return a DOM or an XML string
435
     *
436
     * @return string|\DOMDocument An XML string representing the InputDefinition
437
     *
438
     * @deprecated since version 2.3, to be removed in 3.0.
439
     */
440
    public function asXml($asDom = false)
441
    {
442
        @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
443
444
        $descriptor = new XmlDescriptor();
445
446
        if ($asDom) {
447
            return $descriptor->getInputDefinitionDocument($this);
448
        }
449
450
        $output = new BufferedOutput();
451
        $descriptor->describe($output, $this);
452
453
        return $output->fetch();
454
    }
455
}
456