Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
TemplatesOnThisPageFormatter
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 5
342
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 format
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
56
 formatTemplate
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 getRestrictionsText
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
56
 buildEditLink
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
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
21namespace MediaWiki\EditPage;
22
23use MediaWiki\Cache\LinkBatchFactory;
24use MediaWiki\Context\IContextSource;
25use MediaWiki\Html\Html;
26use MediaWiki\Linker\LinkRenderer;
27use MediaWiki\Page\PageIdentity;
28use MediaWiki\Page\PageReference;
29use MediaWiki\Permissions\RestrictionStore;
30use MediaWiki\Title\Title;
31
32/**
33 * Handles formatting for the "templates used on this page"
34 * lists. Formerly known as Linker::formatTemplates()
35 *
36 * @since 1.28
37 */
38class TemplatesOnThisPageFormatter {
39
40    /**
41     * @var IContextSource
42     */
43    private $context;
44
45    /**
46     * @var LinkRenderer
47     */
48    private $linkRenderer;
49
50    /**
51     * @var LinkBatchFactory
52     */
53    private $linkBatchFactory;
54
55    /**
56     * @var RestrictionStore
57     */
58    private $restrictionStore;
59
60    /**
61     * @param IContextSource $context
62     * @param LinkRenderer $linkRenderer
63     * @param LinkBatchFactory $linkBatchFactory
64     * @param RestrictionStore $restrictionStore
65     */
66    public function __construct(
67        IContextSource $context,
68        LinkRenderer $linkRenderer,
69        LinkBatchFactory $linkBatchFactory,
70        RestrictionStore $restrictionStore
71    ) {
72        $this->context = $context;
73        $this->linkRenderer = $linkRenderer;
74        $this->linkBatchFactory = $linkBatchFactory;
75        $this->restrictionStore = $restrictionStore;
76    }
77
78    /**
79     * Make an HTML list of templates, and then add a "More..." link at
80     * the bottom. If $more is null, do not add a "More..." link. If $more
81     * is a PageReference, make a link to that page and use it. If $more is a string,
82     * directly paste it in as the link (escaping needs to be done manually).
83     *
84     * @param PageIdentity[] $templates
85     * @param string|false $type 'preview' if a preview, 'section' if a section edit, false if neither
86     * @param PageReference|string|null $more An escaped link for "More..." of the templates
87     * @return string HTML output
88     */
89    public function format( array $templates, $type = false, $more = null ) {
90        if ( !$templates ) {
91            // No templates
92            return '';
93        }
94
95        # Do a batch existence check
96        $batch = $this->linkBatchFactory->newLinkBatch( $templates );
97        $batch->setCaller( __METHOD__ );
98        $batch->execute();
99
100        # Construct the HTML
101        $outText = Html::openElement( 'div', [ 'class' => 'mw-templatesUsedExplanation' ] );
102        $count = count( $templates );
103        if ( $type === 'preview' ) {
104            $outText .= $this->context->msg( 'templatesusedpreview' )->numParams( $count )
105                ->parseAsBlock();
106        } elseif ( $type === 'section' ) {
107            $outText .= $this->context->msg( 'templatesusedsection' )->numParams( $count )
108                ->parseAsBlock();
109        } else {
110            $outText .= $this->context->msg( 'templatesused' )->numParams( $count )
111                ->parseAsBlock();
112        }
113        $outText .= Html::closeElement( 'div' ) . Html::openElement( 'ul' ) . "\n";
114
115        usort( $templates, [ Title::class, 'compare' ] );
116        foreach ( $templates as $template ) {
117            $outText .= $this->formatTemplate( $template );
118        }
119
120        if ( $more instanceof PageReference ) {
121            $outText .= Html::rawElement( 'li', [],
122                $this->linkRenderer->makeLink(
123                    $more,
124                    $this->context->msg( 'moredotdotdot' )->text()
125                )
126            );
127        } elseif ( $more ) {
128            // Documented as should already be escaped
129            $outText .= Html::rawElement( 'li', [], $more );
130        }
131
132        $outText .= Html::closeElement( 'ul' );
133        return $outText;
134    }
135
136    /**
137     * Builds a list item for an individual template
138     *
139     * The output of this is repeated for live-preview in resources/src/mediawiki.page.preview.js
140     *
141     * @param PageIdentity $target
142     * @return string
143     */
144    private function formatTemplate( PageIdentity $target ) {
145        $protected = $this->getRestrictionsText(
146            $this->restrictionStore->getRestrictions( $target, 'edit' )
147        );
148        $editLink = $this->buildEditLink( $target );
149        return Html::rawElement( 'li', [], $this->linkRenderer->makeLink( $target )
150            . $this->context->msg( 'word-separator' )->escaped()
151            . $this->context->msg( 'parentheses' )->rawParams( $editLink )->escaped()
152            . $this->context->msg( 'word-separator' )->escaped()
153            . $protected
154        );
155    }
156
157    /**
158     * If the page is protected, get the relevant text
159     * for those restrictions
160     *
161     * @param array $restrictions
162     * @return string HTML
163     */
164    private function getRestrictionsText( array $restrictions ) {
165        $protected = '';
166        if ( !$restrictions ) {
167            return $protected;
168        }
169
170        // Check backwards-compatible messages
171        $msg = null;
172        if ( $restrictions === [ 'sysop' ] ) {
173            $msg = $this->context->msg( 'template-protected' );
174        } elseif ( $restrictions === [ 'autoconfirmed' ] ) {
175            $msg = $this->context->msg( 'template-semiprotected' );
176        }
177        if ( $msg && !$msg->isDisabled() ) {
178            $protected = $msg->parse();
179        } else {
180            // Construct the message from restriction-level-*
181            // e.g. restriction-level-sysop, restriction-level-autoconfirmed
182            $msgs = [];
183            foreach ( $restrictions as $r ) {
184                $msgs[] = $this->context->msg( "restriction-level-$r" )->parse();
185            }
186            $protected = $this->context->msg( 'parentheses' )
187                ->rawParams( $this->context->getLanguage()->commaList( $msgs ) )->escaped();
188        }
189
190        return $protected;
191    }
192
193    /**
194     * Return a link to the edit page, with the text
195     * saying "view source" if the user can't edit the page
196     *
197     * @param PageIdentity $page
198     * @return string HTML
199     */
200    private function buildEditLink( PageIdentity $page ) {
201        if ( $this->context->getAuthority()->probablyCan( 'edit', $page ) ) {
202            $linkMsg = 'editlink';
203        } else {
204            $linkMsg = 'viewsourcelink';
205        }
206
207        return $this->linkRenderer->makeLink(
208            $page,
209            $this->context->msg( $linkMsg )->text(),
210            [],
211            [ 'action' => 'edit' ]
212        );
213    }
214
215}
216
217/** @deprecated class alias since 1.40 */
218class_alias( TemplatesOnThisPageFormatter::class, 'TemplatesOnThisPageFormatter' );