CommandLineOptions::getCoverageReport()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
1
<?php
2
/**
3
 * This file is part of PHP Mess Detector.
4
 *
5
 * Copyright (c) Manuel Pichler <[email protected]>.
6
 * All rights reserved.
7
 *
8
 * Licensed under BSD License
9
 * For full copyright and license information, please see the LICENSE file.
10
 * Redistributions of files must retain the above copyright notice.
11
 *
12
 * @author Manuel Pichler <[email protected]>
13
 * @copyright Manuel Pichler. All rights reserved.
14
 * @license https://opensource.org/licenses/bsd-license.php BSD License
15
 * @link http://phpmd.org/
16
 */
17
18
namespace PHPMD\TextUI;
19
20
use PHPMD\Renderer\HTMLRenderer;
21
use PHPMD\Renderer\JSONRenderer;
22
use PHPMD\Renderer\TextRenderer;
23
use PHPMD\Renderer\XMLRenderer;
24
use PHPMD\Rule;
25
26
/**
27
 * This is a helper class that collects the specified cli arguments and puts them
28
 * into accessible properties.
29
 */
30
class CommandLineOptions
31
{
32
    /**
33
     * Error code for invalid input
34
     */
35
    const INPUT_ERROR = 23;
36
37
    /**
38
     * The minimum rule priority.
39
     *
40
     * @var integer
41
     */
42
    protected $minimumPriority = Rule::LOWEST_PRIORITY;
43
44
    /**
45
     * The maximum rule priority.
46
     *
47
     * @var integer
48
     */
49
    protected $maximumPriority = Rule::HIGHEST_PRIORITY;
50
51
    /**
52
     * A php source code filename or directory.
53
     *
54
     * @var string
55
     */
56
    protected $inputPath;
57
58
    /**
59
     * The specified report format.
60
     *
61
     * @var string
62
     */
63
    protected $reportFormat;
64
65
    /**
66
     * An optional filename for the generated report.
67
     *
68
     * @var string
69
     */
70
    protected $reportFile;
71
72
    /**
73
     * Additional report files.
74
     *
75
     * @var array
76
     */
77
    protected $reportFiles = array();
78
79
    /**
80
     * A ruleset filename or a comma-separated string of ruleset filenames.
81
     *
82
     * @var string
83
     */
84
    protected $ruleSets;
85
86
    /**
87
     * File name of a PHPUnit code coverage report.
88
     *
89
     * @var string
90
     */
91
    protected $coverageReport;
92
93
    /**
94
     * A string of comma-separated extensions for valid php source code filenames.
95
     *
96
     * @var string
97
     */
98
    protected $extensions;
99
100
    /**
101
     * A string of comma-separated pattern that is used to exclude directories.
102
     *
103
     * @var string
104
     */
105
    protected $ignore;
106
107
    /**
108
     * Should the shell show the current phpmd version?
109
     *
110
     * @var boolean
111
     */
112
    protected $version = false;
113
114
    /**
115
     * Should PHPMD run in strict mode?
116
     *
117
     * @var boolean
118
     * @since 1.2.0
119
     */
120
    protected $strict = false;
121
122
    /**
123
     * Should PHPMD exit without error code even if violation is found?
124
     *
125
     * @var boolean
126
     */
127
    protected $ignoreViolationsOnExit = false;
128
129
    /**
130
     * List of available rule-sets.
131
     *
132
     * @var array(string)
133
     */
134
    protected $availableRuleSets = array();
135
136
    /**
137
     * Constructs a new command line options instance.
138
     *
139
     * @param array $args
140
     * @param array $availableRuleSets
141
     * @throws \InvalidArgumentException
142
     */
143 40
    public function __construct(array $args, array $availableRuleSets = array())
144
    {
145
        // Remove current file name
146 40
        array_shift($args);
147
148 40
        $this->availableRuleSets = $availableRuleSets;
149
150 40
        $arguments = array();
151 40
        while (($arg = array_shift($args)) !== null) {
152 40
            switch ($arg) {
153
                case '--min-priority':
154
                case '--minimum-priority':
155
                case '--minimumpriority':
156 1
                    $this->minimumPriority = (int)array_shift($args);
157 1
                    break;
158
                case '--max-priority':
159
                case '--maximum-priority':
160
                case '--maximumpriority':
161 1
                    $this->maximumPriority = (int)array_shift($args);
162 1
                    break;
163
                case '--report-file':
164
                case '--reportfile':
165 4
                    $this->reportFile = array_shift($args);
166 4
                    break;
167
                case '--input-file':
168
                case '--inputfile':
169 6
                    array_unshift($arguments, $this->readInputFile(array_shift($args)));
170 5
                    break;
171
                case '--coverage':
172 1
                    $this->coverageReport = array_shift($args);
173 1
                    break;
174
                case '--extensions':
175 1
                    $this->logDeprecated('extensions', 'suffixes');
176
                    /* Deprecated: We use the suffixes option now */
177 1
                    $this->extensions = array_shift($args);
178 1
                    break;
179
                case '--suffixes':
180
                    $this->extensions = array_shift($args);
181
                    break;
182
                case '--ignore':
183 1
                    $this->logDeprecated('ignore', 'exclude');
184
                    /* Deprecated: We use the exclude option now */
185 1
                    $this->ignore = array_shift($args);
186 1
                    break;
187
                case '--exclude':
188
                    $this->ignore = array_shift($args);
189
                    break;
190
                case '--version':
191 1
                    $this->version = true;
192
193 1
                    return;
194
                case '--strict':
195 1
                    $this->strict = true;
196 1
                    break;
197
                case '--not-strict':
198
                    $this->strict = false;
199
                    break;
200
                case '--ignore-violations-on-exit':
201 1
                    $this->ignoreViolationsOnExit = true;
202 1
                    break;
203
                case '--reportfile-html':
204
                case '--reportfile-text':
205
                case '--reportfile-xml':
206
                case '--reportfile-json':
207 4
                    preg_match('(^\-\-reportfile\-(xml|html|text|json)$)', $arg, $match);
208 4
                    $this->reportFiles[$match[1]] = array_shift($args);
209 4
                    break;
210
                default:
211 39
                    $arguments[] = $arg;
212 39
                    break;
213
            }
214
        }
215
216 38
        if (count($arguments) < 3) {
217 1
            throw new \InvalidArgumentException($this->usage(), self::INPUT_ERROR);
218
        }
219
220 37
        $this->inputPath = (string)array_shift($arguments);
221 37
        $this->reportFormat = (string)array_shift($arguments);
222 37
        $this->ruleSets = (string)array_shift($arguments);
223 37
    }
224
225
    /**
226
     * Returns a php source code filename or directory.
227
     *
228
     * @return string
229
     */
230 6
    public function getInputPath()
231
    {
232 6
        return $this->inputPath;
233
    }
234
235
    /**
236
     * Returns the specified report format.
237
     *
238
     * @return string
239
     */
240 2
    public function getReportFormat()
241
    {
242 2
        return $this->reportFormat;
243
    }
244
245
    /**
246
     * Returns the output filename for a generated report or <b>null</b> when
247
     * the report should be displayed in STDOUT.
248
     *
249
     * @return string
250
     */
251 4
    public function getReportFile()
252
    {
253 4
        return $this->reportFile;
254
    }
255
256
    /**
257
     * Returns a hash with report files specified for different renderers. The
258
     * key represents the report format and the value the report file location.
259
     *
260
     * @return array
261
     */
262 8
    public function getReportFiles()
263
    {
264 8
        return $this->reportFiles;
265
    }
266
267
    /**
268
     * Returns a ruleset filename or a comma-separated string of ruleset
269
     *
270
     * @return string
271
     */
272 6
    public function getRuleSets()
273
    {
274 6
        return $this->ruleSets;
275
    }
276
277
    /**
278
     * Returns the minimum rule priority.
279
     *
280
     * @return integer
281
     */
282 6
    public function getMinimumPriority()
283
    {
284 6
        return $this->minimumPriority;
285
    }
286
287
    /**
288
     * Returns the maximum rule priority.
289
     *
290
     * @return integer
291
     */
292 5
    public function getMaximumPriority()
293
    {
294 5
        return $this->maximumPriority;
295
    }
296
297
    /**
298
     * Returns the file name of a supplied code coverage report or <b>NULL</b>
299
     * if the user has not supplied the --coverage option.
300
     *
301
     * @return string
302
     */
303 6
    public function getCoverageReport()
304
    {
305 6
        return $this->coverageReport;
306
    }
307
308
    /**
309
     * Returns a string of comma-separated extensions for valid php source code
310
     * filenames or <b>null</b> when this argument was not set.
311
     *
312
     * @return string
313
     */
314 4
    public function getExtensions()
315
    {
316 4
        return $this->extensions;
317
    }
318
319
    /**
320
     * Returns  string of comma-separated pattern that is used to exclude
321
     * directories or <b>null</b> when this argument was not set.
322
     *
323
     * @return string
324
     */
325 4
    public function getIgnore()
326
    {
327 4
        return $this->ignore;
328
    }
329
330
    /**
331
     * Was the <b>--version</b> passed to PHPMD's command line interface?
332
     *
333
     * @return boolean
334
     */
335 6
    public function hasVersion()
336
    {
337 6
        return $this->version;
338
    }
339
340
    /**
341
     * Was the <b>--strict</b> option passed to PHPMD's command line interface?
342
     *
343
     * @return boolean
344
     * @since 1.2.0
345
     */
346 6
    public function hasStrict()
347
    {
348 6
        return $this->strict;
349
    }
350
351
    /**
352
     * Was the <b>--ignore-violations-on-exit</b> passed to PHPMD's command line interface?
353
     *
354
     * @return boolean
355
     */
356 6
    public function ignoreViolationsOnExit()
357
    {
358 6
        return $this->ignoreViolationsOnExit;
359
    }
360
361
    /**
362
     * Creates a report renderer instance based on the user's command line
363
     * argument.
364
     *
365
     * Valid renderers are:
366
     * <ul>
367
     *   <li>xml</li>
368
     *   <li>html</li>
369
     *   <li>text</li>
370
     *   <li>json</li>
371
     * </ul>
372
     *
373
     * @param string $reportFormat
374
     * @return \PHPMD\AbstractRenderer
375
     * @throws \InvalidArgumentException When the specified renderer does not exist.
376
     */
377 12
    public function createRenderer($reportFormat = null)
378
    {
379 12
        $reportFormat = $reportFormat ?: $this->reportFormat;
380
381 12
        switch ($reportFormat) {
382
            case 'xml':
383 1
                return $this->createXmlRenderer();
384
            case 'html':
385 1
                return $this->createHtmlRenderer();
386
            case 'text':
387 5
                return $this->createTextRenderer();
388
            case 'json':
389
                return $this->createJsonRenderer();
390
            default:
391 5
                return $this->createCustomRenderer();
392
        }
393
    }
394
395
    /**
396
     * @return \PHPMD\Renderer\XMLRenderer
397
     */
398 1
    protected function createXmlRenderer()
399
    {
400 1
        return new XMLRenderer();
401
    }
402
403
    /**
404
     * @return \PHPMD\Renderer\TextRenderer
405
     */
406 5
    protected function createTextRenderer()
407
    {
408 5
        return new TextRenderer();
409
    }
410
411
    /**
412
     * @return \PHPMD\Renderer\HTMLRenderer
413
     */
414 1
    protected function createHtmlRenderer()
415
    {
416 1
        return new HTMLRenderer();
417
    }
418
419
    /**
420
     * @return \PHPMD\Renderer\JSONRenderer
421
     */
422
    protected function createJsonRenderer()
423
    {
424
        return new JSONRenderer();
425
    }
426
427
    /**
428
     * @return \PHPMD\AbstractRenderer
429
     * @throws \InvalidArgumentException
430
     */
431 5
    protected function createCustomRenderer()
432
    {
433 5
        if ('' === $this->reportFormat) {
434 1
            throw new \InvalidArgumentException(
435 1
                'Can\'t create report with empty format.',
436 1
                self::INPUT_ERROR
437
            );
438
        }
439
440 4
        if (class_exists($this->reportFormat)) {
441 1
            return new $this->reportFormat();
442
        }
443
444
        // Try to load a custom renderer
445 3
        $fileName = strtr($this->reportFormat, '_\\', '//') . '.php';
446
447 3
        $fileHandle = @fopen($fileName, 'r', true);
448 3
        if (is_resource($fileHandle) === false) {
449 1
            throw new \InvalidArgumentException(
450 1
                sprintf(
451 1
                    'Can\'t find the custom report class: %s',
452 1
                    $this->reportFormat
453
                ),
454 1
                self::INPUT_ERROR
455
            );
456
        }
457 2
        @fclose($fileHandle);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
458
459 2
        include_once $fileName;
460
461 2
        return new $this->reportFormat();
462
    }
463
464
    /**
465
     * Returns usage information for the PHPMD command line interface.
466
     *
467
     * @return string
468
     */
469 4
    public function usage()
470
    {
471 4
        $availableRenderers = $this->getListOfAvailableRenderers();
472
473
        return 'Mandatory arguments:' . \PHP_EOL .
474
            '1) A php source code filename or directory. Can be a comma-' .
475
            'separated string' . \PHP_EOL .
476
            '2) A report format' . \PHP_EOL .
477
            '3) A ruleset filename or a comma-separated string of ruleset' .
478
            'filenames' . \PHP_EOL . \PHP_EOL .
479 4
            'Available formats: ' . $availableRenderers . '.' . \PHP_EOL .
480 4
            'Available rulesets: ' . implode(', ', $this->availableRuleSets) . '.' . \PHP_EOL . \PHP_EOL .
481 4
            'Optional arguments that may be put after the mandatory arguments:' .
482 4
            \PHP_EOL .
483 4
            '--minimumpriority: rule priority threshold; rules with lower ' .
484 4
            'priority than this will not be used' . \PHP_EOL .
485 4
            '--reportfile: send report output to a file; default to STDOUT' .
486 4
            \PHP_EOL .
487 4
            '--suffixes: comma-separated string of valid source code ' .
488 4
            'filename extensions, e.g. php,phtml' . \PHP_EOL .
489 4
            '--exclude: comma-separated string of patterns that are used to ' .
490 4
            'ignore directories' . \PHP_EOL .
491 4
            '--strict: also report those nodes with a @SuppressWarnings ' .
492 4
            'annotation' . \PHP_EOL .
493 4
            '--ignore-violations-on-exit: will exit with a zero code, ' .
494 4
            'even if any violations are found' . \PHP_EOL;
495
    }
496
497
    /**
498
     * Get a list of available renderers
499
     *
500
     * @return string The list of renderers found.
501
     */
502 4
    protected function getListOfAvailableRenderers()
503
    {
504 4
        $renderersDirPathName=__DIR__.'/../Renderer';
505 4
        $renderers = array();
506
507 4
        foreach (scandir($renderersDirPathName) as $rendererFileName) {
508 4
            if (preg_match('/^(\w+)Renderer.php$/i', $rendererFileName, $rendererName)) {
509 4
                $renderers[] =  strtolower($rendererName[1]);
510
            }
511
        }
512
513 4
        sort($renderers);
514
515 4
        if (count($renderers) > 1) {
516 4
            return implode(', ', $renderers);
517
        }
518
519
        return array_pop($list);
520
    }
521
522
    /**
523
     * Logs a deprecated option to the current user interface.
524
     *
525
     * @param string $deprecatedName
526
     * @param string $newName
527
     * @return void
528
     */
529 2
    protected function logDeprecated($deprecatedName, $newName)
530
    {
531 2
        $message = sprintf(
532 2
            'The --%s option is deprecated, please use --%s instead.',
533 2
            $deprecatedName,
534 2
            $newName
535
        );
536
537 2
        fwrite(STDERR, $message . PHP_EOL . PHP_EOL);
538 2
    }
539
540
    /**
541
     * This method takes the given input file, reads the newline separated paths
542
     * from that file and creates a comma separated string of the file paths. If
543
     * the given <b>$inputFile</b> not exists, this method will throw an
544
     * exception.
545
     *
546
     * @param string $inputFile Specified input file name.
547
     * @return string
548
     * @throws \InvalidArgumentException If the specified input file does not exist.
549
     * @since 1.1.0
550
     */
551 6
    protected function readInputFile($inputFile)
552
    {
553 6
        if (file_exists($inputFile)) {
554 5
            return join(',', array_map('trim', file($inputFile)));
555
        }
556 1
        throw new \InvalidArgumentException("Input file '{$inputFile}' not exists.");
557
    }
558
}
559