Passed
Push — main ( 66dd99...851719 )
by MusikAnimal
17:51 queued 06:59
created

AppExtension::gitShortHash()   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 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
/**
3
 * This file contains only the AppExtension class.
4
 */
5
6
declare(strict_types = 1);
7
8
namespace AppBundle\Twig;
9
10
use AppBundle\Helper\I18nHelper;
11
use AppBundle\Model\Edit;
12
use AppBundle\Model\Project;
13
use AppBundle\Model\User;
14
use AppBundle\Repository\ProjectRepository;
15
use DateTime;
16
use Symfony\Component\DependencyInjection\ContainerInterface;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\RequestStack;
19
use Symfony\Component\HttpFoundation\Session\SessionInterface;
20
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
21
use Twig\Extension\AbstractExtension;
22
use Twig\TwigFilter;
23
use Twig\TwigFunction;
24
25
/**
26
 * Twig functions and filters for XTools.
27
 */
28
class AppExtension extends AbstractExtension
29
{
30
    /** @var ContainerInterface The application's container interface. */
31
    protected $container;
32
33
    /** @var RequestStack The request stack. */
34
    protected $requestStack;
35
36
    /** @var SessionInterface User's current session. */
37
    protected $session;
38
39
    /** @var I18nHelper For i18n and l10n. */
40
    protected $i18n;
41
42
    /** @var float Duration of the current HTTP request in seconds. */
43
    protected $requestTime;
44
45
    /** @var UrlGeneratorInterface */
46
    private $urlGenerator;
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
     * @param UrlGeneratorInterface $generator
55
     */
56 27
    public function __construct(
57
        ContainerInterface $container,
58
        RequestStack $requestStack,
59
        SessionInterface $session,
60
        I18nHelper $i18n,
61
        UrlGeneratorInterface $generator
62
    ) {
63 27
        $this->container = $container;
64 27
        $this->requestStack = $requestStack;
65 27
        $this->session = $session;
66 27
        $this->i18n = $i18n;
67 27
        $this->urlGenerator = $generator;
68 27
    }
69
70
    /*********************************** FUNCTIONS ***********************************/
71
72
    /**
73
     * Get all functions that this class provides.
74
     * @return TwigFunction[]
75
     * @codeCoverageIgnore
76
     */
77
    public function getFunctions(): array
78
    {
79
        return [
80
            new TwigFunction('request_time', [$this, 'requestTime']),
81
            new TwigFunction('memory_usage', [$this, 'requestMemory']),
82
            new TwigFunction('msgIfExists', [$this, 'msgIfExists'], ['is_safe' => ['html']]),
83
            new TwigFunction('msgExists', [$this, 'msgExists'], ['is_safe' => ['html']]),
84
            new TwigFunction('msg', [$this, 'msg'], ['is_safe' => ['html']]),
85
            new TwigFunction('lang', [$this, 'getLang']),
86
            new TwigFunction('langName', [$this, 'getLangName']),
87
            new TwigFunction('fallbackLangs', [$this, 'getFallbackLangs']),
88
            new TwigFunction('allLangs', [$this, 'getAllLangs']),
89
            new TwigFunction('isRTL', [$this, 'isRTL']),
90
            new TwigFunction('shortHash', [$this, 'gitShortHash']),
91
            new TwigFunction('hash', [$this, 'gitHash']),
92
            new TwigFunction('releaseDate', [$this, 'gitDate']),
93
            new TwigFunction('enabled', [$this, 'toolEnabled']),
94
            new TwigFunction('tools', [$this, 'tools']),
95
            new TwigFunction('color', [$this, 'getColorList']),
96
            new TwigFunction('chartColor', [$this, 'chartColor']),
97
            new TwigFunction('isSingleWiki', [$this, 'isSingleWiki']),
98
            new TwigFunction('getReplagThreshold', [$this, 'getReplagThreshold']),
99
            new TwigFunction('isWMFLabs', [$this, 'isWMFLabs']),
100
            new TwigFunction('replag', [$this, 'replag']),
101
            new TwigFunction('quote', [$this, 'quote']),
102
            new TwigFunction('bugReportURL', [$this, 'bugReportURL']),
103
            new TwigFunction('logged_in_user', [$this, 'loggedInUser']),
104
            new TwigFunction('isUserAnon', [$this, 'isUserAnon']),
105
            new TwigFunction('nsName', [$this, 'nsName']),
106
            new TwigFunction('titleWithNs', [$this, 'titleWithNs']),
107
            new TwigFunction('formatDuration', [$this, 'formatDuration']),
108
            new TwigFunction('numberFormat', [$this, 'numberFormat']),
109
            new TwigFunction('buildQuery', [$this, 'buildQuery']),
110
            new TwigFunction('login_url', [$this, 'loginUrl']),
111
        ];
112
    }
113
114
    /**
115
     * Get the duration of the current HTTP request in seconds.
116
     * @return float
117
     * Untestable since there is no request stack in the tests.
118
     * @codeCoverageIgnore
119
     */
120
    public function requestTime(): float
121
    {
122
        if (!isset($this->requestTime)) {
123
            $this->requestTime = microtime(true) - $this->getRequest()->server->get('REQUEST_TIME_FLOAT');
124
        }
125
126
        return $this->requestTime;
127
    }
128
129
    /**
130
     * Get the formatted real memory usage.
131
     * @return float
132
     */
133 11
    public function requestMemory(): float
134
    {
135 11
        $mem = memory_get_usage(false);
136 11
        $div = pow(1024, 2);
137 11
        return $mem / $div;
138
    }
139
140
    /**
141
     * Get an i18n message.
142
     * @param string $message
143
     * @param string[] $vars
144
     * @return string|null
145
     */
146 10
    public function msg(string $message = '', array $vars = []): ?string
147
    {
148 10
        return $this->i18n->msg($message, $vars);
149
    }
150
151
    /**
152
     * See if a given i18n message exists.
153
     * @param string $message The message.
154
     * @param string[] $vars
155
     * @return bool
156
     */
157
    public function msgExists(?string $message, array $vars = []): bool
158
    {
159
        return $this->i18n->msgExists($message, $vars);
160
    }
161
162
    /**
163
     * Get an i18n message if it exists, otherwise just get the message key.
164
     * @param string $message
165
     * @param string[] $vars
166
     * @return string
167
     */
168
    public function msgIfExists(?string $message, array $vars = []): string
169
    {
170
        return $this->i18n->msgIfExists($message, $vars);
171
    }
172
173
    /**
174
     * Get the current language code.
175
     * @return string
176
     */
177 11
    public function getLang(): string
178
    {
179 11
        return $this->i18n->getLang();
180
    }
181
182
    /**
183
     * Get the current language name (defaults to 'English').
184
     * @return string
185
     */
186 11
    public function getLangName(): string
187
    {
188 11
        return $this->i18n->getLangName();
189
    }
190
191
    /**
192
     * Get the fallback languages for the current language, so we know what to load with jQuery.i18n.
193
     * @return string[]
194
     */
195 10
    public function getFallbackLangs(): array
196
    {
197 10
        return $this->i18n->getFallbacks();
198
    }
199
200
    /**
201
     * Get all available languages in the i18n directory
202
     * @return string[] Associative array of langKey => langName
203
     */
204 11
    public function getAllLangs(): array
205
    {
206 11
        return $this->i18n->getAllLangs();
207
    }
208
209
    /**
210
     * Whether the current language is right-to-left.
211
     * @param string|null $lang Optionally provide a specific lanuage code.
212
     * @return bool
213
     */
214 11
    public function isRTL(?string $lang = null): bool
215
    {
216 11
        return $this->i18n->isRTL($lang);
217
    }
218
219
    /**
220
     * Get the short hash of the currently checked-out Git commit.
221
     * @return string
222
     */
223 10
    public function gitShortHash(): string
224
    {
225 10
        return exec('git rev-parse --short HEAD');
226
    }
227
228
    /**
229
     * Get the full hash of the currently checkout-out Git commit.
230
     * @return string
231
     */
232 11
    public function gitHash(): string
233
    {
234 11
        return exec('git rev-parse HEAD');
235
    }
236
237
    /**
238
     * Get the date of the HEAD commit.
239
     * @return string
240
     */
241 1
    public function gitDate(): string
242
    {
243 1
        $date = new DateTime(exec('git show -s --format=%ci'));
244 1
        return $this->dateFormat($date, 'yyyy-MM-dd');
245
    }
246
247
    /**
248
     * Check whether a given tool is enabled.
249
     * @param string $tool The short name of the tool.
250
     * @return bool
251
     */
252 10
    public function toolEnabled(string $tool = 'index'): bool
253
    {
254 10
        $param = false;
255 10
        if ($this->container->hasParameter("enable.$tool")) {
256 10
            $param = boolval($this->container->getParameter("enable.$tool"));
257
        }
258 10
        return $param;
259
    }
260
261
    /**
262
     * Get a list of the short names of all tools.
263
     * @return string[]
264
     */
265 1
    public function tools(): array
266
    {
267 1
        $retVal = [];
268 1
        if ($this->container->hasParameter('tools')) {
269 1
            $retVal = $this->container->getParameter('tools');
270
        }
271 1
        return $retVal;
272
    }
273
274
    /**
275
     * Get a list of namespace colours (one or all).
276
     * @param int|false $num The NS ID to get. False to get the full list.
277
     * @return string|string[] Color or all all colors indexed by namespace ID.
278
     */
279
    public static function getColorList($num = false)
280
    {
281
        $colors = [
282
            0 => '#FF5555',
283
            1 => '#55FF55',
284
            2 => '#FFEE22',
285
            3 => '#FF55FF',
286
            4 => '#5555FF',
287
            5 => '#55FFFF',
288
            6 => '#C00000',
289
            7 => '#0000C0',
290
            8 => '#008800',
291
            9 => '#00C0C0',
292
            10 => '#FFAFAF',
293
            11 => '#808080',
294
            12 => '#00C000',
295
            13 => '#404040',
296
            14 => '#C0C000',
297
            15 => '#C000C0',
298
            90 => '#991100',
299
            91 => '#99FF00',
300
            92 => '#000000',
301
            93 => '#777777',
302
            100 => '#75A3D1',
303
            101 => '#A679D2',
304
            102 => '#660000',
305
            103 => '#000066',
306
            104 => '#FAFFAF',
307
            105 => '#408345',
308
            106 => '#5c8d20',
309
            107 => '#e1711d',
310
            108 => '#94ef2b',
311
            109 => '#756a4a',
312
            110 => '#6f1dab',
313
            111 => '#301e30',
314
            112 => '#5c9d96',
315
            113 => '#a8cd8c',
316
            114 => '#f2b3f1',
317
            115 => '#9b5828',
318
            116 => '#002288',
319
            117 => '#0000CC',
320
            118 => '#99FFFF',
321
            119 => '#99BBFF',
322
            120 => '#FF99FF',
323
            121 => '#CCFFFF',
324
            122 => '#CCFF00',
325
            123 => '#CCFFCC',
326
            200 => '#33FF00',
327
            201 => '#669900',
328
            202 => '#666666',
329
            203 => '#999999',
330
            204 => '#FFFFCC',
331
            205 => '#FF00CC',
332
            206 => '#FFFF00',
333
            207 => '#FFCC00',
334
            208 => '#FF0000',
335
            209 => '#FF6600',
336
            250 => '#6633CC',
337
            251 => '#6611AA',
338
            252 => '#66FF99',
339
            253 => '#66FF66',
340
            446 => '#06DCFB',
341
            447 => '#892EE4',
342
            460 => '#99FF66',
343
            461 => '#99CC66',
344
            470 => '#CCCC33',
345
            471 => '#CCFF33',
346
            480 => '#6699FF',
347
            481 => '#66FFFF',
348
            484 => '#07C8D6',
349
            485 => '#2AF1FF',
350
            486 => '#79CB21',
351
            487 => '#80D822',
352
            490 => '#995500',
353
            491 => '#998800',
354
            710 => '#FFCECE',
355
            711 => '#FFC8F2',
356
            828 => '#F7DE00',
357
            829 => '#BABA21',
358
            866 => '#FFFFFF',
359
            867 => '#FFCCFF',
360
            1198 => '#FF34B3',
361
            1199 => '#8B1C62',
362
            2300 => '#A900B8',
363
            2301 => '#C93ED6',
364
            2302 => '#8A09C1',
365
            2303 => '#974AB8',
366
            2600 => '#000000',
367
        ];
368
369
        if (false === $num) {
370
            return $colors;
371
        } elseif (isset($colors[$num])) {
372
            return $colors[$num];
373
        } else {
374
            // Default to grey.
375
            return '#CCC';
376
        }
377
    }
378
379
    /**
380
     * Get color-blind friendly colors for use in charts
381
     * @param int $num Index of color
382
     * @return string RGBA color (so you can more easily adjust the opacity)
383
     */
384
    public function chartColor(int $num): string
385
    {
386
        $colors = [
387
            'rgba(171, 212, 235, 1)',
388
            'rgba(178, 223, 138, 1)',
389
            'rgba(251, 154, 153, 1)',
390
            'rgba(253, 191, 111, 1)',
391
            'rgba(202, 178, 214, 1)',
392
            'rgba(207, 182, 128, 1)',
393
            'rgba(141, 211, 199, 1)',
394
            'rgba(252, 205, 229, 1)',
395
            'rgba(255, 247, 161, 1)',
396
            'rgba(252, 146, 114, 1)',
397
            'rgba(217, 217, 217, 1)',
398
        ];
399
400
        return $colors[$num % count($colors)];
401
    }
402
403
    /**
404
     * Whether XTools is running in single-project mode.
405
     * @return bool
406
     */
407 8
    public function isSingleWiki(): bool
408
    {
409 8
        $param = true;
410 8
        if ($this->container->hasParameter('app.single_wiki')) {
411 8
            $param = boolval($this->container->getParameter('app.single_wiki'));
412
        }
413 8
        return $param;
414
    }
415
416
    /**
417
     * Get the database replication-lag threshold.
418
     * @return int
419
     */
420
    public function getReplagThreshold(): int
421
    {
422
        $param = 30;
423
        if ($this->container->hasParameter('app.replag_threshold')) {
424
            $param = $this->container->getParameter('app.replag_threshold');
425
        }
426
        return $param;
427
    }
428
429
    /**
430
     * Whether XTools is running in WMF Labs mode.
431
     * @return bool
432
     */
433 10
    public function isWMFLabs(): bool
434
    {
435 10
        $param = false;
436 10
        if ($this->container->hasParameter('app.is_labs')) {
437 10
            $param = boolval($this->container->getParameter('app.is_labs'));
438
        }
439 10
        return $param;
440
    }
441
442
    /**
443
     * The current replication lag.
444
     * @return int
445
     * @codeCoverageIgnore
446
     */
447
    public function replag(): int
448
    {
449
        if (!$this->isWMFLabs()) {
450
            return 0;
451
        }
452
453
        $projectIdent = $this->getRequest()->get('project', 'enwiki');
454
        $project = ProjectRepository::getProject($projectIdent, $this->container);
455
        $dbName = $project->getDatabaseName();
456
457
        $sql = "SELECT lag FROM `heartbeat_p`.`heartbeat` h
458
                RIGHT JOIN `meta_p`.`wiki` w ON concat(h.shard, \".labsdb\")=w.slice
459
                WHERE dbname LIKE :project LIMIT 1";
460
461
        return (int)$project->getRepository()->executeProjectsQuery('meta', $sql, [
462
            'project' => $dbName,
463
        ])->fetch();
464
    }
465
466
    /**
467
     * Get a random quote for the footer
468
     * @return string
469
     */
470 10
    public function quote(): string
471
    {
472
        // Don't show if Quote is turned off, but always show for Labs
473
        // (so quote is in footer but not in nav).
474 10
        $isLabs = $this->container->getParameter('app.is_labs');
475 10
        if (!$isLabs && !$this->container->getParameter('enable.Quote')) {
476 10
            return '';
477
        }
478
        $quotes = $this->container->getParameter('quotes');
479
        $id = array_rand($quotes);
0 ignored issues
show
Bug introduced by
It seems like $quotes can also be of type boolean and double and integer and null and string; however, parameter $array of array_rand() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

479
        $id = array_rand(/** @scrutinizer ignore-type */ $quotes);
Loading history...
480
        return $quotes[$id];
481
    }
482
483
    /**
484
     * Get the currently logged in user's details.
485
     * @return string[]|object|null
486
     */
487 10
    public function loggedInUser()
488
    {
489 10
        return $this->container->get('session')->get('logged_in_user');
490
    }
491
492
    /**
493
     * Get a URL to the login route with parameters to redirect back to the current page after logging in.
494
     * @param Request $request
495
     * @return string
496
     */
497 10
    public function loginUrl(Request $request): string
498
    {
499 10
        return $this->urlGenerator->generate('login', [
500 10
            'callback' => $this->urlGenerator->generate(
501 10
                'oauth_callback',
502 10
                ['redirect' => $request->getUri()],
503 10
                UrlGeneratorInterface::ABSOLUTE_URL
504
            ),
505 10
        ], UrlGeneratorInterface::ABSOLUTE_URL);
506
    }
507
508
    /*********************************** FILTERS ***********************************/
509
510
    /**
511
     * Get all filters for this extension.
512
     * @return TwigFilter[]
513
     * @codeCoverageIgnore
514
     */
515
    public function getFilters(): array
516
    {
517
        return [
518
            new TwigFilter('ucfirst', [$this, 'capitalizeFirst']),
519
            new TwigFilter('percent_format', [$this, 'percentFormat']),
520
            new TwigFilter('diff_format', [$this, 'diffFormat'], ['is_safe' => ['html']]),
521
            new TwigFilter('num_format', [$this, 'numberFormat']),
522
            new TwigFilter('size_format', [$this, 'sizeFormat']),
523
            new TwigFilter('date_format', [$this, 'dateFormat']),
524
            new TwigFilter('wikify', [$this, 'wikify']),
525
        ];
526
    }
527
528
    /**
529
     * Format a number based on language settings.
530
     * @param int|float $number
531
     * @param int $decimals Number of decimals to format to.
532
     * @return string
533
     */
534 14
    public function numberFormat($number, $decimals = 0): string
535
    {
536 14
        return $this->i18n->numberFormat($number, $decimals);
537
    }
538
539
    /**
540
     * Format the given size (in bytes) as KB, MB, GB, or TB.
541
     * Some code courtesy of Leo, CC BY-SA 4.0
542
     * @see https://stackoverflow.com/a/2510459/604142
543
     * @param int $bytes
544
     * @param int $precision
545
     * @return string
546
     */
547 1
    public function sizeFormat(int $bytes, int $precision = 2): string
548
    {
549 1
        $base = log($bytes, 1024);
550 1
        $suffixes = ['', 'kilobytes', 'megabytes', 'gigabytes', 'terabytes'];
551
552 1
        $index = floor($base);
553
554 1
        if (0 === (int)$index) {
555 1
            return $this->numberFormat($bytes);
556
        }
557
558 1
        $sizeMessage = $this->numberFormat(
559 1
            pow(1024, $base - floor($base)),
560 1
            $precision
561
        );
562
563 1
        return $this->i18n->msg('size-'.$suffixes[floor($base)], [$sizeMessage]);
564
    }
565
566
    /**
567
     * Localize the given date based on language settings.
568
     * @param string|int|DateTime $datetime
569
     * @param string $pattern Format according to this ICU date format.
570
     * @see http://userguide.icu-project.org/formatparse/datetime
571
     * @return string
572
     */
573 12
    public function dateFormat($datetime, $pattern = 'yyyy-MM-dd HH:mm'): string
574
    {
575 12
        return $this->i18n->dateFormat($datetime, $pattern);
576
    }
577
578
    /**
579
     * Convert raw wikitext to HTML-formatted string.
580
     * @param string $str
581
     * @param Project $project
582
     * @return string
583
     */
584 1
    public function wikify(string $str, Project $project): string
585
    {
586 1
        return Edit::wikifyString($str, $project);
587
    }
588
589
    /**
590
     * Mysteriously missing Twig helper to capitalize only the first character.
591
     * E.g. used for table headings for translated messages
592
     * @param string $str The string
593
     * @return string The string, capitalized
594
     */
595 6
    public function capitalizeFirst(string $str): string
596
    {
597 6
        return ucfirst($str);
598
    }
599
600
    /**
601
     * Format a given number or fraction as a percentage.
602
     * @param int|float $numerator Numerator or single fraction if denominator is ommitted.
603
     * @param int $denominator Denominator.
604
     * @param integer $precision Number of decimal places to show.
605
     * @return string Formatted percentage.
606
     */
607 1
    public function percentFormat($numerator, ?int $denominator = null, int $precision = 1): string
608
    {
609 1
        return $this->i18n->percentFormat($numerator, $denominator, $precision);
610
    }
611
612
    /**
613
     * Helper to return whether the given user is an anonymous (logged out) user.
614
     * @param User|string $user User object or username as a string.
615
     * @return bool
616
     */
617 1
    public function isUserAnon($user): bool
618
    {
619 1
        if ($user instanceof User) {
620 1
            $username = $user->getUsername();
621
        } else {
622 1
            $username = $user;
623
        }
624
625 1
        return (bool)filter_var($username, FILTER_VALIDATE_IP);
626
    }
627
628
    /**
629
     * Helper to properly translate a namespace name.
630
     * @param int|string $namespace Namespace key as a string or ID.
631
     * @param string[] $namespaces List of available namespaces as retrieved from Project::getNamespaces().
632
     * @return string Namespace name
633
     */
634
    public function nsName($namespace, array $namespaces): string
635
    {
636
        if ('all' === $namespace) {
637
            return $this->i18n->msg('all');
638
        } elseif ('0' === $namespace || 0 === $namespace || 'Main' === $namespace) {
639
            return $this->i18n->msg('mainspace');
640
        } else {
641
            return $namespaces[$namespace] ?? $this->i18n->msg('unknown');
642
        }
643
    }
644
645
    /**
646
     * Given a page title and namespace, generate the full page title.
647
     * @param string $title
648
     * @param int $namespace
649
     * @param array $namespaces
650
     * @return string
651
     */
652
    public function titleWithNs(string $title, int $namespace, array $namespaces): string
653
    {
654
        if (0 === $namespace) {
655
            return $title;
656
        }
657
        return $this->nsName($namespace, $namespaces).':'.$title;
658
    }
659
660
    /**
661
     * Format a given number as a diff, colouring it green if it's positive, red if negative, gary if zero
662
     * @param int $size Diff size
663
     * @return string Markup with formatted number
664
     */
665 1
    public function diffFormat(int $size): string
666
    {
667 1
        if ($size < 0) {
668 1
            $class = 'diff-neg';
669 1
        } elseif ($size > 0) {
670 1
            $class = 'diff-pos';
671
        } else {
672 1
            $class = 'diff-zero';
673
        }
674
675 1
        $size = $this->numberFormat($size);
676
677 1
        return "<span class='$class'".
678 1
            ($this->i18n->isRTL() ? " dir='rtl'" : '').
679 1
            ">$size</span>";
680
    }
681
682
    /**
683
     * Format a time duration as humanized string.
684
     * @param int $seconds Number of seconds.
685
     * @param bool $translate Used for unit testing. Set to false to return
686
     *   the value and i18n key, instead of the actual translation.
687
     * @return string|mixed[] Examples: '30 seconds', '2 minutes', '15 hours', '500 days',
688
     *   or [30, 'num-seconds'] (etc.) if $translate is false.
689
     */
690 1
    public function formatDuration(int $seconds, bool $translate = true)
691
    {
692 1
        [$val, $key] = $this->getDurationMessageKey($seconds);
693
694 1
        if ($translate) {
695
            return $this->numberFormat($val).' '.$this->i18n->msg("num-$key", [$val]);
696
        } else {
697 1
            return [$this->numberFormat($val), "num-$key"];
698
        }
699
    }
700
701
    /**
702
     * Given a time duration in seconds, generate a i18n message key and value.
703
     * @param int $seconds Number of seconds.
704
     * @return array<integer|string> [int - message value, string - message key]
705
     */
706 1
    private function getDurationMessageKey(int $seconds)
707
    {
708
        /** @var int $val Value to show in message */
709 1
        $val = $seconds;
710
711
        /** @var string $key Unit of time, used in the key for the i18n message */
712 1
        $key = 'seconds';
713
714 1
        if ($seconds >= 86400) {
715
            // Over a day
716 1
            $val = (int) floor($seconds / 86400);
717 1
            $key = 'days';
718 1
        } elseif ($seconds >= 3600) {
719
            // Over an hour, less than a day
720 1
            $val = (int) floor($seconds / 3600);
721 1
            $key = 'hours';
722 1
        } elseif ($seconds >= 60) {
723
            // Over a minute, less than an hour
724 1
            $val = (int) floor($seconds / 60);
725 1
            $key = 'minutes';
726
        }
727
728 1
        return [$val, $key];
729
    }
730
731
    /**
732
     * Build URL query string from given params.
733
     * @param string[] $params
734
     * @return string
735
     */
736 1
    public function buildQuery(array $params): string
737
    {
738 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...
739
    }
740
741
    /**
742
     * Shorthand to get the current request from the request stack.
743
     * @return \Symfony\Component\HttpFoundation\Request
744
     * There is no request stack in the tests.
745
     * @codeCoverageIgnore
746
     */
747
    private function getRequest(): \Symfony\Component\HttpFoundation\Request
748
    {
749
        return $this->container->get('request_stack')->getCurrentRequest();
750
    }
751
}
752