Passed
Push — master ( f0a9b1...5fb29c )
by MusikAnimal
04:44
created

AppExtension::getFallbackLangs()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file contains only the AppExtension class.
4
 */
5
6
namespace AppBundle\Twig;
7
8
use AppBundle\Helper\I18nHelper;
9
use DateTime;
10
use Symfony\Component\DependencyInjection\ContainerInterface;
11
use Symfony\Component\HttpFoundation\RequestStack;
12
use Symfony\Component\HttpFoundation\Session\SessionInterface;
13
use Twig_Extension;
14
use Xtools\Edit;
15
use Xtools\Project;
16
use Xtools\ProjectRepository;
17
use Xtools\User;
18
19
/**
20
 * Twig functions and filters for XTools.
21
 */
22
class AppExtension extends Twig_Extension
23
{
24
    /** @var ContainerInterface The application's container interface. */
25
    protected $container;
26
27
    /** @var RequestStack The request stack. */
28
    protected $requestStack;
29
30
    /** @var SessionInterface User's current session. */
31
    protected $session;
32
33
    /** @var I18nHelper For i18n and l10n. */
34
    protected $i18n;
35
36
    /** @var float Duration of the current HTTP request in seconds. */
37
    protected $requestTime;
38
39
    /**
40
     * Get the name of this extension.
41
     * @return string
42
     */
43 13
    public function getName()
44
    {
45 13
        return 'app_extension';
46
    }
47
48
    /**
49
     * Constructor, with the I18nHelper through dependency injection.
50
     * @param ContainerInterface $container
51
     * @param RequestStack $requestStack
52
     * @param SessionInterface $session
53
     * @param I18nHelper $i18n
54
     */
55 25
    public function __construct(
56
        ContainerInterface $container,
57
        RequestStack $requestStack,
58
        SessionInterface $session,
59
        I18nHelper $i18n
60
    ) {
61 25
        $this->container = $container;
62 25
        $this->requestStack = $requestStack;
63 25
        $this->session = $session;
64 25
        $this->i18n = $i18n;
65 25
    }
66
67
    /*********************************** FUNCTIONS ***********************************/
68
69
    /**
70
     * Get all functions that this class provides.
71
     * @return array
72
     */
73 12
    public function getFunctions()
74
    {
75 12
        $options = ['is_safe' => ['html']];
76
        return [
77 12
            new \Twig_SimpleFunction('request_time', [$this, 'requestTime'], $options),
78 12
            new \Twig_SimpleFunction('memory_usage', [$this, 'requestMemory'], $options),
79 12
            new \Twig_SimpleFunction('year', [$this, 'generateYear'], $options),
80 12
            new \Twig_SimpleFunction('msgIfExists', [$this, 'msgIfExists'], $options),
81 12
            new \Twig_SimpleFunction('msgExists', [$this, 'msgExists'], $options),
82 12
            new \Twig_SimpleFunction('msg', [$this, 'msg'], $options),
83 12
            new \Twig_SimpleFunction('lang', [$this, 'getLang'], $options),
84 12
            new \Twig_SimpleFunction('langName', [$this, 'getLangName'], $options),
85 12
            new \Twig_SimpleFunction('fallbackLangs', [$this, 'getFallbackLangs', $options]),
86 12
            new \Twig_SimpleFunction('allLangs', [$this, 'getAllLangs']),
87 12
            new \Twig_SimpleFunction('isRTL', [$this, 'isRTL']),
88 12
            new \Twig_SimpleFunction('isRTLLang', [$this, 'isRTLLang']),
89 12
            new \Twig_SimpleFunction('shortHash', [$this, 'gitShortHash']),
90 12
            new \Twig_SimpleFunction('hash', [$this, 'gitHash']),
91 12
            new \Twig_SimpleFunction('releaseDate', [$this, 'gitDate']),
92 12
            new \Twig_SimpleFunction('enabled', [$this, 'tabEnabled']),
93 12
            new \Twig_SimpleFunction('tools', [$this, 'allTools']),
94 12
            new \Twig_SimpleFunction('color', [$this, 'getColorList']),
95 12
            new \Twig_SimpleFunction('chartColor', [$this, 'chartColor']),
96 12
            new \Twig_SimpleFunction('isSingleWiki', [$this, 'isSingleWiki']),
97 12
            new \Twig_SimpleFunction('getReplagThreshold', [$this, 'getReplagThreshold']),
98 12
            new \Twig_SimpleFunction('loadStylesheetsFromCDN', [$this, 'loadStylesheetsFromCDN']),
99 12
            new \Twig_SimpleFunction('isWMFLabs', [$this, 'isWMFLabs']),
100 12
            new \Twig_SimpleFunction('replag', [$this, 'replag']),
101 12
            new \Twig_SimpleFunction('quote', [$this, 'quote']),
102 12
            new \Twig_SimpleFunction('bugReportURL', [$this, 'bugReportURL']),
103 12
            new \Twig_SimpleFunction('logged_in_user', [$this, 'functionLoggedInUser']),
104 12
            new \Twig_SimpleFunction('isUserAnon', [$this, 'isUserAnon']),
105 12
            new \Twig_SimpleFunction('nsName', [$this, 'nsName']),
106 12
            new \Twig_SimpleFunction('formatDuration', [$this, 'formatDuration']),
107 12
            new \Twig_SimpleFunction('numberFormat', [$this, 'numberFormat']),
108 12
            new \Twig_SimpleFunction('buildQuery', [$this, 'buildQuery']),
109
        ];
110
    }
111
112
    /**
113
     * Get the duration of the current HTTP request in seconds.
114
     * @return double
115
     * Untestable since there is no request stack in the tests.
116
     * @codeCoverageIgnore
117
     */
118
    public function requestTime()
119
    {
120
        if (!isset($this->requestTime)) {
121
            $this->requestTime = microtime(true) - $this->getRequest()->server->get('REQUEST_TIME_FLOAT');
122
        }
123
124
        return $this->requestTime;
125
    }
126
127
    /**
128
     * Get the formatted real memory usage.
129
     * @return float
130
     */
131 12
    public function requestMemory()
132
    {
133 12
        $mem = memory_get_usage(false);
134 12
        $div = pow(1024, 2);
135 12
        return $mem / $div;
136
    }
137
138
    /**
139
     * Get the current year.
140
     * @return string
141
     */
142
    public function generateYear()
143
    {
144
        return date('Y');
145
    }
146
147
    /**
148
     * Get an i18n message.
149
     * @param string $message
150
     * @param array $vars
151
     * @return mixed|null|string
152
     */
153 11
    public function msg($message = '', $vars = [])
154
    {
155 11
        return $this->i18n->msg($message, $vars);
156
    }
157
158
    /**
159
     * See if a given i18n message exists.
160
     * @param string $message The message.
161
     * @param array $vars
162
     * @return bool
163
     */
164
    public function msgExists($message = '', $vars = [])
165
    {
166
        return $this->i18n->msgExists($message, $vars);
167
    }
168
169
    /**
170
     * Get an i18n message if it exists, otherwise just get the message key.
171
     * @param string $message
172
     * @param array $vars
173
     * @return mixed|null|string
174
     */
175
    public function msgIfExists($message = "", $vars = [])
176
    {
177
        return $this->i18n->msgIfExists($message, $vars);
178
    }
179
180
    /**
181
     * Get the current language code.
182
     * @return string
183
     */
184 12
    public function getLang()
185
    {
186 12
        return $this->i18n->getLang();
187
    }
188
189
    /**
190
     * Get the current language name (defaults to 'English').
191
     * @return string
192
     */
193 12
    public function getLangName()
194
    {
195 12
        return $this->i18n->getLangName();
196
    }
197
198
    /**
199
     * Get the fallback languages for the current language,
200
     * so we know what to load with jQuery.i18n.
201
     * @return string[]
202
     */
203 11
    public function getFallbackLangs()
204
    {
205 11
        return $this->i18n->getFallbacks();
206
    }
207
208
    /**
209
     * Get all available languages in the i18n directory
210
     * @return array Associative array of langKey => langName
211
     */
212 12
    public function getAllLangs()
213
    {
214 12
        return $this->i18n->getAllLangs();
215
    }
216
217
    /**
218
     * Whether the current language is right-to-left.
219
     * @param string|null $lang Optionally provide a specific lanuage code.
220
     * @return bool
221
     */
222 12
    public function isRTL($lang = null)
223
    {
224 12
        return $this->i18n->isRTL($lang);
225
    }
226
227
    /**
228
     * Get the short hash of the currently checked-out Git commit.
229
     * @return string
230
     */
231 11
    public function gitShortHash()
232
    {
233 11
        return exec('git rev-parse --short HEAD');
234
    }
235
236
    /**
237
     * Get the full hash of the currently checkout-out Git commit.
238
     * @return string
239
     */
240 12
    public function gitHash()
241
    {
242 12
        return exec('git rev-parse HEAD');
243
    }
244
245
    /**
246
     * Get the date of the HEAD commit.
247
     * @return string
248
     */
249 2
    public function gitDate()
250
    {
251 2
        $date = new DateTime(exec('git show -s --format=%ci'));
252 2
        return $this->dateFormat($date, 'yyyy-MM-dd');
253
    }
254
255
    /**
256
     * Check whether a given tool is enabled.
257
     * @param string $tool The short name of the tool.
258
     * @return bool
259
     */
260 11
    public function tabEnabled($tool = 'index')
261
    {
262 11
        $param = false;
263 11
        if ($this->container->hasParameter("enable.$tool")) {
264 11
            $param = boolval($this->container->getParameter("enable.$tool"));
265
        }
266 11
        return $param;
267
    }
268
269
    /**
270
     * Get a list of the short names of all tools.
271
     * @return string[]
272
     */
273 11
    public function allTools()
274
    {
275 11
        $retVal = [];
276 11
        if ($this->container->hasParameter('tools')) {
277 11
            $retVal = $this->container->getParameter('tools');
278
        }
279 11
        return $retVal;
280
    }
281
282
    /**
283
     * Get a list of namespace colours (one or all).
284
     * @param bool $num The NS ID to get.
285
     * @return string[]|string Indexed by namespace ID.
286
     */
287
    public static function getColorList($num = false)
288
    {
289
        $colors = [
290
            0 => '#FF5555',
291
            1 => '#55FF55',
292
            2 => '#FFEE22',
293
            3 => '#FF55FF',
294
            4 => '#5555FF',
295
            5 => '#55FFFF',
296
            6 => '#C00000',
297
            7 => '#0000C0',
298
            8 => '#008800',
299
            9 => '#00C0C0',
300
            10 => '#FFAFAF',
301
            11 => '#808080',
302
            12 => '#00C000',
303
            13 => '#404040',
304
            14 => '#C0C000',
305
            15 => '#C000C0',
306
            90 => '#991100',
307
            91 => '#99FF00',
308
            92 => '#000000',
309
            93 => '#777777',
310
            100 => '#75A3D1',
311
            101 => '#A679D2',
312
            102 => '#660000',
313
            103 => '#000066',
314
            104 => '#FAFFAF',
315
            105 => '#408345',
316
            106 => '#5c8d20',
317
            107 => '#e1711d',
318
            108 => '#94ef2b',
319
            109 => '#756a4a',
320
            110 => '#6f1dab',
321
            111 => '#301e30',
322
            112 => '#5c9d96',
323
            113 => '#a8cd8c',
324
            114 => '#f2b3f1',
325
            115 => '#9b5828',
326
            116 => '#002288',
327
            117 => '#0000CC',
328
            118 => '#99FFFF',
329
            119 => '#99BBFF',
330
            120 => '#FF99FF',
331
            121 => '#CCFFFF',
332
            122 => '#CCFF00',
333
            123 => '#CCFFCC',
334
            200 => '#33FF00',
335
            201 => '#669900',
336
            202 => '#666666',
337
            203 => '#999999',
338
            204 => '#FFFFCC',
339
            205 => '#FF00CC',
340
            206 => '#FFFF00',
341
            207 => '#FFCC00',
342
            208 => '#FF0000',
343
            209 => '#FF6600',
344
            250 => '#6633CC',
345
            251 => '#6611AA',
346
            252 => '#66FF99',
347
            253 => '#66FF66',
348
            446 => '#06DCFB',
349
            447 => '#892EE4',
350
            460 => '#99FF66',
351
            461 => '#99CC66',
352
            470 => '#CCCC33',
353
            471 => '#CCFF33',
354
            480 => '#6699FF',
355
            481 => '#66FFFF',
356
            484 => '#07C8D6',
357
            485 => '#2AF1FF',
358
            486 => '#79CB21',
359
            487 => '#80D822',
360
            490 => '#995500',
361
            491 => '#998800',
362
            710 => '#FFCECE',
363
            711 => '#FFC8F2',
364
            828 => '#F7DE00',
365
            829 => '#BABA21',
366
            866 => '#FFFFFF',
367
            867 => '#FFCCFF',
368
            1198 => '#FF34B3',
369
            1199 => '#8B1C62',
370
            2300 => '#A900B8',
371
            2301 => '#C93ED6',
372
            2302 => '#8A09C1',
373
            2303 => '#974AB8',
374
            2600 => '#000000',
375
        ];
376
377
        if ($num === false) {
378
            return $colors;
379
        } elseif (isset($colors[$num])) {
380
            return $colors[$num];
381
        } else {
382
            // Default to grey.
383
            return '#CCC';
384
        }
385
    }
386
387
    /**
388
     * Get color-blind friendly colors for use in charts
389
     * @param  Integer $num Index of color
390
     * @return String RGBA color (so you can more easily adjust the opacity)
391
     */
392
    public function chartColor($num)
393
    {
394
        $colors = [
395
            'rgba(171, 212, 235, 1)',
396
            'rgba(178, 223, 138, 1)',
397
            'rgba(251, 154, 153, 1)',
398
            'rgba(253, 191, 111, 1)',
399
            'rgba(202, 178, 214, 1)',
400
            'rgba(207, 182, 128, 1)',
401
            'rgba(141, 211, 199, 1)',
402
            'rgba(252, 205, 229, 1)',
403
            'rgba(255, 247, 161, 1)',
404
            'rgba(217, 217, 217, 1)',
405
        ];
406
407
        return $colors[$num % count($colors)];
408
    }
409
410
    /**
411
     * Whether XTools is running in single-project mode.
412
     * @return bool
413
     */
414 8
    public function isSingleWiki()
415
    {
416 8
        $param = true;
417 8
        if ($this->container->hasParameter('app.single_wiki')) {
418 8
            $param = boolval($this->container->getParameter('app.single_wiki'));
419
        }
420 8
        return $param;
421
    }
422
423
    /**
424
     * Get the database replication-lag threshold.
425
     * @return int
426
     */
427
    public function getReplagThreshold()
428
    {
429
        $param = 30;
430
        if ($this->container->hasParameter('app.replag_threshold')) {
431
            $param = $this->container->getParameter('app.replag_threshold');
432
        };
433
        return $param;
434
    }
435
436
    /**
437
     * Whether we should load stylesheets from external CDNs or not.
438
     * @return bool
439
     */
440 11
    public function loadStylesheetsFromCDN()
441
    {
442 11
        $param = false;
443 11
        if ($this->container->hasParameter('app.load_stylesheets_from_cdn')) {
444 11
            $param = boolval($this->container->getParameter('app.load_stylesheets_from_cdn'));
445
        }
446 11
        return $param;
447
    }
448
449
    /**
450
     * Whether XTools is running in WMF Labs mode.
451
     * @return bool
452
     */
453 11
    public function isWMFLabs()
454
    {
455 11
        $param = false;
456 11
        if ($this->container->hasParameter('app.is_labs')) {
457 11
            $param = boolval($this->container->getParameter('app.is_labs'));
458
        }
459 11
        return $param;
460
    }
461
462
    /**
463
     * The current replication lag.
464
     * @return int
465
     * @codeCoverageIgnore
466
     */
467
    public function replag()
468
    {
469
        $retVal = 0;
470
471
        if ($this->isWMFLabs()) {
472
            $project = $this->getRequest()->get('project');
473
474
            if (!isset($project)) {
475
                $project = 'enwiki';
476
            }
477
478
            $dbName = ProjectRepository::getProject($project, $this->container)
479
                ->getDatabaseName();
480
481
            $stmt = "SELECT lag FROM `heartbeat_p`.`heartbeat` h
482
            RIGHT JOIN `meta_p`.`wiki` w ON concat(h.shard, \".labsdb\")=w.slice
483
            WHERE dbname LIKE :project LIMIT 1";
484
485
            $conn = $this->container->get('doctrine')->getManager('replicas')->getConnection();
486
487
            // Prepare the query and execute
488
            $resultQuery = $conn->prepare($stmt);
489
            $resultQuery->bindParam('project', $dbName);
490
            $resultQuery->execute();
491
492
            if ($resultQuery->errorCode() == 0) {
493
                $results = $resultQuery->fetchAll();
494
495
                if (isset($results[0]['lag'])) {
496
                    $retVal = $results[0]['lag'];
497
                }
498
            }
499
        }
500
501
        return $retVal;
502
    }
503
504
    /**
505
     * Get a random quote for the footer
506
     * @return string
507
     */
508 11
    public function quote()
509
    {
510
        // Don't show if bash is turned off, but always show for Labs
511
        // (so quote is in footer but not in nav).
512 11
        $isLabs = $this->container->getParameter('app.is_labs');
513 11
        if (!$isLabs && !$this->container->getParameter('enable.bash')) {
514 11
            return '';
515
        }
516
        $quotes = $this->container->getParameter('quotes');
517
        $id = array_rand($quotes);
518
        return $quotes[$id];
519
    }
520
521
    /**
522
     * Get the currently logged in user's details.
523
     * @return string[]
524
     */
525 11
    public function functionLoggedInUser()
526
    {
527 11
        return $this->container->get('session')->get('logged_in_user');
528
    }
529
530
531
    /*********************************** FILTERS ***********************************/
532
533
    /**
534
     * Get all filters for this extension.
535
     * @return array
536
     */
537 12
    public function getFilters()
538
    {
539
        return [
540 12
            new \Twig_SimpleFilter('capitalize_first', [$this, 'capitalizeFirst']),
541 12
            new \Twig_SimpleFilter('percent_format', [$this, 'percentFormat']),
542 12
            new \Twig_SimpleFilter('diff_format', [$this, 'diffFormat'], ['is_safe' => ['html']]),
543 12
            new \Twig_SimpleFilter('num_format', [$this, 'numberFormat']),
544 12
            new \Twig_SimpleFilter('date_format', [$this, 'dateFormat']),
545 12
            new \Twig_SimpleFilter('wikify', [$this, 'wikify']),
546
        ];
547
    }
548
549
    /**
550
     * Format a number based on language settings.
551
     * @param  int|float $number
552
     * @param  int $decimals Number of decimals to format to.
553
     * @return string
554
     */
555 14
    public function numberFormat($number, $decimals = 0)
556
    {
557 14
        return $this->i18n->numberFormat($number, $decimals);
558
    }
559
560
    /**
561
     * Localize the given date based on language settings.
562
     * @param  string|DateTime $datetime
563
     * @param string $pattern Format according to this ICU date format.
564
     * @see http://userguide.icu-project.org/formatparse/datetime
565
     * @return string
566
     */
567 3
    public function dateFormat($datetime, $pattern = 'yyyy-MM-dd HH:mm')
568
    {
569 3
        return $this->i18n->dateFormat($datetime, $pattern);
570
    }
571
572
    /**
573
     * Convert raw wikitext to HTML-formatted string.
574
     * @param string $str
575
     * @param Project $project
576
     * @return string
577
     */
578 1
    public function wikify($str, Project $project)
579
    {
580 1
        return Edit::wikifyString($str, $project);
581
    }
582
583
    /**
584
     * Mysteriously missing Twig helper to capitalize only the first character.
585
     * E.g. used for table headings for translated messages
586
     * @param  string $str The string
587
     * @return string      The string, capitalized
588
     */
589 6
    public function capitalizeFirst($str)
590
    {
591 6
        return ucfirst($str);
592
    }
593
594
    /**
595
     * Format a given number or fraction as a percentage.
596
     * @param  number  $numerator   Numerator or single fraction if denominator is ommitted.
597
     * @param  number  $denominator Denominator.
598
     * @param  integer $precision   Number of decimal places to show.
599
     * @return string               Formatted percentage.
600
     */
601 1
    public function percentFormat($numerator, $denominator = null, $precision = 1)
602
    {
603 1
        return $this->i18n->percentFormat($numerator, $denominator, $precision);
604
    }
605
606
    /**
607
     * Helper to return whether the given user is an anonymous (logged out) user.
608
     * @param  User|string $user User object or username as a string.
609
     * @return bool
610
     */
611 1
    public function isUserAnon($user)
612
    {
613 1
        if ($user instanceof User) {
614 1
            $username = $user->getUsername();
615
        } else {
616 1
            $username = $user;
617
        }
618
619 1
        return (bool)filter_var($username, FILTER_VALIDATE_IP);
620
    }
621
622
    /**
623
     * Helper to properly translate a namespace name
624
     * @param  int|string $namespace Namespace key as a string or ID
625
     * @param  array      $namespaces List of available namespaces
626
     *                                as retrieved from Project::getNamespaces
627
     * @return string Namespace name
628
     */
629
    public function nsName($namespace, $namespaces)
630
    {
631
        if ($namespace === 'all') {
632
            return $this->i18n->msg('all');
633
        } elseif ($namespace === '0' || $namespace === 0 || $namespace === 'Main') {
634
            return $this->i18n->msg('mainspace');
635
        } else {
636
            return $namespaces[$namespace];
637
        }
638
    }
639
640
    /**
641
     * Format a given number as a diff, colouring it green if it's postive, red if negative, gary if zero
642
     * @param  number $size Diff size
643
     * @return string Markup with formatted number
644
     */
645 1
    public function diffFormat($size)
646
    {
647 1
        if ($size < 0) {
648 1
            $class = 'diff-neg';
649 1
        } elseif ($size > 0) {
650 1
            $class = 'diff-pos';
651
        } else {
652 1
            $class = 'diff-zero';
653
        }
654
655 1
        $size = $this->numberFormat($size);
656
657 1
        return "<span class='$class'".
658 1
            ($this->i18n->isRTL() ? " dir='rtl'" : '').
659 1
            ">$size</span>";
660
    }
661
662
    /**
663
     * Format a time duration as humanized string.
664
     * @param int $seconds Number of seconds.
665
     * @param bool $translate Used for unit testing. Set to false to return
666
     *   the value and i18n key, instead of the actual translation.
667
     * @return string|array Examples: '30 seconds', '2 minutes', '15 hours', '500 days',
668
     *   or [30, 'num-seconds'] (etc.) if $translate is false.
669
     */
670 1
    public function formatDuration($seconds, $translate = true)
671
    {
672 1
        list($val, $key) = $this->getDurationMessageKey($seconds);
673
674 1
        if ($translate) {
675
            return $this->numberFormat($val).' '.$this->i18n->msg("num-$key", [$val]);
676
        } else {
677 1
            return [$this->numberFormat($val), "num-$key"];
678
        }
679
    }
680
681
    /**
682
     * Given a time duration in seconds, generate a i18n message key and value.
683
     * @param  int $seconds Number of seconds.
684
     * @return array<integer|string> [int - message value, string - message key]
685
     */
686 1
    private function getDurationMessageKey($seconds)
687
    {
688
        /** @var int Value to show in message */
689 1
        $val = $seconds;
690
691
        /** @var string Unit of time, used in the key for the i18n message */
692 1
        $key = 'seconds';
693
694 1
        if ($seconds >= 86400) {
695
            // Over a day
696 1
            $val = (int) floor($seconds / 86400);
697 1
            $key = 'days';
698 1
        } elseif ($seconds >= 3600) {
699
            // Over an hour, less than a day
700 1
            $val = (int) floor($seconds / 3600);
701 1
            $key = 'hours';
702 1
        } elseif ($seconds >= 60) {
703
            // Over a minute, less than an hour
704 1
            $val = (int) floor($seconds / 60);
705 1
            $key = 'minutes';
706
        }
707
708 1
        return [$val, $key];
709
    }
710
711
    /**
712
     * Build URL query string from given params.
713
     * @param  array $params
714
     * @return string
715
     */
716 1
    public function buildQuery($params)
717
    {
718 1
        return is_array($params) ? http_build_query($params) : '';
0 ignored issues
show
introduced by
The condition is_array($params) is always true.
Loading history...
719
    }
720
721
    /**
722
     * Shorthand to get the current request from the request stack.
723
     * @return \Symfony\Component\HttpFoundation\Request
724
     * There is no request stack in the tests.
725
     * @codeCoverageIgnore
726
     */
727
    private function getRequest()
728
    {
729
        return $this->container->get('request_stack')->getCurrentRequest();
730
    }
731
}
732