Passed
Push — master ( fe254a...d9a044 )
by MusikAnimal
02:02
created

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