Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.21% covered (success)
98.21%
55 / 56
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
VariablesFormatter
98.21% covered (success)
98.21%
55 / 56
75.00% covered (warning)
75.00%
3 / 4
13
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setMessageLocalizer
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 buildVarDumpTable
97.37% covered (success)
97.37%
37 / 38
0.00% covered (danger)
0.00%
0 / 1
4
 formatVar
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
7
1<?php
2
3namespace MediaWiki\Extension\AbuseFilter\Variables;
4
5use MediaWiki\Extension\AbuseFilter\KeywordsManager;
6use MediaWiki\Html\Html;
7use MediaWiki\Language\MessageLocalizer;
8
9/**
10 * Pretty-prints the content of a VariableHolder for use e.g. in AbuseLog hit details
11 */
12class VariablesFormatter {
13    public const SERVICE_NAME = 'AbuseFilterVariablesFormatter';
14
15    public function __construct(
16        private readonly KeywordsManager $keywordsManager,
17        private readonly VariablesManager $varManager,
18        private MessageLocalizer $messageLocalizer
19    ) {
20    }
21
22    public function setMessageLocalizer( MessageLocalizer $messageLocalizer ): void {
23        $this->messageLocalizer = $messageLocalizer;
24    }
25
26    public function buildVarDumpTable( VariableHolder $varHolder ): string {
27        $vars = $this->varManager->exportAllVars( $varHolder );
28
29        $output = '';
30
31        // Now, build the body of the table.
32        foreach ( $vars as $key => $value ) {
33            $key = strtolower( $key );
34
35            $varMsgKey = $this->keywordsManager->getMessageKeyForVar( $key );
36            if ( $varMsgKey ) {
37                $varMsg = $this->messageLocalizer->msg( $varMsgKey );
38                $arg = Html::element( 'code', [], $key );
39                if ( str_contains( $varMsg->plain(), '$1' ) ) {
40                    $keyDisplay = $varMsg->params( $arg )->parse();
41                } else {
42                    // workaround due to 1904cf8 (temporary?)
43                    $keyDisplay = $varMsg->parse() . ' '
44                        . $this->messageLocalizer->msg( 'parentheses' )->rawParams( $arg )->escaped();
45                }
46            } else {
47                $keyDisplay = Html::element( 'code', [], $key );
48            }
49
50            $value = Html::element(
51                'div',
52                [ 'class' => 'mw-abuselog-var-value' ],
53                self::formatVar( $value )
54            );
55
56            $trow =
57                Html::rawElement( 'td', [ 'class' => 'mw-abuselog-var' ], $keyDisplay ) .
58                Html::rawElement( 'td', [ 'class' => 'mw-abuselog-var-value' ], $value );
59            $output .=
60                Html::rawElement( 'tr',
61                    [ 'class' => "mw-abuselog-details-$key mw-abuselog-value" ], $trow
62                ) . "\n";
63        }
64
65        return Html::rawElement( 'table', [ 'class' => 'mw-abuselog-details' ],
66            Html::rawElement( 'thead', [],
67                Html::rawElement( 'tr', [],
68                    Html::element( 'th', [],
69                        $this->messageLocalizer->msg( 'abusefilter-log-details-var' )->text()
70                    ) .
71                    Html::element( 'th', [],
72                        $this->messageLocalizer->msg( 'abusefilter-log-details-val' )->text()
73                    )
74                )
75            ) .
76            Html::rawElement( 'tbody', [], $output )
77        );
78    }
79
80    /**
81     * @param mixed $var
82     * @param string $indent
83     * @return string
84     */
85    public static function formatVar( $var, string $indent = '' ): string {
86        if ( $var === [] ) {
87            return '[]';
88        } elseif ( is_array( $var ) ) {
89            $ret = '[';
90            $indent .= "\t";
91            foreach ( $var as $key => $val ) {
92                $ret .= "\n$indent" . self::formatVar( $key, $indent ) .
93                    ' => ' . self::formatVar( $val, $indent ) . ',';
94            }
95            // Strip trailing commas
96            return substr( $ret, 0, -1 ) . "\n" . substr( $indent, 0, -1 ) . ']';
97        } elseif ( is_string( $var ) ) {
98            // Don't escape the string (specifically backslashes) to avoid displaying wrong stuff
99            return "'$var'";
100        } elseif ( $var === null ) {
101            return 'null';
102        } elseif ( is_float( $var ) ) {
103            // Don't let float precision produce weirdness
104            return (string)$var;
105        }
106        return var_export( $var, true );
107    }
108}