Completed
Push — master ( 4b74f6...76160a )
by Todd
12s
created

CompilerBuffer::createCompilerException()   D

Complexity

Conditions 10
Paths 22

Size

Total Lines 38
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 10

Importance

Changes 0
Metric Value
dl 0
loc 38
ccs 22
cts 22
cp 1
rs 4.8196
c 0
b 0
f 0
cc 10
eloc 25
nc 22
nop 3
crap 10

How to fix   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
 * @author Todd Burry <[email protected]>
4
 * @copyright 2009-2017 Vanilla Forums Inc.
5
 * @license MIT
6
 */
7
8
namespace Ebi;
9
10
11
use Symfony\Component\ExpressionLanguage\SyntaxError;
12
13
class CompilerBuffer {
14
    const STYLE_JOIN = 'join';
15
    const STYLE_ARRAY = 'array';
16
17
    /**
18
     * @var ComponentBuffer[]
19
     */
20
    private $buffers;
21
22
    /**
23
     * @var ComponentBuffer
24
     */
25
    private $current;
26
27
    private $currentName;
28
29
    private $basename;
30
31
    private $style = self::STYLE_JOIN;
32
33
    private $source;
34
35
    private $path;
36
37
    /**
38
     * @var array
39
     */
40
    private $defaults;
41
42
    /**
43
     * @var \SplObjectStorage
44
     */
45
    private $nodeProps;
46
47 64
    public function __construct($style = self::STYLE_JOIN, array $defaults = []) {
48
        $defaults += [
49 64
            'baseIndent' => 0
50
        ];
51
52 64
        $this->buffers = [];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
53 64
        $this->nodeProps = new \SplObjectStorage();
54 64
        $this->style = $style;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
55 64
        $this->defaults = $defaults;
56 64
        $this->select('');
57 64
    }
58
59
    /**
60
     * Select a specific component buffer.
61
     * @param $component
62
     */
63 64
    public function select($component) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
64 64
        $previous = $this->currentName;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
65 64
        $this->currentName = $component;
66
67 64
        if (!array_key_exists($component, $this->buffers)) {
68 64
            $this->buffers[$component] = $buffer = new ComponentBuffer($this->defaults);
0 ignored issues
show
Unused Code introduced by
$buffer is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
69
        }
70
71 64
        $this->current =& $this->buffers[$component];
72
73 64
        return $previous;
74
    }
75
76 58
    public function echoLiteral($value) {
77 58
        $this->current->echoLiteral($value);
78 58
    }
79
80 44
    public function echoCode($php) {
81 44
        $this->current->echoCode($php);
82 44
    }
83
84 64
    public function appendCode($php) {
85 64
        $this->current->appendCode($php);
86 64
    }
87
88 64
    public function indent($add) {
89 64
        $this->current->indent($add);
90 64
    }
91
92 20
    public function depth($add = 1) {
93 20
        $this->current->depth($add);
94 20
    }
95
96 21
    public function depthName($name, $add = 0) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
97 21
        return $this->current->depthName($name, $add);
98
    }
99
100 64
    public function pushScope(array $vars) {
101 64
        $this->current->pushScope($vars);
102 64
    }
103
104 57
    public function popScope() {
105 57
        $this->current->popScope();
106 57
    }
107
108 56
    public function getScopeVariables() {
109 56
        return $this->current->getScopeVariables();
110
    }
111
112 57
    public function flush() {
113 57
        switch ($this->getStyle()) {
114 57
            case self::STYLE_ARRAY:
115 11
                return $this->flushArray();
116
            default:
117 57
                return $this->flushJoin();
118
        }
119
    }
120
121
    private function flushJoin() {
122 57
        return implode("\n\n", array_map(function ($buffer) {
123
            /* @var ComponentBuffer $buffer */
124 57
            return $buffer->flush();
125 57
        }, $this->buffers));
126
    }
127
128 11
    private function flushArray() {
129 11
        $result = [];
130
131 11
        foreach ($this->buffers as $name => $buffer) {
132 11
            $flushed = $buffer->flush();
133 11
            if (empty($flushed)) {
134 9
                continue;
135
            }
136
137 3
            if ($name === '') {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $name (integer) and '' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
138 3
                $result[] = $flushed;
139
            } else {
140 3
                $result[] = var_export($name, true).' => '.$flushed;
141
            }
142
        }
143
144 11
        if (empty($result)) {
145 9
            return '[]';
146
        } else {
147 3
            return "[\n".implode(",\n\n", $result)."\n".$this->px().']';
148
        }
149
    }
150
151 3
    protected function px($add = 0) {
152 3
        return str_repeat(' ', ($this->defaults['baseIndent'] + $add) * 4);
153
    }
154
155
    /**
156
     * Get the style.
157
     *
158
     * @return string Returns the style.
159
     */
160 57
    public function getStyle() {
161 57
        return $this->style;
162
    }
163
164
    /**
165
     * Set the style.
166
     *
167
     * @param string $style One of the **STYLE_*** constants.
168
     * @return $this
169
     */
170
    public function setStyle($style) {
171
        $this->style = $style;
172
        return $this;
173
    }
174
175
    /**
176
     * Get the basename.
177
     *
178
     * @return string Returns the basename.
179
     */
180
    public function getBasename() {
181
        return $this->basename;
182
    }
183
184
    /**
185
     * Set the basename.
186
     *
187
     * @param string $basename
188
     * @return $this
189
     */
190 64
    public function setBasename($basename) {
191 64
        $this->basename = $basename;
192 64
        return $this;
193
    }
194
195 64
    public function getNodeProp(\DOMNode $node, $name, $default = null) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
196 64
        if (!$this->nodeProps->contains($node) || !array_key_exists($name, $this->nodeProps[$node])) {
197 64
            return $default;
198
        }
199 5
        return $this->nodeProps[$node][$name];
200
    }
201
202 32
    public function setNodeProp(\DOMNode $node = null, $name, $value) {
203 32
        if ($node === null) {
204 19
            return $this;
205
        }
206
207 15
        if (!$this->nodeProps->contains($node)) {
208 15
            $this->nodeProps->attach($node, [$name => $value]);
209
        }
210
211 15
        $this->nodeProps[$node] = [$name => $value] + $this->nodeProps[$node];
212 15
        return $this;
213
    }
214
215 11
    public function getIndent() {
216 11
        return $this->current->getIndent();
217
    }
218
219 11
    public function getDepth() {
220 11
        return $this->current->getDepth();
221
    }
222
223
    public function getScope() {
224
        return $this->current->getScope();
225
    }
226
227 11
    public function getAllScopes() {
228 11
        return $this->current->getAllScopes();
229
    }
230
231
    /**
232
     * Create a new **CompileException** with proper context.
233
     *
234
     * @param \DOMNode $node The node that has the error.
235
     * @param \Exception $ex The exception that represents the low-level error.
236
     * @param array $context Custom context information for the exception.
237
     * @return CompileException Returns a new exception that can be thrown.
238
     */
239 7
    public function createCompilerException(\DOMNode $node, \Exception $ex, array $context = []) {
240
        $result = $context + [
241 7
            'path' => $this->getPath(),
242 7
            'source' => '',
243
            'sourcePosition' => null,
244 7
            'line' => $node->getLineNo(),
245
            'lines' => []
246
        ];
247 7
        $message = $ex->getMessage();
248
249 7
        if ($ex instanceof SyntaxError) {
250 3
            list($error, $position) = $this->splitSyntaxError($ex);
0 ignored issues
show
Unused Code introduced by
The assignment to $error is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
251 3
            $result['source'] = $result['source'] ?: ($node instanceof \DOMAttr ? $node->value : $node->nodeValue);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 7 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
252 3
            if (!isset($context['sourcePosition'])) {
253 3
                $result['sourcePosition'] = $position;
254
            }
255 4
        } elseif (empty($result['source'])) {
256 4
            if ($node instanceof \DOMAttr) {
257 3
                $result['source'] = $node->name.'="'.$node->value.'"';
258
            }
259
        }
260
261 7
        if (!empty($this->source)) {
262 7
            $allLines = explode("\n", $this->source);
263
264 7
            $lines = [];
265 7
            $line = $result['line'];
266 7
            for ($i = max(0, $line - 4); $i < $line + 3; $i++) {
267 7
                if (isset($allLines[$i])) {
268 7
                    $lines[$i + 1] = $allLines[$i];
269
                }
270
            }
271
272 7
            $result['lines'] = $lines;
273
        }
274
275 7
        return new CompileException($message, $result, $ex);
276
    }
277
278 3
    private function splitSyntaxError(SyntaxError $ex) {
279 3
        if (preg_match('`^(.*) around position (.*)\.$`', $ex->getMessage(), $m)) {
280 3
            return [$m[1], $m[2]];
281
        } else {
282
            return [$ex->getMessage(), 0];
283
        }
284
    }
285
286
    /**
287
     * Get the source.
288
     *
289
     * @return mixed Returns the source.
290
     */
291
    public function getSource() {
292
        return $this->source;
293
    }
294
295
    /**
296
     * Set the source.
297
     *
298
     * @param mixed $source
299
     * @return $this
300
     */
301 64
    public function setSource($source) {
302 64
        $this->source = $source;
303 64
        return $this;
304
    }
305
306
    /**
307
     * Get the path.
308
     *
309
     * @return mixed Returns the path.
310
     */
311 7
    public function getPath() {
312 7
        return $this->path;
313
    }
314
315
    /**
316
     * Set the path.
317
     *
318
     * @param mixed $path
319
     * @return $this
320
     */
321 64
    public function setPath($path) {
322 64
        $this->path = $path;
323 64
        return $this;
324
    }
325
}
326