Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
36.99% covered (danger)
36.99%
27 / 73
36.36% covered (danger)
36.36%
4 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Licenses
36.99% covered (danger)
36.99%
27 / 73
36.36% covered (danger)
36.36%
4 / 11
209.40
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getMessageFromParams
28.57% covered (danger)
28.57%
2 / 7
0.00% covered (danger)
0.00%
0 / 1
6.28
 buildLine
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 makeLines
86.67% covered (warning)
86.67%
13 / 15
0.00% covered (danger)
0.00%
0 / 1
7.12
 trimStars
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 stackItem
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 makeHtml
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
12
 outputOption
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getLines
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLicenses
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getInputHTML
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * License selector for use on Special:Upload.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup SpecialPage
22 * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
23 * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason
24 */
25
26use MediaWiki\Html\Html;
27use MediaWiki\HTMLForm\HTMLFormField;
28use MediaWiki\MediaWikiServices;
29
30/**
31 * A License class for use on Special:Upload
32 */
33class Licenses extends HTMLFormField {
34    protected string $msg;
35    protected array $lines = [];
36    protected string $html;
37    protected ?string $selected;
38
39    /**
40     * @param array $params
41     */
42    public function __construct( $params ) {
43        parent::__construct( $params );
44
45        $this->msg = static::getMessageFromParams( $params );
46        $this->selected = null;
47
48        $this->makeLines();
49    }
50
51    /**
52     * @param array $params
53     * @return string
54     */
55    protected static function getMessageFromParams( $params ) {
56        if ( !empty( $params['licenses'] ) ) {
57            return $params['licenses'];
58        }
59
60        // If the licenses page is in $wgForceUIMsgAsContentMsg (which is the case
61        // on Commons), translations will be in the database, in subpages of this
62        // message (e.g. MediaWiki:Licenses/<lang>)
63        // If there is no such translation, the result will be '-' (the empty default
64        // in the i18n files), so we'll need to force it to look up the actual licenses
65        // in the default site language (= get the translation from MediaWiki:Licenses)
66        // Also see https://phabricator.wikimedia.org/T3495
67        $defaultMsg = wfMessage( 'licenses' )->inContentLanguage();
68        if ( $defaultMsg->isDisabled() ) {
69            $defaultMsg = wfMessage( 'licenses' )->inLanguage(
70                MediaWikiServices::getInstance()->getContentLanguage() );
71        }
72
73        return $defaultMsg->plain();
74    }
75
76    /**
77     * @param string $line
78     * @return License
79     */
80    protected function buildLine( $line ) {
81        return new License( $line );
82    }
83
84    /**
85     * @internal
86     */
87    protected function makeLines() {
88        $levels = [];
89        $lines = explode( "\n", $this->msg );
90
91        foreach ( $lines as $line ) {
92            if ( !str_starts_with( $line, '*' ) ) {
93                continue;
94            }
95            [ $level, $line ] = $this->trimStars( $line );
96
97            if ( str_contains( $line, '|' ) ) {
98                $obj = $this->buildLine( $line );
99                $this->stackItem( $this->lines, $levels, $obj );
100            } else {
101                if ( $level < count( $levels ) ) {
102                    $levels = array_slice( $levels, 0, $level );
103                }
104                if ( $level == count( $levels ) ) {
105                    $levels[$level - 1] = $line;
106                } elseif ( $level > count( $levels ) ) {
107                    $levels[] = $line;
108                }
109            }
110        }
111    }
112
113    /**
114     * @param string $str
115     * @return array
116     */
117    protected function trimStars( $str ) {
118        $numStars = strspn( $str, '*' );
119        return [ $numStars, ltrim( substr( $str, $numStars ), ' ' ) ];
120    }
121
122    /**
123     * @param array &$list
124     * @param array $path
125     * @param mixed $item
126     */
127    protected function stackItem( &$list, $path, $item ) {
128        $position =& $list;
129        if ( $path ) {
130            foreach ( $path as $key ) {
131                $position =& $position[$key];
132            }
133        }
134        $position[] = $item;
135    }
136
137    /**
138     * @param array $tagset
139     * @param int $depth
140     * @return string
141     */
142    protected function makeHtml( $tagset, $depth = 0 ) {
143        $html = '';
144
145        foreach ( $tagset as $key => $val ) {
146            if ( is_array( $val ) ) {
147                $html .= $this->outputOption(
148                    $key, '',
149                    [
150                        'disabled' => 'disabled'
151                    ],
152                    $depth
153                );
154                $html .= $this->makeHtml( $val, $depth + 1 );
155            } else {
156                $html .= $this->outputOption(
157                    $val->text, $val->template,
158                    [ 'title' => '{{' . $val->template . '}}' ],
159                    $depth
160                );
161            }
162        }
163
164        return $html;
165    }
166
167    /**
168     * @param string $message
169     * @param string $value
170     * @param null|array $attribs
171     * @param int $depth
172     * @return string
173     */
174    protected function outputOption( $message, $value, $attribs = null, $depth = 0 ) {
175        $msgObj = $this->msg( $message );
176        $text = $msgObj->exists() ? $msgObj->text() : $message;
177        $attribs['value'] = $value;
178        if ( $value === $this->selected && !isset( $attribs['disabled'] ) ) {
179            $attribs['selected'] = 'selected';
180        }
181
182        $val = str_repeat( /* &nbsp */ "\u{00A0}", $depth * 2 ) . $text;
183        return str_repeat( "\t", $depth ) . Html::element( 'option', $attribs, $val ) . "\n";
184    }
185
186    /**
187     * Accessor for $this->lines
188     *
189     * @return array
190     */
191    public function getLines() {
192        return $this->lines;
193    }
194
195    /**
196     * Accessor for $this->lines
197     *
198     * @return array
199     *
200     * @deprecated since 1.31 Use getLines() instead
201     */
202    public function getLicenses() {
203        return $this->getLines();
204    }
205
206    /**
207     * @inheritDoc
208     */
209    public function getInputHTML( $value ) {
210        $this->selected = $value;
211
212        // add a default "no license selected" option
213        $default = $this->buildLine( '|nolicense' );
214        array_unshift( $this->lines, $default );
215
216        $html = $this->makeHtml( $this->getLines() );
217
218        $attribs = [
219            'name' => $this->mName,
220            'id' => $this->mID
221        ];
222        if ( !empty( $this->mParams['disabled'] ) ) {
223            $attribs['disabled'] = 'disabled';
224        }
225
226        $html = Html::rawElement( 'select', $attribs, $html );
227
228        // remove default "no license selected" from lines again
229        array_shift( $this->lines );
230
231        return $html;
232    }
233}