PhpDependTask::main()   F
last analyzed

Complexity

Conditions 15
Paths 962

Size

Total Lines 79
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 240

Importance

Changes 0
Metric Value
eloc 40
c 0
b 0
f 0
dl 0
loc 79
ccs 0
cts 43
cp 0
rs 1.8027
cc 15
nc 962
nop 0
crap 240

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the LGPL. For more information please see
18
 * <http://phing.info>.
19
 */
20
21
namespace Phing\Task\Ext\Analyzer\Pdepend;
22
23
use PDepend\Application;
24
use PDepend\Util\Log;
25
use Phing\Exception\BuildException;
26
use Phing\Io\File;
27
use Phing\Task;
28
use Phing\Type\Element\FileSetAware;
29
use Phing\Util\StringHelper;
30
31
/**
32
 * Runs the PHP_Depend software analyzer and metric tool.
33
 * Performs static code analysis on a given source base.
34
 *
35
 * @package phing.tasks.ext.pdepend
36
 * @author  Benjamin Schultz <[email protected]>
37
 * @since   2.4.1
38
 */
39
class PhpDependTask extends Task
40
{
41
    use FileSetAware;
42
43
    /**
44
     * A php source code filename or directory
45
     *
46
     * @var File
47
     */
48
    protected $file = null;
49
50
    /**
51
     * List of allowed file extensions. Default file extensions are <b>php</b>
52
     * and <p>php5</b>.
53
     *
54
     * @var array<string>
55
     */
56
    protected $allowedFileExtensions = ['php', 'php5'];
57
58
    /**
59
     * List of exclude directories. Default exclude dirs are <b>.git</b>,
60
     * <b>.svn</b> and <b>CVS</b>.
61
     *
62
     * @var array<string>
63
     */
64
    protected $excludeDirectories = ['.git', '.svn', 'CVS'];
65
66
    /**
67
     * List of exclude packages
68
     *
69
     * @var array<string>
70
     */
71
    protected $excludePackages = [];
72
73
    /**
74
     * Should the parse ignore doc comment annotations?
75
     *
76
     * @var boolean
77
     */
78
    protected $withoutAnnotations = false;
79
80
    /**
81
     * Should PHP_Depend treat <b>+global</b> as a regular project package?
82
     *
83
     * @var boolean
84
     */
85
    protected $supportBadDocumentation = false;
86
87
    /**
88
     * Flag for enable/disable debugging
89
     *
90
     * @var boolean
91
     */
92
    protected $debug = false;
93
94
    /**
95
     * PHP_Depend configuration file
96
     *
97
     * @var File
98
     */
99
    protected $configFile = null;
100
101
    /**
102
     * Logger elements
103
     *
104
     * @var PhpDependLoggerElement[]
105
     */
106
    protected $loggers = [];
107
108
    /**
109
     * Analyzer elements
110
     *
111
     * @var PhpDependAnalyzerElement[]
112
     */
113
    protected $analyzers = [];
114
115
    /**
116
     * Flag that determines whether to halt on error
117
     *
118
     * @var boolean
119
     */
120
    protected $haltonerror = false;
121
122
    /**
123
     * @var bool
124
     */
125
    private $oldVersion = false;
126
127
    /**
128
     * @var string
129
     */
130
    protected $pharLocation = "";
131
132
    /**
133
     * Load the necessary environment for running PHP_Depend
134
     *
135
     * @throws BuildException
136
     */
137
    protected function requireDependencies()
138
    {
139
        if (!empty($this->pharLocation)) {
140
            // nasty but necessary: reorder the autoloaders so the one in the PHAR gets priority
141
            $autoloadFunctions = spl_autoload_functions();
142
            $composerAutoloader = null;
143
            if (get_class($autoloadFunctions[0][0]) === 'Composer\Autoload\ClassLoader') {
144
                $composerAutoloader = $autoloadFunctions[0];
145
                spl_autoload_unregister($composerAutoloader);
146
            }
147
148
            $GLOBALS['_SERVER']['SCRIPT_NAME'] = '-';
149
            ob_start();
150
            include_once 'phar://' . $this->pharLocation . '/vendor/autoload.php';
151
            ob_end_clean();
152
153
            if ($composerAutoloader !== null) {
154
                spl_autoload_register($composerAutoloader);
155
            }
156
        }
157
158
        // check 2.x version (composer/phar)
159
        if (class_exists('PDepend\\TextUI\\Runner')) {
160
            return;
161
        }
162
163
        throw new BuildException("This task requires PDepend 2.x", $this->getLocation());
164
    }
165
166
    /**
167
     * Set the input source file or directory
168
     *
169
     * @param File $file The input source file or directory
170
     */
171
    public function setFile(File $file)
172
    {
173
        $this->file = $file;
174
    }
175
176
    /**
177
     * Sets a list of filename extensions for valid php source code files
178
     *
179
     * @param string $fileExtensions List of valid file extensions
180
     */
181
    public function setAllowedFileExtensions($fileExtensions)
182
    {
183
        $this->allowedFileExtensions = [];
184
185
        $token = ' ,;';
186
        $ext = strtok($fileExtensions, $token);
187
188
        while ($ext !== false) {
189
            $this->allowedFileExtensions[] = $ext;
190
            $ext = strtok($token);
191
        }
192
    }
193
194
    /**
195
     * Sets a list of exclude directories
196
     *
197
     * @param string $excludeDirectories List of exclude directories
198
     */
199
    public function setExcludeDirectories($excludeDirectories)
200
    {
201
        $this->excludeDirectories = [];
202
203
        $token = ' ,;';
204
        $pattern = strtok($excludeDirectories, $token);
205
206
        while ($pattern !== false) {
207
            $this->excludeDirectories[] = $pattern;
208
            $pattern = strtok($token);
209
        }
210
    }
211
212
    /**
213
     * Sets a list of exclude packages
214
     *
215
     * @param string $excludePackages Exclude packages
216
     */
217
    public function setExcludePackages($excludePackages)
218
    {
219
        $this->excludePackages = [];
220
221
        $token = ' ,;';
222
        $pattern = strtok($excludePackages, $token);
223
224
        while ($pattern !== false) {
225
            $this->excludePackages[] = $pattern;
226
            $pattern = strtok($token);
227
        }
228
    }
229
230
    /**
231
     * Should the parser ignore doc comment annotations?
232
     *
233
     * @param boolean $withoutAnnotations
234
     */
235
    public function setWithoutAnnotations($withoutAnnotations)
236
    {
237
        $this->withoutAnnotations = StringHelper::booleanValue($withoutAnnotations);
238
    }
239
240
    /**
241
     * Should PHP_Depend support projects with a bad documentation. If this
242
     * option is set to <b>true</b>, PHP_Depend will treat the default package
243
     * <b>+global</b> as a regular project package.
244
     *
245
     * @param boolean $supportBadDocumentation
246
     */
247
    public function setSupportBadDocumentation($supportBadDocumentation)
248
    {
249
        $this->supportBadDocumentation = StringHelper::booleanValue($supportBadDocumentation);
250
    }
251
252
    /**
253
     * Set debugging On/Off
254
     *
255
     * @param boolean $debug
256
     */
257
    public function setDebug($debug)
258
    {
259
        $this->debug = StringHelper::booleanValue($debug);
260
    }
261
262
    /**
263
     * Set halt on error
264
     *
265
     * @param boolean $haltonerror
266
     */
267
    public function setHaltonerror($haltonerror)
268
    {
269
        $this->haltonerror = StringHelper::booleanValue($haltonerror);
270
    }
271
272
    /**
273
     * Set the configuration file
274
     *
275
     * @param File $configFile The configuration file
276
     */
277
    public function setConfigFile(File $configFile)
278
    {
279
        $this->configFile = $configFile;
280
    }
281
282
    /**
283
     * Create object for nested logger element
284
     *
285
     * @return PhpDependLoggerElement
286
     */
287
    public function createLogger()
288
    {
289
        $num = array_push($this->loggers, new PhpDependLoggerElement());
290
291
        return $this->loggers[$num - 1];
292
    }
293
294
    /**
295
     * Create object for nested analyzer element
296
     *
297
     * @return PhpDependAnalyzerElement
298
     */
299
    public function createAnalyzer()
300
    {
301
        $num = array_push($this->analyzers, new PhpDependAnalyzerElement());
302
303
        return $this->analyzers[$num - 1];
304
    }
305
306
    /**
307
     * @param string $pharLocation
308
     */
309
    public function setPharLocation($pharLocation)
310
    {
311
        $this->pharLocation = $pharLocation;
312
    }
313
314
    /**
315
     * Executes PHP_Depend_TextUI_Runner against PhingFile or a FileSet
316
     *
317
     * @throws BuildException
318
     */
319
    public function main()
320
    {
321
        $this->requireDependencies();
322
323
        if (!isset($this->file) and count($this->filesets) == 0) {
324
            throw new BuildException('Missing either a nested fileset or attribute "file" set');
325
        }
326
327
        if (count($this->loggers) == 0) {
328
            throw new BuildException('Missing nested "logger" element');
329
        }
330
331
        $this->validateLoggers();
332
        $this->validateAnalyzers();
333
334
        $filesToParse = $this->getFilesToParse();
335
336
        $runner = $this->createRunner();
337
        $runner->setSourceArguments($filesToParse);
338
339
        foreach ($this->loggers as $logger) {
340
            // Register logger
341
            if ($this->oldVersion) {
342
                $runner->addLogger(
343
                    $logger->getType(),
344
                    $logger->getOutfile()->__toString()
345
                );
346
            } else {
347
                $runner->addReportGenerator(
348
                    $logger->getType(),
349
                    $logger->getOutfile()->__toString()
350
                );
351
            }
352
        }
353
354
        foreach ($this->analyzers as $analyzer) {
355
            // Register additional analyzer
356
            $runner->addOption(
357
                $analyzer->getType(),
358
                $analyzer->getValue()
359
            );
360
        }
361
362
        // Disable annotation parsing
363
        if ($this->withoutAnnotations) {
364
            $runner->setWithoutAnnotations();
365
        }
366
367
        // Enable bad documentation support
368
        if ($this->supportBadDocumentation) {
369
            $runner->setSupportBadDocumentation();
370
        }
371
372
        // Check for suffix
373
        if (count($this->allowedFileExtensions) > 0) {
374
            $runner->setFileExtensions($this->allowedFileExtensions);
375
        }
376
377
        // Check for ignore directories
378
        if (count($this->excludeDirectories) > 0) {
379
            $runner->setExcludeDirectories($this->excludeDirectories);
380
        }
381
382
        // Check for exclude packages
383
        if (count($this->excludePackages) > 0) {
384
            $runner->setExcludePackages($this->excludePackages);
385
        }
386
387
        $runner->run();
388
389
        if ($runner->hasParseErrors() === true) {
390
            $this->log('Following errors occurred:');
391
392
            foreach ($runner->getParseErrors() as $error) {
393
                $this->log($error);
394
            }
395
396
            if ($this->haltonerror === true) {
397
                throw new BuildException('Errors occurred during parse process');
398
            }
399
        }
400
    }
401
402
    /**
403
     * Validates the available loggers
404
     *
405
     * @throws BuildException
406
     */
407
    protected function validateLoggers()
408
    {
409
        foreach ($this->loggers as $logger) {
410
            if ($logger->getType() === '') {
411
                throw new BuildException('Logger missing required "type" attribute');
412
            }
413
414
            if ($logger->getOutfile() === null) {
415
                throw new BuildException('Logger requires "outfile" attribute');
416
            }
417
        }
418
    }
419
420
    /**
421
     * Validates the available analyzers
422
     *
423
     * @throws BuildException
424
     */
425
    protected function validateAnalyzers()
426
    {
427
        foreach ($this->analyzers as $analyzer) {
428
            if ($analyzer->getType() === '') {
429
                throw new BuildException('Analyzer missing required "type" attribute');
430
            }
431
432
            if (count($analyzer->getValue()) === 0) {
0 ignored issues
show
Bug introduced by
$analyzer->getValue() of type string is incompatible with the type Countable|array expected by parameter $value of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

432
            if (count(/** @scrutinizer ignore-type */ $analyzer->getValue()) === 0) {
Loading history...
433
                throw new BuildException('Analyzer missing required "value" attribute');
434
            }
435
        }
436
    }
437
438
    /**
439
     * @return array
440
     */
441
    private function getFilesToParse()
442
    {
443
        $filesToParse = [];
444
445
        if ($this->file instanceof File) {
0 ignored issues
show
introduced by
$this->file is always a sub-type of Phing\Io\File.
Loading history...
446
            $filesToParse[] = $this->file->__toString();
447
            return $filesToParse;
448
        }
449
450
        // append any files in filesets
451
        foreach ($this->filesets as $fs) {
452
            $files = $fs->getDirectoryScanner($this->project)->getIncludedFiles();
453
454
            foreach ($files as $filename) {
455
                $f = new File($fs->getDir($this->project), $filename);
456
                $filesToParse[] = $f->getAbsolutePath();
457
            }
458
        }
459
        return $filesToParse;
460
    }
461
462
    /**
463
     * @return object
464
     */
465
    private function createRunner()
466
    {
467
        $application = new Application();
468
469
        if (!empty($this->configFile)) {
470
            if (file_exists($this->configFile->__toString()) === false) {
471
                throw new BuildException(
472
                    'The configuration file "' . $this->configFile->__toString() . '" doesn\'t exist.'
473
                );
474
            }
475
476
            $application->setConfigurationFile($this->configFile);
477
        }
478
479
        $runner = $application->getRunner();
480
481
        if ($this->debug) {
482
            // Enable debug logging
483
            Log::setSeverity(1);
484
        }
485
486
        return $runner;
487
    }
488
}
489