Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
40.87% |
85 / 208 |
|
41.38% |
12 / 29 |
CRAP | |
0.00% |
0 / 1 |
TwigExtension | |
40.87% |
85 / 208 |
|
41.38% |
12 / 29 |
1143.99 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getFunctions | |
100.00% |
26 / 26 |
|
100.00% |
1 / 1 |
1 | |||
isImageAllowed | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
getLanguageDescriptor | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
isNumeric | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getNow | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
getSystemStatus | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
toTextFormat | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
3 | |||
formatDateTime | |
87.50% |
14 / 16 |
|
0.00% |
0 / 1 |
3.02 | |||
currentRoute | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
6 | |||
currentLang | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
currentLocale | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
currentVersion | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
urlGet | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
csvProperty | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
20 | |||
azPrefixList | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
30 | |||
azPrefixListCollator | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
20 | |||
isValueInArray | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
remoteInclude | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
30 | |||
includeUrl | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
baseUrl | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getEsiFromPath | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
12 | |||
getClientHost | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
toSortableString | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
2 | |||
sortByName | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
sortFirstChar | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
dumpAppProfiler | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
kindOfPayment | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
42 |
1 | <?php |
2 | |
3 | /** |
4 | * @package BO Slim |
5 | * @copyright BerlinOnline Stadtportal GmbH & Co. KG |
6 | **/ |
7 | |
8 | namespace BO\Slim; |
9 | |
10 | use Twig\Extension\AbstractExtension; |
11 | |
12 | /** |
13 | * Extension for Twig and Slim |
14 | * |
15 | * @SuppressWarnings(PublicMethod) |
16 | * @SuppressWarnings(TooManyMethods) |
17 | * @SuppressWarnings(Coupling) |
18 | * @SuppressWarnings(Complexity) |
19 | */ |
20 | class TwigExtension extends AbstractExtension |
21 | { |
22 | /** |
23 | * @var \BO\Slim\Container |
24 | */ |
25 | private $container; |
26 | |
27 | public function __construct($container) |
28 | { |
29 | $this->container = $container; |
30 | } |
31 | |
32 | public function getName() |
33 | { |
34 | return 'boslimExtension'; |
35 | } |
36 | |
37 | public function getFunctions() |
38 | { |
39 | $safe = array('is_safe' => array('html')); |
40 | return array( |
41 | new \Twig\TwigFunction('urlGet', array($this, 'urlGet')), |
42 | new \Twig\TwigFunction('csvProperty', array($this, 'csvProperty')), |
43 | new \Twig\TwigFunction('azPrefixList', array($this, 'azPrefixList')), |
44 | new \Twig\TwigFunction('azPrefixListCollator', array($this, 'azPrefixListCollator')), |
45 | new \Twig\TwigFunction('isValueInArray', array($this, 'isValueInArray')), |
46 | new \Twig\TwigFunction('remoteInclude', array($this, 'remoteInclude'), $safe), |
47 | new \Twig\TwigFunction('includeUrl', array($this, 'includeUrl')), |
48 | new \Twig\TwigFunction('getEsiFromPath', array($this, 'getEsiFromPath')), |
49 | new \Twig\TwigFunction('baseUrl', array($this, 'baseUrl')), |
50 | new \Twig\TwigFunction('getLanguageDescriptor', array($this, 'getLanguageDescriptor')), |
51 | new \Twig\TwigFunction('currentLang', array($this, 'currentLang')), |
52 | new \Twig\TwigFunction('currentRoute', array($this, 'currentRoute')), |
53 | new \Twig\TwigFunction('currentLocale', array($this, 'currentLocale')), |
54 | new \Twig\TwigFunction('currentVersion', array($this, 'currentVersion')), |
55 | new \Twig\TwigFunction('formatDateTime', array($this, 'formatDateTime')), |
56 | new \Twig\TwigFunction('toTextFormat', array($this, 'toTextFormat')), |
57 | new \Twig\TwigFunction('getNow', array($this, 'getNow')), |
58 | new \Twig\TwigFunction('isNumeric', array($this, 'isNumeric')), |
59 | new \Twig\TwigFunction('dumpAppProfiler', array($this, 'dumpAppProfiler'), $safe), |
60 | new \Twig\TwigFunction('getSystemStatus', array($this, 'getSystemStatus'), $safe), |
61 | new \Twig\TwigFunction('getClientHost', array($this, 'getClientHost')), |
62 | new \Twig\TwigFunction('kindOfPayment', array($this, 'kindOfPayment')), |
63 | new \Twig\TwigFunction('isImageAllowed', array($this, 'isImageAllowed')), |
64 | ); |
65 | } |
66 | |
67 | |
68 | public static function isImageAllowed() |
69 | { |
70 | return (isset(\App::$isImageAllowed)) ? \App::$isImageAllowed : true; |
71 | } |
72 | |
73 | public function getLanguageDescriptor($locale = 'de') |
74 | { |
75 | $language = \App::$supportedLanguages[$locale] ?? []; |
76 | return $language['name'] ?? null; |
77 | } |
78 | |
79 | public static function isNumeric($var) |
80 | { |
81 | return is_numeric($var); |
82 | } |
83 | |
84 | public static function getNow() |
85 | { |
86 | if (\App::$now instanceof \DateTimeInterface) { |
87 | return \App::$now; |
88 | } |
89 | return new \DateTimeImmutable(); |
90 | } |
91 | |
92 | public static function getSystemStatus($env) |
93 | { |
94 | return getenv($env); |
95 | } |
96 | |
97 | public function toTextFormat($string) |
98 | { |
99 | $string = \strip_tags($string, '<br />'); |
100 | $temp = str_replace(array("<br />"), "\n", $string); |
101 | $lines = explode("\n", $temp); |
102 | $new_lines = array(); |
103 | foreach ($lines as $line) { |
104 | if (!empty($line)) { |
105 | $new_lines[] = trim($line); |
106 | } |
107 | } |
108 | $result = implode("\n", $new_lines); |
109 | return addSlashes($result); |
110 | } |
111 | |
112 | public function formatDateTime($dateString) |
113 | { |
114 | $dateTime = new \DateTimeImmutable( |
115 | $dateString->year . '-' . $dateString->month . '-' . $dateString->day, |
116 | new \DateTimezone('Europe/Berlin') |
117 | ); |
118 | $formatDate['date'] = Helper::getFormatedDates($dateTime, "EE, dd. MMMM yyyy"); |
119 | $formatDate['fulldate'] = Helper::getFormatedDates($dateTime, "EEEE, 'den' dd. MMMM yyyy"); |
120 | $formatDate['weekday'] = (date('w', $dateTime->getTimestamp()) == 0) ? |
121 | date('w', $dateTime->getTimestamp()) + 6 : |
122 | date('w', $dateTime->getTimestamp()) - 1; |
123 | $formatDate['ym'] = $dateTime->format('Y-m'); |
124 | $formatDate['ymd'] = $dateTime->format('Y-m-d'); |
125 | $formatDate['ts'] = $dateTime->getTimestamp(); |
126 | $formatDate['time'] = ($dateTime->format('H:i') != '00:00') ? |
127 | Helper::getFormatedDates($dateTime, 'HH:mm Uhr') : |
128 | false; |
129 | return $formatDate; |
130 | } |
131 | |
132 | public function currentRoute($lang = null) |
133 | { |
134 | $route = array( |
135 | 'name' => 'noroute', |
136 | 'params' => [] |
137 | ); |
138 | if ($this->container->has('currentRoute')) { |
139 | $routeParams = $this->container->get('currentRouteParams'); |
140 | if (null !== $lang && 'de' == $lang) { |
141 | unset($routeParams['lang']); |
142 | } elseif (\App::MULTILANGUAGE) { |
143 | $routeParams['lang'] = ($lang !== null) ? $lang : \App::$language->getCurrentLanguage(); |
144 | } |
145 | |
146 | $routeName = $this->container->get('currentRoute'); |
147 | $route = array( |
148 | 'name' => $routeName, |
149 | 'params' => $routeParams |
150 | ); |
151 | } |
152 | return $route; |
153 | } |
154 | |
155 | public function currentLang() |
156 | { |
157 | return (\App::MULTILANGUAGE) ? \App::$language->getCurrentLanguage() : 'de'; |
158 | } |
159 | |
160 | public function currentLocale() |
161 | { |
162 | $locale = 'de_DE'; |
163 | if (\App::MULTILANGUAGE) { |
164 | $locale = explode('.', \App::$language->getCurrentLocale()); |
165 | $locale = reset($locale); |
166 | } |
167 | return $locale; |
168 | } |
169 | |
170 | public function currentVersion() |
171 | { |
172 | $version = Version::getString(); |
173 | return ($version != Version::UNKNOWN) ? $version : Git::readCurrentVersion(); |
174 | } |
175 | |
176 | public function urlGet($routeName, $params = array(), $getparams = array()) |
177 | { |
178 | $url = \App::$slim->urlFor($routeName, $params); |
179 | $url = preg_replace('#^.*?(https?://)#', '\1', $url); // allow http:// routes |
180 | if ($getparams) { |
181 | $url .= '?' . http_build_query($getparams); |
182 | } |
183 | return Helper::proxySanitizeUri($url); |
184 | } |
185 | |
186 | public function csvProperty($list, $property) |
187 | { |
188 | $propertylist = array(); |
189 | foreach ($list as $item) { |
190 | if (!is_scalar($item) && array_key_exists($property, $item)) { |
191 | $propertylist[] = $item[$property]; |
192 | } |
193 | } |
194 | return implode(',', array_unique($propertylist)); |
195 | } |
196 | |
197 | public function azPrefixList($list, $property) |
198 | { |
199 | $azList = array(); |
200 | foreach ($list as $item) { |
201 | if (!is_scalar($item) && array_key_exists($property, $item)) { |
202 | $currentPrefix = self::sortFirstChar($item[$property]); |
203 | if (!array_key_exists($currentPrefix, $azList)) { |
204 | $azList[$currentPrefix] = array( |
205 | 'prefix' => $currentPrefix, |
206 | 'sublist' => array(), |
207 | ); |
208 | } |
209 | $azList[$currentPrefix]['sublist'][] = $item; |
210 | uasort($azList[$currentPrefix]['sublist'], array($this,'sortByName')); |
211 | ksort($azList); |
212 | } |
213 | } |
214 | return $azList; |
215 | } |
216 | |
217 | public function azPrefixListCollator($list, $property, $locale) |
218 | { |
219 | $collator = collator_create($locale); |
220 | $collator->setAttribute(\Collator::QUATERNARY, \Collator::ON); |
221 | $collator->setAttribute(\Collator::CASE_FIRST, \Collator::ON); |
222 | $collator->setAttribute(\Collator::NUMERIC_COLLATION, \Collator::ON); |
223 | |
224 | if (is_array($list)) { |
225 | uasort($list, function ($itemA, $itemB) use ($collator, $property) { |
226 | return collator_compare($collator, $itemA[$property], $itemB[$property]); |
227 | }); |
228 | } else { |
229 | $list = $list->sortWithCollator($property, $locale); |
230 | } |
231 | |
232 | $azList = array(); |
233 | |
234 | foreach ($list as $item) { |
235 | $currentPrefix = self::sortFirstChar($item[$property]); |
236 | if (!array_key_exists($currentPrefix, $azList)) { |
237 | $azList[$currentPrefix] = array( |
238 | 'prefix' => $currentPrefix, |
239 | 'sublist' => array(), |
240 | ); |
241 | } |
242 | $azList[$currentPrefix]['sublist'][] = $item; |
243 | } |
244 | return $azList; |
245 | } |
246 | |
247 | public function isValueInArray($value, $params) |
248 | { |
249 | $paramsArr = explode(',', $params); |
250 | if (in_array($value, $paramsArr)) { |
251 | return true; |
252 | } |
253 | return false; |
254 | } |
255 | |
256 | public static function remoteInclude($uri) |
257 | { |
258 | $prepend = ''; |
259 | $append = ''; |
260 | if (\App::DEBUG) { |
261 | $prepend = "<!-- include($uri) -->\n"; |
262 | $append = "\n<!-- /include($uri) -->"; |
263 | } |
264 | if (\App::ESI_ENABLED) { |
265 | // Varnish does not support https |
266 | $uri = preg_replace('#^(https?:)?//#', 'http://', $uri); |
267 | if (\App::DEBUG) { |
268 | $prepend = "<!-- replaced uri=$uri --> " . $prepend; |
269 | } |
270 | return $prepend . '<esi:include src="' . $uri . '" />' . $append; |
271 | } else { |
272 | $useragent = 'Client-' . (defined("\App::IDENTIFIER") ? constant("\App::IDENTIFIER") : 'ZMS'); |
273 | $options = array( |
274 | 'http' => array( |
275 | 'method' => "GET", |
276 | 'header' => "Accept-language: de\r\n" . |
277 | "Cookie: zms=development\r\n" . |
278 | "user-agent: $useragent \r\n" |
279 | ) |
280 | ); |
281 | $context = stream_context_create($options); |
282 | return $prepend . file_get_contents($uri, false, $context) . $append; |
283 | } |
284 | } |
285 | |
286 | public function includeUrl($withUri = true) |
287 | { |
288 | if (null === \App::$includeUrl) { |
289 | /** @var Request $request */ |
290 | $request = $this->container['request']; |
291 | $uri = (string)$request->getBasePath(); |
292 | if ($withUri) { |
293 | $uri = $request->getBaseUrl(); |
294 | $uri = preg_replace('#^https?://[^/]+#', '', $uri); //Do not force protocoll or host |
295 | } |
296 | return Helper::proxySanitizeUri($uri); |
297 | } else { |
298 | return \App::$includeUrl; |
299 | } |
300 | } |
301 | |
302 | public function baseUrl() |
303 | { |
304 | return $this->includeUrl(false); |
305 | } |
306 | |
307 | public function getEsiFromPath($path, $locale = false) |
308 | { |
309 | $localePath = ($locale && 'de' != $locale) ? '/' . $locale : ''; |
310 | return \App::$esiBaseUrl . $localePath . \App::$$path; |
311 | } |
312 | |
313 | public function getClientHost() |
314 | { |
315 | $request = $this->container['request']; |
316 | $headerList = ['host', 'x-forwarded-host']; |
317 | foreach ($headerList as $headername) { |
318 | if ($request->hasHeader($headername)) { |
319 | $hostname = $request->getHeaderLine($headername); |
320 | } |
321 | } |
322 | return $hostname; |
323 | } |
324 | |
325 | protected static function toSortableString($string) |
326 | { |
327 | $string = strtr($string, array( |
328 | 'Ä' => 'Ae', |
329 | 'Ö' => 'Oe', |
330 | 'Ü' => 'Ue', |
331 | 'ä' => 'ae', |
332 | 'ö' => 'oe', |
333 | 'ü' => 'ue', |
334 | 'ß' => 'ss', |
335 | '€' => 'E', |
336 | )); |
337 | return $string; |
338 | } |
339 | |
340 | protected static function sortByName($left, $right) |
341 | { |
342 | return strcmp( |
343 | self::toSortableString(strtolower($left['name'])), |
344 | strtolower(self::toSortableString($right['name'])) |
345 | ); |
346 | } |
347 | |
348 | protected static function sortFirstChar($string) |
349 | { |
350 | $firstChar = mb_substr($string, 0, 1); |
351 | $firstChar = mb_strtoupper($firstChar); |
352 | $firstChar = strtr($firstChar, array('Ä' => 'A', 'Ö' => 'O', 'Ü' => 'U')); |
353 | return $firstChar; |
354 | } |
355 | |
356 | public function dumpAppProfiler() |
357 | { |
358 | $output = '<h2>App Profiles</h2>' |
359 | . ' <p>For debugging: This log contains runtime information. |
360 | <strong>DISABLE FOR PRODUCTION!</strong></p><ul>'; |
361 | foreach (Profiler::$profileList as $entry) { |
362 | if ($entry instanceof Profiler) { |
363 | $output .= "<li>$entry</li>"; |
364 | } else { |
365 | $output .= \Tracy\Debugger::dump($entry, true); |
366 | } |
367 | } |
368 | return $output . '</ul>'; |
369 | } |
370 | |
371 | public function kindOfPayment($code) |
372 | { |
373 | $result = ''; |
374 | if ($code == 0) { |
375 | $result = 'eccash'; |
376 | } elseif ($code == 1) { |
377 | $result = 'nocash'; |
378 | } elseif ($code == 2) { |
379 | $result = 'ec'; |
380 | } elseif ($code == 3) { |
381 | $result = 'cash'; |
382 | } elseif ($code == 4) { |
383 | $result = 'subscribecash'; |
384 | } |
385 | return $result; |
386 | } |
387 | } |