PhpTalLint   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 252
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 2 Features 0
Metric Value
wmc 32
c 2
b 2
f 0
lcom 1
cbo 2
dl 0
loc 252
ccs 0
cts 115
cp 0
rs 9.6

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 21 3
A setOptions() 0 8 3
C execute() 0 39 8
B lintItem() 0 14 7
B lintDirectory() 0 23 5
A lintFile() 0 47 3
A getFlags() 0 14 3
1
<?php
2
/**
3
 * PHPCI - Continuous Integration for PHP.
4
 *
5
 * @copyright    Copyright 2014, Block 8 Limited.
6
 * @license      https://github.com/Block8/PHPCI/blob/master/LICENSE.md
7
 *
8
 * @link         https://www.phptesting.org/
9
 */
10
11
namespace PHPCI\Plugin;
12
13
use PHPCI;
14
use PHPCI\Builder;
15
use PHPCI\Model\Build;
16
17
/**
18
 * PHPTAL Lint Plugin - Provides access to PHPTAL lint functionality.
19
 *
20
 * @author       Stephen Ball <[email protected]>
21
 */
22
class PhpTalLint implements PHPCI\Plugin
23
{
24
    protected $directories;
25
    protected $recursive = true;
26
    protected $suffixes;
27
    protected $ignore;
28
29
    /**
30
     * @var \PHPCI\Builder
31
     */
32
    protected $phpci;
33
34
    /**
35
     * @var \PHPCI\Model\Build
36
     */
37
    protected $build;
38
39
    /**
40
     * @var string The path to a file contain custom phptal_tales_ functions
41
     */
42
    protected $tales;
43
44
    /**
45
     * @var int
46
     */
47
    protected $allowed_warnings;
48
49
    /**
50
     * @var int
51
     */
52
    protected $allowed_errors;
53
54
    /**
55
     * @var array The results of the lint scan
56
     */
57
    protected $failedPaths = array();
58
59
    /**
60
     * Standard Constructor.
61
     *
62
     * @param Builder $phpci
63
     * @param Build   $build
64
     * @param array   $options
65
     */
66
    public function __construct(Builder $phpci, Build $build, array $options = array())
67
    {
68
        $this->phpci = $phpci;
69
        $this->build = $build;
70
        $this->directories = array('');
71
        $this->suffixes = array('zpt');
72
        $this->ignore = $phpci->ignore;
73
74
        $this->allowed_warnings = 0;
75
        $this->allowed_errors = 0;
76
77
        if (!empty($options['directory'])) {
78
            $this->directories = array($options['directory']);
79
        }
80
81
        if (isset($options['suffixes'])) {
82
            $this->suffixes = (array) $options['suffixes'];
83
        }
84
85
        $this->setOptions($options);
86
    }
87
88
    /**
89
     * Handle this plugin's options.
90
     *
91
     * @param $options
92
     */
93
    protected function setOptions($options)
94
    {
95
        foreach (array('directories', 'tales', 'allowed_warnings', 'allowed_errors') as $key) {
96
            if (array_key_exists($key, $options)) {
97
                $this->{$key} = $options[$key];
98
            }
99
        }
100
    }
101
102
    /**
103
     * Executes phptal lint.
104
     */
105
    public function execute()
106
    {
107
        $this->phpci->quiet = true;
108
        $this->phpci->logExecOutput(false);
109
110
        foreach ($this->directories as $dir) {
111
            $this->lintDirectory($dir);
112
        }
113
114
        $this->phpci->quiet = false;
115
        $this->phpci->logExecOutput(true);
116
117
        $errors = 0;
118
        $warnings = 0;
119
120
        foreach ($this->failedPaths as $path) {
121
            if ($path['type'] == 'error') {
122
                ++$errors;
123
            } else {
124
                ++$warnings;
125
            }
126
        }
127
128
        $this->build->storeMeta('phptallint-warnings', $warnings);
129
        $this->build->storeMeta('phptallint-errors', $errors);
130
        $this->build->storeMeta('phptallint-data', $this->failedPaths);
131
132
        $success = true;
133
134
        if ($this->allowed_warnings != -1 && $warnings > $this->allowed_warnings) {
135
            $success = false;
136
        }
137
138
        if ($this->allowed_errors != -1 && $errors > $this->allowed_errors) {
139
            $success = false;
140
        }
141
142
        return $success;
143
    }
144
145
    /**
146
     * Lint an item (file or directory) by calling the appropriate method.
147
     *
148
     * @param $item
149
     * @param $itemPath
150
     *
151
     * @return bool
152
     */
153
    protected function lintItem($item, $itemPath)
154
    {
155
        $success = true;
156
157
        if ($item->isFile() && in_array(strtolower($item->getExtension()), $this->suffixes)) {
158
            if (!$this->lintFile($itemPath)) {
159
                $success = false;
160
            }
161
        } elseif ($item->isDir() && $this->recursive && !$this->lintDirectory($itemPath.DIRECTORY_SEPARATOR)) {
162
            $success = false;
163
        }
164
165
        return $success;
166
    }
167
168
    /**
169
     * Run phptal lint against a directory of files.
170
     *
171
     * @param $path
172
     *
173
     * @return bool
174
     */
175
    protected function lintDirectory($path)
176
    {
177
        $success = true;
178
        $directory = new \DirectoryIterator($this->phpci->buildPath.$path);
179
180
        foreach ($directory as $item) {
181
            if ($item->isDot()) {
182
                continue;
183
            }
184
185
            $itemPath = $path.$item->getFilename();
186
187
            if (in_array($itemPath, $this->ignore)) {
188
                continue;
189
            }
190
191
            if (!$this->lintItem($item, $itemPath)) {
192
                $success = false;
193
            }
194
        }
195
196
        return $success;
197
    }
198
199
    /**
200
     * Run phptal lint against a specific file.
201
     *
202
     * @param $path
203
     *
204
     * @return bool
205
     */
206
    protected function lintFile($path)
207
    {
208
        $success = true;
209
210
        list($suffixes, $tales) = $this->getFlags();
211
212
        $lint = dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR;
213
        $lint .= 'vendor'.DIRECTORY_SEPARATOR.'phptal'.DIRECTORY_SEPARATOR.'phptal'.DIRECTORY_SEPARATOR;
214
        $lint .= 'tools'.DIRECTORY_SEPARATOR.'phptal_lint.php';
215
        $cmd = '/usr/bin/env php '.$lint.' %s %s "%s"';
216
217
        $this->phpci->executeCommand($cmd, $suffixes, $tales, $this->phpci->buildPath.$path);
218
219
        $output = $this->phpci->getLastOutput();
220
221
        if (preg_match('/Found (.+?) (error|warning)/i', $output, $matches)) {
222
            $rows = explode(PHP_EOL, $output);
223
224
            unset($rows[0]);
225
            unset($rows[1]);
226
            unset($rows[2]);
227
            unset($rows[3]);
228
229
            foreach ($rows as $row) {
230
                $name = basename($path);
231
232
                $row = str_replace('(use -i to include your custom modifier functions)', '', $row);
233
                $message = str_replace($name.': ', '', $row);
234
235
                $parts = explode(' (line ', $message);
236
237
                $message = trim($parts[0]);
238
                $line = str_replace(')', '', $parts[1]);
239
240
                $this->failedPaths[] = array(
241
                    'file' => $path,
242
                    'line' => $line,
243
                    'type' => $matches[2],
244
                    'message' => $message,
245
                );
246
            }
247
248
            $success = false;
249
        }
250
251
        return $success;
252
    }
253
254
    /**
255
     * Process options and produce an arguments string for PHPTAL Lint.
256
     *
257
     * @return array
258
     */
259
    protected function getFlags()
260
    {
261
        $tales = '';
262
        if (!empty($this->tales)) {
263
            $tales = ' -i '.$this->phpci->buildPath.$this->tales;
264
        }
265
266
        $suffixes = '';
267
        if (count($this->suffixes)) {
268
            $suffixes = ' -e '.implode(',', $this->suffixes);
269
        }
270
271
        return array($suffixes, $tales);
272
    }
273
}
274