MediaWiki REL1_40
SpecialRandomPage.php
Go to the documentation of this file.
1<?php
28
35 private $namespaces; // namespaces to select pages from
36 protected $isRedir = false; // should the result be a redirect?
37 protected $extra = []; // Extra SQL statements
38
40 private $loadBalancer;
41
46 public function __construct(
47 $loadBalancer = null,
48 NamespaceInfo $nsInfo = null
49 ) {
50 parent::__construct( is_string( $loadBalancer ) ? $loadBalancer : 'Randompage' );
51 // This class is extended and therefor fallback to global state - T265308
52 $services = MediaWikiServices::getInstance();
53 $this->loadBalancer = $loadBalancer instanceof ILoadBalancer
54 ? $loadBalancer
55 : $services->getDBLoadBalancer();
56 $nsInfo ??= $services->getNamespaceInfo();
57 $this->namespaces = $nsInfo->getContentNamespaces();
58 }
59
60 public function getNamespaces() {
61 return $this->namespaces;
62 }
63
64 public function setNamespace( $ns ) {
65 if ( !$ns || $ns < NS_MAIN ) {
66 $ns = NS_MAIN;
67 }
68 $this->namespaces = [ $ns ];
69 }
70
71 // select redirects instead of normal pages?
72 public function isRedirect() {
73 return $this->isRedir;
74 }
75
76 public function execute( $par ) {
77 if ( is_string( $par ) ) {
78 // Testing for stringiness since we want to catch
79 // the empty string to mean main namespace only.
80 $this->setNamespace( $this->getContentLanguage()->getNsIndex( $par ) );
81 }
82
83 $title = $this->getRandomTitle();
84
85 if ( $title === null ) {
86 $this->setHeaders();
87 // Message: randompage-nopages, randomredirect-nopages
88 $this->getOutput()->addWikiMsg( strtolower( $this->getName() ) . '-nopages',
89 $this->getNsList(), count( $this->namespaces ) );
90
91 return;
92 }
93
94 $redirectParam = $this->isRedirect() ? [ 'redirect' => 'no' ] : [];
95 $query = array_merge( $this->getRequest()->getValues(), $redirectParam );
96 unset( $query['title'] );
97 $this->getOutput()->redirect( $title->getFullURL( $query ) );
98 }
99
105 private function getNsList() {
106 $contLang = $this->getContentLanguage();
107 $nsNames = [];
108 foreach ( $this->namespaces as $n ) {
109 if ( $n === NS_MAIN ) {
110 $nsNames[] = $this->msg( 'blanknamespace' )->plain();
111 } else {
112 $nsNames[] = $contLang->getNsText( $n );
113 }
114 }
115
116 return $contLang->commaList( $nsNames );
117 }
118
123 public function getRandomTitle() {
124 $randstr = wfRandom();
125 $title = null;
126
127 if ( !$this->getHookRunner()->onSpecialRandomGetRandomTitle(
128 $randstr, $this->isRedir, $this->namespaces,
129 // @phan-suppress-next-line PhanTypeMismatchArgument Type mismatch on pass-by-ref args
130 $this->extra, $title )
131 ) {
132 return $title;
133 }
134
135 $row = $this->selectRandomPageFromDB( $randstr, __METHOD__ );
136
137 /* If we picked a value that was higher than any in
138 * the DB, wrap around and select the page with the
139 * lowest value instead! One might think this would
140 * skew the distribution, but in fact it won't cause
141 * any more bias than what the page_random scheme
142 * causes anyway. Trust me, I'm a mathematician. :)
143 */
144 if ( !$row ) {
145 $row = $this->selectRandomPageFromDB( "0", __METHOD__ );
146 }
147
148 if ( $row ) {
149 return Title::makeTitleSafe( $row->page_namespace, $row->page_title );
150 }
151
152 return null;
153 }
154
155 protected function getQueryInfo( $randstr ) {
156 $redirect = $this->isRedirect() ? 1 : 0;
157 $tables = [ 'page' ];
158 $conds = array_merge( [
159 'page_namespace' => $this->namespaces,
160 'page_is_redirect' => $redirect,
161 'page_random >= ' . $randstr
162 ], $this->extra );
163 $joinConds = [];
164
165 // Allow extensions to modify the query
166 $this->getHookRunner()->onRandomPageQuery( $tables, $conds, $joinConds );
167
168 return [
169 'tables' => $tables,
170 'fields' => [ 'page_title', 'page_namespace' ],
171 'conds' => $conds,
172 'options' => [
173 'ORDER BY' => 'page_random',
174 'LIMIT' => 1,
175 ],
176 'join_conds' => $joinConds
177 ];
178 }
179
180 private function selectRandomPageFromDB( $randstr, $fname = __METHOD__ ) {
181 $dbr = $this->loadBalancer->getConnectionRef( ILoadBalancer::DB_REPLICA );
182
183 $query = $this->getQueryInfo( $randstr );
184 $res = $dbr->select(
185 $query['tables'],
186 $query['fields'],
187 $query['conds'],
188 $fname,
189 $query['options'],
190 $query['join_conds']
191 );
192
193 return $res->fetchObject();
194 }
195
196 protected function getGroupName() {
197 return 'redirects';
198 }
199}
200
205class_alias( SpecialRandomPage::class, 'RandomPage' );
const NS_MAIN
Definition Defines.php:64
wfRandom()
Get a random decimal value in the domain of [0, 1), in a way not likely to give duplicate values for ...
Service locator for MediaWiki core services.
Represents a title within MediaWiki.
Definition Title.php:82
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Parent class for all special pages.
getName()
Get the name of this Special Page.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getRequest()
Get the WebRequest being used for this instance.
getContentLanguage()
Shortcut to get content language.
Special page to direct the user to a random page.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
execute( $par)
Default execute method Checks user permissions.
getRandomTitle()
Choose a random title.
__construct( $loadBalancer=null, NamespaceInfo $nsInfo=null)
This class is a delegate to ILBFactory for a given database cluster.