52 unset( $this->
$name );
65 foreach ( $this->internals
as &$nsLinks ) {
66 foreach ( $nsLinks
as &$entry ) {
67 unset( $entry[
'title'] );
73 foreach ( $this->interwikis
as &$entry ) {
74 unset( $entry[
'title'] );
78 return [
'internals',
'interwikis',
'size' ];
85 foreach ( $this->internals
as &$nsLinks ) {
86 foreach ( $nsLinks
as &$entry ) {
93 foreach ( $this->interwikis
as &$entry ) {
104 foreach ( $other->internals
as $ns => $entries ) {
105 $this->size +=
count( $entries );
106 if ( !isset( $this->internals[$ns] ) ) {
107 $this->internals[$ns] = $entries;
109 $this->internals[$ns] += $entries;
112 $this->interwikis += $other->interwikis;
128 $this->tempIdOffset = $idOffset = $this->parent->nextLinkID();
131 # Renumber internal links
132 foreach ( $other->internals
as $ns => $nsLinks ) {
133 foreach ( $nsLinks
as $key => $entry ) {
134 $newKey = $idOffset + $key;
135 $this->internals[$ns][$newKey] = $entry;
136 $maxId = $newKey > $maxId ? $newKey : $maxId;
139 $texts = preg_replace_callback(
'/(<!--LINK\'" \d+:)(\d+)(-->)/',
140 [ $this,
'mergeForeignCallback' ], $texts );
142 # Renumber interwiki links
143 foreach ( $other->interwikis
as $key => $entry ) {
144 $newKey = $idOffset + $key;
145 $this->interwikis[$newKey] = $entry;
146 $maxId = $newKey > $maxId ? $newKey : $maxId;
148 $texts = preg_replace_callback(
'/(<!--IWLINK\'" )(\d+)(-->)/',
149 [ $this,
'mergeForeignCallback' ], $texts );
151 # Set the parent link ID to be beyond the highest used ID
152 $this->parent->setLinkID( $maxId + 1 );
153 $this->tempIdOffset =
null;
176 while ( $pos < strlen( $text ) ) {
177 if ( !preg_match(
'/<!--LINK\'" (\d+):(\d+)-->/',
178 $text, $m, PREG_OFFSET_CAPTURE, $pos )
184 $sub->internals[$ns][$key] = $this->internals[$ns][$key];
185 $pos = $m[0][1] + strlen( $m[0][0] );
190 while ( $pos < strlen( $text ) ) {
191 if ( !preg_match(
'/<!--IWLINK\'" (\d+)-->/', $text, $m, PREG_OFFSET_CAPTURE, $pos ) ) {
195 $sub->interwikis[$key] = $this->interwikis[$key];
196 $pos = $m[0][1] + strlen( $m[0][0] );
215 $this->internals = [];
216 $this->interwikis = [];
234 if ( !is_object( $nt ) ) {
236 $retVal =
"<!-- ERROR -->{$prefix}{$text}{$trail}";
238 # Separate the link trail from the rest of the link
243 'text' => $prefix . $text . $inside,
244 'pdbk' => $nt->getPrefixedDBkey(),
250 if ( $nt->isExternal() ) {
252 $key = $this->parent->nextLinkID();
253 $this->interwikis[$key] = $entry;
254 $retVal =
"<!--IWLINK'\" $key-->{$trail}";
256 $key = $this->parent->nextLinkID();
257 $ns = $nt->getNamespace();
258 $this->internals[$ns][$key] = $entry;
259 $retVal =
"<!--LINK'\" $ns:$key-->{$trail}";
282 if ( !$this->internals ) {
287 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
288 $output = $this->parent->getOutput();
294 ksort( $this->internals );
296 $linkcolour_ids = [];
300 $lb->setCaller( __METHOD__ );
302 foreach ( $this->internals
as $ns => $entries ) {
303 foreach ( $entries
as $entry ) {
306 $pdbk = $entry[
'pdbk'];
308 # Skip invalid entries.
309 # Result will be ugly, but prevents crash.
310 if ( is_null(
$title ) ) {
314 # Check if it's a static known link, e.g. interwiki
315 if (
$title->isAlwaysKnown() ) {
320 $id = $linkCache->getGoodLinkID( $pdbk );
324 $linkcolour_ids[$id] = $pdbk;
325 } elseif ( $linkCache->isBadLink( $pdbk ) ) {
328 # Not in the link cache, add it to the query
334 if ( !$lb->isEmpty() ) {
335 $fields = array_merge(
337 [
'page_namespace',
'page_title' ]
343 $lb->constructSet(
'page',
$dbr ),
347 # Fetch data and form into an associative array
348 # non-existent = broken
351 $pdbk =
$title->getPrefixedDBkey();
352 $linkCache->addGoodLinkObjFromRow(
$title,
$s );
356 $linkcolour_ids[
$s->page_id] = $pdbk;
360 if (
count( $linkcolour_ids ) ) {
362 Hooks::run(
'GetLinkColours', [ $linkcolour_ids, &
$colours, $this->parent->getTitle() ] );
365 # Do a second query for different language variants of links and categories
366 if ( $this->parent->getContentLanguage()->hasVariants() ) {
370 # Construct search and replace arrays
372 foreach ( $this->internals
as $ns => $entries ) {
373 foreach ( $entries
as $index => $entry ) {
374 $pdbk = $entry[
'pdbk'];
376 $query = $entry[
'query'] ?? [];
378 $searchkey =
"<!--LINK'\" $key-->";
379 $displayText = $entry[
'text'];
380 if ( isset( $entry[
'selflink'] ) ) {
384 if ( $displayText ===
'' ) {
387 $displayText =
new HtmlArmor( $displayText );
394 $linkCache->addBadLinkObj(
$title );
405 $replacePairs[$searchkey] =
$link;
410 $text = preg_replace_callback(
411 '/(<!--LINK\'" .*?-->)/',
425 if ( empty( $this->interwikis ) ) {
429 # Make interwiki link HTML
430 $output = $this->parent->getOutput();
433 foreach ( $this->interwikis
as $key =>
$link ) {
441 $text = preg_replace_callback(
442 '/<!--IWLINK\'" (.*?)-->/',
457 $output = $this->parent->getOutput();
458 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
459 $titlesToBeConverted =
'';
465 foreach ( $this->internals
as $ns => $entries ) {
469 foreach ( $entries
as $index => $entry ) {
470 $pdbk = $entry[
'pdbk'];
473 $titlesAttrs[] = [ $index, $entry[
'title'] ];
476 $titlesToBeConverted .= $entry[
'title']->getText() .
"\0";
482 $titlesAllVariants = $this->parent->getContentLanguage()->
483 autoConvertToAllVariants( rtrim( $titlesToBeConverted,
"\0" ) );
484 $allVariantsName = array_keys( $titlesAllVariants );
485 foreach ( $titlesAllVariants
as &$titlesVariant ) {
486 $titlesVariant = explode(
"\0", $titlesVariant );
490 $parentTitle = $this->parent->getTitle();
491 foreach ( $titlesAttrs
as $i => $attrs ) {
494 $ns =
$title->getNamespace();
495 $text =
$title->getText();
497 foreach ( $allVariantsName
as $variantName ) {
498 $textVariant = $titlesAllVariants[$variantName][$i];
499 if ( $textVariant === $text ) {
508 if ( $variantTitle->equals( $parentTitle ) && !
$title->hasFragment() ) {
509 $this->internals[$ns][$index][
'selflink'] =
true;
513 $linkBatch->addObj( $variantTitle );
514 $variantMap[$variantTitle->getPrefixedDBkey()][] =
"$ns:$index";
521 foreach (
$output->getCategoryLinks()
as $category ) {
523 $linkBatch->addObj( $categoryTitle );
524 $variants = $this->parent->getContentLanguage()->autoConvertToAllVariants( $category );
525 foreach ( $variants
as $variant ) {
526 if ( $variant !== $category ) {
528 if ( is_null( $variantTitle ) ) {
531 $linkBatch->addObj( $variantTitle );
532 $categoryMap[$variant] = [ $category, $categoryTitle ];
537 if ( !$linkBatch->isEmpty() ) {
540 $fields = array_merge(
542 [
'page_namespace',
'page_title' ]
545 $varRes =
$dbr->select(
'page',
547 $linkBatch->constructSet(
'page',
$dbr ),
551 $linkcolour_ids = [];
555 foreach ( $varRes
as $s ) {
557 $varPdbk = $variantTitle->getPrefixedDBkey();
558 $vardbk = $variantTitle->getDBkey();
561 if ( isset( $variantMap[$varPdbk] ) ) {
562 $holderKeys = $variantMap[$varPdbk];
563 $linkCache->addGoodLinkObjFromRow( $variantTitle,
$s );
564 $output->addLink( $variantTitle,
$s->page_id );
568 foreach ( $holderKeys
as $key ) {
569 list( $ns, $index ) = explode(
':', $key, 2 );
570 $entry =& $this->internals[$ns][$index];
571 $pdbk = $entry[
'pdbk'];
575 $entry[
'title'] = $variantTitle;
576 $entry[
'pdbk'] = $varPdbk;
580 $linkcolour_ids[
$s->page_id] = $pdbk;
585 if ( isset( $categoryMap[$vardbk] ) ) {
586 list( $oldkey, $oldtitle ) = $categoryMap[$vardbk];
587 if ( !isset( $varCategories[$oldkey] ) && !$oldtitle->exists() ) {
588 $varCategories[$oldkey] = $vardbk;
592 Hooks::run(
'GetLinkColours', [ $linkcolour_ids, &
$colours, $this->parent->getTitle() ] );
595 if (
count( $varCategories ) > 0 ) {
597 $originalCats =
$output->getCategories();
598 foreach ( $originalCats
as $cat => $sortkey ) {
600 if ( array_key_exists( $cat, $varCategories ) ) {
601 $newCats[$varCategories[$cat]] = $sortkey;
603 $newCats[$cat] = $sortkey;
606 $output->setCategoryLinks( $newCats );
619 $text = preg_replace_callback(
620 '/<!--(LINK|IWLINK)\'" (.*?)-->/',
621 [ $this,
'replaceTextCallback' ],
636 if (
$type ==
'LINK' ) {
637 list( $ns, $index ) = explode(
':', $key, 2 );
638 if ( isset( $this->internals[$ns][$index][
'text'] ) ) {
639 return $this->internals[$ns][$index][
'text'];
641 } elseif (
$type ==
'IWLINK' ) {
642 if ( isset( $this->interwikis[$key][
'text'] ) ) {
643 return $this->interwikis[$key][
'text'];