MediaWiki  master
SpecialDoubleRedirects.php
Go to the documentation of this file.
1 <?php
28 
36 
39 
42 
44  private $dbr;
45 
51  public function __construct(
55  ) {
56  parent::__construct( 'DoubleRedirects' );
57  $this->contentHandlerFactory = $contentHandlerFactory;
58  $this->linkBatchFactory = $linkBatchFactory;
59  $this->setDBLoadBalancer( $loadBalancer );
61  }
62 
63  public function isExpensive() {
64  return true;
65  }
66 
67  public function isSyndicated() {
68  return false;
69  }
70 
71  protected function sortDescending() {
72  return false;
73  }
74 
75  protected function getPageHeader() {
76  return $this->msg( 'doubleredirectstext' )->parseAsBlock();
77  }
78 
79  private function reallyGetQueryInfo( $namespace = null, $title = null ) {
80  $limitToTitle = !( $namespace === null && $title === null );
81  $retval = [
82  'tables' => [
83  'ra' => 'redirect',
84  'rb' => 'redirect',
85  'pa' => 'page',
86  'pb' => 'page'
87  ],
88  'fields' => [
89  'namespace' => 'pa.page_namespace',
90  'title' => 'pa.page_title',
91 
92  'b_namespace' => 'pb.page_namespace',
93  'b_title' => 'pb.page_title',
94 
95  // Select fields from redirect instead of page. Because there may
96  // not actually be a page table row for this target (e.g. for interwiki redirects)
97  'c_namespace' => 'rb.rd_namespace',
98  'c_title' => 'rb.rd_title',
99  'c_fragment' => 'rb.rd_fragment',
100  'c_interwiki' => 'rb.rd_interwiki',
101  ],
102  'conds' => [
103  'ra.rd_from = pa.page_id',
104 
105  // Filter out redirects where the target goes interwiki (T42353).
106  // This isn't an optimization, it is required for correct results,
107  // otherwise a non-double redirect like Bar -> w:Foo will show up
108  // like "Bar -> Foo -> w:Foo".
109 
110  // Need to check both NULL and "" for some reason,
111  // apparently either can be stored for non-iw entries.
112  'ra.rd_interwiki IS NULL OR ra.rd_interwiki = ' . $this->dbr->addQuotes( '' ),
113 
114  'pb.page_namespace = ra.rd_namespace',
115  'pb.page_title = ra.rd_title',
116 
117  'rb.rd_from = pb.page_id',
118  ]
119  ];
120 
121  if ( $limitToTitle ) {
122  $retval['conds']['pa.page_namespace'] = $namespace;
123  $retval['conds']['pa.page_title'] = $title;
124  }
125 
126  return $retval;
127  }
128 
129  public function getQueryInfo() {
130  return $this->reallyGetQueryInfo();
131  }
132 
133  protected function getOrderFields() {
134  return [ 'ra.rd_namespace', 'ra.rd_title' ];
135  }
136 
142  public function formatResult( $skin, $result ) {
143  // If no Title B or C is in the query, it means this came from
144  // querycache (which only saves the 3 columns for title A).
145  // That does save the bulk of the query cost, but now we need to
146  // get a little more detail about each individual entry quickly
147  // using the filter of reallyGetQueryInfo.
148  $deep = false;
149  if ( $result ) {
150  if ( isset( $result->b_namespace ) ) {
151  $deep = $result;
152  } else {
153  $qi = $this->reallyGetQueryInfo(
154  $result->namespace,
155  $result->title
156  );
157  $deep = $this->dbr->selectRow(
158  $qi['tables'],
159  $qi['fields'],
160  $qi['conds'],
161  __METHOD__
162  );
163  }
164  }
165 
166  $titleA = Title::makeTitle( $result->namespace, $result->title );
167 
168  $linkRenderer = $this->getLinkRenderer();
169  if ( !$deep ) {
170  return '<del>' . $linkRenderer->makeLink( $titleA, null, [], [ 'redirect' => 'no' ] ) . '</del>';
171  }
172 
173  // if the page is editable, add an edit link
174  if (
175  // check user permissions
176  $this->getAuthority()->isAllowed( 'edit' ) &&
177  // check, if the content model is editable through action=edit
178  $this->contentHandlerFactory->getContentHandler( $titleA->getContentModel() )
179  ->supportsDirectEditing()
180  ) {
181  $edit = $linkRenderer->makeKnownLink(
182  $titleA,
183  $this->msg( 'parentheses', $this->msg( 'editlink' )->text() )->text(),
184  [],
185  [ 'action' => 'edit' ]
186  );
187  } else {
188  $edit = '';
189  }
190 
191  $linkA = $linkRenderer->makeKnownLink(
192  $titleA,
193  null,
194  [],
195  [ 'redirect' => 'no' ]
196  );
197 
198  $titleB = Title::makeTitle( $deep->b_namespace, $deep->b_title );
199  $linkB = $linkRenderer->makeKnownLink(
200  $titleB,
201  null,
202  [],
203  [ 'redirect' => 'no' ]
204  );
205 
206  $titleC = Title::makeTitle(
207  $deep->c_namespace,
208  $deep->c_title,
209  $deep->c_fragment,
210  $deep->c_interwiki
211  );
212  $linkC = $linkRenderer->makeKnownLink( $titleC, $titleC->getFullText() );
213 
214  $lang = $this->getLanguage();
215  $arr = $lang->getArrow() . $lang->getDirMark();
216 
217  return ( "{$linkA} {$edit} {$arr} {$linkB} {$arr} {$linkC}" );
218  }
219 
220  public function execute( $par ) {
221  $this->addHelpLink( 'Help:Redirects' );
222  parent::execute( $par );
223  }
224 
231  public function preprocessResults( $db, $res ) {
232  if ( !$res->numRows() ) {
233  return;
234  }
235 
236  $batch = $this->linkBatchFactory->newLinkBatch();
237  foreach ( $res as $row ) {
238  $batch->add( $row->namespace, $row->title );
239  if ( isset( $row->b_namespace ) ) {
240  // lazy loaded when using cached results
241  $batch->add( $row->b_namespace, $row->b_title );
242  }
243  if ( isset( $row->c_interwiki ) && !$row->c_interwiki ) {
244  // lazy loaded when using cached result, not added when interwiki link
245  $batch->add( $row->c_namespace, $row->c_title );
246  }
247  }
248  $batch->execute();
249 
250  // Back to start for display
251  $res->seek( 0 );
252  }
253 
254  protected function getGroupName() {
255  return 'maintenance';
256  }
257 }
SpecialPage\$linkRenderer
LinkRenderer null $linkRenderer
Definition: SpecialPage.php:80
SpecialDoubleRedirects\__construct
__construct(IContentHandlerFactory $contentHandlerFactory, LinkBatchFactory $linkBatchFactory, ILoadBalancer $loadBalancer)
Definition: SpecialDoubleRedirects.php:51
SpecialPage\msg
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:912
SpecialDoubleRedirects\getQueryInfo
getQueryInfo()
Subclasses return an SQL query here, formatted as an array with the following keys: tables => Table(s...
Definition: SpecialDoubleRedirects.php:129
SpecialDoubleRedirects\isSyndicated
isSyndicated()
Sometime we don't want to build rss / atom feeds.
Definition: SpecialDoubleRedirects.php:67
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
SpecialDoubleRedirects\$linkBatchFactory
LinkBatchFactory $linkBatchFactory
Definition: SpecialDoubleRedirects.php:41
SpecialPage\getAuthority
getAuthority()
Shortcut to get the Authority executing this instance.
Definition: SpecialPage.php:810
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:830
$res
$res
Definition: testCompression.php:57
QueryPage
This is a class for doing query pages; since they're almost all the same, we factor out some of the f...
Definition: QueryPage.php:41
Wikimedia\Rdbms\ILoadBalancer\getConnectionRef
getConnectionRef( $i, $groups=[], $domain=false, $flags=0)
Get a live database handle reference for a server index.
SpecialDoubleRedirects\preprocessResults
preprocessResults( $db, $res)
Cache page content model and gender distinction for performance.
Definition: SpecialDoubleRedirects.php:231
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
SpecialDoubleRedirects\reallyGetQueryInfo
reallyGetQueryInfo( $namespace=null, $title=null)
Definition: SpecialDoubleRedirects.php:79
SpecialDoubleRedirects\$dbr
IDatabase $dbr
Definition: SpecialDoubleRedirects.php:44
SpecialPage\addHelpLink
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition: SpecialPage.php:948
Wikimedia\Rdbms\IResultWrapper
Result wrapper for grabbing data queried from an IDatabase object.
Definition: IResultWrapper.php:26
SpecialDoubleRedirects
A special page listing redirects to redirecting page.
Definition: SpecialDoubleRedirects.php:35
MediaWiki\Cache\LinkBatchFactory
Definition: LinkBatchFactory.php:39
SpecialDoubleRedirects\formatResult
formatResult( $skin, $result)
Definition: SpecialDoubleRedirects.php:142
$title
$title
Definition: testCompression.php:38
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:651
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
SpecialDoubleRedirects\getOrderFields
getOrderFields()
Subclasses return an array of fields to order by here.
Definition: SpecialDoubleRedirects.php:133
MediaWiki\Content\IContentHandlerFactory
Definition: IContentHandlerFactory.php:10
QueryPage\setDBLoadBalancer
setDBLoadBalancer(ILoadBalancer $loadBalancer)
Definition: QueryPage.php:892
SpecialDoubleRedirects\isExpensive
isExpensive()
Is this query expensive (for some definition of expensive)? Then we don't let it run in miser mode.
Definition: SpecialDoubleRedirects.php:63
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:1028
SpecialDoubleRedirects\sortDescending
sortDescending()
Override to sort by increasing values.
Definition: SpecialDoubleRedirects.php:71
SpecialDoubleRedirects\getPageHeader
getPageHeader()
The content returned by this function will be output before any result.
Definition: SpecialDoubleRedirects.php:75
SpecialDoubleRedirects\execute
execute( $par)
This is the actual workhorse.
Definition: SpecialDoubleRedirects.php:220
SpecialDoubleRedirects\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialDoubleRedirects.php:254
QueryPage\$loadBalancer
ILoadBalancer null $loadBalancer
Definition: QueryPage.php:71
SpecialDoubleRedirects\$contentHandlerFactory
IContentHandlerFactory $contentHandlerFactory
Definition: SpecialDoubleRedirects.php:38
Wikimedia\Rdbms\ILoadBalancer
Database cluster connection, tracking, load balancing, and transaction manager interface.
Definition: ILoadBalancer.php:81