Passed
Pull Request — master (#59)
by
unknown
03:47
created

Plugin.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php namespace VojtaSvoboda\TwigExtensions;
2
3
use App;
4
use Backend;
5
use Carbon\Carbon;
6
use Snilius\Twig\SortByFieldExtension;
7
use System\Classes\PluginBase;
8
use Twig_Extension_StringLoader;
9
use Twig_Extensions_Extension_Array;
10
use Twig_Extensions_Extension_Date;
11
use Twig_Extensions_Extension_Intl;
12
use Twig_Extensions_Extension_Text;
13
use VojtaSvoboda\TwigExtensions\Classes\TimeDiffTranslator;
14
15
/**
16
 * Twig Extensions Plugin.
17
 *
18
 * @see http://twig.sensiolabs.org/doc/extensions/index.html#extensions-install
19
 */
20
class Plugin extends PluginBase
21
{
22
    /**
23
     * @var boolean Determine if this plugin should have elevated privileges.
24
     */
25
    public $elevated = true;
26
27
    /**
28
     * Returns information about this plugin.
29
     *
30
     * @return array
31
     */
32
    public function pluginDetails()
33
    {
34
        return [
35
            'name'        => 'Twig Extensions',
36
            'description' => 'Add more Twig filters to your templates.',
37
            'author'      => 'Vojta Svoboda',
38
            'icon'        => 'icon-plus',
39
            'homepage'    => 'https://github.com/vojtasvoboda/oc-twigextensions-plugin',
40
        ];
41
    }
42
43 View Code Duplication
    public function boot()
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
44
    {
45
        $this->app->singleton('time_diff_translator', function ($app) {
46
            $loader = $app->make('translation.loader');
47
            $locale = $app->config->get('app.locale');
48
            $translator = $app->make(TimeDiffTranslator::class, [$loader, $locale]);
49
            $translator->setFallback($app->config->get('app.fallback_locale'));
50
51
            return $translator;
52
        });
53
    }
54
55
    /**
56
     * Add Twig extensions.
57
     *
58
     * @see Text extensions http://twig.sensiolabs.org/doc/extensions/text.html
59
     * @see Intl extensions http://twig.sensiolabs.org/doc/extensions/intl.html
60
     * @see Array extension http://twig.sensiolabs.org/doc/extensions/array.html
61
     * @see Time extension http://twig.sensiolabs.org/doc/extensions/date.html
62
     *
63
     * @return array
64
     */
65
    public function registerMarkupTags()
66
    {
67
        $filters = [];
68
        $functions = [];
69
70
        // init Twig
71
        $twig = $this->app->make('twig.environment');
72
73
        // add String Loader functions
74
        $functions += $this->getStringLoaderFunctions($twig);
75
76
        // add Config function
77
        $functions += $this->getConfigFunction();
78
79
        // add Env function
80
        $functions += $this->getEnvFunction();
81
82
        // add Session function
83
        $functions += $this->getSessionFunction();
84
85
        // add Trans function
86
        $functions += $this->getTransFunction();
87
88
        // add var_dump function
89
        $functions += $this->getVarDumpFunction();
90
91
        // add Text extensions
92
        $filters += $this->getTextFilters($twig);
93
94
        // add Intl extensions if php5-intl installed
95
        if (class_exists('IntlDateFormatter')) {
96
            $filters += $this->getLocalizedFilters($twig);
97
        }
98
99
        // add Array extensions
100
        $filters += $this->getArrayFilters();
101
102
        // add Time extensions
103
        $filters += $this->getTimeFilters($twig);
104
105
        // add Sort by Field extensions
106
        $filters += $this->getSortByField();
107
108
        // add Mail filters
109
        $filters += $this->getMailFilters();
110
111
        // add PHP functions
112
        $filters += $this->getPhpFunctions();
113
114
        // add File Version filter
115
        $filters += $this->getFileRevision();
116
117
        return [
118
            'filters'   => $filters,
119
            'functions' => $functions,
120
        ];
121
    }
122
123
    /**
124
     * Returns String Loader functions.
125
     *
126
     * @param \Twig_Environment $twig
127
     *
128
     * @return array
129
     */
130
    private function getStringLoaderFunctions($twig)
131
    {
132
        $stringLoader = new Twig_Extension_StringLoader();
133
        $stringLoaderFunc = $stringLoader->getFunctions();
134
135
        return [
136
            'template_from_string' => function ($template) use ($twig, $stringLoaderFunc) {
137
                $callable = $stringLoaderFunc[0]->getCallable();
138
                return $callable($twig, $template);
139
            }
140
        ];
141
    }
142
143
    /**
144
     * Returns Text filters.
145
     *
146
     * @param \Twig_Environment $twig
147
     *
148
     * @return array
149
     */
150
    private function getTextFilters($twig)
151
    {
152
        $textExtension = new Twig_Extensions_Extension_Text();
153
        $textFilters = $textExtension->getFilters();
154
155
        return [
156
            'truncate' => function ($value, $length = 30, $preserve = false, $separator = '...') use ($twig, $textFilters) {
157
                $callable = $textFilters[0]->getCallable();
158
                return $callable($twig, $value, $length, $preserve, $separator);
159
            },
160
            'wordwrap' => function ($value, $length = 80, $separator = "\n", $preserve = false) use ($twig, $textFilters) {
161
                $callable = $textFilters[1]->getCallable();
162
                return $callable($twig, $value, $length, $separator, $preserve);
163
            }
164
        ];
165
    }
166
167
    /**
168
     * Returns Intl filters.
169
     *
170
     * @param \Twig_Environment $twig
171
     *
172
     * @return array
173
     */
174
    private function getLocalizedFilters($twig)
175
    {
176
        $intlExtension = new Twig_Extensions_Extension_Intl();
177
        $intlFilters = $intlExtension->getFilters();
178
179
        return [
180
            'localizeddate' => function ($date, $dateFormat = 'medium', $timeFormat = 'medium', $locale = null, $timezone = null, $format = null) use ($twig, $intlFilters) {
181
                $callable = $intlFilters[0]->getCallable();
182
                return $callable($twig, $date, $dateFormat, $timeFormat, $locale, $timezone, $format);
183
            },
184
            'localizednumber' => function ($number, $style = 'decimal', $type = 'default', $locale = null) use ($twig, $intlFilters) {
185
                $callable = $intlFilters[1]->getCallable();
186
                return $callable($number, $style, $type, $locale);
187
            },
188
            'localizedcurrency' => function ($number, $currency = null, $locale = null) use ($twig, $intlFilters) {
189
                $callable = $intlFilters[2]->getCallable();
190
                return $callable($number, $currency, $locale);
191
            }
192
        ];
193
    }
194
195
    /**
196
     * Returns Array filters.
197
     *
198
     * @return array
199
     */
200
    private function getArrayFilters()
201
    {
202
        $arrayExtension = new Twig_Extensions_Extension_Array();
203
        $arrayFilters = $arrayExtension->getFilters();
204
205
        return [
206
            'shuffle' => function ($array) use ($arrayFilters) {
207
                $callable = $arrayFilters[0]->getCallable();
208
                return $callable($array);
209
            }
210
        ];
211
    }
212
213
    /**
214
     * Returns Date filters.
215
     *
216
     * @param \Twig_Environment $twig
217
     *
218
     * @return array
219
     */
220
    private function getTimeFilters($twig)
221
    {
222
        $translator = $this->app->make('time_diff_translator');
223
        $timeExtension = new Twig_Extensions_Extension_Date($translator);
224
        $timeFilters = $timeExtension->getFilters();
225
226
        return [
227
            'time_diff' => function ($date, $now = null) use ($twig, $timeFilters) {
228
                $callable = $timeFilters[0]->getCallable();
229
                return $callable($twig, $date, $now);
230
            }
231
        ];
232
    }
233
234
    /**
235
     * Returns Sort by Field filters.
236
     *
237
     * @return array
238
     */
239
    private function getSortByField()
240
    {
241
        $extension = new SortByFieldExtension();
242
        $filters = $extension->getFilters();
243
244
        return [
245
            'sortbyfield' => function ($array, $sort_by = null, $direction = 'asc') use ($filters) {
246
                $callable = $filters[0]->getCallable();
247
                return $callable($array, $sort_by, $direction);
248
            }
249
        ];
250
    }
251
252
    /**
253
     * Returns mail filters.
254
     *
255
     * @return array
256
     */
257
    private function getMailFilters()
258
    {
259
        return [
260
            'mailto' => function ($string, $link = true, $protected = true, $text = null, $class = "") {
261
                return $this->hideEmail($string, $link, $protected, $text, $class);
262
            }
263
        ];
264
    }
265
266
    /**
267
     * Returns plain PHP functions.
268
     *
269
     * @return array
270
     */
271
    private function getPhpFunctions()
272
    {
273
        return [
274
            'strftime' => function ($time, $format = '%d.%m.%Y %H:%M:%S') {
275
                $timeObj = new Carbon($time);
276
                return strftime($format, $timeObj->getTimestamp());
277
            },
278
            'uppercase' => function ($string) {
279
                return mb_convert_case($string, MB_CASE_UPPER, "UTF-8");
280
            },
281
            'json_decode' => function ($string) {
282
                return json_decode($string);
283
            },
284
            'lowercase' => function ($string) {
285
                return mb_convert_case($string, MB_CASE_LOWER, "UTF-8");
286
            },
287
            'ucfirst' => function ($string) {
288
                return ucfirst($string);
289
            },
290
            'lcfirst' => function ($string) {
291
                return lcfirst($string);
292
            },
293
            'ltrim' => function ($string, $charlist = " \t\n\r\0\x0B") {
294
                return ltrim($string, $charlist);
295
            },
296
            'rtrim' => function ($string, $charlist = " \t\n\r\0\x0B") {
297
                return rtrim($string, $charlist);
298
            },
299
            'str_repeat' => function ($string, $multiplier = 1) {
300
                return str_repeat($string, $multiplier);
301
            },
302
            'plural' => function ($string, $count = 2) {
303
                return str_plural($string, $count);
304
            },
305
            'strpad' => function ($string, $pad_length, $pad_string = ' ') {
306
                return str_pad($string, $pad_length, $pad_string, $pad_type = STR_PAD_BOTH);
307
            },
308
            'leftpad' => function ($string, $pad_length, $pad_string = ' ') {
309
                return str_pad($string, $pad_length, $pad_string, $pad_type = STR_PAD_LEFT);
310
            },
311
            'rightpad' => function ($string, $pad_length, $pad_string = ' ') {
312
                return str_pad($string, $pad_length, $pad_string, $pad_type = STR_PAD_RIGHT);
313
            },
314
            'rtl' => function ($string) {
315
                return strrev($string);
316
            },
317
            'str_replace' => function ($string, $search, $replace) {
318
                return str_replace($search, $replace, $string);
319
            },
320
            'strip_tags' => function ($string, $allow = '') {
321
                return strip_tags($string, $allow);
322
            },
323
            'var_dump' => function ($expression) {
324
                ob_start();
325
                var_dump($expression);
326
                $result = ob_get_clean();
327
328
                return $result;
329
            },
330
        ];
331
    }
332
333
    /**
334
     * Works like the config() helper function.
335
     *
336
     * @return array
337
     */
338
    private function getConfigFunction()
339
    {
340
        return [
341
            'config' => function ($key = null, $default = null) {
342
                return config($key, $default);
343
            },
344
        ];
345
    }
346
347
    /**
348
     * Works like the env() helper function.
349
     *
350
     * @return array
351
     */
352
    private function getEnvFunction()
353
    {
354
        return [
355
            'env' => function ($key, $default = null) {
356
                return env($key, $default);
357
            },
358
        ];
359
    }
360
361
    /**
362
     * Works like the session() helper function.
363
     *
364
     * @return array
365
     */
366
    private function getSessionFunction()
367
    {
368
        return [
369
            'session' => function ($key = null) {
370
                return session($key);
371
            },
372
        ];
373
    }
374
375
    /**
376
     * Works like the trans() helper function.
377
     *
378
     * @return array
379
     */
380
    private function getTransFunction()
381
    {
382
        return [
383
            'trans' => function ($key = null, $parameters = []) {
384
                return trans($key, $parameters);
385
            },
386
        ];
387
    }
388
389
    /**
390
     * Dumps information about a variable.
391
     *
392
     * @return array
393
     */
394
    private function getVarDumpFunction()
395
    {
396
        return [
397
            'var_dump' => function ($expression) {
398
                ob_start();
399
                var_dump($expression);
400
                $result = ob_get_clean();
401
402
                return $result;
403
            },
404
        ];
405
    }
406
407
    /**
408
     * Create protected link with mailto:
409
     *
410
     * @param string $email Email to render.
411
     * @param bool $link If email should be rendered as link.
412
     * @param bool $protected If email should be protected.
413
     * @param string $text Link text. Render email by default.
414
     *
415
     * @see http://www.maurits.vdschee.nl/php_hide_email/
416
     *
417
     * @return string
418
     */
419
    private function hideEmail($email, $link = true, $protected = true, $text = null, $class = "")
420
    {
421
        // email link text
422
        $linkText = $email;
423
        if ($text !== null) {
424
            $linkText = $text;
425
        }
426
427
        // if we want just unprotected link
428
        if (!$protected) {
429
            return $link ? '<a href="mailto:' . $email . '">' . $linkText . '</a>' : $linkText;
430
        }
431
432
        // turn on protection
433
        $character_set = '+-.0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
434
        $key = str_shuffle($character_set);
435
        $cipher_text = '';
436
        $id = 'e' . rand(1, 999999999);
437
        for ($i = 0; $i < strlen($email); $i += 1) {
438
            $cipher_text .= $key[strpos($character_set, $email[$i])];
439
        }
440
        $script = 'var a="' . $key . '";var b=a.split("").sort().join("");var c="' . $cipher_text . '";var d=""; var cl="'.$class.'";';
441
        $script .= 'for(var e=0;e<c.length;e++)d+=b.charAt(a.indexOf(c.charAt(e)));';
442
        $script .= 'var y = d;';
443
        if ($text !== null) {
444
            $script .= 'var y = "'.$text.'";';
445
        }
446
        if ($link) {
447
            $script .= 'document.getElementById("' . $id . '").innerHTML="<a class=\""+cl+"\" href=\\"mailto:"+d+"\\">"+y+"</a>"';
448
        } else {
449
            $script .= 'document.getElementById("' . $id . '").innerHTML=y';
450
        }
451
        $script = "eval(\"" . str_replace(array("\\", '"'), array("\\\\", '\"'), $script) . "\")";
452
        $script = '<script type="text/javascript">/*<![CDATA[*/' . $script . '/*]]>*/</script>';
453
454
        return '<span id="' . $id . '">[javascript protected email address]</span>' . $script;
455
    }
456
457
    /**
458
     * Appends this pattern: ? . {last modified date}
459
     * to an assets filename to force browser to reload
460
     * cached modified file.
461
     *
462
     * See: https://github.com/vojtasvoboda/oc-twigextensions-plugin/issues/25
463
     *
464
     * @return array
465
     */
466
    private function getFileRevision()
467
    {
468
        return [
469
            'revision' => function ($filename, $format = null) {
470
                // Remove http/web address from the file name if there is one to load it locally
471
                $prefix = url('/');
472
                $filename_ = trim(preg_replace('/^' . preg_quote($prefix, '/') . '/', '', $filename), '/');
473
                if (file_exists($filename_)) {
474
                    $timestamp = filemtime($filename_);
475
                    $prepend = ($format) ? date($format, $timestamp) : $timestamp;
476
477
                    return $filename . "?" . $prepend;
478
                }
479
480
                return $filename;
481
            },
482
        ];
483
    }
484
}
485