8 * Entry point : initialise variables and call subfunctions.
9 * @param $par String: becomes "FOO" when called like Special:Allpages/FOO (default NULL)
10 * @param $specialPage See the SpecialPage object.
12 function wfSpecialAllpages( $par=NULL, $specialPage ) {
13 global $wgRequest, $wgOut, $wgContLang;
16 $from = $wgRequest->getVal( 'from', '' );
17 $to = $wgRequest->getVal( 'to', '' );
18 $namespace = $wgRequest->getInt( 'namespace' );
20 $namespaces = $wgContLang->getNamespaces();
22 $indexPage = new SpecialAllpages();
24 $wgOut->setPagetitle( ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces) ) ) ?
25 wfMsg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) ) :
26 wfMsg( 'allarticles' )
29 $indexPage->showToplevel( $namespace, $from, $to, $specialPage->including() );
33 * Implements Special:Allpages
34 * @ingroup SpecialPage
36 class SpecialAllpages
{
38 * Maximum number of pages to show on single list subpage.
40 protected $maxPerPage = 345;
43 * Maximum number of pages to show on single index subpage.
45 protected $maxLineCount = 200;
48 * Name of this special page. Used to make title objects that reference back
51 protected $name = 'Allpages';
54 * HTML for the top form
55 * @param integer $namespace A namespace constant (default NS_MAIN).
56 * @param string $from dbKey we are starting listing at.
57 * @param string $to dbKey we are ending listing at.
59 function namespaceForm( $namespace = NS_MAIN
, $from = '', $to = '' ) {
61 $t = SpecialPage
::getTitleFor( $this->name
);
63 $out = Xml
::openElement( 'div', array( 'class' => 'namespaceoptions' ) );
64 $out .= Xml
::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
65 $out .= Xml
::hidden( 'title', $t->getPrefixedText() );
66 $out .= Xml
::openElement( 'fieldset' );
67 $out .= Xml
::element( 'legend', null, wfMsg( 'allpages' ) );
68 $out .= Xml
::openElement( 'table', array( 'id' => 'nsselect', 'class' => 'allpages' ) );
70 <td class='mw-label'>" .
71 Xml
::label( wfMsg( 'allpagesfrom' ), 'nsfrom' ) .
73 <td class='mw-input'>" .
74 Xml
::input( 'from', 30, str_replace('_',' ',$from), array( 'id' => 'nsfrom' ) ) .
78 <td class='mw-label'>" .
79 Xml
::label( wfMsg( 'allpagesto' ), 'nsto' ) .
81 <td class='mw-input'>" .
82 Xml
::input( 'to', 30, str_replace('_',' ',$to), array( 'id' => 'nsto' ) ) .
86 <td class='mw-label'>" .
87 Xml
::label( wfMsg( 'namespace' ), 'namespace' ) .
89 <td class='mw-input'>" .
90 Xml
::namespaceSelector( $namespace, null ) . ' ' .
91 Xml
::submitButton( wfMsg( 'allpagessubmit' ) ) .
94 $out .= Xml
::closeElement( 'table' );
95 $out .= Xml
::closeElement( 'fieldset' );
96 $out .= Xml
::closeElement( 'form' );
97 $out .= Xml
::closeElement( 'div' );
102 * @param integer $namespace (default NS_MAIN)
104 function showToplevel( $namespace = NS_MAIN
, $from = '', $to = '', $including = false ) {
105 global $wgOut, $wgContLang;
106 $align = $wgContLang->isRtl() ?
'left' : 'right';
108 # TODO: Either make this *much* faster or cache the title index points
109 # in the querycache table.
111 $dbr = wfGetDB( DB_SLAVE
);
113 $where = array( 'page_namespace' => $namespace );
115 $from = Title
::makeTitleSafe( $namespace, $from );
116 $to = Title
::makeTitleSafe( $namespace, $to );
117 $from = ( $from && $from->isLocal() ) ?
$from->getDBKey() : null;
118 $to = ( $to && $to->isLocal() ) ?
$to->getDBKey() : null;
121 $where[] = 'page_title >= '.$dbr->addQuotes( $from );
123 $where[] = 'page_title <= '.$dbr->addQuotes( $to );
126 $key = wfMemcKey( 'allpages', 'ns', $namespace, $from, $to );
127 $lines = $wgMemc->get( $key );
129 $count = $dbr->estimateRowCount( 'page', '*', $where, __METHOD__
);
130 $maxPerSubpage = intval($count/$this->maxLineCount
);
131 $maxPerSubpage = max($maxPerSubpage,$this->maxPerPage
);
133 if( !is_array( $lines ) ) {
134 $options = array( 'LIMIT' => 1 );
135 $options['ORDER BY'] = 'page_title ASC';
136 $firstTitle = $dbr->selectField( 'page', 'page_title', $where, __METHOD__
, $options );
137 $lastTitle = $firstTitle;
138 # This array is going to hold the page_titles in order.
139 $lines = array( $firstTitle );
140 # If we are going to show n rows, we need n+1 queries to find the relevant titles.
143 // Fetch the last title of this chunk and the first of the next
144 $chunk = is_null( $lastTitle )
146 : 'page_title >= ' . $dbr->addQuotes( $lastTitle );
147 $chunk = array($chunk);
148 $res = $dbr->select( 'page', /* FROM */
149 'page_title', /* WHAT */
150 array_merge($where,$chunk),
152 array ('LIMIT' => 2, 'OFFSET' => $maxPerSubpage - 1, 'ORDER BY' => 'page_title ASC')
155 if( $s = $dbr->fetchObject( $res ) ) {
156 array_push( $lines, $s->page_title
);
158 // Final chunk, but ended prematurely. Go back and find the end.
159 $endTitle = $dbr->selectField( 'page', 'MAX(page_title)',
160 array_merge($where,$chunk),
162 array_push( $lines, $endTitle );
165 if( $s = $dbr->fetchObject( $res ) ) {
166 array_push( $lines, $s->page_title
);
167 $lastTitle = $s->page_title
;
169 // This was a final chunk and ended exactly at the limit.
170 // Rare but convenient!
173 $dbr->freeResult( $res );
175 $wgMemc->add( $key, $lines, 3600 );
178 // If there are only two or less sections, don't even display them.
179 // Instead, display the first section directly.
180 if( count( $lines ) <= 2 ) {
181 $this->showChunk( $namespace, $from, $to, $including );
185 # At this point, $lines should contain an even number of elements.
186 $out .= "<table class='allpageslist' style='background: inherit;'>";
187 while( count ( $lines ) > 0 ) {
188 $inpoint = array_shift( $lines );
189 $outpoint = array_shift( $lines );
190 $out .= $this->showline( $inpoint, $outpoint, $namespace );
193 $nsForm = $this->namespaceForm( $namespace, $from, $to );
199 if( isset($from) ||
isset($to) ) {
201 $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
202 $out2 .= '<tr valign="top"><td>' . $nsForm;
203 $out2 .= '</td><td align="' . $align . '" style="font-size: smaller; margin-bottom: 1em;">' .
204 $wgUser->getSkin()->makeKnownLink( $wgContLang->specialPage( "Allpages" ), wfMsgHtml ( 'allpages' ) );
205 $out2 .= "</td></tr></table><hr />";
207 $out2 = $nsForm . '<hr />';
210 $wgOut->addHtml( $out2 . $out );
215 * @param string $from
216 * @param integer $namespace (Default NS_MAIN)
218 function showline( $inpoint, $outpoint, $namespace = NS_MAIN
) {
220 $align = $wgContLang->isRtl() ?
'left' : 'right';
221 $inpointf = htmlspecialchars( str_replace( '_', ' ', $inpoint ) );
222 $outpointf = htmlspecialchars( str_replace( '_', ' ', $outpoint ) );
223 $queryparams = $namespace ?
"namespace=$namespace&" : '';
224 $special = SpecialPage
::getTitleFor( $this->name
);
225 $link = $special->escapeLocalUrl( $queryparams . 'from=' . urlencode($inpoint) . '&to=' . urlencode($outpoint) );
229 "<a href=\"$link\">$inpointf</a></td><td>",
230 "</td><td><a href=\"$link\">$outpointf</a>"
232 return '<tr><td align="' . $align . '">'.$out.'</td></tr>';
236 * @param integer $namespace (Default NS_MAIN)
237 * @param string $from list all pages from this name (default FALSE)
239 function showChunk( $namespace = NS_MAIN
, $from, $to, $including = false ) {
240 global $wgOut, $wgUser, $wgContLang;
242 $sk = $wgUser->getSkin();
244 $fromList = $this->getNamespaceKeyAndText( $namespace, $from );
245 $toList = $this->getNamespaceKeyAndText( $namespace, $to );
247 $namespaces = $wgContLang->getNamespaces();
248 $align = $wgContLang->isRtl() ?
'left' : 'right';
252 if ( !$fromList ||
!$toList ) {
253 $out = wfMsgWikiHtml( 'allpagesbadtitle' );
254 } elseif ( !in_array( $namespace, array_keys( $namespaces ) ) ) {
255 // Show errormessage and reset to NS_MAIN
256 $out = wfMsgExt( 'allpages-bad-ns', array( 'parseinline' ), $namespace );
257 $namespace = NS_MAIN
;
259 list( $namespace, $fromKey, $from ) = $fromList;
260 list( $namespace, $toKey, $to ) = $toList;
262 $dbr = wfGetDB( DB_SLAVE
);
263 $res = $dbr->select( 'page',
264 array( 'page_namespace', 'page_title', 'page_is_redirect' ),
266 'page_namespace' => $namespace,
267 'page_title >= ' . $dbr->addQuotes( $fromKey ),
268 'page_title <= ' . $dbr->addQuotes( $toKey ),
272 'ORDER BY' => 'page_title ASC',
273 'LIMIT' => $this->maxPerPage +
1,
274 'USE INDEX' => 'name_title',
278 if( $res->numRows() > 0 ) {
279 $out = '<table style="background: inherit;" border="0" width="100%">';
281 while( ($n < $this->maxPerPage
) && ($s = $dbr->fetchObject( $res )) ) {
282 $t = Title
::makeTitle( $s->page_namespace
, $s->page_title
);
284 $link = ($s->page_is_redirect ?
'<div class="allpagesredirect">' : '' ) .
285 $sk->makeKnownLinkObj( $t, htmlspecialchars( $t->getText() ), false, false ) .
286 ($s->page_is_redirect ?
'</div>' : '' );
288 $link = '[[' . htmlspecialchars( $s->page_title
) . ']]';
293 $out .= "<td width=\"33%\">$link</td>";
299 if( ($n %
3) != 0 ) {
311 $nsForm = $this->namespaceForm( $namespace, $from, $to );
312 $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
313 $out2 .= '<tr valign="top"><td>' . $nsForm;
314 $out2 .= '</td><td align="' . $align . '" style="font-size: smaller; margin-bottom: 1em;">' .
315 $sk->makeKnownLink( $wgContLang->specialPage( "Allpages" ), wfMsgHtml ( 'allpages' ) );
316 $out2 .= "</td></tr></table><hr />";
319 $wgOut->addHtml( $out2 . $out );
323 * @param int $ns the namespace of the article
324 * @param string $text the name of the article
325 * @return array( int namespace, string dbkey, string pagename ) or NULL on error
329 function getNamespaceKeyAndText( $ns, $text ) {
331 return array( $ns, '', '' ); # shortcut for common case
333 $t = Title
::makeTitleSafe($ns, $text);
334 if ( $t && $t->isLocal() ) {
335 return array( $t->getNamespace(), $t->getDBkey(), $t->getText() );
340 # try again, in case the problem was an empty pagename
341 $text = preg_replace('/(#|$)/', 'X$1', $text);
342 $t = Title
::makeTitleSafe($ns, $text);
343 if ( $t && $t->isLocal() ) {
344 return array( $t->getNamespace(), '', '' );