Completed
Push — master ( 86adbf...92b61e )
by
unknown
02:54 queued 10s
created

AppExtension::nsName()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 7
nc 3
nop 2
1
<?php
2
/**
3
 * This file contains only the AppExtension class.
4
 */
5
6
namespace AppBundle\Twig;
7
8
/**
9
 * Twig functions and filters for XTools.
10
 */
11
class AppExtension extends Extension
12
{
13
14
    /**
15
     * Get the name of this extension.
16
     * @return string
17
     */
18
    public function getName()
19
    {
20
        return 'app_extension';
21
    }
22
23
    /*********************************** FUNCTIONS ***********************************/
24
25
    /**
26
     * Get all functions that this class provides.
27
     * @return array
28
     */
29
    public function getFunctions()
30
    {
31
        $options = ['is_safe' => ['html']];
32
        return [
33
            new \Twig_SimpleFunction('request_time', [ $this, 'requestTime' ], $options),
34
            new \Twig_SimpleFunction('memory_usage', [ $this, 'requestMemory' ], $options),
35
            new \Twig_SimpleFunction('year', [ $this, 'generateYear' ], $options),
36
            new \Twig_SimpleFunction('msgPrintExists', [ $this, 'intuitionMessagePrintExists' ], $options),
37
            new \Twig_SimpleFunction('msgExists', [ $this, 'intuitionMessageExists' ], $options),
38
            new \Twig_SimpleFunction('msg', [ $this, 'intuitionMessage' ], $options),
39
            new \Twig_SimpleFunction('lang', [ $this, 'getLang' ], $options),
40
            new \Twig_SimpleFunction('langName', [ $this, 'getLangName' ], $options),
41
            new \Twig_SimpleFunction('allLangs', [ $this, 'getAllLangs' ]),
42
            new \Twig_SimpleFunction('isRTL', [ $this, 'intuitionIsRTL' ]),
43
            new \Twig_SimpleFunction('isRTLLang', [ $this, 'intuitionIsRTLLang' ]),
44
            new \Twig_SimpleFunction('shortHash', [ $this, 'gitShortHash' ]),
45
            new \Twig_SimpleFunction('hash', [ $this, 'gitHash' ]),
46
            new \Twig_SimpleFunction('enabled', [ $this, 'tabEnabled' ]),
47
            new \Twig_SimpleFunction('tools', [ $this, 'allTools' ]),
48
            new \Twig_SimpleFunction('color', [ $this, 'getColorList' ]),
49
            new \Twig_SimpleFunction('chartColor', [ $this, 'chartColor' ]),
50
            new \Twig_SimpleFunction('isWMFLabs', [ $this, 'isWMFLabs' ]),
51
            new \Twig_SimpleFunction('isSingleWiki', [ $this, 'isSingleWiki' ]),
52
            new \Twig_SimpleFunction('getReplagThreshold', [ $this, 'getReplagThreshold' ]),
53
            new \Twig_SimpleFunction('loadStylesheetsFromCDN', [ $this, 'loadStylesheetsFromCDN' ]),
54
            new \Twig_SimpleFunction('isWMFLabs', [ $this, 'isWMFLabs' ]),
55
            new \Twig_SimpleFunction('replag', [ $this, 'replag' ]),
56
            new \Twig_SimpleFunction('link', [ $this, 'link' ]),
57
            new \Twig_SimpleFunction('quote', [ $this, 'quote' ]),
58
            new \Twig_SimpleFunction('bugReportURL', [ $this, 'bugReportURL' ]),
59
            new \Twig_SimpleFunction('logged_in_user', [$this, 'functionLoggedInUser']),
60
            new \Twig_SimpleFunction('isUserAnon', [$this, 'isUserAnon']),
61
            new \Twig_SimpleFunction('nsName', [$this, 'nsName']),
62
        ];
63
    }
64
65
    /**
66
     * Get the duration of the current HTTP request in microseconds.
67
     * @param int $decimals
68
     * @return string
69
     */
70
    public function requestTime($decimals = 3)
0 ignored issues
show
Coding Style introduced by
requestTime uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
71
    {
72
        return number_format(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], $decimals);
73
    }
74
75
    /**
76
     * Get the formatted real memory usage.
77
     * @return float
78
     */
79
    public function requestMemory()
80
    {
81
        $mem = memory_get_usage(false);
82
        $div = pow(1024, 2);
83
        $mem = $mem / $div;
84
85
        return round($mem, 2);
86
    }
87
88
    /**
89
     * Get the current year.
90
     * @return string
91
     */
92
    public function generateYear()
93
    {
94
        return date('Y');
95
    }
96
97
    /**
98
     * See if a given i18n message exists.
99
     * @TODO: refactor all intuition stuff so it can be used anywhere
100
     * @param string $message The message.
101
     * @return bool
102
     */
103
    public function intuitionMessageExists($message = "")
104
    {
105
        return $this->getIntuition()->msgExists($message, [ "domain" => "xtools" ]);
106
    }
107
108
    /**
109
     * Get an i18n message if it exists, otherwise just get the message key.
110
     * @param string $message
111
     * @param array $vars
112
     * @return mixed|null|string
113
     */
114
    public function intuitionMessagePrintExists($message = "", $vars = [])
115
    {
116
        if (is_array($message)) {
117
            $vars = $message;
118
            $message = $message[0];
119
            $vars = array_slice($vars, 1);
120
        }
121
        if ($this->intuitionMessageExists($message)) {
122
            return $this->intuitionMessage($message, $vars);
123
        } else {
124
            return $message;
125
        }
126
    }
127
128
    /**
129
     * Get an i18n message.
130
     * @param string $message
131
     * @param array $vars
132
     * @return mixed|null|string
133
     */
134
    public function intuitionMessage($message = "", $vars = [])
135
    {
136
        return $this->getIntuition()->msg($message, [ "domain" => "xtools", "variables" => $vars ]);
137
    }
138
139
    /**
140
     * Get the current language code.
141
     * @return string
142
     */
143
    public function getLang()
144
    {
145
        return $this->getIntuition()->getLang();
146
    }
147
148
    /**
149
     * Get the current language name (defaults to 'English').
150
     * @return string
151
     */
152
    public function getLangName()
153
    {
154
        return in_array($this->getIntuition()->getLangName(), $this->getAllLangs())
155
            ? $this->getIntuition()->getLangName()
156
            : 'English';
157
    }
158
159
    /**
160
     * Get all available languages in the i18n directory
161
     * @return array Associative array of langKey => langName
162
     */
163
    public function getAllLangs()
164
    {
165
        $messageFiles = glob($this->container->getParameter("kernel.root_dir") . '/../i18n/*.json');
166
167
        $languages = array_values(array_unique(array_map(
168
            function ($filename) {
169
                return basename($filename, '.json');
170
            },
171
            $messageFiles
172
        )));
173
174
        $availableLanguages = [];
175
176
        foreach ($languages as $lang) {
177
            $availableLanguages[$lang] = ucfirst($this->getIntuition()->getLangName($lang));
178
        }
179
        asort($availableLanguages);
180
181
        return $availableLanguages;
182
    }
183
184
    /**
185
     * Whether the current language is right-to-left.
186
     * @return bool
187
     */
188
    public function intuitionIsRTL()
189
    {
190
        return $this->getIntuition()->isRTL($this->getIntuition()->getLang());
191
    }
192
193
    /**
194
     * Whether the given language is right-to-left.
195
     * @param string $lang The language code.
196
     * @return bool
197
     */
198
    public function intuitionIsRTLLang($lang)
199
    {
200
        return $this->getIntuition()->isRTL($lang);
201
    }
202
203
    /**
204
     * Get the short hash of the currently checked-out Git commit.
205
     * @return string
206
     */
207
    public function gitShortHash()
208
    {
209
        return exec("git rev-parse --short HEAD");
210
    }
211
212
    /**
213
     * Get the full hash of the currently checkout-out Git commit.
214
     * @return string
215
     */
216
    public function gitHash()
217
    {
218
        return exec("git rev-parse HEAD");
219
    }
220
221
    /**
222
     * Check whether a given tool is enabled.
223
     * @param string $tool The short name of the tool.
224
     * @return bool
225
     */
226 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...
227
    {
228
        $param = false;
229
        if ($this->container->hasParameter("enable.$tool")) {
230
            $param = boolval($this->container->getParameter("enable.$tool"));
231
        }
232
        return $param;
233
    }
234
235
    /**
236
     * Get a list of the short names of all tools.
237
     * @return string[]
238
     */
239
    public function allTools()
240
    {
241
        $retVal = [];
242
        if ($this->container->hasParameter("tools")) {
243
            $retVal = $this->container->getParameter("tools");
244
        }
245
        return $retVal;
246
    }
247
248
    /**
249
     * Get a list of namespace colours (one or all).
250
     * @param bool $num The NS ID to get.
251
     * @return string[]|string Indexed by namespace ID.
252
     */
253
    public static function getColorList($num = false)
254
    {
255
        $colors = [
256
            0 => '#Cc0000',# '#FF005A', #red '#FF5555',
257
            1 => '#F7b7b7',
258
            2 => '#5c8d20',# '#008800', #green'#55FF55',
259
            3 => '#85eD82',
260
            4 => '#2E97E0', # blue
261
            5 => '#B9E3F9',
262
            6 => '#e1711d',  # orange
263
            7 => '#ffc04c',
264
            8 => '#FDFF98', # yellow
265
            9 => '#5555FF',
266
            10 => '#55FFFF',
267
            11 => '#0000C0',  #
268
            12 => '#008800',  # green
269
            13 => '#00C0C0',
270
            14 => '#FFAFAF',  # rosé
271
            15 => '#808080',  # gray
272
            16 => '#00C000',
273
            17 => '#404040',
274
            18 => '#C0C000',  # green
275
            19 => '#C000C0',
276
            100 => '#75A3D1',  # blue
277
            101 => '#A679D2',  # purple
278
            102 => '#660000',
279
            103 => '#000066',
280
            104 => '#FAFFAF',  # caramel
281
            105 => '#408345',
282
            106 => '#5c8d20',
283
            107 => '#e1711d',  # red
284
            108 => '#94ef2b',  # light green
285
            109 => '#756a4a',  # brown
286
            110 => '#6f1dab',
287
            111 => '#301e30',
288
            112 => '#5c9d96',
289
            113 => '#a8cd8c',  # earth green
290
            114 => '#f2b3f1',  # light purple
291
            115 => '#9b5828',
292
            118 => '#99FFFF',
293
            119 => '#99BBFF',
294
            120 => '#FF99FF',
295
            121 => '#CCFFFF',
296
            122 => '#CCFF00',
297
            123 => '#CCFFCC',
298
            200 => '#33FF00',
299
            201 => '#669900',
300
            202 => '#666666',
301
            203 => '#999999',
302
            204 => '#FFFFCC',
303
            205 => '#FF00CC',
304
            206 => '#FFFF00',
305
            207 => '#FFCC00',
306
            208 => '#FF0000',
307
            209 => '#FF6600',
308
            446 => '#06DCFB',
309
            447 => '#892EE4',
310
            460 => '#99FF66',
311
            461 => '#99CC66',  # green
312
            470 => '#CCCC33',  # ocker
313
            471 => '#CCFF33',
314
            480 => '#6699FF',
315
            481 => '#66FFFF',
316
            490 => '#995500',
317
            491 => '#998800',
318
            710 => '#FFCECE',
319
            711 => '#FFC8F2',
320
            828 => '#F7DE00',
321
            829 => '#BABA21',
322
            866 => '#FFFFFF',
323
            867 => '#FFCCFF',
324
            1198 => '#FF34B3',
325
            1199 => '#8B1C62',
326
327
            '#61a9f3',# blue
328
            '#f381b9',# pink
329
            '#61E3A9',
330
            '#D56DE2',
331
            '#85eD82',
332
            '#F7b7b7',
333
            '#CFDF49',
334
            '#88d8f2',
335
            '#07AF7B',# green
336
            '#B9E3F9',
337
            '#FFF3AD',
338
            '#EF606A',# red
339
            '#EC8833',
340
            '#FFF100',
341
            '#87C9A5',
342
            '#FFFB11',
343
            '#005EBC',
344
            '#9AEB67',
345
            '#FF4A26',
346
            '#FDFF98',
347
            '#6B7EFF',
348
            '#BCE02E',
349
            '#E0642E',
350
            '#E0D62E',
351
            '#02927F',
352
            '#FF005A',
353
            '#61a9f3', # blue' #FFFF55',
354
        ];
355
356
        if ($num === false) {
357
            return $colors;
358
        } elseif (isset($colors[$num])) {
359
            return $colors[$num];
360
        } else {
361
            // Default to grey.
362
            return '#CCC';
363
        }
364
    }
365
366
    /**
367
     * Get color-blind friendly colors for use in charts
368
     * @param  Integer $num Index of color
369
     * @return String RGBA color (so you can more easily adjust the opacity)
370
     */
371
    public function chartColor($num)
372
    {
373
        $colors = [
374
            'rgba(171, 212, 235, 1)',
375
            'rgba(178, 223, 138, 1)',
376
            'rgba(251, 154, 153, 1)',
377
            'rgba(253, 191, 111, 1)',
378
            'rgba(202, 178, 214, 1)',
379
            'rgba(207, 182, 128, 1)',
380
            'rgba(141, 211, 199, 1)',
381
            'rgba(252, 205, 229, 1)',
382
            'rgba(255, 247, 161, 1)',
383
            'rgba(217, 217, 217, 1)',
384
        ];
385
386
        return $colors[$num % count($colors)];
387
    }
388
389
    /**
390
     * Whether XTools is running in single-project mode.
391
     * @return bool
392
     */
393 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...
394
    {
395
        $param = true;
396
        if ($this->container->hasParameter("app.single_wiki")) {
397
            $param = boolval($this->container->getParameter("app.single_wiki"));
398
        }
399
        return $param;
400
    }
401
402
    /**
403
     * Get the database replication-lag threshold.
404
     * @return int
405
     */
406
    public function getReplagThreshold()
407
    {
408
        $param = 30;
409
        if ($this->container->hasParameter("app.replag_threshold")) {
410
            $param = $this->container->getParameter("app.replag_threshold");
411
        };
412
        return $param;
413
    }
414
415
    /**
416
     * Whether we should load stylesheets from external CDNs or not.
417
     * @return bool
418
     */
419 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...
420
    {
421
        $param = false;
422
        if ($this->container->hasParameter("app.load_stylesheets_from_cdn")) {
423
            $param = boolval($this->container->getParameter("app.load_stylesheets_from_cdn"));
424
        }
425
        return $param;
426
    }
427
428
    /**
429
     * Whether XTools is running in WMF Labs mode.
430
     * @return bool
431
     */
432 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...
433
    {
434
        $param = false;
435
        if ($this->container->hasParameter("app.is_labs")) {
436
            $param = boolval($this->container->getParameter("app.is_labs"));
437
        }
438
        return $param;
439
    }
440
441
    /**
442
     * The current replication lag.
443
     * @return int
444
     */
445
    public function replag()
446
    {
447
        $retVal = 0;
448
449
        if ($this->isWMFLabs()) {
450
            $project = $this->container->get("request_stack")->getCurrentRequest()->get('project');
451
452
            if (!isset($project)) {
453
                $project = "enwiki";
454
            }
455
456
            $stmt = "SELECT lag FROM `heartbeat_p`.`heartbeat` h
457
            RIGHT JOIN `meta_p`.`wiki` w ON concat(h.shard, \".labsdb\")=w.slice
458
            WHERE dbname LIKE :project OR name LIKE :project OR url LIKE :project LIMIT 1";
459
460
            $conn = $this->container->get('doctrine')->getManager("replicas")->getConnection();
461
462
            // Prepare the query and execute
463
            $resultQuery = $conn->prepare($stmt);
464
            $resultQuery->bindParam("project", $project);
465
            $resultQuery->execute();
466
467
            if ($resultQuery->errorCode() == 0) {
468
                $results = $resultQuery->fetchAll();
469
470
                if (isset($results[0]["lag"])) {
471
                    $retVal = $results[0]["lag"];
472
                }
473
            }
474
        }
475
476
        return $retVal;
477
    }
478
479
    /**
480
     * Generate an XTools URL.
481
     * @deprecated Use path() instead.
482
     * @param string $path The path.
483
     * @return string
484
     */
485
    public function link($path = "/")
486
    {
487
        $base_path = $this->container->getParameter("app.base_path");
488
        $retVal = $path;
489
490
        if (isset($base_path)) {
491
            $retVal = "$base_path/$path";
492
        }
493
494
        $retVal = str_replace("//", "/", $retVal);
495
496
        return $retVal;
497
    }
498
499
    /**
500
     * Get a random quote for the footer
501
     * @return string
502
     */
503
    public function quote()
504
    {
505
        $quotes = $this->container->getParameter('quotes');
506
        $id = array_rand($quotes);
507
        return $quotes[$id];
508
    }
509
510
    /**
511
     * Get the currently logged in user's details.
512
     * @return string[]
513
     */
514
    public function functionLoggedInUser()
515
    {
516
        return $this->container->get('session')->get('logged_in_user');
517
    }
518
519
520
    /*********************************** FILTERS ***********************************/
521
522
    /**
523
     * Get all filters for this extension.
524
     * @return array
525
     */
526
    public function getFilters()
527
    {
528
        return [
529
            new \Twig_SimpleFilter('capitalize_first', [ $this, 'capitalizeFirst' ]),
530
            new \Twig_SimpleFilter('percent_format', [ $this, 'percentFormat' ]),
531
        ];
532
    }
533
534
    /**
535
     * Mysteriously missing Twig helper to capitalize only the first character.
536
     * E.g. used for table headings for translated messages
537
     * @param  string $str The string
538
     * @return string      The string, capitalized
539
     */
540
    public function capitalizeFirst($str)
541
    {
542
        return ucfirst($str);
543
    }
544
545
    /**
546
     * Format a given number or fraction as a percentage
547
     * @param  number  $numerator     Numerator or single fraction if denominator is ommitted
548
     * @param  number  [$denominator] Denominator
549
     * @param  integer [$precision]   Number of decimal places to show
550
     * @return string                 Formatted percentage
551
     */
552
    public function percentFormat($numerator, $denominator = null, $precision = 1)
553
    {
554
        if (!$denominator) {
555
            $quotient = $numerator;
556
        } else {
557
            $quotient = ( $numerator / $denominator ) * 100;
558
        }
559
560
        return round($quotient, $precision) . '%';
561
    }
562
563
    /**
564
     * Helper to return whether the given user is an anonymous (logged out) user
565
     * @param  User|string $user User object or username as a string
566
     * @return bool
567
     */
568
    public function isUserAnon($user)
569
    {
570
        if ($user instanceof User) {
0 ignored issues
show
Bug introduced by
The class AppBundle\Twig\User does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
571
            $username = $user.username;
572
        } else {
573
            $username = $user;
574
        }
575
576
        return filter_var($username, FILTER_VALIDATE_IP);
577
    }
578
579
    /**
580
     * Helper to properly translate a namespace name
581
     * @param  int|string $namespace Namespace key as a string or ID
582
     * @param  array      $namespaces List of available namespaces
583
     *                                as retrieved from Project::getNamespaces
584
     * @return string Namespace name
585
     */
586
    public function nsName($namespace, $namespaces)
587
    {
588
        if ($namespace === 'all') {
589
            return $this->getIntuition()->msg('all');
590
        } elseif ($namespace === '0' || $namespace === 0 || $namespace === 'Main') {
591
            return $this->getIntuition()->msg('mainspace');
592
        } else {
593
            return $namespaces[$namespace];
594
        }
595
    }
596
}
597