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