wiki.techinc.nl/includes/deferred/LinksUpdate/LangLinksTable.php
C. Scott Ananian 7495f9bc15 Deduplicate language links in ParserOutput and OutputPage
Move deduplication of language links out of Parser.php and into the
ParserOutput in order to be compatible with alternate Parsers (Parsoid).
Clean up various inconsistencies: ensure deduplication also happens in
OutputPage when multiple ParserOutputs are merged into the final output,
and ensure that the deduplication in LinksUpdate is done in the same
order (first link prevails) as in Parser/ParserOutput/OutputPage.

Deprecate OutputPage::setLanguageLinks() (the matching
ParserOutput::setLanguageLinks() was deprecated in 1.42).

As a breaking change, return an array, not an array *reference*, from
ParserOutput::getLanguageLinks().  This allows us to safely modify the
internal representation of language links. As far as I can tell, no one
used the returned reference to sneakily modify the list of language
links, and there not a good way to have deprecated this before making
the breaking change.

While we're at it, we've added tests to ensure that language link
fragments are preserved.

Bug: T26502
Bug: T358950
Bug: T375005
Change-Id: I82a05a51d94782ebb9fa87ff889ca0f633b3e15c
2024-09-26 15:28:49 -04:00

102 lines
2.4 KiB
PHP

<?php
namespace MediaWiki\Deferred\LinksUpdate;
use MediaWiki\Parser\ParserOutput;
/**
* langlinks
*
* Link ID format: string[]
* - 0: Language code
* - 1: Foreign title
*
* @since 1.38
*/
class LangLinksTable extends LinksTable {
/** @var string[] */
private $newLinks = [];
/** @var string[]|null */
private $existingLinks;
public function setParserOutput( ParserOutput $parserOutput ) {
// Convert the format of the interlanguage links
// I didn't want to change it in the ParserOutput, because that array is passed all
// the way back to the skin, so either a skin API break would be required, or an
// inefficient back-conversion.
$ill = $parserOutput->getLanguageLinks();
$this->newLinks = [];
foreach ( $ill as $link ) {
[ $key, $title ] = explode( ':', $link, 2 );
// Ensure that the "first" link has precedence: T26502
$this->newLinks[$key] ??= $title;
}
}
protected function getTableName() {
return 'langlinks';
}
protected function getFromField() {
return 'll_from';
}
protected function getExistingFields() {
return [ 'll_lang', 'll_title' ];
}
protected function getNewLinkIDs() {
foreach ( $this->newLinks as $key => $title ) {
yield [ (string)$key, $title ];
}
}
/**
* Get the existing links as an array where the key is the language code
* and the value is the title of the target in that language.
*
* @return array
*/
private function getExistingLinks() {
if ( $this->existingLinks === null ) {
$this->existingLinks = [];
foreach ( $this->fetchExistingRows() as $row ) {
$this->existingLinks[$row->ll_lang] = $row->ll_title;
}
}
return $this->existingLinks;
}
protected function getExistingLinkIDs() {
foreach ( $this->getExistingLinks() as $lang => $title ) {
yield [ (string)$lang, $title ];
}
}
protected function isExisting( $linkId ) {
$links = $this->getExistingLinks();
[ $lang, $title ] = $linkId;
return \array_key_exists( $lang, $links )
&& $links[$lang] === $title;
}
protected function isInNewSet( $linkId ) {
[ $lang, $title ] = $linkId;
return \array_key_exists( $lang, $this->newLinks )
&& $this->newLinks[$lang] === $title;
}
protected function insertLink( $linkId ) {
[ $lang, $title ] = $linkId;
$this->insertRow( [
'll_lang' => $lang,
'll_title' => $title
] );
}
protected function deleteLink( $linkId ) {
$this->deleteRow( [
'll_lang' => $linkId[0]
] );
}
}