This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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 | use DOMAttr; |
||
11 | use DOMElement; |
||
12 | use DOMNode; |
||
13 | use Symfony\Component\ExpressionLanguage\SyntaxError; |
||
14 | |||
15 | class Compiler { |
||
16 | const T_IF = 'x-if'; |
||
0 ignored issues
–
show
|
|||
17 | const T_EACH = 'x-each'; |
||
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 6 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. ![]() |
|||
18 | const T_WITH = 'x-with'; |
||
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 6 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. ![]() |
|||
19 | const T_LITERAL = 'x-literal'; |
||
0 ignored issues
–
show
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. ![]() |
|||
20 | const T_AS = 'x-as'; |
||
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 8 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. ![]() |
|||
21 | const T_COMPONENT = 'x-component'; |
||
22 | const T_CHILDREN = 'x-children'; |
||
23 | const T_BLOCK = 'x-block'; |
||
0 ignored issues
–
show
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. ![]() |
|||
24 | const T_ELSE = 'x-else'; |
||
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 6 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. ![]() |
|||
25 | const T_EMPTY = 'x-empty'; |
||
0 ignored issues
–
show
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. ![]() |
|||
26 | const T_X = 'x'; |
||
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 9 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. ![]() |
|||
27 | const T_INCLUDE = 'x-include'; |
||
0 ignored issues
–
show
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. ![]() |
|||
28 | const T_EBI = 'ebi'; |
||
0 ignored issues
–
show
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. ![]() |
|||
29 | const T_UNESCAPE = 'x-unescape'; |
||
30 | const T_TAG = 'x-tag'; |
||
0 ignored issues
–
show
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. ![]() |
|||
31 | |||
32 | const IDENT_REGEX = '`^([a-z0-9-]+)$`i'; |
||
33 | |||
34 | protected static $special = [ |
||
35 | self::T_COMPONENT => 1, |
||
36 | self::T_IF => 2, |
||
37 | self::T_ELSE => 3, |
||
38 | self::T_EACH => 4, |
||
39 | self::T_EMPTY => 5, |
||
40 | self::T_CHILDREN => 6, |
||
41 | self::T_INCLUDE => 7, |
||
42 | self::T_WITH => 8, |
||
43 | self::T_BLOCK => 9, |
||
44 | self::T_LITERAL => 10, |
||
45 | self::T_AS => 11, |
||
46 | self::T_UNESCAPE => 12, |
||
47 | self::T_TAG => 13 |
||
48 | ]; |
||
49 | |||
50 | protected static $htmlTags = [ |
||
51 | 'a' => 'i', |
||
52 | 'abbr' => 'i', |
||
53 | 'acronym' => 'i', // deprecated |
||
54 | 'address' => 'b', |
||
55 | // 'applet' => 'i', // deprecated |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
50% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
56 | 'area' => 'i', |
||
57 | 'article' => 'b', |
||
58 | 'aside' => 'b', |
||
59 | 'audio' => 'i', |
||
60 | 'b' => 'i', |
||
61 | 'base' => 'i', |
||
62 | // 'basefont' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
63 | 'bdi' => 'i', |
||
64 | 'bdo' => 'i', |
||
65 | // 'bgsound' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
54% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
66 | // 'big' => 'i', |
||
67 | 'x' => 'i', |
||
68 | // 'blink' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
69 | 'blockquote' => 'b', |
||
70 | 'body' => 'b', |
||
71 | 'br' => 'i', |
||
72 | 'button' => 'i', |
||
73 | 'canvas' => 'b', |
||
74 | 'caption' => 'i', |
||
75 | // 'center' => 'b', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
76 | 'cite' => 'i', |
||
77 | 'code' => 'i', |
||
78 | 'col' => 'i', |
||
79 | 'colgroup' => 'i', |
||
80 | // 'command' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
81 | 'content' => 'i', |
||
82 | 'data' => 'i', |
||
83 | 'datalist' => 'i', |
||
84 | 'dd' => 'b', |
||
85 | 'del' => 'i', |
||
86 | 'details' => 'i', |
||
87 | 'dfn' => 'i', |
||
88 | 'dialog' => 'i', |
||
89 | // 'dir' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
90 | 'div' => 'i', |
||
91 | 'dl' => 'b', |
||
92 | 'dt' => 'b', |
||
93 | // 'element' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
94 | 'em' => 'i', |
||
95 | 'embed' => 'i', |
||
96 | 'fieldset' => 'b', |
||
97 | 'figcaption' => 'b', |
||
98 | 'figure' => 'b', |
||
99 | // 'font' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
100 | 'footer' => 'b', |
||
101 | 'form' => 'b', |
||
102 | 'frame' => 'i', |
||
103 | 'frameset' => 'i', |
||
104 | 'h1' => 'b', |
||
105 | 'h2' => 'b', |
||
106 | 'h3' => 'b', |
||
107 | 'h4' => 'b', |
||
108 | 'h5' => 'b', |
||
109 | 'h6' => 'b', |
||
110 | 'head' => 'b', |
||
111 | 'header' => 'b', |
||
112 | 'hgroup' => 'b', |
||
113 | 'hr' => 'b', |
||
114 | 'html' => 'b', |
||
115 | 'i' => 'i', |
||
116 | 'iframe' => 'i', |
||
117 | 'image' => 'i', |
||
118 | 'img' => 'i', |
||
119 | 'input' => 'i', |
||
120 | 'ins' => 'i', |
||
121 | 'isindex' => 'i', |
||
122 | 'kbd' => 'i', |
||
123 | 'keygen' => 'i', |
||
124 | 'label' => 'i', |
||
125 | 'legend' => 'i', |
||
126 | 'li' => 'i', |
||
127 | 'link' => 'i', |
||
128 | // 'listing' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
129 | 'main' => 'b', |
||
130 | 'map' => 'i', |
||
131 | 'mark' => 'i', |
||
132 | // 'marquee' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
133 | 'menu' => 'i', |
||
134 | 'menuitem' => 'i', |
||
135 | 'meta' => 'i', |
||
136 | 'meter' => 'i', |
||
137 | 'multicol' => 'i', |
||
138 | 'nav' => 'b', |
||
139 | 'nobr' => 'i', |
||
140 | 'noembed' => 'i', |
||
141 | 'noframes' => 'i', |
||
142 | 'noscript' => 'b', |
||
143 | 'object' => 'i', |
||
144 | 'ol' => 'b', |
||
145 | 'optgroup' => 'i', |
||
146 | 'option' => 'b', |
||
147 | 'output' => 'i', |
||
148 | 'p' => 'b', |
||
149 | 'param' => 'i', |
||
150 | 'picture' => 'i', |
||
151 | // 'plaintext' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
152 | 'pre' => 'b', |
||
153 | 'progress' => 'i', |
||
154 | 'q' => 'i', |
||
155 | 'rp' => 'i', |
||
156 | 'rt' => 'i', |
||
157 | 'rtc' => 'i', |
||
158 | 'ruby' => 'i', |
||
159 | 's' => 'i', |
||
160 | 'samp' => 'i', |
||
161 | 'script' => 'i', |
||
162 | 'section' => 'b', |
||
163 | 'select' => 'i', |
||
164 | // 'shadow' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
165 | 'slot' => 'i', |
||
166 | 'small' => 'i', |
||
167 | 'source' => 'i', |
||
168 | // 'spacer' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
169 | 'span' => 'i', |
||
170 | // 'strike' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
171 | 'strong' => 'i', |
||
172 | 'style' => 'i', |
||
173 | 'sub' => 'i', |
||
174 | 'summary' => 'i', |
||
175 | 'sup' => 'i', |
||
176 | 'table' => 'b', |
||
177 | 'tbody' => 'i', |
||
178 | 'td' => 'i', |
||
179 | 'template' => 'i', |
||
180 | 'textarea' => 'i', |
||
181 | 'tfoot' => 'b', |
||
182 | 'th' => 'i', |
||
183 | 'thead' => 'i', |
||
184 | 'time' => 'i', |
||
185 | 'title' => 'i', |
||
186 | 'tr' => 'i', |
||
187 | 'track' => 'i', |
||
188 | // 'tt' => 'i', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
189 | 'u' => 'i', |
||
190 | 'ul' => 'b', |
||
191 | 'var' => 'i', |
||
192 | 'video' => 'b', |
||
193 | 'wbr' => 'i', |
||
194 | |||
195 | /// SVG /// |
||
196 | 'animate' => 's', |
||
197 | 'animateColor' => 's', |
||
198 | 'animateMotion' => 's', |
||
199 | 'animateTransform' => 's', |
||
200 | // 'canvas' => 's', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
201 | 'circle' => 's', |
||
202 | 'desc' => 's', |
||
203 | 'defs' => 's', |
||
204 | 'discard' => 's', |
||
205 | 'ellipse' => 's', |
||
206 | 'g' => 's', |
||
207 | // 'image' => 's', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
208 | 'line' => 's', |
||
209 | 'marker' => 's', |
||
210 | 'mask' => 's', |
||
211 | 'missing-glyph' => 's', |
||
212 | 'mpath' => 's', |
||
213 | 'metadata' => 's', |
||
214 | 'path' => 's', |
||
215 | 'pattern' => 's', |
||
216 | 'polygon' => 's', |
||
217 | 'polyline' => 's', |
||
218 | 'rect' => 's', |
||
219 | 'set' => 's', |
||
220 | 'svg' => 's', |
||
221 | 'switch' => 's', |
||
222 | 'symbol' => 's', |
||
223 | 'text' => 's', |
||
224 | // 'unknown' => 's', |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
58% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
225 | 'use' => 's', |
||
226 | ]; |
||
227 | |||
228 | protected static $boolAttributes = [ |
||
229 | 'checked' => 1, |
||
230 | 'itemscope' => 1, |
||
231 | 'required' => 1, |
||
232 | 'selected' => 1, |
||
233 | ]; |
||
234 | |||
235 | /** |
||
236 | * @var ExpressionLanguage |
||
237 | */ |
||
238 | protected $expressions; |
||
239 | |||
240 | 86 | public function __construct() { |
|
241 | 86 | $this->expressions = new ExpressionLanguage(); |
|
242 | 86 | $this->expressions->setNamePattern('/[@a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A'); |
|
243 | 86 | $this->expressions->register( |
|
244 | 86 | 'hasChildren', |
|
245 | function ($name = null) { |
||
246 | 1 | return empty($name) ? 'isset($children[0])' : "isset(\$children[$name ?: 0])"; |
|
247 | 86 | }, |
|
248 | function ($name = null) { |
||
0 ignored issues
–
show
|
|||
249 | return false; |
||
250 | 86 | }); |
|
251 | 86 | } |
|
252 | |||
253 | /** |
||
254 | * Register a runtime function. |
||
255 | * |
||
256 | * @param string $name The name of the function. |
||
257 | * @param callable $function The function callback. |
||
0 ignored issues
–
show
Should the type for parameter
$function not be callable|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
258 | */ |
||
259 | 84 | public function defineFunction($name, $function = null) { |
|
260 | 84 | if ($function === null) { |
|
261 | 1 | $function = $name; |
|
262 | 1 | } |
|
263 | |||
264 | 84 | $this->expressions->register( |
|
265 | 84 | $name, |
|
266 | 84 | $this->getFunctionCompiler($name, $function), |
|
267 | 84 | $this->getFunctionEvaluator($function) |
|
268 | 84 | ); |
|
269 | 84 | } |
|
270 | |||
271 | 84 | private function getFunctionEvaluator($function) { |
|
0 ignored issues
–
show
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 ![]() |
|||
272 | 84 | if ($function === 'empty') { |
|
273 | return function ($expr) { |
||
274 | return empty($expr); |
||
275 | 84 | }; |
|
276 | 83 | } elseif ($function === 'isset') { |
|
277 | return function ($expr) { |
||
278 | return isset($expr); |
||
279 | }; |
||
280 | } |
||
281 | |||
282 | 83 | return $function; |
|
283 | } |
||
284 | |||
285 | 84 | private function getFunctionCompiler($name, $function) { |
|
286 | 84 | $var = var_export(strtolower($name), true); |
|
287 | $fn = function (...$args) use ($var) { |
||
288 | 2 | return "\$this->call($var, ".implode(', ', $args).')'; |
|
289 | 84 | }; |
|
290 | |||
291 | 84 | if (is_string($function)) { |
|
292 | $fn = function (...$args) use ($function) { |
||
293 | 16 | return $function.'('.implode(', ', $args).')'; |
|
294 | 84 | }; |
|
295 | 84 | } elseif (is_array($function)) { |
|
296 | 83 | if (is_string($function[0])) { |
|
297 | $fn = function (...$args) use ($function) { |
||
298 | return "$function[0]::$function[1](".implode(', ', $args).')'; |
||
299 | }; |
||
300 | 83 | } elseif ($function[0] instanceof Ebi) { |
|
301 | $fn = function (...$args) use ($function) { |
||
302 | 17 | return "\$this->$function[1](".implode(', ', $args).')'; |
|
303 | 83 | }; |
|
304 | 83 | } |
|
305 | 83 | } |
|
306 | |||
307 | 84 | return $fn; |
|
308 | 1 | } |
|
309 | |||
310 | 78 | public function compile($src, array $options = []) { |
|
311 | 78 | $options += ['basename' => '', 'path' => '', 'runtime' => true]; |
|
312 | |||
313 | 78 | $src = trim($src); |
|
314 | |||
315 | 78 | $out = new CompilerBuffer(); |
|
316 | |||
317 | 78 | $out->setBasename($options['basename']); |
|
318 | 78 | $out->setSource($src); |
|
319 | 78 | $out->setPath($options['path']); |
|
320 | |||
321 | 78 | $dom = new \DOMDocument(); |
|
322 | |||
323 | 78 | $fragment = false; |
|
324 | 78 | if (strpos($src, '<html') === false) { |
|
325 | 76 | $src = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><html><body>$src</body></html>"; |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 6 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. ![]() |
|||
326 | 76 | $fragment = true; |
|
327 | 76 | } |
|
328 | |||
329 | 78 | libxml_use_internal_errors(true); |
|
330 | 78 | $dom->loadHTML($src, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOCDATA | LIBXML_NOXMLDECL); |
|
331 | // $arr = $this->domToArray($dom); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
59% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
332 | |||
333 | 78 | if ($options['runtime']) { |
|
334 | 77 | $name = var_export($options['basename'], true); |
|
335 | 77 | $out->appendCode("\$this->defineComponent($name, function (\$props = [], \$children = []) {\n"); |
|
336 | 77 | } else { |
|
337 | 1 | $out->appendCode("function (\$props = [], \$children = []) {\n"); |
|
338 | } |
||
339 | |||
340 | 78 | $out->pushScope(['this' => 'props']); |
|
341 | 78 | $out->indent(+1); |
|
342 | |||
343 | 78 | $parent = $fragment ? $dom->firstChild->nextSibling->firstChild : $dom; |
|
344 | |||
345 | 78 | foreach ($parent->childNodes as $node) { |
|
346 | 78 | $this->compileNode($node, $out); |
|
347 | 70 | } |
|
348 | |||
349 | 70 | $out->indent(-1); |
|
350 | 70 | $out->popScope(); |
|
351 | |||
352 | 70 | if ($options['runtime']) { |
|
353 | 69 | $out->appendCode("});"); |
|
354 | 69 | } else { |
|
355 | 1 | $out->appendCode("};"); |
|
356 | } |
||
357 | |||
358 | 70 | $r = $out->flush(); |
|
359 | |||
360 | 70 | $errs = libxml_get_errors(); |
|
0 ignored issues
–
show
$errs 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 ![]() |
|||
361 | |||
362 | 70 | return $r; |
|
363 | } |
||
364 | |||
365 | 57 | protected function isComponent($tag) { |
|
366 | 57 | return !isset(static::$htmlTags[$tag]); |
|
367 | } |
||
368 | |||
369 | 78 | protected function compileNode(DOMNode $node, CompilerBuffer $out) { |
|
370 | 78 | if ($out->getNodeProp($node, 'skip')) { |
|
371 | 4 | return; |
|
372 | } |
||
373 | |||
374 | 78 | switch ($node->nodeType) { |
|
375 | 78 | case XML_TEXT_NODE: |
|
376 | 64 | $this->compileTextNode($node, $out); |
|
377 | 64 | break; |
|
378 | 73 | case XML_ELEMENT_NODE: |
|
379 | /* @var \DOMElement $node */ |
||
380 | 73 | $this->compileElementNode($node, $out); |
|
381 | 66 | break; |
|
382 | 4 | case XML_COMMENT_NODE: |
|
383 | /* @var \DOMComment $node */ |
||
384 | 1 | $this->compileCommentNode($node, $out); |
|
385 | 1 | break; |
|
386 | 3 | case XML_DOCUMENT_TYPE_NODE: |
|
387 | 1 | $out->echoLiteral("<!DOCTYPE {$node->name}>\n"); |
|
0 ignored issues
–
show
The property
name does not seem to exist in DOMNode .
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading. ![]() |
|||
388 | 1 | break; |
|
389 | 2 | case XML_CDATA_SECTION_NODE: |
|
390 | 2 | $this->compileTextNode($node, $out); |
|
391 | 2 | break; |
|
392 | default: |
||
393 | $r = "// Unknown node\n". |
||
0 ignored issues
–
show
$r 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 ![]() |
|||
394 | '// '.str_replace("\n", "\n// ", $node->ownerDocument->saveHTML($node)); |
||
395 | 72 | } |
|
396 | 72 | } |
|
397 | |||
398 | protected function domToArray(DOMNode $root) { |
||
0 ignored issues
–
show
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 ![]() |
|||
399 | $result = []; |
||
400 | |||
401 | if ($root->hasAttributes()) { |
||
402 | $attrs = $root->attributes; |
||
403 | foreach ($attrs as $attr) { |
||
404 | $result['@attributes'][$attr->name] = $attr->value; |
||
405 | } |
||
406 | } |
||
407 | |||
408 | if ($root->hasChildNodes()) { |
||
409 | $children = $root->childNodes; |
||
410 | if ($children->length == 1) { |
||
411 | $child = $children->item(0); |
||
412 | if ($child->nodeType == XML_TEXT_NODE) { |
||
413 | $result['_value'] = $child->nodeValue; |
||
414 | return count($result) == 1 |
||
415 | ? $result['_value'] |
||
416 | : $result; |
||
417 | } |
||
418 | } |
||
419 | $groups = []; |
||
420 | foreach ($children as $child) { |
||
421 | if (!isset($result[$child->nodeName])) { |
||
422 | $result[$child->nodeName] = $this->domToArray($child); |
||
423 | } else { |
||
424 | if (!isset($groups[$child->nodeName])) { |
||
425 | $result[$child->nodeName] = [$result[$child->nodeName]]; |
||
426 | $groups[$child->nodeName] = 1; |
||
427 | } |
||
428 | $result[$child->nodeName][] = $this->domToArray($child); |
||
429 | } |
||
430 | } |
||
431 | } |
||
432 | |||
433 | return $result; |
||
434 | } |
||
435 | |||
436 | 1 | protected function newline(DOMNode $node, CompilerBuffer $out) { |
|
437 | 1 | if ($node->previousSibling && $node->previousSibling->nodeType !== XML_COMMENT_NODE) { |
|
438 | $out->appendCode("\n"); |
||
439 | } |
||
440 | 1 | } |
|
441 | |||
442 | 1 | protected function compileCommentNode(\DOMComment $node, CompilerBuffer $out) { |
|
443 | 1 | $comments = explode("\n", trim($node->nodeValue)); |
|
444 | |||
445 | 1 | $this->newline($node, $out); |
|
446 | 1 | foreach ($comments as $comment) { |
|
447 | 1 | $out->appendCode("// $comment\n"); |
|
448 | 1 | } |
|
449 | 1 | } |
|
450 | |||
451 | 66 | protected function compileTextNode(DOMNode $node, CompilerBuffer $out) { |
|
452 | 66 | $nodeText = $node->nodeValue; |
|
453 | |||
454 | 66 | $items = $this->splitExpressions($nodeText); |
|
455 | 66 | foreach ($items as $i => list($text, $offset)) { |
|
456 | 66 | if (preg_match('`^{\S`', $text)) { |
|
457 | 34 | if (preg_match('`^{\s*unescape\((.+)\)\s*}$`', $text, $m)) { |
|
458 | 4 | $out->echoCode($this->expr($m[1], $out)); |
|
459 | 4 | } else { |
|
460 | try { |
||
461 | 31 | $expr = substr($text, 1, -1); |
|
462 | 31 | $out->echoCode($this->compileEscape($this->expr($expr, $out))); |
|
463 | 31 | } catch (SyntaxError $ex) { |
|
464 | 1 | $nodeLineCount = substr_count($nodeText, "\n"); |
|
0 ignored issues
–
show
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. ![]() |
|||
465 | 1 | $offsetLineCount = substr_count($nodeText, "\n", 0, $offset); |
|
466 | 1 | $line = $node->getLineNo() - $nodeLineCount + $offsetLineCount; |
|
0 ignored issues
–
show
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. ![]() |
|||
467 | 1 | throw $out->createCompilerException($node, $ex, ['source' => $expr, 'line' => $line]); |
|
468 | } |
||
469 | } |
||
470 | 33 | } else { |
|
471 | 66 | if ($i === 0) { |
|
472 | 66 | $text = $this->ltrim($text, $node, $out); |
|
473 | 66 | } |
|
474 | 66 | if ($i === count($items) - 1) { |
|
475 | 66 | $text = $this->rtrim($text, $node, $out); |
|
476 | 66 | } |
|
477 | |||
478 | 66 | $out->echoLiteral($text); |
|
479 | } |
||
480 | 66 | } |
|
481 | 66 | } |
|
482 | |||
483 | 73 | protected function compileElementNode(DOMElement $node, CompilerBuffer $out) { |
|
484 | 73 | list($attributes, $special) = $this->splitAttributes($node); |
|
485 | |||
486 | 73 | if ($node->tagName === 'script' && ((isset($attributes['type']) && $attributes['type']->value === self::T_EBI) || !empty($special[self::T_AS]) || !empty($special[self::T_UNESCAPE]))) { |
|
487 | 10 | $this->compileExpressionNode($node, $attributes, $special, $out); |
|
488 | 71 | } elseif (!empty($special) || $this->isComponent($node->tagName)) { |
|
489 | 46 | $this->compileSpecialNode($node, $attributes, $special, $out); |
|
490 | 41 | } else { |
|
491 | 35 | $this->compileBasicElement($node, $attributes, $special, $out); |
|
492 | } |
||
493 | 66 | } |
|
494 | |||
495 | 66 | protected function splitExpressions($value) { |
|
496 | 66 | $values = preg_split('`({\S[^}]*?})`', $value, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE); |
|
497 | 66 | return $values; |
|
498 | } |
||
499 | |||
500 | /** |
||
501 | * Compile the PHP for an expression |
||
502 | * |
||
503 | * @param string $expr The expression to compile. |
||
504 | * @param CompilerBuffer $out The current output buffer. |
||
505 | * @param DOMAttr|null $attr The owner of the expression. |
||
506 | * @return string Returns a string of PHP code. |
||
507 | */ |
||
508 | 70 | protected function expr($expr, CompilerBuffer $out, DOMAttr $attr = null) { |
|
509 | 70 | $names = $out->getScopeVariables(); |
|
510 | |||
511 | try { |
||
512 | $compiled = $this->expressions->compile($expr, function ($name) use ($names) { |
||
0 ignored issues
–
show
function ($name) use($na...e, true) . ']'; } } is of type object<Closure> , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
513 | 63 | if (isset($names[$name])) { |
|
514 | 38 | return $names[$name]; |
|
515 | 39 | } elseif ($name[0] === '@') { |
|
516 | 1 | return 'this->meta['.var_export(substr($name, 1), true).']'; |
|
517 | } else { |
||
518 | 38 | return $names['this'].'['.var_export($name, true).']'; |
|
519 | } |
||
520 | 70 | }); |
|
521 | 70 | } catch (SyntaxError $ex) { |
|
522 | 3 | if ($attr !== null) { |
|
523 | 1 | throw $out->createCompilerException($attr, $ex); |
|
524 | } else { |
||
525 | 2 | throw $ex; |
|
526 | } |
||
527 | } |
||
528 | |||
529 | 67 | if ($attr !== null && null !== $fn = $this->getAttributeFunction($attr)) { |
|
530 | 10 | $compiled = call_user_func($fn, $compiled); |
|
531 | 10 | } |
|
532 | |||
533 | 67 | return $compiled; |
|
534 | } |
||
535 | |||
536 | /** |
||
537 | * Get the compiler function to wrap an attribute. |
||
538 | * |
||
539 | * Attribute functions are regular expression functions, but with a special naming convention. The following naming |
||
540 | * conventions are supported: |
||
541 | * |
||
542 | * - **@tag:attribute**: Applies to an attribute only on a specific tag. |
||
543 | * - **@attribute**: Applies to all attributes with a given name. |
||
544 | * |
||
545 | * @param DOMAttr $attr The attribute to look at. |
||
546 | * @return callable|null A function or **null** if the attribute doesn't have a function. |
||
547 | */ |
||
548 | 41 | private function getAttributeFunction(DOMAttr $attr) { |
|
549 | 41 | $keys = ['@'.$attr->ownerElement->tagName.':'.$attr->name, '@'.$attr->name]; |
|
550 | |||
551 | 41 | foreach ($keys as $key) { |
|
552 | 41 | if (null !== $fn = $this->expressions->getFunctionCompiler($key)) { |
|
553 | 17 | return $fn; |
|
554 | } |
||
555 | 41 | } |
|
556 | 31 | } |
|
557 | |||
558 | /** |
||
559 | * @param DOMElement $node |
||
560 | */ |
||
561 | 73 | protected function splitAttributes(DOMElement $node) { |
|
562 | 73 | $attributes = []; |
|
563 | 73 | $special = []; |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 4 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. ![]() |
|||
564 | |||
565 | 73 | foreach ($node->attributes as $name => $attribute) { |
|
566 | 69 | if (isset(static::$special[$name])) { |
|
567 | 50 | $special[$name] = $attribute; |
|
568 | 50 | } else { |
|
569 | 33 | $attributes[$name] = $attribute; |
|
570 | } |
||
571 | 73 | } |
|
572 | |||
573 | uksort($special, function ($a, $b) { |
||
574 | 13 | return strnatcmp(static::$special[$a], static::$special[$b]); |
|
575 | 73 | }); |
|
576 | |||
577 | 73 | return [$attributes, $special]; |
|
578 | } |
||
579 | |||
580 | 46 | protected function compileSpecialNode(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
581 | 46 | $specialName = key($special); |
|
582 | |||
583 | switch ($specialName) { |
||
584 | 46 | case self::T_COMPONENT: |
|
585 | 10 | $this->compileComponentRegister($node, $attributes, $special, $out); |
|
586 | 10 | break; |
|
587 | 46 | case self::T_IF: |
|
588 | 11 | $this->compileIf($node, $attributes, $special, $out); |
|
589 | 10 | break; |
|
590 | 45 | case self::T_EACH: |
|
591 | 16 | $this->compileEach($node, $attributes, $special, $out); |
|
592 | 15 | break; |
|
593 | 33 | case self::T_BLOCK: |
|
594 | 3 | $this->compileBlock($node, $attributes, $special, $out); |
|
595 | 2 | break; |
|
596 | 32 | case self::T_CHILDREN: |
|
597 | 4 | $this->compileChildBlock($node, $attributes, $special, $out); |
|
598 | 4 | break; |
|
599 | 32 | case self::T_INCLUDE: |
|
600 | 1 | $this->compileComponentInclude($node, $attributes, $special, $out); |
|
601 | 1 | break; |
|
602 | 32 | case self::T_WITH: |
|
603 | 5 | if ($this->isComponent($node->tagName)) { |
|
604 | // With has a special meaning in components. |
||
605 | 3 | $this->compileComponentInclude($node, $attributes, $special, $out); |
|
606 | 3 | } else { |
|
607 | 2 | $this->compileWith($node, $attributes, $special, $out); |
|
608 | } |
||
609 | 4 | break; |
|
610 | 30 | case self::T_LITERAL: |
|
611 | 2 | $this->compileLiteral($node, $attributes, $special, $out); |
|
612 | 2 | break; |
|
613 | 28 | case '': |
|
614 | 24 | if ($this->isComponent($node->tagName)) { |
|
615 | 10 | $this->compileComponentInclude($node, $attributes, $special, $out); |
|
616 | 9 | } else { |
|
617 | 22 | $this->compileElement($node, $attributes, $special, $out); |
|
618 | } |
||
619 | 23 | break; |
|
620 | 5 | case self::T_TAG: |
|
621 | 5 | default: |
|
622 | // This is only a tag node so it just gets compiled as an element. |
||
623 | 5 | $this->compileBasicElement($node, $attributes, $special, $out); |
|
624 | 5 | break; |
|
625 | } |
||
626 | 41 | } |
|
627 | |||
628 | /** |
||
629 | * Compile component registering. |
||
630 | * |
||
631 | * @param DOMElement $node |
||
632 | * @param $attributes |
||
633 | * @param $special |
||
634 | * @param CompilerBuffer $out |
||
635 | */ |
||
636 | 10 | public function compileComponentRegister(DOMElement $node, $attributes, $special, CompilerBuffer $out) { |
|
637 | 10 | $name = strtolower($special[self::T_COMPONENT]->value); |
|
638 | 10 | unset($special[self::T_COMPONENT]); |
|
639 | |||
640 | 10 | $prev = $out->select($name); |
|
641 | |||
642 | 10 | $varName = var_export($name, true); |
|
643 | 10 | $out->appendCode("\$this->defineComponent($varName, function (\$props = [], \$children = []) {\n"); |
|
644 | 10 | $out->pushScope(['this' => 'props']); |
|
645 | 10 | $out->indent(+1); |
|
646 | |||
647 | try { |
||
648 | 10 | $this->compileSpecialNode($node, $attributes, $special, $out); |
|
649 | 10 | } finally { |
|
650 | 10 | $out->popScope(); |
|
651 | 10 | $out->indent(-1); |
|
652 | 10 | $out->appendCode("});"); |
|
653 | 10 | $out->select($prev); |
|
654 | 10 | } |
|
655 | 10 | } |
|
656 | |||
657 | 3 | private function compileBlock(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
658 | // Blocks must be direct descendants of component includes. |
||
659 | 3 | if (!$out->getNodeProp($node->parentNode, self::T_INCLUDE)) { |
|
660 | 1 | throw $out->createCompilerException($node, new \Exception("Blocks must be direct descendants of component includes.")); |
|
661 | } |
||
662 | |||
663 | 2 | $name = strtolower($special[self::T_BLOCK]->value); |
|
664 | 2 | if (empty($name)) { |
|
665 | throw $out->createCompilerException($special[self::T_BLOCK], new \Exception("Block names cannot be empty.")); |
||
666 | } |
||
667 | 2 | if (!preg_match(self::IDENT_REGEX, $name)) { |
|
668 | throw $out->createCompilerException($special[self::T_BLOCK], new \Exception("The block name isn't a valid identifier.")); |
||
669 | } |
||
670 | |||
671 | 2 | unset($special[self::T_BLOCK]); |
|
672 | |||
673 | 2 | $prev = $out->select($name, true); |
|
674 | |||
675 | 2 | $vars = array_filter(array_unique($out->getScopeVariables())); |
|
0 ignored issues
–
show
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. ![]() |
|||
676 | 2 | $vars[] = 'children'; |
|
677 | 2 | $use = '$'.implode(', $', array_unique($vars)); |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 4 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. ![]() |
|||
678 | |||
679 | 2 | $out->appendCode("function () use ($use) {\n"); |
|
680 | 2 | $out->pushScope(['this' => 'props']); |
|
681 | 2 | $out->indent(+1); |
|
682 | |||
683 | try { |
||
684 | 2 | $this->compileSpecialNode($node, $attributes, $special, $out); |
|
685 | 2 | } finally { |
|
686 | 2 | $out->indent(-1); |
|
687 | 2 | $out->popScope(); |
|
688 | 2 | $out->appendCode("}"); |
|
689 | 2 | $out->select($prev); |
|
690 | 2 | } |
|
691 | |||
692 | 2 | return $out; |
|
693 | } |
||
694 | |||
695 | /** |
||
696 | * Compile component inclusion and rendering. |
||
697 | * |
||
698 | * @param DOMElement $node |
||
699 | * @param DOMAttr[] $attributes |
||
700 | * @param DOMAttr[] $special |
||
701 | * @param CompilerBuffer $out |
||
702 | */ |
||
703 | 14 | protected function compileComponentInclude(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
704 | // Mark the node as a component include. |
||
705 | 14 | $out->setNodeProp($node, self::T_INCLUDE, true); |
|
706 | |||
707 | // Generate the attributes into a property array. |
||
708 | 14 | $props = []; |
|
709 | 14 | foreach ($attributes as $name => $attribute) { |
|
710 | /* @var DOMAttr $attr */ |
||
711 | 6 | if ($this->isExpression($attribute->value)) { |
|
712 | 5 | $expr = $this->expr(substr($attribute->value, 1, -1), $out, $attribute); |
|
713 | 5 | } else { |
|
714 | 2 | $expr = var_export($attribute->value, true); |
|
715 | } |
||
716 | |||
717 | 6 | $props[] = var_export($name, true).' => '.$expr; |
|
718 | 14 | } |
|
719 | 14 | $propsStr = '['.implode(', ', $props).']'; |
|
720 | |||
721 | 14 | if (isset($special[self::T_WITH])) { |
|
722 | 3 | $withExpr = $this->expr($special[self::T_WITH]->value, $out, $special[self::T_WITH]); |
|
723 | 3 | unset($special[self::T_WITH]); |
|
724 | |||
725 | 3 | $propsStr = empty($props) ? $withExpr : $propsStr.' + (array)'.$withExpr; |
|
726 | 14 | } elseif (empty($props)) { |
|
727 | // By default the current context is passed to components. |
||
728 | 6 | $propsStr = $this->expr('this', $out); |
|
729 | 6 | } |
|
730 | |||
731 | // Compile the children blocks. |
||
732 | 14 | $blocks = $this->compileComponentBlocks($node, $out); |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 4 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. ![]() |
|||
733 | 13 | $blocksStr = $blocks->flush(); |
|
734 | |||
735 | 13 | if (isset($special[self::T_INCLUDE])) { |
|
736 | 1 | $name = $this->expr($special[self::T_INCLUDE]->value, $out, $special[self::T_INCLUDE]); |
|
737 | 1 | } else { |
|
738 | 12 | $name = var_export($node->tagName, true); |
|
739 | } |
||
740 | |||
741 | 13 | $out->appendCode("\$this->write($name, $propsStr, $blocksStr);\n"); |
|
742 | 13 | } |
|
743 | |||
744 | /** |
||
745 | * @param DOMElement $parent |
||
746 | * @return CompilerBuffer |
||
747 | */ |
||
748 | 14 | protected function compileComponentBlocks(DOMElement $parent, CompilerBuffer $out) { |
|
749 | 14 | $blocksOut = new CompilerBuffer(CompilerBuffer::STYLE_ARRAY, [ |
|
750 | 14 | 'baseIndent' => $out->getIndent(), |
|
751 | 14 | 'indent' => $out->getIndent() + 1, |
|
752 | 14 | 'depth' => $out->getDepth(), |
|
753 | 14 | 'scopes' => $out->getAllScopes(), |
|
754 | 14 | 'nodeProps' => $out->getNodePropArray() |
|
755 | 14 | ]); |
|
756 | 14 | $blocksOut->setSource($out->getSource()); |
|
757 | |||
758 | 14 | if ($this->isEmptyNode($parent)) { |
|
759 | 10 | return $blocksOut; |
|
760 | } |
||
761 | |||
762 | 5 | $use = '$'.implode(', $', $blocksOut->getScopeVariables()).', $children'; |
|
763 | |||
764 | 5 | $blocksOut->appendCode("function () use ($use) {\n"); |
|
765 | 5 | $blocksOut->indent(+1); |
|
766 | |||
767 | try { |
||
768 | 5 | foreach ($parent->childNodes as $node) { |
|
769 | 5 | $this->compileNode($node, $blocksOut); |
|
770 | 4 | } |
|
771 | 4 | } finally { |
|
772 | 5 | $blocksOut->indent(-1); |
|
773 | 5 | $blocksOut->appendCode("}"); |
|
774 | 5 | } |
|
775 | |||
776 | 4 | return $blocksOut; |
|
777 | } |
||
778 | |||
779 | /** |
||
780 | * Output the source of a node as a PHP comment. |
||
781 | * |
||
782 | * @param DOMElement $node The node to output. |
||
783 | * @param DOMAttr[] $attributes Regular attributes. |
||
784 | * @param DOMAttr[] $special Special attributes. |
||
785 | * @param CompilerBuffer $out The output buffer for the results. |
||
786 | */ |
||
787 | 34 | protected function compileTagComment(DOMElement $node, $attributes, $special, CompilerBuffer $out) { |
|
0 ignored issues
–
show
|
|||
788 | // Don't double up comments. |
||
789 | 34 | if ($node->previousSibling && $node->previousSibling->nodeType === XML_COMMENT_NODE) { |
|
790 | return; |
||
791 | } |
||
792 | |||
793 | 34 | $str = '<'.$node->tagName; |
|
794 | 34 | foreach ($special as $attr) { |
|
795 | /* @var DOMAttr $attr */ |
||
796 | 34 | $str .= ' '.$attr->name.(empty($attr->value) ? '' : '="'.str_replace('"', '"', $attr->value).'"'); |
|
797 | 34 | } |
|
798 | 34 | $str .= '>'; |
|
0 ignored issues
–
show
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. ![]() |
|||
799 | 34 | $comments = explode("\n", $str); |
|
800 | 34 | foreach ($comments as $comment) { |
|
801 | 34 | $out->appendCode("// $comment\n"); |
|
802 | 34 | } |
|
803 | 34 | } |
|
804 | |||
805 | /** |
||
806 | * @param DOMElement $node |
||
807 | * @param DOMAttr[] $attributes |
||
808 | * @param DOMAttr[] $special |
||
809 | * @param CompilerBuffer $out |
||
810 | * @param bool $force |
||
811 | */ |
||
812 | 62 | protected function compileOpenTag(DOMElement $node, $attributes, $special, CompilerBuffer $out, $force = false) { |
|
813 | 62 | $tagNameExpr = !empty($special[self::T_TAG]) ? $special[self::T_TAG]->value : ''; |
|
814 | |||
815 | 62 | if ($node->tagName === self::T_X && empty($tagNameExpr)) { |
|
816 | 6 | return; |
|
817 | } |
||
818 | |||
819 | 59 | if (!empty($tagNameExpr)) { |
|
820 | 5 | $tagNameExpr = $this->expr($tagNameExpr, $out, $special[self::T_TAG]); |
|
821 | 5 | $tagName = $node->tagName === 'x' ? "''" : var_export($node->tagName, true); |
|
0 ignored issues
–
show
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. ![]() |
|||
822 | |||
823 | 5 | $tagVar = $out->depthName('$tag', 1); |
|
824 | 5 | if ($node->hasChildNodes() || $force) { |
|
825 | 5 | $out->setNodeProp($node, self::T_TAG, $tagVar); |
|
826 | 5 | $out->depth(+1); |
|
827 | 5 | } |
|
828 | |||
829 | 5 | $out->appendCode("\n"); |
|
830 | 5 | $this->compileTagComment($node, $attributes, $special, $out); |
|
831 | 5 | $out->appendCode("$tagVar = \$this->tagName($tagNameExpr, $tagName);\n"); |
|
832 | 5 | $out->appendCode("if ($tagVar) {\n"); |
|
833 | 5 | $out->indent(+1); |
|
834 | 5 | $out->echoLiteral('<'); |
|
835 | 5 | $out->echoCode($tagVar); |
|
836 | 5 | } else { |
|
837 | 55 | $out->echoLiteral('<'.$node->tagName); |
|
838 | } |
||
839 | |||
840 | /* @var DOMAttr $attribute */ |
||
841 | 59 | foreach ($attributes as $name => $attribute) { |
|
842 | // Check for an attribute expression. |
||
843 | 27 | if ($this->isExpression($attribute->value)) { |
|
844 | 19 | $out->echoCode( |
|
845 | 19 | '$this->attribute('.var_export($name, true).', '. |
|
846 | 19 | $this->expr(substr($attribute->value, 1, -1), $out, $attribute). |
|
847 | 19 | ')'); |
|
848 | 27 | } elseif (null !== $fn = $this->getAttributeFunction($attribute)) { |
|
849 | 7 | $value = call_user_func($fn, var_export($attribute->value, true)); |
|
0 ignored issues
–
show
Equals sign not aligned correctly; expected 1 space but found 2 spaces
This check looks for improperly formatted assignments. Every assignment must have exactly one space before and one space after the equals operator. To illustrate: $a = "a";
$ab = "ab";
$abc = "abc";
will have no issues, while $a = "a";
$ab = "ab";
$abc = "abc";
will report issues in lines 1 and 2. ![]() |
|||
850 | |||
851 | 7 | $out->echoCode('$this->attribute('.var_export($name, true).', '.$value.')'); |
|
852 | 9 | } elseif ((empty($attribute->value) || $attribute->value === $name) && isset(self::$boolAttributes[$name])) { |
|
0 ignored issues
–
show
|
|||
853 | 2 | $out->echoLiteral(' '.$name); |
|
854 | 2 | } else { |
|
855 | 4 | $out->echoLiteral(' '.$name.'="'); |
|
856 | 4 | $out->echoLiteral(htmlspecialchars($attribute->value)); |
|
857 | 4 | $out->echoLiteral('"'); |
|
858 | } |
||
859 | 59 | } |
|
860 | |||
861 | 59 | if ($node->hasChildNodes() || $force) { |
|
862 | 57 | $out->echoLiteral('>'); |
|
863 | 57 | } else { |
|
864 | 3 | $out->echoLiteral(" />"); |
|
865 | } |
||
866 | |||
867 | 59 | if (!empty($tagNameExpr)) { |
|
868 | 5 | $out->indent(-1); |
|
869 | 5 | $out->appendCode("}\n\n"); |
|
870 | 5 | } |
|
871 | 59 | } |
|
872 | |||
873 | 31 | private function isExpression($value) { |
|
874 | 31 | return preg_match('`^{\S.*}$`', $value); |
|
875 | } |
||
876 | |||
877 | 60 | protected function compileCloseTag(DOMElement $node, $special, CompilerBuffer $out, $force = false) { |
|
0 ignored issues
–
show
|
|||
878 | 60 | if (!$force && !$node->hasChildNodes()) { |
|
879 | 3 | return; |
|
880 | } |
||
881 | |||
882 | 58 | $tagNameExpr = $out->getNodeProp($node, self::T_TAG); //!empty($special[self::T_TAG]) ? $special[self::T_TAG]->value : ''; |
|
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
74% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
883 | 58 | if (!empty($tagNameExpr)) { |
|
884 | 5 | $out->appendCode("\n"); |
|
885 | 5 | $out->appendCode("if ($tagNameExpr) {\n"); |
|
886 | 5 | $out->indent(+1); |
|
887 | |||
888 | 5 | $out->echoLiteral('</'); |
|
889 | 5 | $out->echoCode($tagNameExpr); |
|
890 | 5 | $out->echoLiteral('>'); |
|
891 | 5 | $out->indent(-1); |
|
892 | 5 | $out->appendCode("}\n"); |
|
893 | 5 | $out->depth(-1); |
|
894 | 58 | } elseif ($node->tagName !== self::T_X) { |
|
895 | 51 | $out->echoLiteral("</{$node->tagName}>"); |
|
896 | 51 | } |
|
897 | 58 | } |
|
898 | |||
899 | 4 | protected function isEmptyText(DOMNode $node) { |
|
900 | 4 | return $node instanceof \DOMText && empty(trim($node->data)); |
|
901 | } |
||
902 | |||
903 | 14 | protected function isEmptyNode(DOMNode $node) { |
|
904 | 14 | if (!$node->hasChildNodes()) { |
|
905 | 10 | return true; |
|
906 | } |
||
907 | |||
908 | 5 | foreach ($node->childNodes as $childNode) { |
|
909 | 5 | if ($childNode instanceof DOMElement) { |
|
910 | 3 | return false; |
|
911 | } |
||
912 | 2 | if ($childNode instanceof \DOMText && !$this->isEmptyText($childNode)) { |
|
913 | 2 | return false; |
|
914 | } |
||
915 | } |
||
916 | |||
917 | return true; |
||
918 | } |
||
919 | |||
920 | 11 | protected function compileIf(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
921 | 11 | $this->compileTagComment($node, $attributes, $special, $out); |
|
922 | 11 | $expr = $this->expr($special[self::T_IF]->value, $out, $special[self::T_IF]); |
|
923 | 10 | unset($special[self::T_IF]); |
|
924 | |||
925 | 10 | $elseNode = $this->findSpecialNode($node, self::T_ELSE, self::T_IF); |
|
926 | 10 | $out->setNodeProp($elseNode, 'skip', true); |
|
927 | |||
928 | 10 | $out->appendCode('if ('.$expr.") {\n"); |
|
929 | 10 | $out->indent(+1); |
|
930 | |||
931 | 10 | $this->compileSpecialNode($node, $attributes, $special, $out); |
|
932 | |||
933 | 10 | $out->indent(-1); |
|
934 | |||
935 | 10 | if ($elseNode) { |
|
936 | 2 | list($attributes, $special) = $this->splitAttributes($elseNode); |
|
937 | 2 | unset($special[self::T_ELSE]); |
|
938 | |||
939 | 2 | $out->appendCode("} else {\n"); |
|
940 | |||
941 | 2 | $out->indent(+1); |
|
942 | 2 | $this->compileSpecialNode($elseNode, $attributes, $special, $out); |
|
943 | 2 | $out->indent(-1); |
|
944 | 2 | } |
|
945 | |||
946 | 10 | $out->appendCode("}\n"); |
|
947 | 10 | } |
|
948 | |||
949 | 16 | protected function compileEach(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
950 | 16 | $this->compileTagComment($node, $attributes, $special, $out); |
|
951 | 16 | $this->compileOpenTag($node, $attributes, $special, $out); |
|
952 | |||
953 | 16 | $emptyNode = $this->findSpecialNode($node, self::T_EMPTY, self::T_ELSE); |
|
954 | 16 | $out->setNodeProp($emptyNode, 'skip', true); |
|
955 | |||
956 | 16 | if ($emptyNode === null) { |
|
957 | 14 | $this->compileEachLoop($node, $attributes, $special, $out); |
|
958 | 13 | } else { |
|
959 | 2 | $expr = $this->expr("empty({$special[self::T_EACH]->value})", $out); |
|
960 | |||
961 | 2 | list ($emptyAttributes, $emptySpecial) = $this->splitAttributes($emptyNode); |
|
962 | 2 | unset($emptySpecial[self::T_EMPTY]); |
|
963 | |||
964 | 2 | $out->appendCode('if ('.$expr.") {\n"); |
|
965 | |||
966 | 2 | $out->indent(+1); |
|
967 | 2 | $this->compileSpecialNode($emptyNode, $emptyAttributes, $emptySpecial, $out); |
|
968 | 2 | $out->indent(-1); |
|
969 | |||
970 | 2 | $out->appendCode("} else {\n"); |
|
971 | |||
972 | 2 | $out->indent(+1); |
|
973 | 2 | $this->compileEachLoop($node, $attributes, $special, $out); |
|
974 | 2 | $out->indent(-1); |
|
975 | |||
976 | 2 | $out->appendCode("}\n"); |
|
977 | } |
||
978 | |||
979 | 15 | $this->compileCloseTag($node, $special, $out); |
|
980 | 15 | } |
|
981 | |||
982 | 2 | protected function compileWith(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
983 | 2 | $this->compileTagComment($node, $attributes, $special, $out); |
|
984 | |||
985 | 2 | $out->depth(+1); |
|
986 | 2 | $scope = ['this' => $out->depthName('props')]; |
|
987 | 2 | if (!empty($special[self::T_AS])) { |
|
988 | 2 | if (preg_match(self::IDENT_REGEX, $special[self::T_AS]->value, $m)) { |
|
989 | // The template specified an x-as attribute to alias the with expression. |
||
990 | 1 | $scope = [$m[1] => $out->depthName('props')]; |
|
991 | 1 | } else { |
|
992 | 1 | throw $out->createCompilerException( |
|
993 | 1 | $special[self::T_AS], |
|
994 | 1 | new \Exception("Invalid identifier in x-as attribute.") |
|
995 | 1 | ); |
|
996 | } |
||
997 | 1 | } |
|
998 | 1 | $with = $this->expr($special[self::T_WITH]->value, $out); |
|
999 | |||
1000 | 1 | unset($special[self::T_WITH], $special[self::T_AS]); |
|
1001 | |||
1002 | 1 | $out->pushScope($scope); |
|
1003 | 1 | $out->appendCode('$'.$out->depthName('props')." = $with;\n"); |
|
1004 | |||
1005 | 1 | $this->compileSpecialNode($node, $attributes, $special, $out); |
|
1006 | |||
1007 | 1 | $out->depth(-1); |
|
1008 | 1 | $out->popScope(); |
|
1009 | 1 | } |
|
1010 | |||
1011 | 2 | protected function compileLiteral(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
1012 | 2 | $this->compileTagComment($node, $attributes, $special, $out); |
|
1013 | 2 | unset($special[self::T_LITERAL]); |
|
1014 | |||
1015 | 2 | $this->compileOpenTag($node, $attributes, $special, $out); |
|
1016 | |||
1017 | 2 | foreach ($node->childNodes as $childNode) { |
|
1018 | 2 | $html = $childNode->ownerDocument->saveHTML($childNode); |
|
1019 | 2 | $out->echoLiteral($html); |
|
1020 | 2 | } |
|
1021 | |||
1022 | 2 | $this->compileCloseTag($node, $special, $out); |
|
1023 | 2 | } |
|
1024 | |||
1025 | 22 | protected function compileElement(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
1026 | 22 | $this->compileOpenTag($node, $attributes, $special, $out); |
|
1027 | |||
1028 | 22 | foreach ($node->childNodes as $childNode) { |
|
1029 | 22 | $this->compileNode($childNode, $out); |
|
1030 | 22 | } |
|
1031 | |||
1032 | 22 | $this->compileCloseTag($node, $special, $out); |
|
1033 | 22 | } |
|
1034 | |||
1035 | /** |
||
1036 | * Find a special node in relation to another node. |
||
1037 | * |
||
1038 | * This method is used to find things such as x-empty and x-else elements. |
||
1039 | * |
||
1040 | * @param DOMElement $node The node to search in relation to. |
||
1041 | * @param string $attribute The name of the attribute to search for. |
||
1042 | * @param string $parentAttribute The name of the parent attribute to resolve conflicts. |
||
1043 | * @return DOMElement|null Returns the found element node or **null** if not found. |
||
1044 | */ |
||
1045 | 25 | protected function findSpecialNode(DOMElement $node, $attribute, $parentAttribute) { |
|
1046 | // First look for a sibling after the node. |
||
1047 | 25 | for ($sibNode = $node->nextSibling; $sibNode !== null; $sibNode = $sibNode->nextSibling) { |
|
1048 | 2 | if ($sibNode instanceof DOMElement && $sibNode->hasAttribute($attribute)) { |
|
1049 | 2 | return $sibNode; |
|
1050 | } |
||
1051 | |||
1052 | // Stop searching if we encounter another node. |
||
1053 | 2 | if (!$this->isEmptyText($sibNode)) { |
|
1054 | break; |
||
1055 | } |
||
1056 | 2 | } |
|
1057 | |||
1058 | // Next look inside the node. |
||
1059 | 23 | $parentFound = false; |
|
1060 | 23 | foreach ($node->childNodes as $childNode) { |
|
1061 | 22 | if (!$parentFound && $childNode instanceof DOMElement && $childNode->hasAttribute($attribute)) { |
|
1062 | 2 | return $childNode; |
|
1063 | } |
||
1064 | |||
1065 | 22 | if ($childNode instanceof DOMElement) { |
|
1066 | 16 | $parentFound = $childNode->hasAttribute($parentAttribute); |
|
1067 | 22 | } elseif ($childNode instanceof \DOMText && !empty(trim($childNode->data))) { |
|
1068 | 6 | $parentFound = false; |
|
1069 | 6 | } |
|
1070 | 23 | } |
|
1071 | |||
1072 | 21 | return null; |
|
1073 | } |
||
1074 | |||
1075 | /** |
||
1076 | * @param DOMElement $node |
||
1077 | * @param array $attributes |
||
1078 | * @param array $special |
||
1079 | * @param CompilerBuffer $out |
||
1080 | */ |
||
1081 | 16 | private function compileEachLoop(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
0 ignored issues
–
show
|
|||
1082 | 16 | $each = $this->expr($special[self::T_EACH]->value, $out); |
|
1083 | 16 | unset($special[self::T_EACH]); |
|
1084 | |||
1085 | 16 | $as = ['', $out->depthName('props', 1)]; |
|
0 ignored issues
–
show
Equals sign not aligned with surrounding assignments; expected 4 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. ![]() |
|||
1086 | 16 | $scope = ['this' => $as[1]]; |
|
1087 | 16 | if (!empty($special[self::T_AS])) { |
|
1088 | 9 | if (preg_match('`^(?:([a-z0-9]+)\s+)?([a-z0-9]+)$`i', $special[self::T_AS]->value, $m)) { |
|
1089 | 8 | $scope = [$m[2] => $as[1]]; |
|
1090 | 8 | if (!empty($m[1])) { |
|
1091 | 5 | $scope[$m[1]] = $as[0] = $out->depthName('i', 1); |
|
1092 | |||
1093 | // Add loop tracking variables. |
||
1094 | 5 | $d = $out->depthName('', 1); |
|
1095 | 5 | } |
|
1096 | 8 | } else { |
|
1097 | 1 | throw $out->createCompilerException( |
|
1098 | 1 | $special[self::T_AS], |
|
1099 | 1 | new \Exception("Invalid identifier in x-as attribute.") |
|
1100 | 1 | ); |
|
1101 | } |
||
1102 | 8 | } |
|
1103 | 15 | unset($special[self::T_AS]); |
|
1104 | |||
1105 | 15 | if (isset($d)) { |
|
1106 | 5 | $out->appendCode("\$count$d = count($each);\n"); |
|
1107 | 5 | $out->appendCode("\$index$d = -1;\n"); |
|
1108 | 5 | } |
|
1109 | |||
1110 | 15 | if (empty($as[0])) { |
|
1111 | 10 | $out->appendCode("foreach ($each as \${$as[1]}) {\n"); |
|
1112 | 10 | } else { |
|
1113 | 5 | $out->appendCode("foreach ($each as \${$as[0]} => \${$as[1]}) {\n"); |
|
1114 | } |
||
1115 | 15 | $out->depth(+1); |
|
1116 | 15 | $out->indent(+1); |
|
1117 | 15 | $out->pushScope($scope); |
|
1118 | |||
1119 | 15 | if (isset($d)) { |
|
1120 | 5 | $out->appendCode("\$index$d++;\n"); |
|
1121 | 5 | $out->appendCode("\$first$d = \$index$d === 0;\n"); |
|
1122 | 5 | $out->appendCode("\$last$d = \$index$d === \$count$d - 1;\n"); |
|
1123 | 5 | } |
|
1124 | |||
1125 | 15 | foreach ($node->childNodes as $childNode) { |
|
1126 | 15 | $this->compileNode($childNode, $out); |
|
1127 | 15 | } |
|
1128 | |||
1129 | 15 | $out->indent(-1); |
|
1130 | 15 | $out->depth(-1); |
|
1131 | 15 | $out->popScope(); |
|
1132 | 15 | $out->appendCode("}\n"); |
|
1133 | 15 | } |
|
1134 | |||
1135 | 66 | protected function ltrim($text, \DOMNode $node, CompilerBuffer $out) { |
|
0 ignored issues
–
show
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 ![]() |
|||
1136 | 66 | if ($this->inPre($node)) { |
|
1137 | return $text; |
||
1138 | } |
||
1139 | |||
1140 | |||
1141 | 66 | for ($sib = $node->previousSibling; $sib !== null && $this->canSkip($sib, $out); $sib = $sib->previousSibling) { |
|
0 ignored issues
–
show
|
|||
1142 | // |
||
1143 | 5 | } |
|
1144 | 66 | if ($sib === null) { |
|
1145 | 66 | return ltrim($text); |
|
1146 | } |
||
1147 | // if ($this->canSkip($sib, $out)) { |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
61% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
1148 | // return ltrim($text); |
||
1149 | // } |
||
1150 | |||
1151 | 7 | $text = preg_replace('`^\s*\n\s*`', "\n", $text, -1, $count); |
|
1152 | 7 | if ($count === 0) { |
|
1153 | $text = preg_replace('`^\s+`', ' ', $text); |
||
1154 | } |
||
1155 | |||
1156 | // if ($sib !== null && ($sib->nodeType === XML_COMMENT_NODE || in_array($sib->tagName, static::$blocks))) { |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
53% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
1157 | // return ltrim($text); |
||
1158 | // } |
||
1159 | 7 | return $text; |
|
1160 | } |
||
1161 | |||
1162 | /** |
||
1163 | * Whether or not a node can be skipped for the purposes of trimming whitespace. |
||
1164 | * |
||
1165 | * @param DOMNode|null $node The node to test. |
||
1166 | * @param CompilerBuffer|null $out The compiler information. |
||
1167 | * @return bool Returns **true** if whitespace can be trimmed right up to the node or **false** otherwise. |
||
1168 | */ |
||
1169 | 13 | private function canSkip(\DOMNode $node, CompilerBuffer $out) { |
|
1170 | 13 | if ($out->getNodeProp($node, 'skip')) { |
|
1171 | 2 | return true; |
|
1172 | } |
||
1173 | |||
1174 | 13 | switch ($node->nodeType) { |
|
1175 | 13 | case XML_TEXT_NODE: |
|
1176 | 2 | return false; |
|
1177 | 13 | case XML_COMMENT_NODE: |
|
1178 | 1 | return true; |
|
1179 | 13 | case XML_ELEMENT_NODE: |
|
1180 | /* @var \DOMElement $node */ |
||
1181 | 13 | if ($node->tagName === self::T_X |
|
1182 | 13 | || ($node->tagName === 'script' && $node->hasAttribute(self::T_AS)) // expression assignment |
|
1183 | 12 | || ($node->hasAttribute(self::T_WITH) && $node->hasAttribute(self::T_AS)) // with assignment |
|
1184 | 9 | || ($node->hasAttribute(self::T_BLOCK) || $node->hasAttribute(self::T_COMPONENT)) |
|
1185 | 13 | ) { |
|
1186 | 6 | return true; |
|
1187 | } |
||
1188 | 8 | } |
|
1189 | |||
1190 | 8 | return false; |
|
1191 | } |
||
1192 | |||
1193 | 66 | protected function rtrim($text, \DOMNode $node, CompilerBuffer $out) { |
|
0 ignored issues
–
show
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 ![]() |
|||
1194 | 66 | if ($this->inPre($node)) { |
|
1195 | return $text; |
||
1196 | } |
||
1197 | |||
1198 | 66 | for ($sib = $node->nextSibling; $sib !== null && $this->canSkip($sib, $out); $sib = $sib->nextSibling) { |
|
0 ignored issues
–
show
|
|||
1199 | // |
||
1200 | 5 | } |
|
1201 | 66 | if ($sib === null) { |
|
1202 | 65 | return rtrim($text); |
|
1203 | } |
||
1204 | |||
1205 | 5 | $text = preg_replace('`\s*\n\s*$`', "\n", $text, -1, $count); |
|
1206 | 5 | if ($count === 0) { |
|
1207 | 5 | $text = preg_replace('`\s+$`', ' ', $text); |
|
1208 | 5 | } |
|
1209 | |||
1210 | // if ($sib !== null && ($sib->nodeType === XML_COMMENT_NODE || in_array($sib->tagName, static::$blocks))) { |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
53% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
1211 | // return rtrim($text); |
||
1212 | // } |
||
1213 | 5 | return $text; |
|
1214 | } |
||
1215 | |||
1216 | 66 | protected function inPre(\DOMNode $node) { |
|
1217 | 66 | for ($node = $node->parentNode; $node !== null; $node = $node->parentNode) { |
|
1218 | 66 | if (in_array($node->nodeType, ['code', 'pre'], true)) { |
|
1219 | return true; |
||
1220 | } |
||
1221 | 66 | } |
|
1222 | 66 | return false; |
|
1223 | } |
||
1224 | |||
1225 | 4 | private function compileChildBlock(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
1226 | /* @var DOMAttr $child */ |
||
1227 | 4 | $child = $special[self::T_CHILDREN]; |
|
1228 | 4 | unset($special[self::T_CHILDREN]); |
|
1229 | |||
1230 | 4 | $name = $child->value === '' ? 0 : strtolower($child->value); |
|
1231 | 4 | if ($name !== 0) { |
|
1232 | 2 | if (empty($name)) { |
|
1233 | throw $out->createCompilerException($special[self::T_BLOCK], new \Exception("Block names cannot be empty.")); |
||
1234 | } |
||
1235 | 2 | if (!preg_match(self::IDENT_REGEX, $name)) { |
|
1236 | throw $out->createCompilerException($special[self::T_BLOCK], new \Exception("The block name isn't a valid identifier.")); |
||
1237 | } |
||
1238 | 2 | } |
|
1239 | |||
1240 | 4 | $keyStr = var_export($name, true); |
|
1241 | |||
1242 | 4 | $this->compileOpenTag($node, $attributes, $special, $out, true); |
|
1243 | |||
1244 | 4 | $out->appendCode("\$this->writeChildren(\$children[{$keyStr}]);\n"); |
|
1245 | |||
1246 | 4 | $this->compileCloseTag($node, $special, $out, true); |
|
1247 | 4 | } |
|
1248 | |||
1249 | /** |
||
1250 | * Compile an `<script type="ebi">` node. |
||
1251 | * |
||
1252 | * @param DOMElement $node The node to compile. |
||
1253 | * @param DOMAttr[] $attributes The node's attributes. |
||
1254 | * @param DOMAttr[] $special An array of special attributes. |
||
1255 | * @param CompilerBuffer $out The compiler output. |
||
1256 | */ |
||
1257 | 10 | private function compileExpressionNode(DOMElement $node, array $attributes, array $special, CompilerBuffer $out) { |
|
0 ignored issues
–
show
|
|||
1258 | 10 | $str = $node->nodeValue; |
|
1259 | |||
1260 | try { |
||
1261 | 10 | $expr = $this->expr($str, $out); |
|
1262 | 10 | } catch (SyntaxError $ex) { |
|
1263 | 1 | $context = []; |
|
1264 | 1 | if (preg_match('`^(.*) around position (\d*)\.$`', $ex->getMessage(), $m)) { |
|
1265 | 1 | $add = substr_count($str, "\n", 0, $m[2]); |
|
1266 | |||
1267 | 1 | $context['line'] = $node->getLineNo() + $add; |
|
1268 | 1 | } |
|
1269 | |||
1270 | 1 | throw $out->createCompilerException($node, $ex, $context); |
|
1271 | } |
||
1272 | |||
1273 | 9 | if (isset($special[self::T_AS])) { |
|
1274 | 7 | if (null !== $this->closest($node, function (\DOMNode $n) use ($out) { |
|
1275 | 7 | return $out->getNodeProp($n, self::T_INCLUDE); |
|
1276 | 7 | })) { |
|
1277 | 1 | throw $out->createCompilerException( |
|
1278 | 1 | $node, |
|
1279 | 1 | new \Exception("Expressions with x-as assignments cannot be declared inside child blocks.") |
|
1280 | 1 | ); |
|
1281 | } |
||
1282 | |||
1283 | 6 | if (preg_match(self::IDENT_REGEX, $special[self::T_AS]->value, $m)) { |
|
1284 | // The template specified an x-as attribute to alias the with expression. |
||
1285 | 5 | $out->depth(+1); |
|
1286 | 5 | $scope = [$m[1] => $out->depthName('expr')]; |
|
1287 | 5 | $out->pushScope($scope); |
|
1288 | 5 | $out->appendCode('$'.$out->depthName('expr')." = $expr;\n"); |
|
1289 | 5 | } else { |
|
1290 | 1 | throw $out->createCompilerException( |
|
1291 | 1 | $special[self::T_AS], |
|
1292 | 1 | new \Exception("Invalid identifier in x-as attribute.") |
|
1293 | 1 | ); |
|
1294 | } |
||
1295 | 7 | } elseif (!empty($special[self::T_UNESCAPE])) { |
|
1296 | 1 | $out->echoCode($expr); |
|
1297 | 1 | } else { |
|
1298 | 1 | $out->echoCode($this->compileEscape($expr)); |
|
1299 | } |
||
1300 | 7 | } |
|
1301 | |||
1302 | /** |
||
1303 | * Similar to jQuery's closest method. |
||
1304 | * |
||
1305 | * @param DOMNode $node |
||
1306 | * @param callable $test |
||
1307 | * @return DOMNode |
||
1308 | */ |
||
1309 | 7 | private function closest(\DOMNode $node, callable $test) { |
|
1310 | 7 | for ($visitor = $node; $visitor !== null && !$test($visitor); $visitor = $visitor->parentNode) { |
|
0 ignored issues
–
show
|
|||
1311 | // Do nothing. The logic is all in the loop. |
||
1312 | 7 | } |
|
1313 | 7 | return $visitor; |
|
1314 | } |
||
1315 | |||
1316 | /** |
||
1317 | * @param DOMElement $node |
||
1318 | * @param $attributes |
||
1319 | * @param $special |
||
1320 | * @param CompilerBuffer $out |
||
1321 | */ |
||
1322 | 39 | protected function compileBasicElement(DOMElement $node, $attributes, $special, CompilerBuffer $out) { |
|
1323 | 39 | $this->compileOpenTag($node, $attributes, $special, $out); |
|
1324 | |||
1325 | 39 | foreach ($node->childNodes as $childNode) { |
|
1326 | 37 | $this->compileNode($childNode, $out); |
|
1327 | 39 | } |
|
1328 | |||
1329 | 38 | $this->compileCloseTag($node, $special, $out); |
|
1330 | 38 | } |
|
1331 | |||
1332 | 31 | protected function compileEscape($php) { |
|
1333 | // return 'htmlspecialchars('.$php.')'; |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
56% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
1334 | 31 | return '$this->escape('.$php.')'; |
|
1335 | } |
||
1336 | } |
||
1337 |
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
will produce issues in the first and second line, while this second example
will produce no issues.