MediaWiki REL1_41
LinkBatch.php
Go to the documentation of this file.
1<?php
32use Psr\Log\LoggerInterface;
33use Wikimedia\Assert\Assert;
37
44class LinkBatch {
48 public $data = [];
49
53 private $pageIdentities = null;
54
58 protected $caller;
59
63 private $linkCache;
64
68 private $titleFormatter;
69
73 private $contentLanguage;
74
78 private $genderCache;
79
83 private $dbProvider;
84
86 private $linksMigration;
87
89 private $logger;
90
104 public function __construct(
105 iterable $arr,
106 LinkCache $linkCache,
107 TitleFormatter $titleFormatter,
108 Language $contentLanguage,
109 GenderCache $genderCache,
110 IConnectionProvider $dbProvider,
111 LinksMigration $linksMigration,
112 LoggerInterface $logger
113 ) {
114 $this->linkCache = $linkCache;
115 $this->titleFormatter = $titleFormatter;
116 $this->contentLanguage = $contentLanguage;
117 $this->genderCache = $genderCache;
118 $this->dbProvider = $dbProvider;
119 $this->linksMigration = $linksMigration;
120 $this->logger = $logger;
121
122 foreach ( $arr as $item ) {
123 $this->addObj( $item );
124 }
125 }
126
135 public function setCaller( $caller ) {
136 $this->caller = $caller;
137
138 return $this;
139 }
140
144 public function addObj( $link ) {
145 if ( !$link ) {
146 // Don't die if we got null, just skip. There is nothing to do anyway.
147 // For now, let's avoid things like T282180. We should be more strict in the future.
148 $this->logger->warning(
149 'Skipping null link, probably due to a bad title.',
150 [ 'exception' => new RuntimeException() ]
151 );
152 return;
153 }
154 if ( $link instanceof LinkTarget && $link->isExternal() ) {
155 $this->logger->warning(
156 'Skipping interwiki link',
157 [ 'exception' => new RuntimeException() ]
158 );
159 return;
160 }
161
162 Assert::parameterType( [ LinkTarget::class, PageReference::class ], $link, '$link' );
163 $this->add( $link->getNamespace(), $link->getDBkey() );
164 }
165
170 public function add( $ns, $dbkey ) {
171 if ( $ns < 0 || $dbkey === '' ) {
172 // T137083
173 return;
174 }
175 $this->data[$ns][strtr( $dbkey, ' ', '_' )] = 1;
176 }
177
184 public function setArray( $array ) {
185 $this->data = $array;
186 }
187
193 public function isEmpty() {
194 return $this->getSize() == 0;
195 }
196
202 public function getSize() {
203 return count( $this->data );
204 }
205
211 public function execute() {
212 return $this->executeInto( $this->linkCache );
213 }
214
222 public function getPageIdentities(): array {
223 if ( $this->pageIdentities === null ) {
224 $this->execute();
225 }
226
227 return $this->pageIdentities;
228 }
229
237 protected function executeInto( $cache ) {
238 $res = $this->doQuery();
239 $this->doGenderQuery();
240 return $this->addResultToCache( $cache, $res );
241 }
242
253 public function addResultToCache( $cache, $res ) {
254 if ( !$res ) {
255 return [];
256 }
257
258 // For each returned entry, add it to the list of good links, and remove it from $remaining
259
260 $this->pageIdentities ??= [];
261
262 $ids = [];
263 $remaining = $this->data;
264 foreach ( $res as $row ) {
265 try {
266 $title = new TitleValue( (int)$row->page_namespace, $row->page_title );
267
268 $cache->addGoodLinkObjFromRow( $title, $row );
269 $pdbk = $this->titleFormatter->getPrefixedDBkey( $title );
270 $ids[$pdbk] = $row->page_id;
271
272 $pageIdentity = new PageIdentityValue(
273 (int)$row->page_id,
274 (int)$row->page_namespace,
275 $row->page_title,
276 ProperPageIdentity::LOCAL
277 );
278
279 $key = CacheKeyHelper::getKeyForPage( $pageIdentity );
280 $this->pageIdentities[$key] = $pageIdentity;
281 } catch ( InvalidArgumentException $ex ) {
282 $this->logger->warning(
283 'Encountered invalid title',
284 [ 'title_namespace' => $row->page_namespace, 'title_dbkey' => $row->page_title ]
285 );
286 }
287
288 unset( $remaining[$row->page_namespace][$row->page_title] );
289 }
290
291 // The remaining links in $data are bad links, register them as such
292 foreach ( $remaining as $ns => $dbkeys ) {
293 foreach ( $dbkeys as $dbkey => $unused ) {
294 try {
295 $title = new TitleValue( (int)$ns, (string)$dbkey );
296
297 $cache->addBadLinkObj( $title );
298 $pdbk = $this->titleFormatter->getPrefixedDBkey( $title );
299 $ids[$pdbk] = 0;
300
301 $pageIdentity = new PageIdentityValue( 0, (int)$ns, $dbkey, ProperPageIdentity::LOCAL );
302 $key = CacheKeyHelper::getKeyForPage( $pageIdentity );
303 $this->pageIdentities[$key] = $pageIdentity;
304 } catch ( InvalidArgumentException $ex ) {
305 $this->logger->warning(
306 'Encountered invalid title',
307 [ 'title_namespace' => $ns, 'title_dbkey' => $dbkey ]
308 );
309 }
310 }
311 }
312
313 return $ids;
314 }
315
320 public function doQuery() {
321 if ( $this->isEmpty() ) {
322 return false;
323 }
324
325 // This is similar to LinkHolderArray::replaceInternal
326 $dbr = $this->dbProvider->getReplicaDatabase();
327 $queryBuilder = $dbr->newSelectQueryBuilder()
328 ->select( LinkCache::getSelectFields() )
329 ->from( 'page' )
330 ->where( $this->constructSet( 'page', $dbr ) );
331
332 $caller = __METHOD__;
333 if ( strval( $this->caller ) !== '' ) {
334 $caller .= " (for {$this->caller})";
335 }
336
337 return $queryBuilder->caller( $caller )->fetchResultSet();
338 }
339
345 public function doGenderQuery() {
346 if ( $this->isEmpty() || !$this->contentLanguage->needsGenderDistinction() ) {
347 return false;
348 }
349
350 $this->genderCache->doLinkBatch( $this->data, $this->caller );
351
352 return true;
353 }
354
366 public function constructSet( $prefix, $db ) {
367 if ( isset( $this->linksMigration::$prefixToTableMapping[$prefix] ) ) {
368 [ $blNamespace, $blTitle ] = $this->linksMigration->getTitleFields(
369 $this->linksMigration::$prefixToTableMapping[$prefix]
370 );
371 } else {
372 $blNamespace = "{$prefix}_namespace";
373 $blTitle = "{$prefix}_title";
374 }
375 return $db->makeWhereFrom2d( $this->data, $blNamespace, $blTitle );
376 }
377}
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:88
Look up "gender" user preference.
Base class for language-specific code.
Definition Language.php:63
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition LinkBatch.php:44
doGenderQuery()
Do (and cache) {{GENDER:...}} information for userpages in this LinkBatch.
__construct(iterable $arr, LinkCache $linkCache, TitleFormatter $titleFormatter, Language $contentLanguage, GenderCache $genderCache, IConnectionProvider $dbProvider, LinksMigration $linksMigration, LoggerInterface $logger)
add( $ns, $dbkey)
getSize()
Returns the size of the batch.
addObj( $link)
addResultToCache( $cache, $res)
Add a result wrapper containing IDs and titles to a LinkCache object.
isEmpty()
Returns true if no pages have been added, false otherwise.
setCaller( $caller)
Use ->setCaller( METHOD ) to indicate which code is using this class.
constructSet( $prefix, $db)
Construct a WHERE clause which will match all the given titles.
getPageIdentities()
Do the query, add the results to the LinkCache object, and return ProperPageIdentity instances corres...
execute()
Do the query and add the results to the LinkCache object.
setArray( $array)
Set the link list to a given 2-d array First key is the namespace, second is the DB key,...
string null $caller
For debugging which method is using this class.
Definition LinkBatch.php:58
array< int, array< string, mixed > > $data
2-d array, first index namespace, second index dbkey, value arbitrary
Definition LinkBatch.php:48
executeInto( $cache)
Do the query and add the results to a given LinkCache object Return an array mapping PDBK to ID.
doQuery()
Perform the existence test query, return a result wrapper with page_id fields.
Cache for article titles (prefixed DB keys) and ids linked from one source.
Definition LinkCache.php:45
Helper class for mapping value objects representing basic entities to cache keys.
Service for compat reading of links tables.
Immutable value object representing a page identity.
Represents the target of a wiki link.
Represents the target of a wiki link.
isExternal()
Whether this LinkTarget has an interwiki component.
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.
Interface for a page that is (or could be, or used to be) an editable wiki page.
A title formatter service for MediaWiki.
Provide primary and replica IDatabase connections.
Result wrapper for grabbing data queried from an IDatabase object.
Interface for query language.