Passed
Push — master ( f43d54...b6518a )
by MusikAnimal
01:39
created

AppExtension::dateFormatStd()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 3
rs 9.4285
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 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 12
            new \Twig_SimpleFunction('buildQuery', [$this, 'buildQuery']),
79
        ];
80
    }
81
82
    /**
83
     * Get the duration of the current HTTP request in seconds.
84
     * @return double
85
     * Untestable since there is no request stack in the tests.
86
     * @codeCoverageIgnore
87
     */
88
    public function requestTime()
89
    {
90
        if (!isset($this->requestTime)) {
91
            $this->requestTime = microtime(true) - $this->getCurrentRequest()->server->get('REQUEST_TIME_FLOAT');
92
        }
93
94
        return $this->requestTime;
95
    }
96
97
    /**
98
     * Get the formatted real memory usage.
99
     * @return float
100
     */
101 12
    public function requestMemory()
102
    {
103 12
        $mem = memory_get_usage(false);
104 12
        $div = pow(1024, 2);
105 12
        return $mem / $div;
106
    }
107
108
    /**
109
     * Get the current year.
110
     * @return string
111
     */
112
    public function generateYear()
113
    {
114
        return date('Y');
115
    }
116
117
    /**
118
     * See if a given i18n message exists.
119
     * @TODO: refactor all intuition stuff so it can be used anywhere
120
     * @param string $message The message.
121
     * @param array $vars
122
     * @return bool
123
     */
124
    public function intuitionMessageExists($message = '', $vars = [])
125
    {
126
        return $this->getIntuition()->msgExists($message, array_merge(
127
            [
128
                'domain' => 'xtools'
129
            ],
130
            [
131
                'variables' => $vars
132
            ]
133
        ));
134
    }
135
136
    /**
137
     * Get an i18n message if it exists, otherwise just get the message key.
138
     * @param string $message
139
     * @param array $vars
140
     * @return mixed|null|string
141
     */
142
    public function intuitionMessagePrintExists($message = "", $vars = [])
143
    {
144
        if (is_array($message)) {
0 ignored issues
show
introduced by
The condition is_array($message) can never be true.
Loading history...
145
            $vars = $message;
146
            $message = $message[0];
147
            $vars = array_slice($vars, 1);
148
        }
149
        if ($this->intuitionMessageExists($message, $vars)) {
150
            return $this->intuitionMessage($message, $vars);
151
        } else {
152
            return $message;
153
        }
154
    }
155
156
    /**
157
     * Get an i18n message.
158
     * @param string $message
159
     * @param array $vars
160
     * @return mixed|null|string
161
     */
162 11
    public function intuitionMessage($message = "", $vars = [])
163
    {
164 11
        return $this->getIntuition()->msg($message, [ "domain" => "xtools", "variables" => $vars ]);
165
    }
166
167
    /**
168
     * Get the current language code.
169
     * @return string
170
     */
171 12
    public function getLang()
172
    {
173 12
        return $this->getIntuition()->getLang();
174
    }
175
176
    /**
177
     * Get the current language name (defaults to 'English').
178
     * @return string
179
     */
180 12
    public function getLangName()
181
    {
182 12
        return in_array(ucfirst($this->getIntuition()->getLangName()), $this->getAllLangs())
183 12
            ? $this->getIntuition()->getLangName()
184 12
            : 'English';
185
    }
186
187
    /**
188
     * Get all available languages in the i18n directory
189
     * @return array Associative array of langKey => langName
190
     */
191 12
    public function getAllLangs()
192
    {
193 12
        $messageFiles = glob($this->container->getParameter("kernel.root_dir") . '/../i18n/*.json');
194
195 12
        $languages = array_values(array_unique(array_map(
196 12
            function ($filename) {
197 12
                return basename($filename, '.json');
198 12
            },
199 12
            $messageFiles
200
        )));
201
202 12
        $availableLanguages = [];
203
204 12
        foreach ($languages as $lang) {
205 12
            $availableLanguages[$lang] = ucfirst($this->getIntuition()->getLangName($lang));
206
        }
207 12
        asort($availableLanguages);
208
209 12
        return $availableLanguages;
210
    }
211
212
    /**
213
     * Whether the current language is right-to-left.
214
     * @return bool
215
     */
216 11
    public function intuitionIsRTL()
217
    {
218 11
        return $this->getIntuition()->isRTL($this->getIntuition()->getLang());
219
    }
220
221
    /**
222
     * Whether the given language is right-to-left.
223
     * @param string $lang The language code.
224
     * @return bool
225
     */
226 1
    public function intuitionIsRTLLang($lang)
227
    {
228 1
        return $this->getIntuition()->isRTL($lang);
229
    }
230
231
    /**
232
     * Get the short hash of the currently checked-out Git commit.
233
     * @return string
234
     */
235 11
    public function gitShortHash()
236
    {
237 11
        return exec("git rev-parse --short HEAD");
238
    }
239
240
    /**
241
     * Get the full hash of the currently checkout-out Git commit.
242
     * @return string
243
     */
244 12
    public function gitHash()
245
    {
246 12
        return exec("git rev-parse HEAD");
247
    }
248
249
    /**
250
     * Get the date of the HEAD commit.
251
     * @return string
252
     */
253 2
    public function gitDate()
254
    {
255 2
        $date = new DateTime(exec('git show -s --format=%ci'));
256 2
        return $date->format('Y-m-d');
257
    }
258
259
    /**
260
     * Check whether a given tool is enabled.
261
     * @param string $tool The short name of the tool.
262
     * @return bool
263
     */
264 11
    public function tabEnabled($tool = "index")
265
    {
266 11
        $param = false;
267 11
        if ($this->container->hasParameter("enable.$tool")) {
268 11
            $param = boolval($this->container->getParameter("enable.$tool"));
269
        }
270 11
        return $param;
271
    }
272
273
    /**
274
     * Get a list of the short names of all tools.
275
     * @return string[]
276
     */
277 11
    public function allTools()
278
    {
279 11
        $retVal = [];
280 11
        if ($this->container->hasParameter("tools")) {
281 11
            $retVal = $this->container->getParameter("tools");
282
        }
283 11
        return $retVal;
284
    }
285
286
    /**
287
     * Get a list of namespace colours (one or all).
288
     * @param bool $num The NS ID to get.
289
     * @return string[]|string Indexed by namespace ID.
290
     */
291
    public static function getColorList($num = false)
292
    {
293
        $colors = [
294
            0 => '#FF5555',
295
            1 => '#55FF55',
296
            2 => '#FFEE22',
297
            3 => '#FF55FF',
298
            4 => '#5555FF',
299
            5 => '#55FFFF',
300
            6 => '#C00000',
301
            7 => '#0000C0',
302
            8 => '#008800',
303
            9 => '#00C0C0',
304
            10 => '#FFAFAF',
305
            11 => '#808080',
306
            12 => '#00C000',
307
            13 => '#404040',
308
            14 => '#C0C000',
309
            15 => '#C000C0',
310
            90 => '#991100',
311
            91 => '#99FF00',
312
            92 => '#000000',
313
            93 => '#777777',
314
            100 => '#75A3D1',
315
            101 => '#A679D2',
316
            102 => '#660000',
317
            103 => '#000066',
318
            104 => '#FAFFAF',
319
            105 => '#408345',
320
            106 => '#5c8d20',
321
            107 => '#e1711d',
322
            108 => '#94ef2b',
323
            109 => '#756a4a',
324
            110 => '#6f1dab',
325
            111 => '#301e30',
326
            112 => '#5c9d96',
327
            113 => '#a8cd8c',
328
            114 => '#f2b3f1',
329
            115 => '#9b5828',
330
            116 => '#002288',
331
            117 => '#0000CC',
332
            118 => '#99FFFF',
333
            119 => '#99BBFF',
334
            120 => '#FF99FF',
335
            121 => '#CCFFFF',
336
            122 => '#CCFF00',
337
            123 => '#CCFFCC',
338
            200 => '#33FF00',
339
            201 => '#669900',
340
            202 => '#666666',
341
            203 => '#999999',
342
            204 => '#FFFFCC',
343
            205 => '#FF00CC',
344
            206 => '#FFFF00',
345
            207 => '#FFCC00',
346
            208 => '#FF0000',
347
            209 => '#FF6600',
348
            250 => '#6633CC',
349
            251 => '#6611AA',
350
            252 => '#66FF99',
351
            253 => '#66FF66',
352
            446 => '#06DCFB',
353
            447 => '#892EE4',
354
            460 => '#99FF66',
355
            461 => '#99CC66',
356
            470 => '#CCCC33',
357
            471 => '#CCFF33',
358
            480 => '#6699FF',
359
            481 => '#66FFFF',
360
            484 => '#07C8D6',
361
            485 => '#2AF1FF',
362
            486 => '#79CB21',
363
            487 => '#80D822',
364
            490 => '#995500',
365
            491 => '#998800',
366
            710 => '#FFCECE',
367
            711 => '#FFC8F2',
368
            828 => '#F7DE00',
369
            829 => '#BABA21',
370
            866 => '#FFFFFF',
371
            867 => '#FFCCFF',
372
            1198 => '#FF34B3',
373
            1199 => '#8B1C62',
374
            2300 => '#A900B8',
375
            2301 => '#C93ED6',
376
            2302 => '#8A09C1',
377
            2303 => '#974AB8',
378
            2600 => '#000000',
379
        ];
380
381
        if ($num === false) {
382
            return $colors;
383
        } elseif (isset($colors[$num])) {
384
            return $colors[$num];
385
        } else {
386
            // Default to grey.
387
            return '#CCC';
388
        }
389
    }
390
391
    /**
392
     * Get color-blind friendly colors for use in charts
393
     * @param  Integer $num Index of color
394
     * @return String RGBA color (so you can more easily adjust the opacity)
395
     */
396
    public function chartColor($num)
397
    {
398
        $colors = [
399
            'rgba(171, 212, 235, 1)',
400
            'rgba(178, 223, 138, 1)',
401
            'rgba(251, 154, 153, 1)',
402
            'rgba(253, 191, 111, 1)',
403
            'rgba(202, 178, 214, 1)',
404
            'rgba(207, 182, 128, 1)',
405
            'rgba(141, 211, 199, 1)',
406
            'rgba(252, 205, 229, 1)',
407
            'rgba(255, 247, 161, 1)',
408
            'rgba(217, 217, 217, 1)',
409
        ];
410
411
        return $colors[$num % count($colors)];
412
    }
413
414
    /**
415
     * Whether XTools is running in single-project mode.
416
     * @return bool
417
     */
418 8
    public function isSingleWiki()
419
    {
420 8
        $param = true;
421 8
        if ($this->container->hasParameter('app.single_wiki')) {
422 8
            $param = boolval($this->container->getParameter('app.single_wiki'));
423
        }
424 8
        return $param;
425
    }
426
427
    /**
428
     * Get the database replication-lag threshold.
429
     * @return int
430
     */
431
    public function getReplagThreshold()
432
    {
433
        $param = 30;
434
        if ($this->container->hasParameter('app.replag_threshold')) {
435
            $param = $this->container->getParameter('app.replag_threshold');
436
        };
437
        return $param;
438
    }
439
440
    /**
441
     * Whether we should load stylesheets from external CDNs or not.
442
     * @return bool
443
     */
444 11
    public function loadStylesheetsFromCDN()
445
    {
446 11
        $param = false;
447 11
        if ($this->container->hasParameter('app.load_stylesheets_from_cdn')) {
448 11
            $param = boolval($this->container->getParameter('app.load_stylesheets_from_cdn'));
449
        }
450 11
        return $param;
451
    }
452
453
    /**
454
     * Whether XTools is running in WMF Labs mode.
455
     * @return bool
456
     */
457 11
    public function isWMFLabs()
458
    {
459 11
        $param = false;
460 11
        if ($this->container->hasParameter('app.is_labs')) {
461 11
            $param = boolval($this->container->getParameter('app.is_labs'));
462
        }
463 11
        return $param;
464
    }
465
466
    /**
467
     * The current replication lag.
468
     * @return int
469
     * @codeCoverageIgnore
470
     */
471
    public function replag()
472
    {
473
        $retVal = 0;
474
475
        if ($this->isWMFLabs()) {
476
            $project = $this->getCurrentRequest()->get('project');
477
478
            if (!isset($project)) {
479
                $project = 'enwiki';
480
            }
481
482
            $dbName = ProjectRepository::getProject($project, $this->container)
483
                ->getDatabaseName();
484
485
            $stmt = "SELECT lag FROM `heartbeat_p`.`heartbeat` h
486
            RIGHT JOIN `meta_p`.`wiki` w ON concat(h.shard, \".labsdb\")=w.slice
487
            WHERE dbname LIKE :project LIMIT 1";
488
489
            $conn = $this->container->get('doctrine')->getManager('replicas')->getConnection();
490
491
            // Prepare the query and execute
492
            $resultQuery = $conn->prepare($stmt);
493
            $resultQuery->bindParam('project', $dbName);
494
            $resultQuery->execute();
495
496
            if ($resultQuery->errorCode() == 0) {
497
                $results = $resultQuery->fetchAll();
498
499
                if (isset($results[0]['lag'])) {
500
                    $retVal = $results[0]['lag'];
501
                }
502
            }
503
        }
504
505
        return $retVal;
506
    }
507
508
    /**
509
     * Get a random quote for the footer
510
     * @return string
511
     */
512 11
    public function quote()
513
    {
514
        // Don't show if bash is turned off, but always show for Labs
515
        // (so quote is in footer but not in nav).
516 11
        $isLabs = $this->container->getParameter('app.is_labs');
517 11
        if (!$isLabs && !$this->container->getParameter('enable.bash')) {
518 11
            return '';
519
        }
520
        $quotes = $this->container->getParameter('quotes');
521
        $id = array_rand($quotes);
522
        return $quotes[$id];
523
    }
524
525
    /**
526
     * Get the currently logged in user's details.
527
     * @return string[]
528
     */
529 11
    public function functionLoggedInUser()
530
    {
531 11
        return $this->container->get('session')->get('logged_in_user');
532
    }
533
534
535
    /*********************************** FILTERS ***********************************/
536
537
    /**
538
     * Get all filters for this extension.
539
     * @return array
540
     */
541 12
    public function getFilters()
542
    {
543
        return [
544 12
            new \Twig_SimpleFilter('capitalize_first', [ $this, 'capitalizeFirst' ]),
545 12
            new \Twig_SimpleFilter('percent_format', [ $this, 'percentFormat' ]),
546 12
            new \Twig_SimpleFilter('diff_format', [ $this, 'diffFormat' ], [ 'is_safe' => [ 'html' ] ]),
547 12
            new \Twig_SimpleFilter('num_format', [$this, 'numberFormat']),
548 12
            new \Twig_SimpleFilter('date_format', [$this, 'dateFormatStd']),
549 12
            new \Twig_SimpleFilter('date_localize', [$this, 'dateFormat']),
550
        ];
551
    }
552
553
    /**
554
     * Format a number based on language settings.
555
     * @param  int|float $number
556
     * @param  int $decimals Number of decimals to format to.
557
     * @return string
558
     */
559 15
    public function numberFormat($number, $decimals = 0)
560
    {
561 15
        if (!isset($this->numFormatter)) {
562 15
            $lang = $this->getIntuition()->getLang();
563 15
            $this->numFormatter = new NumberFormatter($lang, NumberFormatter::DECIMAL);
0 ignored issues
show
Bug introduced by
The call to NumberFormatter::__construct() has too few arguments starting with pattern. ( Ignorable by Annotation )

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

563
            $this->numFormatter = /** @scrutinizer ignore-call */ new NumberFormatter($lang, NumberFormatter::DECIMAL);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
564
        }
565
566
        // Get separator symbols.
567 15
        $decimal = $this->numFormatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL);
568 15
        $thousands = $this->numFormatter->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL);
569
570 15
        $formatted = number_format($number, $decimals, $decimal, $thousands);
571
572
        // Remove trailing .0's (e.g. 40.00 -> 40).
573 15
        return preg_replace("/\\".$decimal."0+$/", '', $formatted);
574
    }
575
576
    /**
577
     * Localize the given date based on language settings.
578
     * @param  string|DateTime $datetime
579
     * @return string
580
     */
581 1
    public function dateFormat($datetime)
582
    {
583 1
        if (!isset($this->dateFormatter)) {
584 1
            $this->dateFormatter = new IntlDateFormatter(
0 ignored issues
show
Bug introduced by
The call to IntlDateFormatter::__construct() has too few arguments starting with timezone. ( Ignorable by Annotation )

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

584
            $this->dateFormatter = /** @scrutinizer ignore-call */ new IntlDateFormatter(

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
585 1
                $this->getIntuition()->getLang(),
586 1
                IntlDateFormatter::SHORT,
587 1
                IntlDateFormatter::SHORT
588
            );
589
        }
590
591 1
        if (is_string($datetime) || is_int($datetime)) {
592 1
            $datetime = new DateTime($datetime);
0 ignored issues
show
Bug introduced by
It seems like $datetime can also be of type DateTime; however, parameter $time of DateTime::__construct() does only seem to accept string, 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

592
            $datetime = new DateTime(/** @scrutinizer ignore-type */ $datetime);
Loading history...
593
        }
594
595 1
        return $this->dateFormatter->format($datetime);
596
    }
597
598
    /**
599
     * Format the given date to ISO 8601.
600
     * @param  string|DateTime $datetime
601
     * @return string
602
     */
603 1
    public function dateFormatStd($datetime)
604
    {
605 1
        if (is_string($datetime) || is_int($datetime)) {
606 1
            $datetime = new DateTime($datetime);
0 ignored issues
show
Bug introduced by
It seems like $datetime can also be of type DateTime; however, parameter $time of DateTime::__construct() does only seem to accept string, 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

606
            $datetime = new DateTime(/** @scrutinizer ignore-type */ $datetime);
Loading history...
607
        }
608
609 1
        return $datetime->format('Y-m-d H:i');
610
    }
611
612
    /**
613
     * Mysteriously missing Twig helper to capitalize only the first character.
614
     * E.g. used for table headings for translated messages
615
     * @param  string $str The string
616
     * @return string      The string, capitalized
617
     */
618 5
    public function capitalizeFirst($str)
619
    {
620 5
        return ucfirst($str);
621
    }
622
623
    /**
624
     * Format a given number or fraction as a percentage.
625
     * @param  number  $numerator   Numerator or single fraction if denominator is ommitted.
626
     * @param  number  $denominator Denominator.
627
     * @param  integer $precision   Number of decimal places to show.
628
     * @return string               Formatted percentage.
629
     */
630 1
    public function percentFormat($numerator, $denominator = null, $precision = 1)
631
    {
632 1
        if (!$denominator) {
633 1
            $quotient = $numerator;
634
        } else {
635 1
            $quotient = ( $numerator / $denominator ) * 100;
636
        }
637
638 1
        return $this->numberFormat($quotient, $precision) . '%';
639
    }
640
641
    /**
642
     * Helper to return whether the given user is an anonymous (logged out) user.
643
     * @param  User|string $user User object or username as a string.
644
     * @return bool
645
     */
646 1
    public function isUserAnon($user)
647
    {
648 1
        if ($user instanceof User) {
649 1
            $username = $user->getUsername();
650
        } else {
651 1
            $username = $user;
652
        }
653
654 1
        return (bool)filter_var($username, FILTER_VALIDATE_IP);
655
    }
656
657
    /**
658
     * Helper to properly translate a namespace name
659
     * @param  int|string $namespace Namespace key as a string or ID
660
     * @param  array      $namespaces List of available namespaces
661
     *                                as retrieved from Project::getNamespaces
662
     * @return string Namespace name
663
     */
664
    public function nsName($namespace, $namespaces)
665
    {
666
        if ($namespace === 'all') {
667
            return $this->getIntuition()->msg('all');
668
        } elseif ($namespace === '0' || $namespace === 0 || $namespace === 'Main') {
669
            return $this->getIntuition()->msg('mainspace');
670
        } else {
671
            return $namespaces[$namespace];
672
        }
673
    }
674
675
    /**
676
     * Format a given number as a diff, colouring it green if it's postive, red if negative, gary if zero
677
     * @param  number $size Diff size
678
     * @return string       Markup with formatted number
679
     */
680 1
    public function diffFormat($size)
681
    {
682 1
        if ($size < 0) {
683 1
            $class = 'diff-neg';
684 1
        } elseif ($size > 0) {
685 1
            $class = 'diff-pos';
686
        } else {
687 1
            $class = 'diff-zero';
688
        }
689
690 1
        $size = $this->numberFormat($size);
691
692 1
        return "<span class='$class'>$size</span>";
693
    }
694
695
    /**
696
     * Format a time duration as humanized string.
697
     * @param int $seconds Number of seconds.
698
     * @param bool $translate Used for unit testing. Set to false to return
699
     *   the value and i18n key, instead of the actual translation.
700
     * @return string|array Examples: '30 seconds', '2 minutes', '15 hours', '500 days',
701
     *   or [30, 'num-seconds'] (etc.) if $translate is false.
702
     */
703 1
    public function formatDuration($seconds, $translate = true)
704
    {
705 1
        list($val, $key) = $this->getDurationMessageKey($seconds);
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
    /**
715
     * Given a time duration in seconds, generate a i18n message key and value.
716
     * @param  int $seconds Number of seconds.
717
     * @return array<integer|string> [int - message value, string - message key]
718
     */
719 1
    private function getDurationMessageKey($seconds)
720
    {
721
        /** @var int Value to show in message */
722 1
        $val = $seconds;
723
724
        /** @var string Unit of time, used in the key for the i18n message */
725 1
        $key = 'seconds';
726
727 1
        if ($seconds >= 86400) {
728
            // Over a day
729 1
            $val = (int) floor($seconds / 86400);
730 1
            $key = 'days';
731 1
        } elseif ($seconds >= 3600) {
732
            // Over an hour, less than a day
733 1
            $val = (int) floor($seconds / 3600);
734 1
            $key = 'hours';
735 1
        } elseif ($seconds >= 60) {
736
            // Over a minute, less than an hour
737 1
            $val = (int) floor($seconds / 60);
738 1
            $key = 'minutes';
739
        }
740
741 1
        return [$val, $key];
742
    }
743
744
    /**
745
     * Build URL query string from given params.
746
     * @param  array $params
747
     * @return string
748
     */
749 1
    public function buildQuery($params)
750
    {
751 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...
752
    }
753
}
754