Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 99
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
Listings
0.00% covered (danger)
0.00%
0 / 99
0.00% covered (danger)
0.00%
0 / 10
2352
0.00% covered (danger)
0.00%
0 / 1
 onParserFirstCallInit
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 buyListings
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doListings
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 drinkListings
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 eatListings
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 otherListings
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 seeListings
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 sleepListings
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getParsedSymbol
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 listingsTag
0.00% covered (danger)
0.00%
0 / 82
0.00% covered (danger)
0.00%
0 / 1
1482
1<?php
2
3namespace MediaWiki\Extension\Listings;
4
5use MediaWiki\Hook\ParserFirstCallInitHook;
6use MediaWiki\Html\Html;
7use MediaWiki\Parser\Sanitizer;
8use Parser;
9
10class Listings implements ParserFirstCallInitHook {
11
12    /**
13     * Register parser hooks
14     *
15     * @param Parser $parser
16     */
17    public function onParserFirstCallInit( $parser ) {
18        $parser->setHook( 'buy', [ self::class, 'buyListings' ] );
19        $parser->setHook( 'do', [ self::class, 'doListings' ] );
20        $parser->setHook( 'drink', [ self::class, 'drinkListings' ] );
21        $parser->setHook( 'eat', [ self::class, 'eatListings' ] );
22        $parser->setHook( 'listing', [ self::class, 'otherlistings' ] );
23        $parser->setHook( 'see', [ self::class, 'seeListings' ] );
24        $parser->setHook( 'sleep', [ self::class, 'sleepListings' ] );
25    }
26
27    /**
28     * @param string $input
29     * @param array $args
30     * @param Parser $parser
31     * @return string
32     */
33    public static function buyListings( $input, array $args, $parser ) {
34        return self::listingsTag( 'buy', $input, $args, $parser );
35    }
36
37    /**
38     * @param string $input
39     * @param array $args
40     * @param Parser $parser
41     * @return string
42     */
43    public static function doListings( $input, array $args, $parser ) {
44        return self::listingsTag( 'do', $input, $args, $parser );
45    }
46
47    /**
48     * @param string $input
49     * @param array $args
50     * @param Parser $parser
51     * @return string
52     */
53    public static function drinkListings( $input, array $args, $parser ) {
54        return self::listingsTag( 'drink', $input, $args, $parser );
55    }
56
57    /**
58     * @param string $input
59     * @param array $args
60     * @param Parser $parser
61     * @return string
62     */
63    public static function eatListings( $input, array $args, $parser ) {
64        return self::listingsTag( 'eat', $input, $args, $parser );
65    }
66
67    /**
68     * @param string $input
69     * @param array $args
70     * @param Parser $parser
71     * @return string
72     */
73    public static function otherListings( $input, array $args, $parser ) {
74        return self::listingsTag( 'listing', $input, $args, $parser );
75    }
76
77    /**
78     * @param string $input
79     * @param array $args
80     * @param Parser $parser
81     * @return string
82     */
83    public static function seeListings( $input, array $args, $parser ) {
84        return self::listingsTag( 'see', $input, $args, $parser );
85    }
86
87    /**
88     * @param string $input
89     * @param array $args
90     * @param Parser $parser
91     * @return string
92     */
93    public static function sleepListings( $input, array $args, $parser ) {
94        return self::listingsTag( 'sleep', $input, $args, $parser );
95    }
96
97    /**
98     * This method handles messages for phone, fax, tollfree, email
99     * and processes the following messages:
100     * - listings-phone, listings-phone-symbol
101     * - listings-fax, listings-fax-symbol
102     * - listings-tollfree, listings-tollfree-symbol
103     * - listings-email, listings-email-symbol
104     *
105     * @param string $symbolType
106     * @return string
107     */
108    private static function getParsedSymbol( string $symbolType ): string {
109        $symbolType = wfMessage( "listings-$symbolType" )->inContentLanguage()->escaped();
110        $symbol = wfMessage( "listings-$symbolType-symbol" )->inContentLanguage()->parse();
111        return $symbol !== '' ? "<abbr title='$symbolType'>$symbol</abbr>" : $symbolType;
112    }
113
114    /**
115     * @param string $aType
116     * @param string $input
117     * @param array $args
118     * @param Parser $parser
119     * @return string
120     */
121    private static function listingsTag( $aType, $input, $args, $parser ) {
122        /*
123         * if a {{listings}} template exists,
124         * feed tag name and parameter list to template verbatim and exit
125         */
126        $listingsTemplate = '';
127        if ( !wfMessage( 'listings-template' )->inContentLanguage()->isDisabled() ) {
128            $listingsTemplate = wfMessage( 'listings-template' )->inContentLanguage()->text();
129        }
130        if ( $listingsTemplate !== '' ) {
131            $inputText = '{{' . $listingsTemplate . '|type=' . $aType;
132            foreach ( $args as $key => $value ) {
133                $inputText .= '|' . $key . '=' . $value;
134            }
135            $inputText .= '|' . $input . '}}';
136            return $parser->internalParse( $inputText );
137        }
138
139        /*
140         * if no pre-defined template exists, generate listing from parameters normally
141         */
142
143        // @todo Should the args be made safe HTML?
144
145        $position = '';
146        $lat = ( isset( $args['lat'] ) && is_numeric( $args['lat'] ) ) ? $args['lat'] : 361;
147        $long = ( isset( $args['long'] ) && is_numeric( $args['long'] ) ) ? $args['long'] : 361;
148        // @fixme: incorrect validation
149        if ( $lat < 361 && $long < 361 &&
150            !wfMessage( 'listings-position-template' )->inContentLanguage()->isDisabled()
151        ) {
152            $positionTemplate = wfMessage( 'listings-position-template', $lat, $long )
153                ->inContentLanguage()->text();
154            if ( $positionTemplate !== '' ) {
155                $parsedTemplate = $parser->internalParse( '{{' . $positionTemplate . '}}' );
156                // @todo FIXME: i18n issue (hard coded colon/space)
157                $position = wfMessage( 'listings-position' )->inContentLanguage()
158                    ->rawParams( $parsedTemplate )->escaped();
159            }
160        }
161
162        // @fixme: a lot of localisation-unfriendly patchwork below
163        $name = $args['name'] ?? wfMessage( 'listings-unknown' )->inContentLanguage()->text();
164        $out = Html::element( 'strong', [], $name );
165
166        $url = $args['url'] ?? '';
167        if ( $url !== '' ) {
168            $sanitizedHref = Sanitizer::validateAttributes(
169                [ 'href' => $url ],
170                [ 'href' => true ]
171            );
172            if ( isset( $sanitizedHref['href'] ) ) {
173                $out = Html::rawElement( 'a',
174                    $sanitizedHref + [ 'class' => 'external text', 'rel' => 'nofollow', 'title' => $name ],
175                    $out
176                );
177            }
178        }
179
180        $alt = isset( $args['alt'] ) ? $parser->internalParse( $args['alt'] ) : '';
181        if ( $alt !== '' ) {
182            // @todo FIXME: i18n issue (hard coded parentheses)
183            $out .= ' (<em>' . $alt . '</em>)';
184        }
185
186        $address = isset( $args['address'] ) ? $parser->internalParse( $args['address'] ) : '';
187        $directions = isset( $args['directions'] ) ? $parser->internalParse( $args['directions'] ) : '';
188        if ( ( $address !== '' ) || ( $directions !== '' ) || ( $position !== '' ) ) {
189            $out .= ', ' . $address;
190            if ( ( $directions !== '' ) || ( $position !== '' ) ) {
191                // @todo FIXME: i18n issue (hard coded parentheses)
192                $out .= ' (<em>' . $directions;
193                if ( ( $directions !== '' ) && ( $position !== '' ) ) {
194                    // @todo FIXME: i18n issue (hard coded comma list or list to text)
195                    $out .= ', ';
196                }
197                if ( $position !== '' ) {
198                    $out .= $position;
199                }
200                $out .= '</em>)';
201            }
202        }
203
204        $phone = $args['phone'] ?? '';
205        $tollFree = $args['tollfree'] ?? '';
206        if ( ( $phone !== '' ) || ( $tollFree !== '' ) ) {
207            $phoneSymbol = self::getParsedSymbol( 'phone' );
208            // @todo FIXME: i18n issue (hard coded comma list, space)
209            $out .= ', ' . $phoneSymbol . ' ' . htmlspecialchars( $phone );
210            if ( $tollFree !== '' ) {
211                $tollFreeSymbol = self::getParsedSymbol( 'tollfree' );
212                // @todo FIXME: i18n issue (hard coded parentheses)
213                $out .= ' (' . $tollFreeSymbol . ': ' . htmlspecialchars( $tollFree ) . ')';
214            }
215        }
216
217        $fax = $args['fax'] ?? '';
218        if ( $fax !== '' ) {
219            $faxSymbol = self::getParsedSymbol( 'fax' );
220            // @todo FIXME: i18n issue (hard coded comma list, colon/space)
221            $out .= ', ' . $faxSymbol . ': ' . htmlspecialchars( $fax );
222        }
223
224        $email = $args['email'] ?? '';
225        if ( $email !== '' ) {
226            $emailSymbol = self::getParsedSymbol( 'email' );
227            // @todo FIXME: i18n issue (hard comma list, coded colon/space)
228            $out .= ', ' . $emailSymbol . ': '
229                . Html::element( 'a', [ 'class' => 'email', 'href' => "mailto:$email" ], $email );
230        }
231        // @todo FIXME: i18n issue (hard coded text)
232        $out .= '. ';
233
234        $hours = $args['hours'] ?? '';
235        if ( $hours !== '' ) {
236            $out .= htmlspecialchars( $hours ) . '. ';
237        }
238
239        $checkin = $args['checkin'] ?? '';
240        $checkout = $args['checkout'] ?? '';
241        if ( ( $checkin !== '' ) || ( $checkout !== '' ) ) {
242            if ( $checkin !== '' ) {
243                $out .= wfMessage( 'listings-checkin', $checkin )->inContentLanguage()->escaped();
244                if ( $checkout !== '' ) {
245                    // @todo FIXME: i18n issue (hard coded comma list)
246                    $out .= ', ';
247                }
248            }
249            if ( $checkout !== '' ) {
250                $out .= wfMessage( 'listings-checkout', $checkout )->inContentLanguage()->escaped();
251            }
252            // @todo FIXME: i18n issue (hard coded wut?)
253            $out .= '. ';
254        }
255
256        $price = $args['price'] ?? '';
257        if ( $price !== '' ) {
258            // @todo FIXME: i18n issue (hard coded text)
259            $out .= htmlspecialchars( $price ) . '. ';
260        }
261
262        return $out . $parser->internalParse( $input );
263    }
264}