Passed
Push — master ( d62b89...abb8c8 )
by Michiel
06:34
created

PHPMDTask::loadDependencies()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.5923

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 11
dl 0
loc 22
ccs 8
cts 12
cp 0.6667
rs 9.9
c 1
b 0
f 0
cc 4
nc 6
nop 0
crap 4.5923
1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19
20
use Phing\Exception\BuildException;
21
use Phing\Io\File;
22
use Phing\Task;
23
use Phing\Type\Element\FileSetAware;
24
use Phing\Util\DataStore;
25
use PHPMD\AbstractRule;
26
use PHPMD\RuleSetFactory;
27
28
/**
29
 * Runs PHP Mess Detector. Checking PHP files for several potential problems
30
 * based on rulesets.
31
 *
32
 * @package phing.tasks.ext.phpmd
33
 * @author  Benjamin Schultz <[email protected]>
34
 * @since   2.4.1
35
 */
36
class PHPMDTask extends Task
37
{
38
    use FileSetAware;
39
40
    /**
41
     * A php source code filename or directory
42
     *
43
     * @var File
44
     */
45
    protected $file = null;
46
47
    /**
48
     * The rule-set filenames or identifier.
49
     *
50
     * @var string
51
     */
52
    protected $rulesets = 'codesize,unusedcode';
53
54
    /**
55
     * The minimum priority for rules to load.
56
     *
57
     * @var integer
58
     */
59
    protected $minimumPriority = 0;
60
61
    /**
62
     * List of valid file extensions for analyzed files.
63
     *
64
     * @var array
65
     */
66
    protected $allowedFileExtensions = ['php'];
67
68
    /**
69
     * List of exclude directory patterns.
70
     *
71
     * @var array
72
     */
73
    protected $ignorePatterns = ['.git', '.svn', 'CVS', '.bzr', '.hg'];
74
75
    /**
76
     * The format for the report
77
     *
78
     * @var string
79
     */
80
    protected $format = 'text';
81
82
    /**
83
     * Formatter elements.
84
     *
85
     * @var PHPMDFormatterElement[]
86
     */
87
    protected $formatters = [];
88
89
    /**
90
     * @var string
91
     */
92
    protected $pharLocation = "";
93
94
    /**
95
     * Cache data storage
96
     *
97
     * @var DataStore
98
     */
99
    protected $cache;
100
101
    /**
102
     * Set the input source file or directory.
103
     *
104
     * @param File $file The input source file or directory.
105
     */
106
    public function setFile(File $file)
107
    {
108
        $this->file = $file;
109
    }
110
111
    /**
112
     * Sets the minimum rule priority.
113
     *
114
     * @param integer $minimumPriority Minimum rule priority.
115
     */
116
    public function setMinimumPriority($minimumPriority)
117
    {
118
        $this->minimumPriority = $minimumPriority;
119
    }
120
121
    /**
122
     * Sets the rule-sets.
123
     *
124
     * @param string $ruleSetFileNames Comma-separated string of rule-set filenames or identifier.
125
     */
126
    public function setRulesets($ruleSetFileNames)
127
    {
128
        $this->rulesets = $ruleSetFileNames;
129
    }
130
131
    /**
132
     * Sets a list of filename extensions for valid php source code files.
133
     *
134
     * @param string $fileExtensions List of valid file extensions without leading dot.
135
     */
136
    public function setAllowedFileExtensions($fileExtensions)
137
    {
138
        $this->allowedFileExtensions = [];
139
140
        $token = ' ,;';
141
        $ext = strtok($fileExtensions, $token);
142
143
        while ($ext !== false) {
144
            $this->allowedFileExtensions[] = $ext;
145
            $ext = strtok($token);
146
        }
147
    }
148
149
    /**
150
     * Sets a list of ignore patterns that is used to exclude directories from the source analysis.
151
     *
152
     * @param string $ignorePatterns List of ignore patterns.
153
     */
154
    public function setIgnorePatterns($ignorePatterns)
155
    {
156
        $this->ignorePatterns = [];
157
158
        $token = ' ,;';
159
        $pattern = strtok($ignorePatterns, $token);
160
161
        while ($pattern !== false) {
162
            $this->ignorePatterns[] = $pattern;
163
            $pattern = strtok($token);
164
        }
165
    }
166
167
    /**
168
     * Create object for nested formatter element.
169
     *
170
     * @return PHPMDFormatterElement
171
     */
172 3
    public function createFormatter()
173
    {
174 3
        $num = array_push($this->formatters, new PHPMDFormatterElement());
175
176 3
        return $this->formatters[$num - 1];
177
    }
178
179
    /**
180
     * @param string $format
181
     */
182
    public function setFormat($format)
183
    {
184
        $this->format = $format;
185
    }
186
187
    /**
188
     * @param string $pharLocation
189
     */
190
    public function setPharLocation($pharLocation)
191
    {
192
        $this->pharLocation = $pharLocation;
193
    }
194
195
    /**
196
     * Whether to store last-modified times in cache
197
     *
198
     * @param File $file
199
     */
200
    public function setCacheFile(File $file)
201
    {
202
        $this->cache = new DataStore($file);
203
    }
204
205
    /**
206
     * Find PHPMD
207
     *
208
     * @return string
209
     * @throws BuildException
210
     */
211 3
    protected function loadDependencies()
212
    {
213 3
        if (!empty($this->pharLocation)) {
214
            include_once 'phar://' . $this->pharLocation . '/vendor/autoload.php';
215
        }
216
217 3
        $className = '\PHPMD\PHPMD';
218
219 3
        if (!class_exists($className)) {
220
            throw new BuildException(
221
                'PHPMDTask depends on PHPMD being installed and on include_path or listed in pharLocation.',
222
                $this->getLocation()
223
            );
224
        }
225
226 3
        $minPriority = AbstractRule::LOWEST_PRIORITY;
227
228 3
        if (!$this->minimumPriority) {
229 3
            $this->minimumPriority = $minPriority;
230
        }
231
232 3
        return $className;
233
    }
234
235
    /**
236
     * Return the list of files to parse
237
     *
238
     * @return string[] list of absolute files to parse
239
     */
240 3
    protected function getFilesToParse()
241
    {
242 3
        $filesToParse = [];
243
244 3
        if ($this->file instanceof File) {
0 ignored issues
show
introduced by
$this->file is always a sub-type of Phing\Io\File.
Loading history...
245
            $filesToParse[] = $this->file->getPath();
246
        } else {
247
            // append any files in filesets
248 3
            foreach ($this->filesets as $fs) {
249 3
                $dir = $fs->getDir($this->project)->getAbsolutePath();
250 3
                foreach ($fs->getDirectoryScanner($this->project)->getIncludedFiles() as $filename) {
251 3
                    $fileAbsolutePath = $dir . DIRECTORY_SEPARATOR . $filename;
252 3
                    if ($this->cache) {
253
                        $lastMTime = $this->cache->get($fileAbsolutePath);
254
                        $currentMTime = filemtime($fileAbsolutePath);
255
                        if ($lastMTime >= $currentMTime) {
256
                            continue;
257
                        }
258
259
                        $this->cache->put($fileAbsolutePath, $currentMTime);
260
                    }
261 3
                    $filesToParse[] = $fileAbsolutePath;
262
                }
263
            }
264
        }
265 3
        return $filesToParse;
266
    }
267
268
    /**
269
     * Executes PHPMD against PhingFile or a FileSet
270
     *
271
     * @throws BuildException - if the phpmd classes can't be loaded.
272
     */
273 3
    public function main()
274
    {
275 3
        $className = $this->loadDependencies();
276
277 3
        if (!isset($this->file) and count($this->filesets) == 0) {
278
            throw new BuildException('Missing either a nested fileset or attribute "file" set');
279
        }
280
281 3
        if (count($this->formatters) == 0) {
282
            // turn legacy format attribute into formatter
283
            $fmt = new PHPMDFormatterElement();
284
            $fmt->setType($this->format);
285
            $fmt->setUseFile(false);
286
287
            $this->formatters[] = $fmt;
288
        }
289
290 3
        $reportRenderers = [];
291
292 3
        foreach ($this->formatters as $fe) {
293 3
            if ($fe->getType() == '') {
294
                throw new BuildException('Formatter missing required "type" attribute.');
295
            }
296
297 3
            if ($fe->getUsefile() && $fe->getOutfile() === null) {
298
                throw new BuildException('Formatter requires "outfile" attribute when "useFile" is true.');
299
            }
300
301 3
            $reportRenderers[] = $fe->getRenderer();
302
        }
303
304 3
        if ($this->cache) {
305
            $reportRenderers[] = new PHPMDRendererRemoveFromCache($this->cache);
306
        } else {
307 3
            $this->cache = null; // cache not compatible to old version
308
        }
309
310
        // Create a rule set factory
311 3
        $ruleSetFactory = new RuleSetFactory();
312 3
        $ruleSetFactory->setMinimumPriority($this->minimumPriority);
313
314
        /**
315
         * @var PHPMD\PHPMD $phpmd
316
         */
317 3
        $phpmd = new $className();
318 3
        $phpmd->setFileExtensions($this->allowedFileExtensions);
319 3
        $phpmd->setIgnorePattern($this->ignorePatterns);
320
321 3
        $filesToParse = $this->getFilesToParse();
322
323 3
        if (count($filesToParse) > 0) {
324 3
            $inputPath = implode(',', $filesToParse);
325
326 3
            $this->log('Processing files...');
327
328 3
            $phpmd->processFiles($inputPath, $this->rulesets, $reportRenderers, $ruleSetFactory);
329
330 3
            if ($this->cache) {
331
                $this->cache->commit();
332
            }
333
334 3
            $this->log('Finished processing files');
335
        } else {
336
            $this->log('No files to process');
337
        }
338 3
    }
339
}
340