CompilerBuffer::getPath()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
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 78
    public function __construct($style = self::STYLE_JOIN, array $defaults = []) {
48
        $defaults += [
49
            'baseIndent' => 0
50 78
        ];
51
52 78
        $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 78
        $this->nodeProps = isset($defaults['nodeProps']) ? $defaults['nodeProps'] : new \SplObjectStorage();
54 78
        $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 78
        $this->defaults = $defaults;
56 78
        $this->select('');
57 78
    }
58
59
    /**
60
     * Select a specific component buffer.
61
     * @param string $component The name of the component to select.
62
     * @param bool $add Whether to add a new component if there is already a compile buffer with the same name.
63
     */
64 78
    public function select($component, $add = false) {
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...
65 78
        $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...
66 78
        $this->currentName = $component;
67
68 78
        if (!array_key_exists($component, $this->buffers)) {
69 78
            $this->buffers[$component] = $buffer = new ComponentBuffer($this->defaults);
70 78
        } elseif ($add) {
71 1
            if (is_array($this->buffers[$component])) {
72
                $this->buffers[$component][] = $buffer = new ComponentBuffer($this->defaults);
73
            } else {
74 1
                $this->buffers[$component] = [
75 1
                    $this->buffers[$component],
76 1
                    $buffer = new ComponentBuffer($this->defaults)
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 16 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...
77 1
                ];
78
            }
79 1
        } else {
80 10
            $buffer = $this->buffers[$component];
81 10
            if (is_array($buffer)) {
82
                $buffer = end($buffer);
83
                if ($previous === $component) {
84
                    $buffer = prev($buffer);
85
                }
86
            }
87
        }
88
89 78
        $this->current = $buffer;
90
91 78
        return $previous;
92
    }
93
94 71
    public function echoLiteral($value) {
95 71
        $this->current->echoLiteral($value);
96 71
    }
97
98 56
    public function echoCode($php) {
99 56
        $this->current->echoCode($php);
100 56
    }
101
102 78
    public function appendCode($php) {
103 78
        $this->current->appendCode($php);
104 78
    }
105
106 78
    public function indent($add) {
107 78
        $this->current->indent($add);
108 78
    }
109
110 26
    public function depth($add = 1) {
111 26
        $this->current->depth($add);
112 26
    }
113
114 27
    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...
115 27
        return $this->current->depthName($name, $add);
116
    }
117
118 78
    public function pushScope(array $vars) {
119 78
        $this->current->pushScope($vars);
120 78
    }
121
122 70
    public function popScope() {
123 70
        $this->current->popScope();
124 70
    }
125
126 70
    public function getScopeVariables() {
127 70
        return $this->current->getScopeVariables();
128
    }
129
130 70
    public function flush() {
131 70
        switch ($this->getStyle()) {
132 70
            case self::STYLE_ARRAY:
133 13
                return $this->flushArray();
134 70
            default:
135 70
                return $this->flushJoin();
136 70
        }
137
    }
138
139
    private function flushJoin() {
140 70
        return implode("\n\n", array_map(function ($buffer) {
141
            /* @var ComponentBuffer $buffer */
142 70
            return $buffer->flush();
143 70
        }, $this->buffers));
144
    }
145
146 13
    private function flushArray() {
147 13
        $result = [];
148
149 13
        foreach ($this->buffers as $name => $buffers) {
150 13
            $flushed = [];
151 13
            if (is_array($buffers)) {
152 1
                foreach ($buffers as $buffer) {
153 1
                    $flushed[] = $buffer->flush();
154 1
                }
155 1
            } else {
156 13
                $flushed = [$buffers->flush()];
157
            }
158
159 13
            $flushed = array_filter($flushed);
160 13
            if (empty($flushed)) {
161 10
                continue;
162
            }
163
164 4
            if (count($flushed) === 1) {
165 4
                $children = reset($flushed);
166 4
            } else {
167 1
                $children = "[\n".implode(",\n", $flushed)."\n".$this->px(+1).']';
168
            }
169
170 4
            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...
171 4
                $result[] = $children;
172 4
            } else {
173 2
                $result[] = var_export($name, true).' => '.ltrim($children);
174
            }
175 13
        }
176
177 13
        if (empty($result)) {
178 10
            return '[]';
179
        } else {
180 4
            return "[\n".implode(",\n\n".$this->px(+1), $result)."\n".$this->px().']';
181
        }
182
    }
183
184 4
    protected function px($add = 0) {
185 4
        return str_repeat(' ', ($this->defaults['baseIndent'] + $add) * 4);
186
    }
187
188
    /**
189
     * Get the style.
190
     *
191
     * @return string Returns the style.
192
     */
193 70
    public function getStyle() {
194 70
        return $this->style;
195
    }
196
197
    /**
198
     * Set the style.
199
     *
200
     * @param string $style One of the **STYLE_*** constants.
201
     * @return $this
202
     */
203
    public function setStyle($style) {
204
        $this->style = $style;
205
        return $this;
206
    }
207
208
    /**
209
     * Get the basename.
210
     *
211
     * @return string Returns the basename.
212
     */
213
    public function getBasename() {
214
        return $this->basename;
215
    }
216
217
    /**
218
     * Set the basename.
219
     *
220
     * @param string $basename
221
     * @return $this
222
     */
223 78
    public function setBasename($basename) {
224 78
        $this->basename = $basename;
225 78
        return $this;
226
    }
227
228 78
    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...
229 78
        if (!$this->nodeProps->contains($node) || !array_key_exists($name, $this->nodeProps[$node])) {
230 78
            return $default;
231
        }
232 12
        return $this->nodeProps[$node][$name];
233
    }
234
235 40
    public function setNodeProp(\DOMNode $node = null, $name, $value) {
236 40
        if ($node === null) {
237 21
            return $this;
238
        }
239
240 23
        if (!$this->nodeProps->contains($node)) {
241 23
            $this->nodeProps->attach($node, [$name => $value]);
242 23
        }
243
244 23
        $this->nodeProps[$node] = [$name => $value] + $this->nodeProps[$node];
245 23
        return $this;
246
    }
247
248 14
    public function getIndent() {
249 14
        return $this->current->getIndent();
250
    }
251
252 14
    public function getDepth() {
253 14
        return $this->current->getDepth();
254
    }
255
256
    public function getScope() {
257
        return $this->current->getScope();
258
    }
259
260 14
    public function getAllScopes() {
261 14
        return $this->current->getAllScopes();
262
    }
263
264
    /**
265
     * Create a new **CompileException** with proper context.
266
     *
267
     * @param \DOMNode $node The node that has the error.
268
     * @param \Exception $ex The exception that represents the low-level error.
269
     * @param array $context Custom context information for the exception.
270
     * @return CompileException Returns a new exception that can be thrown.
271
     */
272 8
    public function createCompilerException(\DOMNode $node, \Exception $ex, array $context = []) {
273
        $result = $context + [
274 8
            'path' => $this->getPath(),
275 8
            'source' => '',
276 8
            'sourcePosition' => null,
277 8
            'line' => $node->getLineNo(),
278 8
            'lines' => []
279 8
        ];
280 8
        $message = $ex->getMessage();
281
282 8
        if ($ex instanceof SyntaxError) {
283 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...
284 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...
285 3
            if (!isset($context['sourcePosition'])) {
286 3
                $result['sourcePosition'] = $position;
287 3
            }
288 8
        } elseif (empty($result['source'])) {
289 5
            if ($node instanceof \DOMAttr) {
290 3
                $result['source'] = $node->name.'="'.$node->value.'"';
291 3
            }
292 5
        }
293
294 8
        if (!empty($this->source)) {
295 8
            $allLines = explode("\n", $this->source);
296
297 8
            $lines = [];
298 8
            $line = $result['line'];
299 8
            for ($i = max(0, $line - 4); $i < $line + 3; $i++) {
300 8
                if (isset($allLines[$i])) {
301 8
                    $lines[$i + 1] = $allLines[$i];
302 8
                }
303 8
            }
304
305 8
            $result['lines'] = $lines;
306 8
        }
307
308 8
        return new CompileException($message, $result, $ex);
309
    }
310
311 3
    private function splitSyntaxError(SyntaxError $ex) {
312 3
        if (preg_match('`^(.*) around position (.*)\.$`', $ex->getMessage(), $m)) {
313 3
            return [$m[1], $m[2]];
314
        } else {
315
            return [$ex->getMessage(), 0];
316
        }
317
    }
318
319
    /**
320
     * Get the source.
321
     *
322
     * @return mixed Returns the source.
323
     */
324 14
    public function getSource() {
325 14
        return $this->source;
326
    }
327
328
    /**
329
     * Set the source.
330
     *
331
     * @param mixed $source
332
     * @return $this
333
     */
334 78
    public function setSource($source) {
335 78
        $this->source = $source;
336 78
        return $this;
337
    }
338
339
    /**
340
     * Get the path.
341
     *
342
     * @return mixed Returns the path.
343
     */
344 8
    public function getPath() {
345 8
        return $this->path;
346
    }
347
348
    /**
349
     * Set the path.
350
     *
351
     * @param mixed $path
352
     * @return $this
353
     */
354 78
    public function setPath($path) {
355 78
        $this->path = $path;
356 78
        return $this;
357
    }
358
359
    /**
360
     * Get the entire node property array.
361
     *
362
     * @return \SplObjectStorage Returns the node properties.
363
     */
364 14
    public function getNodePropArray() {
365 14
        return $this->nodeProps;
366
    }
367
}
368