Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
98.55% |
136 / 138 |
|
66.67% |
2 / 3 |
CRAP | |
0.00% |
0 / 1 |
Parser | |
98.55% |
136 / 138 |
|
66.67% |
2 / 3 |
66 | |
0.00% |
0 / 1 |
parseArrays | |
100.00% |
85 / 85 |
|
100.00% |
1 / 1 |
41 | |||
parseConditionals | |
94.29% |
33 / 35 |
|
0.00% |
0 / 1 |
10.02 | |||
parseScalars | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
15 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\View\Template\Stream; |
15 | |
16 | /** |
17 | * View stream template parser class |
18 | * |
19 | * @category Pop |
20 | * @package Pop\View |
21 | * @author Nick Sagona, III <dev@nolainteractive.com> |
22 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
23 | * @license http://www.popphp.org/license New BSD License |
24 | * @version 4.0.0 |
25 | */ |
26 | class Parser |
27 | { |
28 | |
29 | /** |
30 | * Parse arrays in the template string |
31 | * |
32 | * @param string $template |
33 | * @param array $data |
34 | * @param string $output |
35 | * @return string |
36 | */ |
37 | public static function parseArrays(string $template, array $data, string $output): string |
38 | { |
39 | foreach ($data as $key => $value) { |
40 | if (is_array($value) || ($value instanceof \ArrayAccess)) { |
41 | $start = '[{' . $key . '}]'; |
42 | $end = '[{/' . $key . '}]'; |
43 | if ((str_contains($template, $start)) && (str_contains($template, $end))) { |
44 | $loopCode = substr($template, strpos($template, $start)); |
45 | $loopCode = substr($loopCode, 0, (strpos($loopCode, $end) + strlen($end))); |
46 | |
47 | $outputLoop = ''; |
48 | $i = 0; |
49 | foreach ($value as $ky => $val) { |
50 | $loop = str_replace($start, '', $loopCode); |
51 | $loop = str_replace($end, '', $loop); |
52 | if (str_contains($loop, '[{if(')) { |
53 | $matches = []; |
54 | preg_match_all('/\[{if/mi', $loop, $matches, PREG_OFFSET_CAPTURE); |
55 | |
56 | if (isset($matches[0]) && isset($matches[0][0])) { |
57 | foreach ($matches[0] as $match) { |
58 | $cond = substr($loop, $match[1]); |
59 | $cond = substr($cond, 0, strpos($cond, '[{/if}]') + 7); |
60 | $var = substr($cond, strpos($cond, '(') + 1); |
61 | $var = substr($var, 0, strpos($var, ')')); |
62 | // If var is an array |
63 | if (str_contains($var, '[')) { |
64 | $index = substr($var, (strpos($var, '[') + 1)); |
65 | $index = substr($index, 0, strpos($index, ']')); |
66 | $var = substr($var, 0, strpos($var, '[')); |
67 | $varSet = (!empty($val[$var][$index])); |
68 | } else { |
69 | $index = null; |
70 | $varSet = (!empty($val[$var])); |
71 | } |
72 | if (str_contains($cond, '[{else}]')) { |
73 | if ($varSet) { |
74 | $code = substr($cond, (strpos($cond, ')}]') + 3)); |
75 | $code = substr($code, 0, strpos($code, '[{else}]')); |
76 | $code = ($index !== null) ? |
77 | str_replace('[{' . $var . '[' . $index . ']}]', $val[$var][$index], $code) : |
78 | str_replace('[{' . $var . '}]', $val[$var], $code); |
79 | $loop = str_replace($cond, $code, $loop); |
80 | } else { |
81 | $code = substr($cond, (strpos($cond, '[{else}]') + 8)); |
82 | $code = substr($code, 0, strpos($code, '[{/if}]')); |
83 | $loop = str_replace($cond, $code, $loop); |
84 | } |
85 | } else { |
86 | if ($varSet) { |
87 | $code = substr($cond, (strpos($cond, ')}]') + 3)); |
88 | $code = substr($code, 0, strpos($code, '[{/if}]')); |
89 | $code = ($index !== null) ? |
90 | str_replace('[{' . $var . '[' . $index . ']}]', $val[$var][$index], $code) : |
91 | str_replace('[{' . $var . '}]', $val[$var], $code); |
92 | $loop = str_replace($cond, $code, $loop); |
93 | } else { |
94 | $loop = str_replace($cond, '', $loop); |
95 | } |
96 | } |
97 | } |
98 | } |
99 | } |
100 | |
101 | // Handle nested array |
102 | if (is_array($val) || ($value instanceof \ArrayAccess) || ($val instanceof \ArrayObject)) { |
103 | if (is_numeric($ky)) { |
104 | $oLoop = $loop; |
105 | foreach ($val as $k => $v) { |
106 | // Check is value is stringable |
107 | if ((is_object($v) && method_exists($v, '__toString')) || |
108 | (!is_object($v) && !is_array($v))) { |
109 | $oLoop = str_replace('[{' . $k . '}]', $v, $oLoop); |
110 | } |
111 | } |
112 | if (str_contains($oLoop, '[{i}]')) { |
113 | $oLoop = str_replace('[{i}]', ($i + 1), $oLoop); |
114 | } |
115 | $outputLoop .= $oLoop; |
116 | } else { |
117 | $s = '[{' . $ky . '}]'; |
118 | $e = '[{/' . $ky . '}]'; |
119 | if ((str_contains($loop, $s)) && (str_contains($loop, $e))) { |
120 | $l = $loop; |
121 | $lCode = substr($l, strpos($l, $s)); |
122 | $lCode = substr($lCode, 0, (strpos($lCode, $e) + strlen($e))); |
123 | |
124 | $l = str_replace($s, '', $lCode); |
125 | $l = str_replace($e, '', $l); |
126 | $oLoop = ''; |
127 | $j = 1; |
128 | |
129 | foreach ($val as $k => $v) { |
130 | // Check is value is stringable |
131 | if ((is_object($v) && method_exists($v, '__toString')) || |
132 | (!is_object($v) && !is_array($v))) { |
133 | if (str_contains($l, '[{i}]')) { |
134 | $oLoop .= str_replace(['[{key}]', '[{value}]', '[{i}]'], [$k, $v, $j], $l); |
135 | } else { |
136 | $oLoop .= str_replace(['[{key}]', '[{value}]'], [$k, $v], $l); |
137 | } |
138 | $j++; |
139 | } |
140 | } |
141 | $outputLoop = str_replace($lCode, $oLoop, $loop); |
142 | } |
143 | } |
144 | // Handle scalar |
145 | } else { |
146 | // Check is value is stringable |
147 | if ((is_object($val) && method_exists($val, '__toString')) || |
148 | (!is_object($val) && !is_array($val))) { |
149 | if (str_contains($loop, '[{i}]')) { |
150 | $outputLoop .= str_replace(['[{key}]', '[{value}]', '[{i}]'], [$ky, $val, ($i + 1)], $loop); |
151 | } else { |
152 | $outputLoop .= str_replace(['[{key}]', '[{value}]'], [$ky, $val], $loop); |
153 | } |
154 | } |
155 | } |
156 | $i++; |
157 | if ($i < count($value)) { |
158 | $outputLoop .= PHP_EOL; |
159 | } |
160 | } |
161 | $output = str_replace($loopCode, $outputLoop, $output); |
162 | } |
163 | } |
164 | } |
165 | |
166 | return $output; |
167 | } |
168 | |
169 | /** |
170 | * Parse conditionals in the template string |
171 | * |
172 | * @param string $template |
173 | * @param array $data |
174 | * @param string $output |
175 | * @return string |
176 | */ |
177 | public static function parseConditionals(string $template, array $data, string $output): string |
178 | { |
179 | $matches = []; |
180 | preg_match_all('/\[{if/mi', $template, $matches, PREG_OFFSET_CAPTURE); |
181 | if (isset($matches[0]) && isset($matches[0][0])) { |
182 | foreach ($matches[0] as $match) { |
183 | $cond = substr($template, $match[1]); |
184 | $cond = substr($cond, 0, strpos($cond, '[{/if}]') + 7); |
185 | $var = substr($cond, strpos($cond, '(') + 1); |
186 | $var = substr($var, 0, strpos($var, ')')); |
187 | |
188 | // If var is an array |
189 | if (str_contains($var, '[')) { |
190 | $index = substr($var, (strpos($var, '[') + 1)); |
191 | $index = substr($index, 0, strpos($index, ']')); |
192 | $var = substr($var, 0, strpos($var, '[')); |
193 | $varSet = (!empty($data[$var][$index])); |
194 | } else { |
195 | $index = null; |
196 | $varSet = (!empty($data[$var])); |
197 | } |
198 | if (str_contains($cond, '[{else}]')) { |
199 | if ($varSet) { |
200 | $code = substr($cond, (strpos($cond, ')}]') + 3)); |
201 | $code = substr($code, 0, strpos($code, '[{else}]')); |
202 | $code = ($index !== null) ? |
203 | str_replace('[{' . $var . '[' . $index . ']}]', $data[$var][$index], $code) : |
204 | str_replace('[{' . $var . '}]', $data[$var], $code); |
205 | $output = str_replace($cond, $code, $output); |
206 | } else { |
207 | $code = substr($cond, (strpos($cond, '[{else}]') + 8)); |
208 | $code = substr($code, 0, strpos($code, '[{/if}]')); |
209 | $output = str_replace($cond, $code, $output); |
210 | } |
211 | } else { |
212 | if ($varSet) { |
213 | $code = substr($cond, (strpos($cond, ')}]') + 3)); |
214 | $code = substr($code, 0, strpos($code, '[{/if}]')); |
215 | $code = ($index !== null) ? |
216 | str_replace('[{' . $var . '[' . $index . ']}]', $data[$var][$index], $code) : |
217 | str_replace('[{' . $var . '}]', $data[$var], $code); |
218 | $output = str_replace($cond, $code, $output); |
219 | } else { |
220 | $output = str_replace($cond, '', $output); |
221 | } |
222 | } |
223 | } |
224 | } |
225 | |
226 | return $output; |
227 | } |
228 | |
229 | /** |
230 | * Parse scalar values in the template string |
231 | * |
232 | * @param array $data |
233 | * @param string $output |
234 | * @return string |
235 | */ |
236 | public static function parseScalars(array $data, string $output): string |
237 | { |
238 | foreach ($data as $key => $value) { |
239 | if (is_array($value) && (str_contains($output, '[{' . $key . '['))) { |
240 | $matches = []; |
241 | preg_match_all('/\[{' . $key .'\[/mi', $output, $matches, PREG_OFFSET_CAPTURE); |
242 | |
243 | if (isset($matches[0]) && isset($matches[0][0])) { |
244 | $indices = []; |
245 | foreach ($matches[0] as $match) { |
246 | $i = substr($output, $match[1] + (strlen($key) + 3)); |
247 | $i = substr($i, 0, strpos($i, ']')); |
248 | $indices[] = $i; |
249 | } |
250 | foreach ($indices as $i) { |
251 | if (isset($value[$i])) { |
252 | $output = str_replace('[{' . $key . '[' . $i . ']}]', $value[$i], $output); |
253 | } else { |
254 | $output = str_replace('[{' . $key . '[' . $i . ']}]', '', $output); |
255 | } |
256 | } |
257 | } |
258 | } else if (!is_array($value) && !($value instanceof \ArrayAccess)) { |
259 | // Check is value is stringable |
260 | if ((is_object($value) && method_exists($value, '__toString')) || (!is_object($value) && !is_array($value))) { |
261 | $output = str_replace('[{' . $key . '}]', $value, $output); |
262 | } |
263 | } |
264 | } |
265 | |
266 | return $output; |
267 | } |
268 | } |