Completed
Push — master ( aebb60...558ce3 )
by Todd
12s
created

CompilerBuffer::createCompilerException()   C

Complexity

Conditions 8
Paths 18

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 8

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 33
ccs 18
cts 18
cp 1
rs 5.3846
cc 8
eloc 21
nc 18
nop 3
crap 8
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 57
    public function __construct($style = self::STYLE_JOIN, array $defaults = []) {
48
        $defaults += [
49 57
            'baseIndent' => 0
50
        ];
51
52 57
        $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 57
        $this->nodeProps = new \SplObjectStorage();
54 57
        $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 57
        $this->defaults = $defaults;
56 57
        $this->select('');
57 57
    }
58
59
    /**
60
     * Select a specific component buffer.
61
     * @param $component
62
     */
63 57
    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 57
        $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 57
        $this->currentName = $component;
66
67 57
        if (!array_key_exists($component, $this->buffers)) {
68 57
            $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 57
        $this->current =& $this->buffers[$component];
72
73 57
        return $previous;
74
    }
75
76 53
    public function echoLiteral($value) {
77 53
        $this->current->echoLiteral($value);
78 53
    }
79
80 42
    public function echoCode($php) {
81 42
        $this->current->echoCode($php);
82 42
    }
83
84 57
    public function appendCode($php) {
85 57
        $this->current->appendCode($php);
86 57
    }
87
88 57
    public function indent($add) {
89 57
        $this->current->indent($add);
90 57
    }
91
92 18
    public function depth($add = 1) {
93 18
        $this->current->depth($add);
94 18
    }
95
96 18
    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 18
        return $this->current->depthName($name, $add);
98
    }
99
100 57
    public function pushScope(array $vars) {
101 57
        $this->current->pushScope($vars);
102 57
    }
103
104 54
    public function popScope() {
105 54
        $this->current->popScope();
106 54
    }
107
108 52
    public function getScopeVariables() {
109 52
        return $this->current->getScopeVariables();
110
    }
111
112 54
    public function flush() {
113 54
        switch ($this->getStyle()) {
114 54
            case self::STYLE_ARRAY:
115 11
                return $this->flushArray();
116
            default:
117 54
                return $this->flushJoin();
118
        }
119
    }
120
121
    private function flushJoin() {
122 54
        return implode("\n\n", array_map(function ($buffer) {
123
            /* @var ComponentBuffer $buffer */
124 54
            return $buffer->flush();
125 54
        }, $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 54
    public function getStyle() {
161 54
        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 57
    public function setBasename($basename) {
191 57
        $this->basename = $basename;
192 57
        return $this;
193
    }
194
195 57
    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 57
        if (!$this->nodeProps->contains($node) || !array_key_exists($name, $this->nodeProps[$node])) {
197 57
            return $default;
198
        }
199 4
        return $this->nodeProps[$node][$name];
200
    }
201
202 21
    public function setNodeProp(\DOMNode $node = null, $name, $value) {
203 21
        if ($node === null) {
204 17
            return $this;
205
        }
206
207 4
        if (!$this->nodeProps->contains($node)) {
208 4
            $this->nodeProps->attach($node, [$name => $value]);
209
        }
210
211 4
        $this->nodeProps[$node] = [$name => $value] + $this->nodeProps[$node];
212 4
        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 3
    public function createCompilerException(\DOMNode $node, \Exception $ex, array $context = []) {
240
        $result = $context + [
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 13 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...
241 3
            'path' => $this->getPath(),
242 3
            'source' => '',
243
            'sourcePosition' => null,
244 3
            'line' => $line = $node->getLineNo(),
245
            'lines' => []
246
        ];
247 3
        $message = $ex->getMessage();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 12 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...
248
249 3
        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
        }
256
257 3
        if (!empty($this->source)) {
258 3
            $allLines = explode("\n", $this->source);
259
260 3
            $lines = [];
261 3
            for ($i = max(0, $line - 3); $i < $line + 2; $i++) {
262 3
                if (isset($allLines[$i])) {
263 3
                    $lines[$i + 1] = $allLines[$i];
264
                }
265
            }
266
267 3
            $result['lines'] = $lines;
268
        }
269
270 3
        return new CompileException($message, $result, $ex);
271
    }
272
273 3
    private function splitSyntaxError(SyntaxError $ex) {
274 3
        if (preg_match('`^(.*) around position (.*)\.$`', $ex->getMessage(), $m)) {
275 3
            return [$m[1], $m[2]];
276
        } else {
277
            return [$ex->getMessage(), 0];
278
        }
279
    }
280
281
    /**
282
     * Get the source.
283
     *
284
     * @return mixed Returns the source.
285
     */
286
    public function getSource() {
287
        return $this->source;
288
    }
289
290
    /**
291
     * Set the source.
292
     *
293
     * @param mixed $source
294
     * @return $this
295
     */
296 57
    public function setSource($source) {
297 57
        $this->source = $source;
298 57
        return $this;
299
    }
300
301
    /**
302
     * Get the path.
303
     *
304
     * @return mixed Returns the path.
305
     */
306 3
    public function getPath() {
307 3
        return $this->path;
308
    }
309
310
    /**
311
     * Set the path.
312
     *
313
     * @param mixed $path
314
     * @return $this
315
     */
316 57
    public function setPath($path) {
317 57
        $this->path = $path;
318 57
        return $this;
319
    }
320
}
321