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