TemplatesOnThisPageFormatter::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This program is free software; you can redistribute it and/or modify
4
 * it under the terms of the GNU General Public License as published by
5
 * the Free Software Foundation; either version 2 of the License, or
6
 * (at your option) any later version.
7
 *
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
 * GNU General Public License for more details.
12
 *
13
 * You should have received a copy of the GNU General Public License along
14
 * with this program; if not, write to the Free Software Foundation, Inc.,
15
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
 * http://www.gnu.org/copyleft/gpl.html
17
 *
18
 * @file
19
 */
20
21
use MediaWiki\Linker\LinkRenderer;
22
use MediaWiki\Linker\LinkTarget;
23
24
/**
25
 * Handles formatting for the "templates used on this page"
26
 * lists. Formerly known as Linker::formatTemplates()
27
 *
28
 * @since 1.28
29
 */
30
class TemplatesOnThisPageFormatter {
31
32
	/**
33
	 * @var IContextSource
34
	 */
35
	private $context;
36
37
	/**
38
	 * @var LinkRenderer
39
	 */
40
	private $linkRenderer;
41
42
	/**
43
	 * @param IContextSource $context
44
	 * @param LinkRenderer $linkRenderer
45
	 */
46
	public function __construct( IContextSource $context, LinkRenderer $linkRenderer ) {
47
		$this->context = $context;
48
		$this->linkRenderer = $linkRenderer;
49
	}
50
51
	/**
52
	 * Make an HTML list of templates, and then add a "More..." link at
53
	 * the bottom. If $more is null, do not add a "More..." link. If $more
54
	 * is a LinkTarget, make a link to that title and use it. If $more is a string,
55
	 * directly paste it in as the link (escaping needs to be done manually).
56
	 *
57
	 * @param LinkTarget[] $templates
58
	 * @param string|bool $type 'preview' if a preview, 'section' if a section edit, false if neither
59
	 * @param LinkTarget|string|null $more An escaped link for "More..." of the templates
60
	 * @return string HTML output
61
	 */
62
	public function format( array $templates, $type = false, $more = null ) {
63
		if ( !$templates ) {
64
			// No templates
65
			return '';
66
		}
67
68
		# Do a batch existence check
69
		$batch = new LinkBatch;
70
		foreach ( $templates as $title ) {
71
			$batch->addObj( $title );
72
		}
73
		$batch->execute();
74
75
		# Construct the HTML
76
		$outText = '<div class="mw-templatesUsedExplanation">';
77
		$count = count( $templates );
78
		if ( $type === 'preview' ) {
79
			$outText .= $this->context->msg( 'templatesusedpreview' )->numParams( $count )
80
				->parseAsBlock();
81
		} elseif ( $type === 'section' ) {
82
			$outText .= $this->context->msg( 'templatesusedsection' )->numParams( $count )
83
				->parseAsBlock();
84
		} else {
85
			$outText .= $this->context->msg( 'templatesused' )->numParams( $count )
86
				->parseAsBlock();
87
		}
88
		$outText .= "</div><ul>\n";
89
90
		usort( $templates, 'Title::compare' );
91
		foreach ( $templates as $template ) {
92
			$outText .= $this->formatTemplate( $template );
93
		}
94
95
		if ( $more instanceof LinkTarget ) {
96
			$outText .= Html::rawElement( 'li', [], $this->linkRenderer->makeLink(
97
				$more, $this->context->msg( 'moredotdotdot' )->text() ) );
98
		} elseif ( $more ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $more of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
99
			// Documented as should already be escaped
100
			$outText .= Html::rawElement( 'li', [], $more );
101
		}
102
103
		$outText .= '</ul>';
104
		return $outText;
105
	}
106
107
	/**
108
	 * Builds an <li> item for an individual template
109
	 *
110
	 * @param LinkTarget $target
111
	 * @return string
112
	 */
113
	private function formatTemplate( LinkTarget $target ) {
114
		// TODO Would be nice if we didn't have to use Title here
115
		$titleObj = Title::newFromLinkTarget( $target );
116
		$protected = $this->getRestrictionsText( $titleObj->getRestrictions( 'edit' ) );
117
		$editLink = $this->buildEditLink( $titleObj );
118
		return '<li>' . $this->linkRenderer->makeLink( $target )
119
			. $this->context->msg( 'word-separator' )->escaped()
120
			. $this->context->msg( 'parentheses' )->rawParams( $editLink )->escaped()
121
			. $this->context->msg( 'word-separator' )->escaped()
122
			. $protected . '</li>';
123
	}
124
125
	/**
126
	 * If the page is protected, get the relevant text
127
	 * for those restrictions
128
	 *
129
	 * @param array $restrictions
130
	 * @return string
131
	 */
132
	private function getRestrictionsText( array $restrictions ) {
133
		$protected = '';
134
		if ( !$restrictions ) {
135
			return $protected;
136
		}
137
138
		// Check backwards-compatible messages
139
		$msg = null;
140
		if ( $restrictions === [ 'sysop' ] ) {
141
			$msg = $this->context->msg( 'template-protected' );
142
		} elseif ( $restrictions === [ 'autoconfirmed' ] ) {
143
			$msg = $this->context->msg( 'template-semiprotected' );
144
		}
145
		if ( $msg && !$msg->isDisabled() ) {
146
			$protected = $msg->parse();
147
		} else {
148
			// Construct the message from restriction-level-*
149
			// e.g. restriction-level-sysop, restriction-level-autoconfirmed
150
			$msgs = [];
151
			foreach ( $restrictions as $r ) {
152
				$msgs[] = $this->context->msg( "restriction-level-$r" )->parse();
153
			}
154
			$protected = $this->context->msg( 'parentheses' )
155
				->rawParams( $this->context->getLanguage()->commaList( $msgs ) )->escaped();
156
		}
157
158
		return $protected;
159
	}
160
161
	/**
162
	 * Return a link to the edit page, with the text
163
	 * saying "view source" if the user can't edit the page
164
	 *
165
	 * @param Title $titleObj
166
	 * @return string
167
	 */
168
	private function buildEditLink( Title $titleObj ) {
169
		if ( $titleObj->quickUserCan( 'edit', $this->context->getUser() ) ) {
170
			$linkMsg = 'editlink';
171
		} else {
172
			$linkMsg = 'viewsourcelink';
173
		}
174
175
		return $this->linkRenderer->makeLink(
176
			$titleObj,
177
			$this->context->msg( $linkMsg )->text(),
178
			[],
179
			[ 'action' => 'edit' ]
180
		);
181
	}
182
183
}
184