]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - includes/SpecialWhatlinkshere.php
MediaWiki 1.11.0-scripts
[autoinstallsdev/mediawiki.git] / includes / SpecialWhatlinkshere.php
1 <?php
2 /**
3  *
4  * @addtogroup SpecialPage
5  */
6
7 /**
8  * Entry point
9  * @param string $par An article name ??
10  */
11 function wfSpecialWhatlinkshere($par = NULL) {
12         global $wgRequest;
13         $page = new WhatLinksHerePage( $wgRequest, $par );
14         $page->execute();
15 }
16
17 /**
18  * implements Special:Whatlinkshere
19  * @addtogroup SpecialPage
20  */
21 class WhatLinksHerePage {
22         var $request, $par;
23         var $limit, $from, $back, $target;
24         var $selfTitle, $skin;
25
26         private $namespace;
27
28         function WhatLinksHerePage( &$request, $par = null ) {
29                 global $wgUser;
30                 $this->request =& $request;
31                 $this->skin = $wgUser->getSkin();
32                 $this->par = $par;
33         }
34
35         function execute() {
36                 global $wgOut;
37
38                 $this->limit = min( $this->request->getInt( 'limit', 50 ), 5000 );
39                 if ( $this->limit <= 0 ) {
40                         $this->limit = 50;
41                 }
42                 $this->from = $this->request->getInt( 'from' );
43                 $this->back = $this->request->getInt( 'back' );
44
45                 $targetString = isset($this->par) ? $this->par : $this->request->getVal( 'target' );
46
47                 if (is_null($targetString)) {
48                         $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
49                         return;
50                 }
51
52                 $this->target = Title::newFromURL( $targetString );
53                 if( !$this->target ) {
54                         $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
55                         return;
56                 }
57                 $this->selfTitle = Title::makeTitleSafe( NS_SPECIAL,
58                         'Whatlinkshere/' . $this->target->getPrefixedDBkey() );
59                         
60                 $wgOut->setPageTitle( wfMsg( 'whatlinkshere-title', $this->target->getPrefixedText() ) );
61                 $wgOut->setSubtitle( wfMsg( 'linklistsub' ) );
62
63                 $wgOut->addHTML( wfMsg( 'whatlinkshere-barrow' ) . ' '  .$this->skin->makeLinkObj($this->target, '', 'redirect=no' )."<br />\n");
64
65                 $this->showIndirectLinks( 0, $this->target, $this->limit, $this->from, $this->back );
66         }
67
68         /**
69          * @param int       $level      Recursion level
70          * @param Title     $target     Target title
71          * @param int       $limit      Number of entries to display
72          * @param Title     $from       Display from this article ID
73          * @param Title     $back       Display from this article ID at backwards scrolling
74          * @private
75          */
76         function showIndirectLinks( $level, $target, $limit, $from = 0, $back = 0 ) {
77                 global $wgOut;
78                 $fname = 'WhatLinksHerePage::showIndirectLinks';
79                 $dbr = wfGetDB( DB_READ );
80                 $options = array();
81
82                 $ns = $this->request->getIntOrNull( 'namespace' );
83                 if ( isset( $ns ) ) {
84                         $options['namespace'] = $ns;
85                         $this->setNamespace( $options['namespace'] );
86                 } else {
87                         $options['namespace'] = '';
88                 }
89
90                 // Make the query
91                 $plConds = array(
92                         'page_id=pl_from',
93                         'pl_namespace' => $target->getNamespace(),
94                         'pl_title' => $target->getDBkey(),
95                 );
96
97                 $tlConds = array(
98                         'page_id=tl_from',
99                         'tl_namespace' => $target->getNamespace(),
100                         'tl_title' => $target->getDBkey(),
101                 );
102
103                 if ( $this->namespace !== null ){
104                         $plConds['page_namespace'] = (int)$this->namespace;
105                         $tlConds['page_namespace'] = (int)$this->namespace;
106                 }
107
108                 if ( $from ) {
109                         $from = (int)$from; // just in case
110                         $tlConds[] = "tl_from >= $from";
111                         $plConds[] = "pl_from >= $from";
112                 } 
113
114                 // Read an extra row as an at-end check
115                 $queryLimit = $limit + 1;
116                 
117                 // enforce join order, sometimes namespace selector may 
118                 // trigger filesorts which are far less efficient than scanning many entries
119                 $options[] = 'STRAIGHT_JOIN';
120                 
121                 $options['LIMIT'] = $queryLimit;
122                 $fields = array( 'page_id', 'page_namespace', 'page_title', 'page_is_redirect' );
123
124                 $options['ORDER BY'] = 'pl_from';
125                 $plRes = $dbr->select( array( 'pagelinks', 'page' ), $fields,
126                         $plConds, $fname, $options );
127                         
128                 $options['ORDER BY'] = 'tl_from';
129                 $tlRes = $dbr->select( array( 'templatelinks', 'page' ), $fields,
130                         $tlConds, $fname, $options );
131                 
132                 if ( !$dbr->numRows( $plRes ) && !$dbr->numRows( $tlRes ) ) {
133                         if ( 0 == $level && !isset( $this->namespace ) ) {
134                                 // really no links to here
135                                 $wgOut->addWikiText( wfMsg( 'nolinkshere', $this->target->getPrefixedText() ) );
136                         } elseif ( 0 == $level && isset( $this->namespace ) ) {
137                                 // no links from requested namespace to here
138                                 $options = array(); // reinitialize for a further namespace search
139                                 $options['namespace'] = $this->namespace;
140                                 $options['target'] = $this->target->getPrefixedText();
141                                 list( $options['limit'], $options['offset']) = wfCheckLimits();
142                                 $wgOut->addHTML( $this->whatlinkshereForm( $options ) );
143                                 $wgOut->addWikiText( wfMsg( 'nolinkshere-ns', $this->target->getPrefixedText() ) );
144                         }
145                         return;
146                 }
147
148                 $options = array();
149                 list( $options['limit'], $options['offset']) = wfCheckLimits();
150                 if ( ( $ns = $this->request->getVal( 'namespace', null ) ) !== null && $ns !== '' && ctype_digit($ns) ) {
151                         $options['namespace'] = intval( $ns );
152                         $this->setNamespace( $options['namespace'] );
153                 } else {
154                         $options['namespace'] = '';
155                         $this->setNamespace( null );
156                 }
157                 $options['offset'] = $this->request->getVal( 'offset' );
158                 /* Offset must be an integral. */
159                 if ( !strlen( $options['offset'] ) || !preg_match( '/^[0-9]+$/', $options['offset'] ) )
160                 $options['offset'] = '';
161                 $options['target'] = $this->target->getPrefixedDBkey();
162
163                 // Read the rows into an array and remove duplicates
164                 // templatelinks comes second so that the templatelinks row overwrites the
165                 // pagelinks row, so we get (inclusion) rather than nothing
166                 while ( $row = $dbr->fetchObject( $plRes ) ) {
167                         $row->is_template = 0;
168                         $rows[$row->page_id] = $row;
169                 }
170                 $dbr->freeResult( $plRes );
171                 while ( $row = $dbr->fetchObject( $tlRes ) ) {
172                         $row->is_template = 1;
173                         $rows[$row->page_id] = $row;
174                 }
175                 $dbr->freeResult( $tlRes );
176
177                 // Sort by key and then change the keys to 0-based indices
178                 ksort( $rows );
179                 $rows = array_values( $rows );
180
181                 $numRows = count( $rows );
182
183                 // Work out the start and end IDs, for prev/next links
184                 if ( $numRows > $limit ) {
185                         // More rows available after these ones
186                         // Get the ID from the last row in the result set
187                         $nextId = $rows[$limit]->page_id;
188                         // Remove undisplayed rows
189                         $rows = array_slice( $rows, 0, $limit );
190                 } else {
191                         // No more rows after
192                         $nextId = false;
193                 }
194                 $prevId = $from;
195
196                 if ( $level == 0 ) {
197                         $wgOut->addHTML( $this->whatlinkshereForm( $options ) );
198                         $wgOut->addWikiText( wfMsg( 'linkshere', $this->target->getPrefixedText() ) );
199                 }
200                 $isredir = wfMsg( 'isredirect' );
201                 $istemplate = wfMsg( 'istemplate' );
202
203                 if( $level == 0 ) {
204                         $prevnext = $this->getPrevNext( $limit, $prevId, $nextId, $options['namespace'] );
205                         $wgOut->addHTML( $prevnext );
206                 }
207
208                 $wgOut->addHTML( '<ul>' );
209                 foreach ( $rows as $row ) {
210                         $nt = Title::makeTitle( $row->page_namespace, $row->page_title );
211
212                         if ( $row->page_is_redirect ) {
213                                 $extra = 'redirect=no';
214                         } else {
215                                 $extra = '';
216                         }
217
218                         $link = $this->skin->makeKnownLinkObj( $nt, '', $extra );
219                         $wgOut->addHTML( '<li>'.$link );
220
221                         // Display properties (redirect or template)
222                         $props = array();
223                         if ( $row->page_is_redirect ) {
224                                 $props[] = $isredir;
225                         }
226                         if ( $row->is_template ) {
227                                 $props[] = $istemplate;
228                         }
229                         if ( count( $props ) ) {
230                                 // FIXME? Cultural assumption, hard-coded punctuation
231                                 $wgOut->addHTML( ' (' . implode( ', ', $props ) . ') ' );
232                         }
233
234                         # Space for utilities links, with a what-links-here link provided
235                         $wlh = $this->skin->makeKnownLinkObj(
236                                 SpecialPage::getTitleFor( 'Whatlinkshere' ),
237                                 wfMsgHtml( 'whatlinkshere-links' ),
238                                 'target=' . $nt->getPrefixedUrl()
239                         );
240                         $wgOut->addHtml( ' <span class="mw-whatlinkshere-tools">(' . $wlh . ')</span>' );                       
241                         
242                         if ( $row->page_is_redirect ) {
243                                 if ( $level < 2 ) {
244                                         $this->showIndirectLinks( $level + 1, $nt, 500 );
245                                 }
246                         }
247                         $wgOut->addHTML( "</li>\n" );
248                 }
249                 $wgOut->addHTML( "</ul>\n" );
250
251                 if( $level == 0 ) {
252                         $wgOut->addHTML( $prevnext );
253                 }
254         }
255
256         function makeSelfLink( $text, $query ) {
257                 return $this->skin->makeKnownLinkObj( $this->selfTitle, $text, $query );
258         }
259
260         function getPrevNext( $limit, $prevId, $nextId ) {
261                 global $wgLang;
262                 $fmtLimit = $wgLang->formatNum( $limit );
263                 $prev = wfMsgExt( 'whatlinkshere-prev', array( 'parsemag', 'escape' ), $fmtLimit );
264                 $next = wfMsgExt( 'whatlinkshere-next', array( 'parsemag', 'escape' ), $fmtLimit );
265
266                 $nsText = '';
267                 if( is_int($this->namespace) ) {
268                         $nsText = "&namespace={$this->namespace}";
269                 }
270
271                 if ( 0 != $prevId ) {
272                         $prevLink = $this->makeSelfLink( $prev, "limit={$limit}&from={$this->back}{$nsText}" );
273                 } else {
274                         $prevLink = $prev;
275                 }
276                 if ( 0 != $nextId ) {
277                         $nextLink = $this->makeSelfLink( $next, "limit={$limit}&from={$nextId}&back={$prevId}{$nsText}" );
278                 } else {
279                         $nextLink = $next;
280                 }
281                 $nums = $this->numLink( 20, $prevId ) . ' | ' .
282                   $this->numLink( 50, $prevId ) . ' | ' .
283                   $this->numLink( 100, $prevId ) . ' | ' .
284                   $this->numLink( 250, $prevId ) . ' | ' .
285                   $this->numLink( 500, $prevId );
286
287                 return wfMsg( 'viewprevnext', $prevLink, $nextLink, $nums );
288         }
289
290         function numLink( $limit, $from, $ns = null ) {
291                 global $wgLang;
292                 $query = "limit={$limit}&from={$from}";
293                 if( is_int($this->namespace) ) { $query .= "&namespace={$this->namespace}";}
294                 $fmtLimit = $wgLang->formatNum( $limit );
295                 return $this->makeSelfLink( $fmtLimit, $query );
296         }
297
298         function whatlinkshereForm( $options ) {
299                 global $wgScript, $wgTitle;
300
301                 $options['title'] = $wgTitle->getPrefixedText();
302
303                 $f = Xml::openElement( 'form', array( 'method' => 'get', 'action' => "$wgScript" ) ) .
304                         '<fieldset>' .
305                         Xml::element( 'legend', array(), wfMsg( 'whatlinkshere' ) );
306
307                 foreach ( $options as $name => $value ) {
308                         if( $name === 'namespace') continue;
309                         $f .= "\t" . Xml::hidden( $name, $value ). "\n";
310                 }
311
312                 $f .= Xml::label( wfMsg( 'namespace' ), 'namespace' ) . ' ' .
313                         Xml::namespaceSelector( $options['namespace'], '' ) .
314                         Xml::submitButton( wfMsg( 'allpagessubmit' ) ) .
315                         '</fieldset>' .
316                         Xml::closeElement( 'form' ) . "\n";
317
318                 return $f;
319         }
320
321         /** Set the namespace we are filtering on */
322         private function setNamespace( $ns ) {
323                 $this->namespace = $ns;
324         }
325
326 }
327
328