Completed
Push — master ( 129dcd...701d92 )
by Craig
06:47
created

CoreExtension::pageSetVar()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 8
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 2
nop 2
dl 8
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Zikula package.
5
 *
6
 * Copyright Zikula Foundation - http://zikula.org/
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Zikula\Bundle\CoreBundle\Twig\Extension;
13
14
use Symfony\Component\DependencyInjection\ContainerInterface;
15
use Zikula\Bundle\CoreBundle\Twig;
16
use Zikula\Bundle\CoreBundle\Twig\Extension\SimpleFunction\DefaultPathSimpleFunction;
17
use Zikula\Bundle\CoreBundle\Twig\Extension\SimpleFunction\DispatchEventSimpleFunction;
18
use Zikula\Common\Translator\TranslatorInterface;
19
use Zikula\ThemeModule\Engine\AssetBag;
20
21
class CoreExtension extends \Twig_Extension
22
{
23
    /**
24
     * @var ContainerInterface
25
     */
26
    private $container;
27
28
    /**
29
     * @var TranslatorInterface
30
     */
31
    private $translator;
32
33
    public function __construct(ContainerInterface $container = null)
34
    {
35
        $this->container = $container;
36
        $this->translator = $container->get('translator.default');
0 ignored issues
show
Bug introduced by
It seems like $container is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
37
    }
38
39
    /**
40
     * @return ContainerInterface
41
     */
42
    public function getContainer()
43
    {
44
        return $this->container;
45
    }
46
47
    public function getTokenParsers()
48
    {
49
        return [
50
            new Twig\TokenParser\SwitchTokenParser()
51
        ];
52
    }
53
54
    /**
55
     * Returns a list of functions to add to the existing list.
56
     *
57
     * @return array An array of functions
58
     */
59
    public function getFunctions()
60
    {
61
        $functions = [
62
            new \Twig_SimpleFunction('button', [$this, 'button']),
63
            new \Twig_SimpleFunction('img', [$this, 'img']),
64
            new \Twig_SimpleFunction('icon', [$this, 'icon']),
65
            new \Twig_SimpleFunction('lang', [$this, 'lang']),
66
            new \Twig_SimpleFunction('langdirection', [$this, 'langDirection']),
67
            new \Twig_SimpleFunction('zasset', [$this, 'getAssetPath']),
68
            new \Twig_SimpleFunction('showflashes', [$this, 'showFlashes'], ['is_safe' => ['html']]),
69
            new \Twig_SimpleFunction('array_unset', [$this, 'arrayUnset']),
70
            new \Twig_SimpleFunction('pageSetVar', [$this, 'pageSetVar']),
71
            new \Twig_SimpleFunction('pageAddAsset', [$this, 'pageAddAsset']),
72
            new \Twig_SimpleFunction('pageGetVar', [$this, 'pageGetVar']),
73
            new \Twig_SimpleFunction('getModVar', [$this, 'getModVar']),
74
            new \Twig_SimpleFunction('getSystemVar', [$this, 'getSystemVar']),
75
            new \Twig_SimpleFunction('setMetaTag', [$this, 'setMetaTag']),
76
            new \Twig_SimpleFunction('defaultPath', [new DefaultPathSimpleFunction($this), 'getDefaultPath']),
77
            new \Twig_SimpleFunction('modAvailable', [$this, 'modAvailable']),
78
            new \Twig_SimpleFunction('callFunc', [$this, 'callFunc']),
79
        ];
80
        if (is_object($this->container)) {
81
            $functions[] = new \Twig_SimpleFunction('dispatchEvent', [new DispatchEventSimpleFunction($this->container->get('event_dispatcher')), 'dispatchEvent']);
82
        }
83
84
        return $functions;
85
    }
86
87
    public function getFilters()
88
    {
89
        return [
90
            new \Twig_SimpleFilter('languageName', [$this, 'languageName']),
91
            new \Twig_SimpleFilter('yesNo', [$this, 'yesNo']),
92
            new \Twig_SimpleFilter('php', [$this, 'applyPhp']),
93
            new \Twig_SimpleFilter('protectMail', [$this, 'protectMailAddress'], ['is_safe' => ['html']]),
94
            new \Twig_SimpleFilter('profileLinkByUserId', [$this, 'profileLinkByUserId'], ['is_safe' => ['html']]),
95
            new \Twig_SimpleFilter('profileLinkByUserName', [$this, 'profileLinkByUserName'], ['is_safe' => ['html']])
96
        ];
97
    }
98
99
    public function getAssetPath($path)
100
    {
101
        return $this->container->get('zikula_core.common.theme.asset_helper')->resolve($path);
102
    }
103
104
    /**
105
     * Function to get the language direction
106
     *
107
     * @return string   the language direction
108
     */
109
    public function langDirection()
110
    {
111
        return \ZLanguage::getDirection();
112
    }
113
114
    public function button()
115
    {
116
    }
117
118
    public function img()
119
    {
120
    }
121
122
    public function icon()
123
    {
124
    }
125
126
    /**
127
     * Display flash messages in twig template. Defaults to bootstrap alert classes.
128
     *
129
     * <pre>
130
     *  {{ showflashes() }}
131
     *  {{ showflashes({'class': 'custom-class', 'tag': 'span'}) }}
132
     * </pre>
133
     *
134
     * @param array $params
135
     * @return string
136
     */
137
    public function showFlashes(array $params = [])
138
    {
139
        $result = '';
140
        $total_messages = [];
141
        $messageTypeMap = [
142
            'error' => 'danger',
143
            'warning' => 'warning',
144
            'status' => 'success',
145
            'danger' => 'danger',
146
            'success' => 'success',
147
            'info' => 'info'
148
            // @todo provide some class constants to use instead of direct strings
149
        ];
150
151
        foreach ($messageTypeMap as $messageType => $bootstrapClass) {
152
            $session = $this->container->get('session');
153
            $messages = $session->isStarted() ? $session->getFlashBag()->get($messageType) : [];
154
            if (count($messages) > 0) {
155
                // Set class for the messages.
156
                $class = (!empty($params['class'])) ? $params['class'] : "alert alert-$bootstrapClass";
157
                $total_messages = $total_messages + $messages;
158
                // Build output of the messages.
159
                if (empty($params['tag']) || ($params['tag'] != 'span')) {
160
                    $params['tag'] = 'div';
161
                }
162
                $result .= '<' . $params['tag'] . ' class="' . $class . '"';
163
                if (!empty($params['style'])) {
164
                    $result .= ' style="' . $params['style'] . '"';
165
                }
166
                $result .= '>';
167
                $result .= implode('<hr />', $messages);
168
                $result .= '</' . $params['tag'] . '>';
169
            }
170
        }
171
172
        if (empty($total_messages)) {
173
            return "";
174
        }
175
176
        return $result;
177
    }
178
179
    /**
180
     * Delete a key of an array
181
     *
182
     * @param array  $array Source array
183
     * @param string $key   The key to remove
184
     *
185
     * @return array
186
     */
187
    public function arrayUnset($array, $key)
188
    {
189
        unset($array[$key]);
190
191
        return $array;
192
    }
193
194
    /**
195
     * @param string $code
196
     * @return string
197
     */
198
    public function languageName($code)
199
    {
200
        return \ZLanguage::getLanguageName($code);
201
    }
202
203
    public function yesNo($string)
204
    {
205
        if ($string != '0' && $string != '1') {
206
            return $string;
207
        }
208
209
        return (bool)$string ? $this->translator->__('Yes') : $this->translator->__('No');
210
    }
211
212
    /**
213
     * Apply an existing function (e.g. php's `md5`) to a string.
214
     *
215
     * @param $string
216
     * @param $func
217
     * @return mixed
218
     */
219
    public function applyPhp($string, $func)
220
    {
221
        if (function_exists($func)) {
222
            return $func($string);
223
        }
224
225
        return $string;
226
    }
227
228
    /**
229
     * Protect a given mail address by finding the text 'x@y' and replacing
230
     * it with HTML entities. This provides protection against email harvesters.
231
     *
232
     * @param string
233
     * @return string
234
     */
235
    public function protectMailAddress($string)
236
    {
237
        $string = preg_replace_callback(
238
            '/(.)@(.)/s',
239
            function ($m) {
240
                return "&#" . sprintf("%03d", ord($m[1])) . ";&#064;&#" .sprintf("%03d", ord($m[2])) . ";";
241
            },
242
            $string
243
        );
244
245
        return $string;
246
    }
247
248
    /**
249
     * Create a link to a users profile from the UID.
250
     *
251
     * Examples
252
     *
253
     *   Simple version, shows the username
254
     *   {{ uid|profileLinkByUserId() }}
255
     *   Simple version, shows username, using class="classname"
256
     *   {{ uid|profileLinkByUserId(class='classname') }}
257
     *   Using profile.gif instead of username, no class
258
     *   {{ uid|profileLinkByUserId(image='images/profile.gif') }}
259
     *
260
     * @param integer $userId    The users uid
261
     * @param string  $class     The class name for the link (optional)
262
     * @param string  $image     Path to the image to show instead of the username (optional)
263
     * @param integer $maxLength If set then user names are truncated to x chars
264
     * @return string The output
265
     */
266 View Code Duplication
    public function profileLinkByUserId($userId, $class = '', $image = '', $maxLength = 0)
0 ignored issues
show
Duplication introduced by
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...
267
    {
268
        if (empty($userId) || (int)$userId < 1) {
269
            return $userId;
270
        }
271
272
        return $this->determineProfileLink((int)$userId, null, $class, $image, $maxLength);
273
    }
274
275
    /**
276
     * Create a link to a users profile from the username.
277
     *
278
     * Examples
279
     *
280
     *   Simple version, shows the username
281
     *   {{ username|profileLinkByUserName() }}
282
     *   Simple version, shows username, using class="classname"
283
     *   {{ username|profileLinkByUserName(class='classname') }}
284
     *   Using profile.gif instead of username, no class
285
     *   {{ username|profileLinkByUserName('image'='images/profile.gif') }}
286
     *
287
     * @param string  $userName  The users name
288
     * @param string  $class     The class name for the link (optional)
289
     * @param string  $image     Path to the image to show instead of the username (optional)
290
     * @param integer $maxLength If set then user names are truncated to x chars
291
     * @return string The output
292
     */
293 View Code Duplication
    public function profileLinkByUserName($userName, $class = '', $image = '', $maxLength = 0)
0 ignored issues
show
Duplication introduced by
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...
294
    {
295
        if (empty($userName)) {
296
            return $userName;
297
        }
298
299
        return $this->determineProfileLink(null, $userName, $class, $image, $maxLength);
300
    }
301
302
    /**
303
     * Internal function used by profileLinkByUserId() and profileLinkByUserName().
304
     *
305
     * @param integer $userId    The users uid
306
     * @param string  $userName  The users name
307
     * @param string  $class     The class name for the link (optional)
308
     * @param string  $imagePath Path to the image to show instead of the username (optional)
309
     * @param integer $maxLength If set then user names are truncated to x chars
310
     * @return string The output
311
     */
312
    private function determineProfileLink($userId = null, $userName = null, $class = '', $imagePath = '', $maxLength = 0)
313
    {
314
        if (!isset($userId) && !isset($userName)) {
315
            throw new \InvalidArgumentException();
316
        }
317
        if ($userId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $userId of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
318
            $user = $this->container->get('zikula_users_module.user_repository')->find($userId);
319
        } else {
320
            $user = $this->container->get('zikula_users_module.user_repository')->findBy(['uname' => $userName]);
321
        }
322
323
        $profileModule = $this->container->get('zikula_extensions_module.api.variable')->getSystemVar('profilemodule', '');
324
        if (empty($profileModule) || !$this->container->get('kernel')->isBundle($profileModule)) {
325
            return $user->getUname();
326
        }
327
328
        // @todo replace with ProfileInterface usage
329
        $userDisplayName = \ModUtil::apiFunc($profileModule, 'user', 'getUserDisplayName', ['uid' => $user->getUid()]);
330
        if (empty($userDisplayName)) {
331
            $userDisplayName = $user->getUname();
332
        }
333
        $class = !empty($class) ? ' class="' . htmlspecialchars($class, ENT_QUOTES) . '"' : '';
334
335
        if (!empty($imagePath)) {
336
            $show = '<img src="' . htmlspecialchars($imagePath, ENT_QUOTES) . '" alt="' . htmlspecialchars($userDisplayName, ENT_QUOTES) . '" />';
337
        } elseif ($maxLength > 0) {
338
            // truncate the user name to $maxLength chars
339
            $length = strlen($userDisplayName);
340
            $truncEnd = ($maxLength > $length) ? $length : $maxLength;
341
            $show  = htmlspecialchars(substr($userDisplayName, 0, $truncEnd), ENT_QUOTES);
342
        } else {
343
            $show = htmlspecialchars($userDisplayName, ENT_QUOTES);
344
        }
345
        // @todo replace with ProfileInterface usage
346
        $href = htmlspecialchars(\ModUtil::url($profileModule, 'user', 'view', ['uid' => $userId], null, null, true));
347
348
        return '<a' . $class . ' title="' . (__('Profile')) . ': ' . htmlspecialchars($userDisplayName, ENT_QUOTES) . '" href="' . $href . '">' . $show . '</a>';
349
    }
350
351
    /**
352
     * Zikula imposes no restriction on page variable names.
353
     * Typical usage is to set `title` `meta.charset` `lang` etc.
354
     * array values are set using `.` in the `$name` string (e.g. `meta.charset`)
355
     * @param string $name
356
     * @param string $value
357
     */
358 View Code Duplication
    public function pageSetVar($name, $value)
0 ignored issues
show
Duplication introduced by
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...
359
    {
360
        if (empty($name) || empty($value)) {
361
            throw new \InvalidArgumentException($this->translator->__('Empty argument at') . ':' . __FILE__ . '::' . __LINE__);
362
        }
363
364
        $this->container->get('zikula_core.common.theme.pagevars')->set($name, $value);
365
    }
366
367
    /**
368
     * Zikula allows only the following asset types
369
     * <ul>
370
     *  <li>stylesheet</li>
371
     *  <li>javascript</li>
372
     *  <li>header</li>
373
     *  <li>footer</li>
374
     * </ul>
375
     *
376
     * @param string $type
377
     * @param string $value
378
     * @param int $weight
379
     */
380
    public function pageAddAsset($type, $value, $weight = AssetBag::WEIGHT_DEFAULT)
381
    {
382
        if (empty($type) || empty($value)) {
383
            throw new \InvalidArgumentException($this->translator->__('Empty argument at') . ':' . __FILE__ . '::' . __LINE__);
384
        }
385
        if (!in_array($type, ['stylesheet', 'javascript', 'header', 'footer']) || !is_numeric($weight)) {
386
            throw new \InvalidArgumentException($this->translator->__('Empty argument at') . ':' . __FILE__ . '::' . __LINE__);
387
        }
388
389
        // ensure proper variable types
390
        $value = (string) $value;
391
        $type = (string) $type;
392
        $weight = (int) $weight;
393
394
        if ('stylesheet' == $type) {
395
            $this->container->get('zikula_core.common.theme.assets_css')->add([$value => $weight]);
396
        } elseif ('javascript' == $type) {
397
            $this->container->get('zikula_core.common.theme.assets_js')->add([$value => $weight]);
398
        } elseif ('header' == $type) {
399
            $this->container->get('zikula_core.common.theme.assets_header')->add([$value => $weight]);
400
        } elseif ('footer' == $type) {
401
            $this->container->get('zikula_core.common.theme.assets_footer')->add([$value => $weight]);
402
        }
403
    }
404
405
    /**
406
     * @param $name
407
     * @param null $default
408
     * @return mixed
409
     */
410 View Code Duplication
    public function pageGetVar($name, $default = null)
0 ignored issues
show
Duplication introduced by
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...
411
    {
412
        if (empty($name)) {
413
            throw new \InvalidArgumentException($this->translator->__('Empty argument at') . ':' . __FILE__ . '::' . __LINE__);
414
        }
415
416
        return $this->container->get('zikula_core.common.theme.pagevars')->get($name, $default);
417
    }
418
419
    /**
420
     * @param $module
421
     * @param $name
422
     * @param null $default
423
     * @return mixed
424
     */
425 View Code Duplication
    public function getModVar($module, $name, $default = null)
0 ignored issues
show
Duplication introduced by
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...
426
    {
427
        if (empty($module) || empty($name)) {
428
            throw new \InvalidArgumentException($this->translator->__('Empty argument at') . ':' . __FILE__ . '::' . __LINE__);
429
        }
430
431
        return $this->container->get('zikula_extensions_module.api.variable')->get($module, $name, $default);
432
    }
433
434
    /**
435
     * @param $name
436
     * @param null $default
437
     * @return mixed
438
     */
439 View Code Duplication
    public function getSystemVar($name, $default = null)
0 ignored issues
show
Duplication introduced by
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...
440
    {
441
        if (empty($name)) {
442
            throw new \InvalidArgumentException($this->translator->__('Empty argument at') . ':' . __FILE__ . '::' . __LINE__);
443
        }
444
445
        return $this->container->get('zikula_extensions_module.api.variable')->getSystemVar($name, $default);
446
    }
447
448
    /**
449
     * @param string $name
450
     * @param string $value
451
     */
452
    public function setMetaTag($name, $value)
453
    {
454
        if (empty($name) || empty($value)) {
455
            throw new \InvalidArgumentException($this->translator->__('Empty argument at') . ':' . __FILE__ . '::' . __LINE__);
456
        }
457
458
        $metaTags = $this->container->hasParameter('zikula_view.metatags') ? $this->container->getParameter('zikula_view.metatags') : [];
459
        $metaTags[$name] = htmlspecialchars($value, ENT_QUOTES);
460
        $this->container->setParameter('zikula_view.metatags', $metaTags);
461
    }
462
463
    /**
464
     * @deprecated remove at Core-2.0
465
     * @param string $modname
466
     * @param bool $force
467
     * @return bool
468
     */
469
    public function modAvailable($modname, $force = false)
470
    {
471
        $result = \ModUtil::available($modname, $force);
472
473
        return (bool)$result;
474
    }
475
476
    /**
477
     * Call a php callable with parameters.
478
     * @param callable $callable
479
     * @param array $params
480
     * @return mixed
481
     */
482
    public function callFunc(callable $callable, array $params = [])
483
    {
484
        if (function_exists($callable)) {
485
            return call_user_func_array($callable, $params);
486
        }
487
        throw new \InvalidArgumentException($this->translator->__('Function does not exist or is not callable.') . ':' . __FILE__ . '::' . __LINE__);
488
    }
489
}
490