Passed
Push — master ( 23707e...d837db )
by MusikAnimal
03:38
created

AppExtension::gitDate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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