Completed
Push — master ( 20b0ec...0fa80a )
by Siad
15:26
created

PhpLintTask::lint()   D

Complexity

Conditions 16
Paths 198

Size

Total Lines 68
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 20.6676

Importance

Changes 0
Metric Value
cc 16
eloc 39
c 0
b 0
f 0
nc 198
nop 1
dl 0
loc 68
ccs 28
cts 38
cp 0.7368
crap 20.6676
rs 4.75

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
 * 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
/**
21
 * A PHP lint task. Checking syntax of one or more PHP source file.
22
 *
23
 * @author  Knut Urdalen <[email protected]>
24
 * @author  Stefan Priebsch <[email protected]>
25
 * @package phing.tasks.ext
26
 */
27
class PhpLintTask extends Task
28
{
29
    use FileSetAware;
30
    use LogLevelAware;
31
32
    protected $file; // the source file (from xml attribute)
33
34
    protected $errorProperty;
35
    protected $haltOnFailure = false;
36
    protected $hasErrors = false;
37
    protected $badFiles = [];
38
    protected $interpreter = ''; // php interpreter to use for linting
39
40
    protected $cache = null;
41
42
    protected $tofile = null;
43
44
    protected $deprecatedAsError = false;
45
46
    /**
47
     * Initialize the interpreter with the Phing property php.interpreter
48
     */
49 4
    public function init()
50
    {
51 4
        $this->setInterpreter($this->project->getProperty('php.interpreter'));
52 4
    }
53
54
    /**
55
     * Override default php interpreter
56
     *
57
     * @todo  Do some sort of checking if the path is correct but would
58
     *          require traversing the systems executeable path too
59
     * @param string $sPhp
60
     */
61 4
    public function setInterpreter($sPhp)
62
    {
63 4
        if (strpos($sPhp, ' ') !== false) {
64
            $sPhp = escapeshellarg($sPhp);
65
        }
66 4
        $this->interpreter = $sPhp;
67 4
    }
68
69
    /**
70
     * The haltonfailure property
71
     *
72
     * @param boolean $aValue
73
     */
74 2
    public function setHaltOnFailure($aValue)
75
    {
76 2
        $this->haltOnFailure = $aValue;
77 2
    }
78
79
    /**
80
     * File to be performed syntax check on
81
     *
82
     * @param PhingFile $file
83
     */
84 2
    public function setFile(PhingFile $file)
85
    {
86 2
        $this->file = $file;
87 2
    }
88
89
    /**
90
     * Set an property name in which to put any errors.
91
     *
92
     * @param string $propname
93
     */
94
    public function setErrorproperty($propname)
95
    {
96
        $this->errorProperty = $propname;
97
    }
98
99
    /**
100
     * Whether to store last-modified times in cache
101
     *
102
     * @param PhingFile $file
103
     */
104
    public function setCacheFile(PhingFile $file)
105
    {
106
        $this->cache = new DataStore($file);
107
    }
108
109
    /**
110
     * File to save error messages to
111
     *
112
     * @param    PhingFile $tofile
113
     * @internal param PhingFile $file
114
     */
115
    public function setToFile(PhingFile $tofile)
116
    {
117
        $this->tofile = $tofile;
118
    }
119
120
    /**
121
     * Sets whether to treat deprecated warnings (introduced in PHP 5.3) as errors
122
     *
123
     * @param boolean $deprecatedAsError
124
     */
125 1
    public function setDeprecatedAsError($deprecatedAsError)
126
    {
127 1
        $this->deprecatedAsError = $deprecatedAsError;
128 1
    }
129
130
    /**
131
     * Execute lint check against PhingFile or a FileSet
132
     */
133 4
    public function main()
134
    {
135 4
        if (!isset($this->file) and count($this->filesets) == 0) {
136
            throw new BuildException("Missing either a nested fileset or attribute 'file' set");
137
        }
138
139 4
        if ($this->file instanceof PhingFile) {
140 2
            $this->lint($this->file->getPath());
141
        } else { // process filesets
142 2
            $project = $this->getProject();
143 2
            foreach ($this->filesets as $fs) {
144 2
                $ds = $fs->getDirectoryScanner($project);
145 2
                $files = $ds->getIncludedFiles();
146 2
                $dir = $fs->getDir($this->project)->getPath();
147 2
                foreach ($files as $file) {
148 2
                    $this->lint($dir . DIRECTORY_SEPARATOR . $file);
149
                }
150
            }
151
        }
152
153
        // write list of 'bad files' to file (if specified)
154 4
        if ($this->tofile) {
155
            $writer = new FileWriter($this->tofile);
156
157
            foreach ($this->badFiles as $file => $messages) {
158
                foreach ($messages as $msg) {
159
                    $writer->write($file . "=" . $msg . PHP_EOL);
160
                }
161
            }
162
163
            $writer->close();
164
        }
165
166 4
        $message = '';
167 4
        foreach ($this->badFiles as $file => $messages) {
168 2
            foreach ($messages as $msg) {
169 2
                $message .= $file . "=" . $msg . PHP_EOL;
170
            }
171
        }
172
173
        // save list of 'bad files' with errors to property errorproperty (if specified)
174 4
        if ($this->errorProperty) {
175
            $this->project->setProperty($this->errorProperty, $message);
176
        }
177
178 4
        if (!empty($this->cache)) {
179
            $this->cache->commit();
180
        }
181
182 4
        if ($this->haltOnFailure && $this->hasErrors) {
183 1
            throw new BuildException('Syntax error(s) in PHP files: ' . $message);
184
        }
185 3
    }
186
187
    /**
188
     * Performs the actual syntax check
189
     *
190
     * @param  string $file
191
     * @throws BuildException
192
     */
193 4
    protected function lint($file)
194
    {
195 4
        $command = $this->interpreter == ''
196
            ? 'php'
197 4
            : $this->interpreter;
198
199 4
        if (strpos($command, 'hhvm') !== false) {
200
            $command .= ' --no-config -l';
201
        } else {
202 4
            if ($this->deprecatedAsError) {
203 1
                $command .= ' -d error_reporting=32767 ';
204
            }
205
206 4
            $command .= ' -n -l ';
207
        }
208
209 4
        if (!file_exists($file)) {
210
            throw new BuildException('File not found: ' . $file);
211
        }
212
213 4
        if (!is_readable($file)) {
214
            throw new BuildException('Permission denied: ' . $file);
215
        }
216
217 4
        if ($this->cache) {
218
            $lastmtime = $this->cache->get($file);
219
220
            if ($lastmtime >= filemtime($file)) {
221
                $this->log("Not linting '" . $file . "' due to cache", Project::MSG_DEBUG);
222
223
                return;
224
            }
225
        }
226
227 4
        $messages = [];
228 4
        $errorCount = 0;
229
230 4
        exec($command . '"' . $file . '" 2>&1', $messages);
231
232 4
        for ($i = 0, $messagesCount = count($messages); $i < $messagesCount; $i++) {
233 4
            $message = $messages[$i];
234 4
            if (trim($message) == '') {
235 2
                continue;
236
            }
237
238
            if (
239 4
                (!preg_match('/^(.*)Deprecated:/', $message) ||
240
                    $this->deprecatedAsError) &&
241 4
                !preg_match('/^No syntax errors detected/', $message)
242
            ) {
243 2
                $this->log($message, Project::MSG_ERR);
244
245 2
                if (!isset($this->badFiles[$file])) {
246 2
                    $this->badFiles[$file] = [];
247
                }
248
249 2
                $this->badFiles[$file][] = $message;
250
251 2
                $this->hasErrors = true;
252 2
                $errorCount++;
253
            }
254
        }
255
256 4
        if (!$errorCount) {
257 2
            $this->log($file . ': No syntax errors detected', $this->logLevel);
258
259 2
            if ($this->cache) {
260
                $this->cache->put($file, filemtime($file));
261
            }
262
        }
263 4
    }
264
}
265