50 unset( $this->
$name );
63 foreach ( $this->internals
as &$nsLinks ) {
64 foreach ( $nsLinks
as &$entry ) {
65 unset( $entry[
'title'] );
71 foreach ( $this->interwikis
as &$entry ) {
72 unset( $entry[
'title'] );
76 return [
'internals',
'interwikis',
'size' ];
83 foreach ( $this->internals
as &$nsLinks ) {
84 foreach ( $nsLinks
as &$entry ) {
91 foreach ( $this->interwikis
as &$entry ) {
102 foreach ( $other->internals
as $ns => $entries ) {
103 $this->size +=
count( $entries );
104 if ( !isset( $this->internals[$ns] ) ) {
105 $this->internals[$ns] = $entries;
107 $this->internals[$ns] += $entries;
110 $this->interwikis += $other->interwikis;
126 $this->tempIdOffset = $idOffset = $this->parent->nextLinkID();
129 # Renumber internal links
130 foreach ( $other->internals
as $ns => $nsLinks ) {
131 foreach ( $nsLinks
as $key => $entry ) {
132 $newKey = $idOffset + $key;
133 $this->internals[$ns][$newKey] = $entry;
134 $maxId = $newKey > $maxId ? $newKey : $maxId;
137 $texts = preg_replace_callback(
'/(<!--LINK \d+:)(\d+)(-->)/',
138 [ $this,
'mergeForeignCallback' ], $texts );
140 # Renumber interwiki links
141 foreach ( $other->interwikis
as $key => $entry ) {
142 $newKey = $idOffset + $key;
143 $this->interwikis[$newKey] = $entry;
144 $maxId = $newKey > $maxId ? $newKey : $maxId;
146 $texts = preg_replace_callback(
'/(<!--IWLINK )(\d+)(-->)/',
147 [ $this,
'mergeForeignCallback' ], $texts );
149 # Set the parent link ID to be beyond the highest used ID
150 $this->parent->setLinkID( $maxId + 1 );
151 $this->tempIdOffset =
null;
174 while ( $pos < strlen( $text ) ) {
175 if ( !preg_match(
'/<!--LINK (\d+):(\d+)-->/',
176 $text, $m, PREG_OFFSET_CAPTURE, $pos )
182 $sub->internals[$ns][$key] = $this->internals[$ns][$key];
183 $pos = $m[0][1] + strlen( $m[0][0] );
188 while ( $pos < strlen( $text ) ) {
189 if ( !preg_match(
'/<!--IWLINK (\d+)-->/', $text, $m, PREG_OFFSET_CAPTURE, $pos ) ) {
193 $sub->interwikis[$key] = $this->interwikis[$key];
194 $pos = $m[0][1] + strlen( $m[0][0] );
213 $this->internals = [];
214 $this->interwikis = [];
232 if ( !is_object( $nt ) ) {
234 $retVal =
"<!-- ERROR -->{$prefix}{$text}{$trail}";
236 # Separate the link trail from the rest of the link
241 'text' => $prefix . $text . $inside,
242 'pdbk' => $nt->getPrefixedDBkey(),
248 if ( $nt->isExternal() ) {
250 $key = $this->parent->nextLinkID();
251 $this->interwikis[$key] = $entry;
252 $retVal =
"<!--IWLINK $key-->{$trail}";
254 $key = $this->parent->nextLinkID();
255 $ns = $nt->getNamespace();
256 $this->internals[$ns][$key] = $entry;
257 $retVal =
"<!--LINK $ns:$key-->{$trail}";
279 if ( !$this->internals ) {
287 $output = $this->parent->getOutput();
293 ksort( $this->internals );
295 $linkcolour_ids = [];
299 $lb->setCaller( __METHOD__ );
301 foreach ( $this->internals
as $ns => $entries ) {
302 foreach ( $entries
as $entry ) {
305 $pdbk = $entry[
'pdbk'];
307 # Skip invalid entries.
308 # Result will be ugly, but prevents crash.
309 if ( is_null(
$title ) ) {
313 # Check if it's a static known link, e.g. interwiki
314 if (
$title->isAlwaysKnown() ) {
319 $id = $linkCache->getGoodLinkID( $pdbk );
323 $linkcolour_ids[$id] = $pdbk;
324 } elseif ( $linkCache->isBadLink( $pdbk ) ) {
327 # Not in the link cache, add it to the query
333 if ( !$lb->isEmpty() ) {
334 $fields = array_merge(
336 [
'page_namespace',
'page_title' ]
342 $lb->constructSet(
'page',
$dbr ),
346 # Fetch data and form into an associative array
347 # non-existent = broken
350 $pdbk =
$title->getPrefixedDBkey();
351 $linkCache->addGoodLinkObjFromRow(
$title,
$s );
355 $linkcolour_ids[
$s->page_id] = $pdbk;
359 if (
count( $linkcolour_ids ) ) {
364 # Do a second query for different language variants of links and categories
369 # Construct search and replace arrays
371 foreach ( $this->internals
as $ns => $entries ) {
372 foreach ( $entries
as $index => $entry ) {
373 $pdbk = $entry[
'pdbk'];
375 $query = isset( $entry[
'query'] ) ? $entry[
'query'] : [];
377 $searchkey =
"<!--LINK $key-->";
378 $displayText = $entry[
'text'];
379 if ( isset( $entry[
'selflink'] ) ) {
383 if ( $displayText ===
'' ) {
386 $displayText =
new HtmlArmor( $displayText );
393 $linkCache->addBadLinkObj(
$title );
404 $replacePairs[$searchkey] =
$link;
410 $text = preg_replace_callback(
411 '/(<!--LINK .*?-->)/',
422 if ( empty( $this->interwikis ) ) {
426 # Make interwiki link HTML
427 $output = $this->parent->getOutput();
430 foreach ( $this->interwikis
as $key =>
$link ) {
439 $text = preg_replace_callback(
440 '/<!--IWLINK (.*?)-->/',
453 $output = $this->parent->getOutput();
455 $titlesToBeConverted =
'';
461 foreach ( $this->internals
as $ns => $entries ) {
465 foreach ( $entries
as $index => $entry ) {
466 $pdbk = $entry[
'pdbk'];
469 $titlesAttrs[] = [ $index, $entry[
'title'] ];
472 $titlesToBeConverted .= $entry[
'title']->getText() .
"\0";
478 $titlesAllVariants =
$wgContLang->autoConvertToAllVariants( rtrim( $titlesToBeConverted,
"\0" ) );
479 $allVariantsName = array_keys( $titlesAllVariants );
480 foreach ( $titlesAllVariants
as &$titlesVariant ) {
481 $titlesVariant = explode(
"\0", $titlesVariant );
485 $parentTitle = $this->parent->getTitle();
486 foreach ( $titlesAttrs
as $i => $attrs ) {
489 $ns =
$title->getNamespace();
490 $text =
$title->getText();
492 foreach ( $allVariantsName
as $variantName ) {
493 $textVariant = $titlesAllVariants[$variantName][$i];
494 if ( $textVariant === $text ) {
503 if ( $variantTitle->equals( $parentTitle ) && !
$title->hasFragment() ) {
504 $this->internals[$ns][$index][
'selflink'] =
true;
508 $linkBatch->addObj( $variantTitle );
509 $variantMap[$variantTitle->getPrefixedDBkey()][] =
"$ns:$index";
516 foreach (
$output->getCategoryLinks()
as $category ) {
518 $linkBatch->addObj( $categoryTitle );
519 $variants =
$wgContLang->autoConvertToAllVariants( $category );
520 foreach ( $variants
as $variant ) {
521 if ( $variant !== $category ) {
523 if ( is_null( $variantTitle ) ) {
526 $linkBatch->addObj( $variantTitle );
527 $categoryMap[$variant] = [ $category, $categoryTitle ];
532 if ( !$linkBatch->isEmpty() ) {
535 $fields = array_merge(
537 [
'page_namespace',
'page_title' ]
540 $varRes =
$dbr->select(
'page',
542 $linkBatch->constructSet(
'page',
$dbr ),
546 $linkcolour_ids = [];
550 foreach ( $varRes
as $s ) {
552 $varPdbk = $variantTitle->getPrefixedDBkey();
553 $vardbk = $variantTitle->getDBkey();
556 if ( isset( $variantMap[$varPdbk] ) ) {
557 $holderKeys = $variantMap[$varPdbk];
558 $linkCache->addGoodLinkObjFromRow( $variantTitle,
$s );
559 $output->addLink( $variantTitle,
$s->page_id );
563 foreach ( $holderKeys
as $key ) {
564 list( $ns, $index ) = explode(
':', $key, 2 );
565 $entry =& $this->internals[$ns][$index];
566 $pdbk = $entry[
'pdbk'];
570 $entry[
'title'] = $variantTitle;
571 $entry[
'pdbk'] = $varPdbk;
575 $linkcolour_ids[
$s->page_id] = $pdbk;
580 if ( isset( $categoryMap[$vardbk] ) ) {
581 list( $oldkey, $oldtitle ) = $categoryMap[$vardbk];
582 if ( !isset( $varCategories[$oldkey] ) && !$oldtitle->exists() ) {
583 $varCategories[$oldkey] = $vardbk;
590 if (
count( $varCategories ) > 0 ) {
592 $originalCats =
$output->getCategories();
593 foreach ( $originalCats
as $cat => $sortkey ) {
595 if ( array_key_exists( $cat, $varCategories ) ) {
596 $newCats[$varCategories[$cat]] = $sortkey;
598 $newCats[$cat] = $sortkey;
601 $output->setCategoryLinks( $newCats );
614 $text = preg_replace_callback(
615 '/<!--(LINK|IWLINK) (.*?)-->/',
616 [ $this,
'replaceTextCallback' ],
632 if (
$type ==
'LINK' ) {
633 list( $ns, $index ) = explode(
':', $key, 2 );
634 if ( isset( $this->internals[$ns][$index][
'text'] ) ) {
635 return $this->internals[$ns][$index][
'text'];
637 } elseif (
$type ==
'IWLINK' ) {
638 if ( isset( $this->interwikis[$key][
'text'] ) ) {
639 return $this->interwikis[$key][
'text'];