162 if ( !$this->internals ) {
167 $services = MediaWikiServices::getInstance();
168 $linkCache = $services->getLinkCache();
169 $output = $this->parent->getOutput();
170 $linkRenderer = $this->parent->getLinkRenderer();
172 $dbr = $services->getConnectionProvider()->getReplicaDatabase();
175 ksort( $this->internals );
180 $linkBatchFactory = $services->getLinkBatchFactory();
181 $lb = $linkBatchFactory->newLinkBatch();
182 $lb->setCaller( __METHOD__ );
184 foreach ( $this->internals as $ns => $entries ) {
185 foreach ( $entries as [
'title' => $title,
'pdbk' => $pdbk ] ) {
187 # Check if it's a static known link, e.g. interwiki
188 if ( $title->isAlwaysKnown() ) {
189 $classes[$pdbk] =
'';
191 $classes[$pdbk] =
'new';
193 $id = $linkCache->getGoodLinkID( $pdbk );
195 $classes[$pdbk] = $linkRenderer->getLinkClasses( $title );
196 $output->addLink( $title, $id );
197 $pagemap[$id] = $pdbk;
198 } elseif ( $linkCache->isBadLink( $pdbk ) ) {
199 $classes[$pdbk] =
'new';
201 # Not in the link cache, add it to the query
202 $lb->addObj( $title );
207 if ( !$lb->isEmpty() ) {
208 $res = $dbr->newSelectQueryBuilder()
209 ->select( LinkCache::getSelectFields() )
211 ->where( [ $lb->constructSet(
'page', $dbr ) ] )
212 ->caller( __METHOD__ )
215 # Fetch data and form into an associative array
216 # non-existent = broken
217 foreach ( $res as $s ) {
218 $title = Title::makeTitle( $s->page_namespace, $s->page_title );
219 $pdbk = $title->getPrefixedDBkey();
220 $linkCache->addGoodLinkObjFromRow( $title, $s );
221 $output->addLink( $title, $s->page_id );
222 $classes[$pdbk] = $linkRenderer->getLinkClasses( $title );
224 $pagemap[$s->page_id] = $pdbk;
228 if ( $pagemap !== [] ) {
230 $this->hookRunner->onGetLinkColours( $pagemap, $classes, $this->parent->getTitle() );
233 # Do a second query for different language variants of links and categories
234 if ( $this->languageConverter->hasVariants() ) {
238 # Construct search and replace arrays
240 foreach ( $this->internals as $ns => $entries ) {
241 foreach ( $entries as $index => $entry ) {
242 $pdbk = $entry[
'pdbk'];
243 $title = $entry[
'title'];
244 $query = $entry[
'query'] ?? [];
245 $searchkey =
"$ns:$index";
246 $displayTextHtml = $entry[
'text'];
247 if ( isset( $entry[
'selflink'] ) ) {
248 $replacePairs[$searchkey] = Linker::makeSelfLinkObj(
249 $title, $displayTextHtml, $query,
'',
'',
250 Sanitizer::escapeIdForLink( $title->getFragment() )
255 $displayText = $displayTextHtml ===
'' ? null :
new HtmlArmor( $displayTextHtml );
256 if ( !isset( $classes[$pdbk] ) ) {
257 $classes[$pdbk] =
'new';
259 if ( $classes[$pdbk] ===
'new' ) {
260 $linkCache->addBadLinkObj( $title );
261 $output->addLink( $title, 0 );
262 $link = $linkRenderer->makeBrokenLink(
263 $title, $displayText, [], $query
266 $link = $linkRenderer->makePreloadedLink(
267 $title, $displayText, $classes[$pdbk], [], $query
271 $replacePairs[$searchkey] = $link;
276 $text = preg_replace_callback(
277 '/<!--LINK\'" (-?[\d:]+)-->/',
278 static function ( array
$matches ) use ( $replacePairs ) {
317 $linkBatchFactory = MediaWikiServices::getInstance()->getLinkBatchFactory();
318 $linkBatch = $linkBatchFactory->newLinkBatch();
320 $output = $this->parent->getOutput();
321 $titlesToBeConverted =
'';
327 foreach ( $this->internals as $ns => $entries ) {
331 foreach ( $entries as $index => [
'title' => $title,
'pdbk' => $pdbk ] ) {
333 if ( !isset( $classes[$pdbk] ) || $classes[$pdbk] ===
'new' ) {
334 $titlesAttrs[] = [ $index, $title ];
337 $titlesToBeConverted .= $title->getText() .
"\0";
343 $titlesAllVariants = $this->languageConverter->
344 autoConvertToAllVariants( rtrim( $titlesToBeConverted,
"\0" ) );
345 foreach ( $titlesAllVariants as &$titlesVariant ) {
346 $titlesVariant = explode(
"\0", $titlesVariant );
350 $parentTitle = $this->parent->getTitle();
351 foreach ( $titlesAttrs as $i => [ $index, $title ] ) {
353 $ns = $title->getNamespace();
354 $text = $title->getText();
356 foreach ( $titlesAllVariants as $textVariants ) {
357 $textVariant = $textVariants[$i];
358 if ( $textVariant === $text ) {
362 $variantTitle = Title::makeTitle( $ns, $textVariant );
367 if ( $variantTitle->equals( $parentTitle ) ) {
368 $this->internals[$ns][$index][
'selflink'] =
true;
372 $linkBatch->addObj( $variantTitle );
373 $variantMap[$variantTitle->getPrefixedDBkey()][] =
"$ns:$index";
379 foreach ( $output->getCategoryNames() as $category ) {
380 $categoryTitle = Title::makeTitleSafe(
NS_CATEGORY, $category );
381 $linkBatch->addObj( $categoryTitle );
382 $variants = $this->languageConverter->autoConvertToAllVariants( $category );
383 foreach ( $variants as $variant ) {
384 if ( $variant !== $category ) {
385 $variantTitle = Title::makeTitleSafe(
NS_CATEGORY, $variant );
386 if ( $variantTitle ) {
387 $linkBatch->addObj( $variantTitle );
388 $categoryMap[$variant] = [ $category, $categoryTitle ];
394 if ( $linkBatch->isEmpty() ) {
399 $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
401 $varRes = $dbr->newSelectQueryBuilder()
402 ->select( LinkCache::getSelectFields() )
404 ->where( [ $linkBatch->constructSet(
'page', $dbr ) ] )
405 ->caller( __METHOD__ )
410 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
411 $linkRenderer = $this->parent->getLinkRenderer();
414 foreach ( $varRes as $s ) {
415 $variantTitle = Title::makeTitle( $s->page_namespace, $s->page_title );
416 $varPdbk = $variantTitle->getPrefixedDBkey();
418 if ( !isset( $variantMap[$varPdbk] ) ) {
422 $linkCache->addGoodLinkObjFromRow( $variantTitle, $s );
423 $output->addLink( $variantTitle, $s->page_id );
426 foreach ( $variantMap[$varPdbk] as $key ) {
427 [ $ns, $index ] = explode(
':', $key, 2 );
428 $entry =& $this->internals[(int)$ns][(
int)$index];
433 if ( isset( $entry[
'selflink'] ) ) {
437 $pdbk = $entry[
'pdbk'];
438 if ( !isset( $classes[$pdbk] ) || $classes[$pdbk] ===
'new' ) {
440 $entry[
'title'] = $variantTitle;
441 $entry[
'pdbk'] = $varPdbk;
444 if ( !isset( $classes[$varPdbk] ) ) {
445 $classes[$varPdbk] = $linkRenderer->getLinkClasses( $variantTitle );
446 $pagemap[$s->page_id] = $varPdbk;
452 $vardbk = $variantTitle->getDBkey();
453 if ( isset( $categoryMap[$vardbk] ) ) {
454 [ $oldkey, $oldtitle ] = $categoryMap[$vardbk];
455 if ( !isset( $varCategories[$oldkey] ) && !$oldtitle->exists() ) {
456 $varCategories[$oldkey] = $vardbk;
460 $this->hookRunner->onGetLinkColours( $pagemap, $classes, $this->parent->getTitle() );
463 if ( $varCategories !== [] ) {
465 foreach ( $output->getCategoryNames() as $cat ) {
466 $sortkey = $output->getCategorySortKey( $cat );
468 $newCats[$varCategories[$cat] ?? $cat] = $sortkey;
470 $output->setCategories( $newCats );