protected $key = null;
/**
- * @var int One of the MIGRATION_* constants
+ * @var int One of the MIGRATION_* constants, or an appropriate combination
+ * of SCHEMA_COMPAT_* constants.
* @todo Deprecate and remove once extensions seem unlikely to need to use
* it for migration anymore.
*/
/**
* @param Language $lang Language to use for comment truncation. Defaults
* to content language.
- * @param int $migrationStage One of the MIGRATION_* constants. Always
- * MIGRATION_NEW for MediaWiki core since 1.33.
+ * @param int $stage One of the MIGRATION_* constants, or an appropriate
+ * combination of SCHEMA_COMPAT_* constants. Always MIGRATION_NEW for
+ * MediaWiki core since 1.33.
*/
- public function __construct( Language $lang, $migrationStage ) {
- $this->stage = $migrationStage;
+ public function __construct( Language $lang, $stage ) {
+ if ( ( $stage & SCHEMA_COMPAT_WRITE_BOTH ) === 0 ) {
+ throw new InvalidArgumentException( '$stage must include a write mode' );
+ }
+ if ( ( $stage & SCHEMA_COMPAT_READ_BOTH ) === 0 ) {
+ throw new InvalidArgumentException( '$stage must include a read mode' );
+ }
+
+ $this->stage = $stage;
$this->lang = $lang;
}
public function getFields( $key = null ) {
$key = $this->getKey( $key );
$fields = [];
- if ( $this->stage === MIGRATION_OLD ) {
+ if ( ( $this->stage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD ) {
$fields["{$key}_text"] = $key;
$fields["{$key}_data"] = 'NULL';
$fields["{$key}_cid"] = 'NULL';
- } else {
- if ( $this->stage < MIGRATION_NEW ) {
+ } else { // READ_BOTH or READ_NEW
+ if ( $this->stage & SCHEMA_COMPAT_READ_OLD ) {
$fields["{$key}_old"] = $key;
}
$tempTableStage = isset( $this->tempTables[$key] )
? $this->tempTables[$key]['stage'] : MIGRATION_NEW;
- if ( $tempTableStage < MIGRATION_NEW ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_READ_OLD ) {
$fields["{$key}_pk"] = $this->tempTables[$key]['joinPK'];
}
- if ( $tempTableStage > MIGRATION_OLD ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_READ_NEW ) {
$fields["{$key}_id"] = "{$key}_id";
}
}
$fields = [];
$joins = [];
- if ( $this->stage === MIGRATION_OLD ) {
+ if ( ( $this->stage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD ) {
$fields["{$key}_text"] = $key;
$fields["{$key}_data"] = 'NULL';
$fields["{$key}_cid"] = 'NULL';
- } else {
- $join = $this->stage === MIGRATION_NEW ? 'JOIN' : 'LEFT JOIN';
+ } else { // READ_BOTH or READ_NEW
+ $join = ( $this->stage & SCHEMA_COMPAT_READ_OLD ) ? 'LEFT JOIN' : 'JOIN';
$tempTableStage = isset( $this->tempTables[$key] )
? $this->tempTables[$key]['stage'] : MIGRATION_NEW;
- if ( $tempTableStage < MIGRATION_NEW ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_READ_OLD ) {
$t = $this->tempTables[$key];
$alias = "temp_$key";
$tables[$alias] = $t['table'];
$joins[$alias] = [ $join, "{$alias}.{$t['pk']} = {$t['joinPK']}" ];
- if ( $tempTableStage === MIGRATION_OLD ) {
+ if ( ( $tempTableStage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD ) {
$joinField = "{$alias}.{$t['field']}";
} else {
// Nothing hits this code path for now, but will in the future when we set
$tables[$alias] = 'comment';
$joins[$alias] = [ $join, "{$alias}.comment_id = {$joinField}" ];
- if ( $this->stage === MIGRATION_NEW ) {
+ if ( ( $this->stage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_NEW ) {
$fields["{$key}_text"] = "{$alias}.comment_text";
} else {
$fields["{$key}_text"] = "COALESCE( {$alias}.comment_text, $key )";
$cid = $row["{$key}_cid"] ?? null;
$text = $row["{$key}_text"];
$data = $row["{$key}_data"];
- } elseif ( $this->stage === MIGRATION_OLD ) {
+ } elseif ( ( $this->stage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD ) {
$cid = null;
if ( $fallback && isset( $row[$key] ) ) {
wfLogWarning( "Using deprecated fallback handling for comment $key" );
$text = $row[$key];
} else {
- wfLogWarning( "Missing {$key}_text and {$key}_data fields in row with MIGRATION_OLD" );
+ wfLogWarning(
+ "Missing {$key}_text and {$key}_data fields in row with MIGRATION_OLD / READ_OLD"
+ );
$text = '';
}
$data = null;
$tempTableStage = isset( $this->tempTables[$key] )
? $this->tempTables[$key]['stage'] : MIGRATION_NEW;
$row2 = null;
- if ( $tempTableStage > MIGRATION_OLD && array_key_exists( "{$key}_id", $row ) ) {
+ if ( ( $tempTableStage & SCHEMA_COMPAT_READ_NEW ) && array_key_exists( "{$key}_id", $row ) ) {
if ( !$db ) {
throw new InvalidArgumentException(
"\$row does not contain fields needed for comment $key and getComment(), but "
__METHOD__
);
}
- if ( !$row2 && $tempTableStage < MIGRATION_NEW && array_key_exists( "{$key}_pk", $row ) ) {
+ if ( !$row2 && ( $tempTableStage & SCHEMA_COMPAT_READ_OLD ) &&
+ array_key_exists( "{$key}_pk", $row )
+ ) {
if ( !$db ) {
throw new InvalidArgumentException(
"\$row does not contain fields needed for comment $key and getComment(), but "
$cid = $row2->comment_id;
$text = $row2->comment_text;
$data = $row2->comment_data;
- } elseif ( $this->stage < MIGRATION_NEW && array_key_exists( "{$key}_old", $row ) ) {
+ } elseif ( ( $this->stage & SCHEMA_COMPAT_READ_OLD ) &&
+ array_key_exists( "{$key}_old", $row )
+ ) {
$cid = null;
$text = $row["{$key}_old"];
$data = null;
# Truncate comment in a Unicode-sensitive manner
$comment->text = $this->lang->truncateForVisual( $comment->text, self::COMMENT_CHARACTER_LIMIT );
- if ( $this->stage > MIGRATION_OLD && !$comment->id ) {
+ if ( ( $this->stage & SCHEMA_COMPAT_WRITE_NEW ) && !$comment->id ) {
$dbData = $comment->data;
if ( !$comment->message instanceof RawMessage ) {
if ( $dbData === null ) {
$comment = $this->createComment( $dbw, $comment, $data );
- if ( $this->stage <= MIGRATION_WRITE_BOTH ) {
+ if ( $this->stage & SCHEMA_COMPAT_WRITE_OLD ) {
$fields[$key] = $this->lang->truncateForDatabase( $comment->text, 255 );
}
- if ( $this->stage >= MIGRATION_WRITE_BOTH ) {
+ if ( $this->stage & SCHEMA_COMPAT_WRITE_NEW ) {
$tempTableStage = isset( $this->tempTables[$key] )
? $this->tempTables[$key]['stage'] : MIGRATION_NEW;
- if ( $tempTableStage <= MIGRATION_WRITE_BOTH ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_WRITE_OLD ) {
$t = $this->tempTables[$key];
$func = __METHOD__;
$commentId = $comment->id;
);
};
}
- if ( $tempTableStage >= MIGRATION_WRITE_BOTH ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_WRITE_NEW ) {
$fields["{$key}_id"] = $comment->id;
}
}
$tempTableStage = isset( $this->tempTables[$key] )
? $this->tempTables[$key]['stage'] : MIGRATION_NEW;
- if ( $tempTableStage < MIGRATION_WRITE_NEW ) {
+ if ( $tempTableStage & SCHEMA_COMPAT_WRITE_OLD ) {
throw new InvalidArgumentException( "Must use insertWithTempTable() for $key" );
}
try {
$this->main();
} catch ( ErrorPageError $e ) {
+ $out = $this->context->getOutput();
+ // TODO: Should ErrorPageError::report accept a OutputPage parameter?
+ $e->report( ErrorPageError::STAGE_OUTPUT );
+
// T64091: while exceptions are convenient to bubble up GUI errors,
// they are not internal application faults. As with normal requests, this
// should commit, print the output, do deferred updates, jobs, and profiling.
$this->doPreOutputCommit();
- $e->report(); // display the GUI error
+ $out->output(); // display the GUI error
}
} catch ( Exception $e ) {
$context = $this->context;
$titlesByPageId = [];
foreach ( $rows as $row ) {
if ( isset( $rowsByRevId[$row->rev_id] ) ) {
- throw new InvalidArgumentException( "Duplicate rows in newRevisionsFromBatch {$row->rev_id}" );
+ $result->warning(
+ 'internalerror',
+ "Duplicate rows in newRevisionsFromBatch, rev_id {$row->rev_id}"
+ );
}
if ( $title && $row->rev_page != $title->getArticleID() ) {
throw new InvalidArgumentException(
$res = $this->select( __METHOD__ );
if ( is_null( $resultPageSet ) ) {
+ $this->executeGenderCacheFromResultWrapper( $res, __METHOD__ );
+
$count = 0;
foreach ( $res as $row ) {
if ( ++$count > $params['limit'] ) {
* @file
*/
+use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\IResultWrapper;
);
}
+ /**
+ * Preprocess the result set to fill the GenderCache with the necessary information
+ * before using self::addTitleInfo
+ *
+ * @param IResultWrapper $res Result set to work on.
+ * The result set must have _namespace and _title fields with the provided field prefix
+ * @param string $fname The caller function name, always use __METHOD__
+ * @param string $fieldPrefix Prefix for fields to check gender for
+ */
+ protected function executeGenderCacheFromResultWrapper(
+ IResultWrapper $res, $fname = __METHOD__, $fieldPrefix = 'page'
+ ) {
+ if ( !$res->numRows() ) {
+ return;
+ }
+
+ $services = MediaWikiServices::getInstance();
+ $nsInfo = $services->getNamespaceInfo();
+ $namespaceField = $fieldPrefix . '_namespace';
+ $titleField = $fieldPrefix . '_title';
+
+ $usernames = [];
+ foreach ( $res as $row ) {
+ if ( $nsInfo->hasGenderDistinction( $row->$namespaceField ) ) {
+ $usernames[] = $row->$titleField;
+ }
+ }
+
+ if ( $usernames === [] ) {
+ return;
+ }
+
+ $genderCache = $services->getGenderCache();
+ $genderCache->doQuery( $usernames, $fname );
+ }
+
/** @} */
/************************************************************************//**
*/
class BadRequestError extends ErrorPageError {
- public function report() {
+ public function report( $action = self::SEND_OUTPUT ) {
global $wgOut;
$wgOut->setStatusCode( 400 );
- parent::report();
+ parent::report( $action );
}
}
* @ingroup Exception
*/
class ErrorPageError extends MWException implements ILocalizedException {
+ const SEND_OUTPUT = 0;
+ const STAGE_OUTPUT = 1;
public $title, $msg, $params;
/**
return wfMessage( $this->msg, $this->params );
}
- public function report() {
+ public function report( $action = self::SEND_OUTPUT ) {
if ( self::isCommandLine() || defined( 'MW_API' ) ) {
parent::report();
} else {
global $wgOut;
$wgOut->showErrorPage( $this->title, $this->msg, $this->params );
- $wgOut->output();
+ // Allow skipping of the final output step, so that web-based page views
+ // from MediaWiki.php, can inspect the staged OutputPage state, and perform
+ // graceful shutdown via doPreOutputCommit first, just like for regular
+ // output when there isn't an error page.
+ if ( $action === self::SEND_OUTPUT ) {
+ $wgOut->output();
+ }
}
}
}
parent::__construct( 'permissionserrors', Message::newFromSpecifier( $errors[0] ) );
}
- public function report() {
+ public function report( $action = self::SEND_OUTPUT ) {
global $wgOut;
$wgOut->showPermissionsErrorPage( $this->errors, $this->permission );
- $wgOut->output();
+ if ( $action === self::SEND_OUTPUT ) {
+ $wgOut->output();
+ }
}
}
);
}
- public function report() {
+ public function report( $action = ErrorPageError::SEND_OUTPUT ) {
global $wgOut;
$wgOut->setStatusCode( 429 );
- parent::report();
+ parent::report( $action );
}
}
* Redirect to Special:Userlogin if the specified message is compatible. Otherwise,
* show an error page as usual.
*/
- public function report() {
+ public function report( $action = self::SEND_OUTPUT ) {
// If an unsupported message is used, don't try redirecting to Special:Userlogin,
// since the message may not be compatible.
if ( !in_array( $this->msg, LoginHelper::getValidErrorMessages() ) ) {
- parent::report();
+ parent::report( $action );
return;
}
'warning' => $this->msg,
] ) );
- $output->output();
+ if ( $action === self::SEND_OUTPUT ) {
+ $output->output();
+ }
}
}
);
}
- public function report() {
+ public function report( $action = self::SEND_OUTPUT ) {
global $wgOut;
$wgOut->setStatusCode( 429 );
- parent::report();
+ parent::report( $action );
}
}
*/
public function setTitle( $t ) {
if ( !$t ) {
- $t = Title::newFromText( 'NO TITLE' );
+ $t = Title::makeTitle( NS_SPECIAL, 'Badtitle/Parser' );
}
if ( $t->hasFragment() ) {
"tog-numberheadings": "isinin nomor murda anggen cara otomatis",
"tog-editondblclick": "sunting lembar nganggen klik kaping pindo",
"tog-editsectiononrightclick": "sayagayang panyuntingan kepahan anggen ngeklik tengen ring kepahan judul",
- "tog-watchcreations": "imbuhin lembar sane karyanin titiang ring kepahan pangiwasan",
+ "tog-watchcreations": "Tambeh kaca sané kardi titiang miwah berkas sané unggah titiang ring pangawasan titiang",
"tog-watchdefault": "imbuhin lembar panyuntingansane sunting titiang ring kepahan pangiwasan",
- "tog-watchmoves": "imbuhang lembar sane kakisidang titiang ring kepahan pangiwasan",
+ "tog-watchmoves": "Tambeh kaca miwan berkas sané gingsirang titiang ring pangawasan titiang",
"tog-watchdeletion": "imbuhin lembar sane kaapus ring kepahan pangiwasan",
- "tog-watchuploads": "Tambehin berkas anyar sané unggah tiang ka pupulan pantaun\nTambahkan berkas baru yang saya unggah ke daftar pantauan",
+ "tog-watchuploads": "Tambeh berkas anyar sané unggah titiang ring pangawasan titiang",
"tog-watchrollback": "Tambehin kaca sané sampun uliang tiang ka tengah pupulan pantauan tiangé",
"tog-minordefault": "pingetin samian suntingan dados suntingan alit sane ajeg",
"tog-previewontop": "tampilang pratayang sadurung kotak sunting lan nenten sadurungnyane",
"authors": [
"C.R.",
"E. abu Filumena",
- "SabineCretella"
+ "SabineCretella",
+ "Sannita"
]
},
"exif-imagewidth": "Larghezza",
"exif-imagedescription": "Titulo 'e l'immaggene",
"exif-make": "Frabbeca ca muntaje 'a camera",
"exif-model": "Mudello d' 'a camera",
- "exif-software": "Software ausàto",
+ "exif-software": "Software ausato",
"exif-artist": "Autore",
"exif-copyright": "Titolare d' 'o Copyright",
- "exif-exifversion": "Verzione d'Exif",
+ "exif-exifversion": "Verzione 'e ll'exif",
"exif-flashpixversion": "Verziona Flashpix suppurtata",
"exif-colorspace": "Spazio d' 'e culore",
"exif-componentsconfiguration": "Significato d'ogne componente",
"version-specialpages": "Toimintosivut",
"version-parserhooks": "Jäsenninkytkökset",
"version-variables": "Muuttujat",
- "version-editors": "Muokkaajat",
+ "version-editors": "Muokkaimet",
"version-antispam": "Roskalinkkien estäminen",
"version-other": "Muut",
"version-mediahandlers": "Median käsittelijät",
"thursday": "jeudi",
"friday": "vendredi",
"saturday": "samedi",
- "sun": "Dim.",
- "mon": "Lun.",
- "tue": "Mar.",
- "wed": "Mer.",
- "thu": "Jeu.",
- "fri": "Ven.",
- "sat": "Sam.",
+ "sun": "dim.",
+ "mon": "lun.",
+ "tue": "mar.",
+ "wed": "mer.",
+ "thu": "jeu.",
+ "fri": "ven.",
+ "sat": "sam.",
"january": "janvier",
"february": "février",
"march": "mars",
"ipblocklist-legend": "Cerca un utente bloccato",
"blocklist-userblocks": "Nascondi i blocchi degli utenti registrati",
"blocklist-tempblocks": "Nascondi i blocchi temporanei",
+ "blocklist-indefblocks": "Nascondi blocchi infiniti",
"blocklist-addressblocks": "Nascondi i blocchi di un solo IP",
"blocklist-type": "Tipo:",
"blocklist-type-opt-all": "Tutto",
"password-login-forbidden": "Šī lietotājvārda un paroles izmantošana ir aizliegta.",
"mailmypassword": "Atiestatīt paroli",
"passwordremindertitle": "Jauna pagaidu parole no {{SITENAME}}s",
- "passwordremindertext": "Kāds (iespējams, Tu pats, no IP adreses $1)\nlūdza, lai nosūtām Tev jaunu {{SITENAME}} ($4) paroli.\nLietotajam $2 pagaidu parole tagad ir $3.\nLudzu, nomaini paroli, kad esi veiksmīgi iekļuvis iekšš.\nTavas pagaidu paroles derīguma termiņš beigsies pēc {{PLURAL:$5|$5 dienām|$5 dienas|$5 dienām}}.\n\nJa paroles pieprasījumu bija nosūtījis kāds cits, vai arī tu atcerējies savu veco paroli, šo var ignorēt. Vecā parole joprojām darbojas.",
+ "passwordremindertext": "Kāds (no IP adreses $1)\nlūdza, lai nosūtām tev jaunu {{SITENAME}} ($4) paroli.\nLietotajam $2 izveidota pagaidu parole $3. Ja tāds bija tavs mērķis, tagad tev jāpieslēdzas un jānomaina parole. Tavas pagaidu paroles derīguma termiņš beigsies pēc {{PLURAL:$5|$5 dienām|$5 dienas|$5 dienām}}.\n\nJa paroles pieprasījumu bija nosūtījis kāds cits, vai arī tu atcerējies savu veco paroli, šo var ignorēt. Vecā parole joprojām darbojas.",
"noemail": "Lietotājs \"$1\" nav reģistrējis e-pasta adresi.",
"noemailcreate": "Tev jānorāda derīgu e-pasta adresi",
"passwordsent": "Esam nosūtījuši jaunu paroli uz e-pasta adresi, kuru ir norādījis lietotājs $1. Lūdzu, nāc iekšā ar jauno paroli, kad būsi to saņēmis.",
"protect": "Prutegge",
"protect_change": "càgna",
"unprotect": "Càgna prutezzione",
- "newpage": "Paggena nòva",
+ "newpage": "Paggena nova",
"talkpagelinktext": "Chiàcchiera",
"specialpage": "Paggena speciàle",
"personaltools": "Strumiente perzonale",
"shown-title": "Fa verè {{PLURAL:$1|nu risultato|$1 risultate}} pe paggena",
"viewprevnext": "Vire ($1 {{int:pipe-separator}} $2) ($3).",
"searchmenu-exists": "'''Ncopp' 'o sito esiste na paggena c' 'o nomme \"[[:$1]]\"'''\n{{PLURAL:$2|0=|Vedite pure dint'a l'ati risultate 'e cerca.}}",
- "searchmenu-new": "<strong>'''Crèa 'a paggena \"[[:$1]]\" ncopp'a stu wiki!'''</strong> {{PLURAL:$2|0=|Vedite pure 'a paggena truvata c' 'a recerca vuosta|Vedite pure 'e risultate d\"a recerca}}",
+ "searchmenu-new": "<strong>'''Crèa 'a paggena \"[[:$1]]\" ncopp'a sta wiki!'''</strong> {{PLURAL:$2|0=|Vedite pure 'a paggena truvata c' 'a recerca vuosta|Vedite pure 'e risultate d' 'a recerca}}",
"searchprofile-articles": "Paggene 'e contenute",
"searchprofile-images": "Multimedia",
"searchprofile-everything": "Tutto",
"right-suppressionlog": "Vide 'e riggistre private",
"right-block": "Nun fa fa' cagnamienti a ll'at'utente",
"right-blockemail": "Nun fa mannà e-mail a n'utente",
- "right-hideuser": "Blocca n'utente e fallo sparì 'a 'o pubbreco",
+ "right-hideuser": "Fremma n'utente e annascunnillo r'o pubbreco",
"right-ipblock-exempt": "Ignora 'e blocche 'e l'IP, 'e blocche automatece e li blocche 'e range 'e l'IP",
"right-unblockself": "Sblocca se stesso",
"right-protect": "Cagna 'e livelle 'e prutezione 'e cagna paggene prutette ricurzivamente",
"right-mergehistory": "Aunisce 'a cronologgia d' 'e paggene",
"right-userrights": "Cagna 'e deritte 'e ll'utente",
"right-userrights-interwiki": "Cagna 'e deritte 'e ll'utente int'a l'ati wiki",
- "right-siteadmin": "Blocca e sblocca 'o database",
+ "right-siteadmin": "Chiure e arape 'o database",
"right-override-export-depth": "Esporta 'e paggene azzeccanno 'e paggene cullegate nfin'a na profondità 'e 5",
"right-sendemail": "Manna na mail a ll'at'utente",
"right-managechangetags": "Crìa e appiccia/stuta 'e [[Special:Tags|tag]]",
"uploadlogpage": "Riggistro 'e carreche",
"uploadlogpagetext": "Ccà abbascio song'alencate l'urdeme file carrecate.\nCuntrullate 'a [[Special:NewFiles|gallaria d' 'e file nuove]] pe' ve ffà na guardata cchiù visuale 'e tutto.",
"filename": "Nomme d' 'o file",
- "filedesc": "Énnece",
+ "filedesc": "Riepilego",
"fileuploadsummary": "Dettaglie:",
"filereuploadsummary": "Cagnamiente a 'o file:",
"filestatus": "Stato d' 'o copyright:",
"tog-watchlisthideminor": "చిన్న మార్పులను నా వీక్షణా జాబితాలో చూపించొద్దు",
"tog-watchlisthideliu": "లాగిన్ ఐన వాడుకరులు చేసే మార్పులను వీక్షణా జాబితాలో చూపించకు",
"tog-watchlistreloadautomatically": "ఫిల్టరు మారినప్పుడెల్లా వీక్షణ జాబితాను తిరిగి లోడు చెయ్యి (JavaScript అవసరం)",
+ "tog-watchlistunwatchlinks": "మార్పులు జరిగిన వీక్షణ పేజీలకు నేరుగా వీక్షించు/వద్దు సూచికలను ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) చేర్చు (టాగుల్ చెయాలంటే JavaScript ఆవశ్యకం)",
"tog-watchlisthideanons": "అజ్ఞాత వాడుకరుల మార్పులను వీక్షణా జాబితాలో చూపించకు",
"tog-watchlisthidepatrolled": "నిఘా ఉన్న మార్పులను వీక్షణజాబితా నుంచి దాచిపెట్టు",
"tog-watchlisthidecategorization": "పేజీ వర్గీకరణను దాచు",
"tog-useeditwarning": "ఏదైనా పేజీని నేను వదిలివెళ్తున్నప్పుడు దానిలో భద్రపరచని మార్పులు ఉంటే నన్ను హెచ్చరించు",
"tog-prefershttps": "లాగిన్ అయి ఉన్నప్పుడెల్లా భద్ర కనెక్షనునే వాడు",
"tog-showrollbackconfirmation": "రోల్బ్యాక్ లింకును నొక్కినపుడు నిర్ధారించుకునే సందేశాన్ని చూపించు",
+ "tog-requireemail": "సంకేతపదం మార్చుకోడానికి ఈమెయిలు ఆవశ్యకం",
"underline-always": "ఎల్లప్పుడూ",
"underline-never": "ఎప్పటికీ వద్దు",
"underline-default": "అలంకారపు లేదా విహారిణి అప్రమేయం",
"createaccountmail": "ఏదో ఒక తాత్కాలిక సంకేతపదాన్ని వాడి దాన్ని పేర్కొన్న ఈమెయిలు చిరునామాకు పంపించు",
"createaccountmail-help": "సంకేతపదం తెలుసుకోనవసరం లేకుండా వేరొకరి కోసం ఖాతా సృష్టించేందుకు వాడవచ్చు.",
"createacct-realname": "అసలు పేరు (ఐచ్చికం)",
- "createacct-reason": "కారణం",
+ "createacct-reason": "కారణం (అందరికీ కనిపిస్తుంది)",
"createacct-reason-ph": "మీరు మరో ఖాతాను ఎందుకు సృష్టించుకుంటున్నారు",
"createacct-reason-help": "సృష్టించిన ఖాతాల చిట్టాలో చూపించే సందేశం",
"createacct-submit": "మీ ఖాతాను సృష్టించుకోండి",
"botpasswords": "బాట్ సంకేతపదాలు",
"botpasswords-disabled": "బాట్ సంకేతపదాలను అచేతనం చేసాం.",
"botpasswords-no-central-id": "బాఅత్ సంకేతపదాలను వాడాలంటే, మీరు ఒక కేంద్రీకృత ఖాతాలోకి లాగినవ్వాలి.",
+ "botpasswords-existing": "ప్రస్తుతం ఉన్న బాట్ సంకేతపదాలు",
"botpasswords-createnew": "ఓ కొత్త బాట్ సంకేతపదాన్ని సృష్టించండి",
"botpasswords-editexisting": "ఉనికిలో ఉన్న బాట్ సంకేతపదాన్ని మార్చండి",
+ "botpasswords-label-needsreset": "(సంకేతపదాన్ని మార్చాల్సిన అవసరం ఉంది)",
"botpasswords-label-appid": "బాట్ పేరు:",
"botpasswords-label-create": "సృష్టించు",
"botpasswords-label-update": "తాజాకరించు",
return $store;
}
+ /**
+ * @dataProvider provideConstructor
+ * @param int $stage
+ * @param string|null $exceptionMsg
+ */
+ public function testConstructor( $stage, $exceptionMsg ) {
+ try {
+ $m = new CommentStore( Language::factory( 'qqx' ), $stage );
+ if ( $exceptionMsg !== null ) {
+ $this->fail( 'Expected exception not thrown' );
+ }
+ $this->assertInstanceOf( CommentStore::class, $m );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame( $exceptionMsg, $ex->getMessage() );
+ }
+ }
+
+ public static function provideConstructor() {
+ return [
+ [ 0, '$stage must include a write mode' ],
+ [ SCHEMA_COMPAT_READ_OLD, '$stage must include a write mode' ],
+ [ SCHEMA_COMPAT_READ_NEW, '$stage must include a write mode' ],
+ [ SCHEMA_COMPAT_READ_BOTH, '$stage must include a write mode' ],
+
+ [ SCHEMA_COMPAT_WRITE_OLD, '$stage must include a read mode' ],
+ [ SCHEMA_COMPAT_WRITE_OLD | SCHEMA_COMPAT_READ_OLD, null ],
+ [ SCHEMA_COMPAT_WRITE_OLD | SCHEMA_COMPAT_READ_NEW, null ],
+ [ SCHEMA_COMPAT_WRITE_OLD | SCHEMA_COMPAT_READ_BOTH, null ],
+
+ [ SCHEMA_COMPAT_WRITE_NEW, '$stage must include a read mode' ],
+ [ SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_OLD, null ],
+ [ SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_NEW, null ],
+ [ SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_BOTH, null ],
+
+ [ SCHEMA_COMPAT_WRITE_BOTH, '$stage must include a read mode' ],
+ [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, null ],
+ [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, null ],
+ [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_BOTH, null ],
+ ];
+ }
+
/**
* @dataProvider provideGetFields
* @param int $stage
MIGRATION_NEW, 'ipb_reason',
[ 'ipb_reason_id' => 'ipb_reason_id' ],
],
+ 'Simple table, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'ipb_reason',
+ [ 'ipb_reason_text' => 'ipb_reason', 'ipb_reason_data' => 'NULL', 'ipb_reason_cid' => 'NULL' ],
+ ],
+ 'Simple table, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'ipb_reason',
+ [ 'ipb_reason_id' => 'ipb_reason_id' ],
+ ],
'Revision, old' => [
MIGRATION_OLD, 'rev_comment',
MIGRATION_NEW, 'rev_comment',
[ 'rev_comment_pk' => 'rev_id' ],
],
+ 'Revision, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rev_comment',
+ [
+ 'rev_comment_text' => 'rev_comment',
+ 'rev_comment_data' => 'NULL',
+ 'rev_comment_cid' => 'NULL',
+ ],
+ ],
+ 'Revision, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rev_comment',
+ [ 'rev_comment_pk' => 'rev_id' ],
+ ],
'Image, old' => [
MIGRATION_OLD, 'img_description',
'img_description_id' => 'img_description_id'
],
],
+ 'Image, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'img_description',
+ [
+ 'img_description_text' => 'img_description',
+ 'img_description_data' => 'NULL',
+ 'img_description_cid' => 'NULL',
+ ],
+ ],
+ 'Image, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'img_description',
+ [
+ 'img_description_id' => 'img_description_id'
+ ],
+ ],
];
}
],
],
],
+ 'Simple table, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'ipb_reason', [
+ 'tables' => [],
+ 'fields' => [
+ 'ipb_reason_text' => 'ipb_reason',
+ 'ipb_reason_data' => 'NULL',
+ 'ipb_reason_cid' => 'NULL',
+ ],
+ 'joins' => [],
+ ],
+ ],
+ 'Simple table, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'ipb_reason', [
+ 'tables' => [ 'comment_ipb_reason' => 'comment' ],
+ 'fields' => [
+ 'ipb_reason_text' => 'comment_ipb_reason.comment_text',
+ 'ipb_reason_data' => 'comment_ipb_reason.comment_data',
+ 'ipb_reason_cid' => 'comment_ipb_reason.comment_id',
+ ],
+ 'joins' => [
+ 'comment_ipb_reason' => [ 'JOIN', 'comment_ipb_reason.comment_id = ipb_reason_id' ],
+ ],
+ ],
+ ],
'Revision, old' => [
MIGRATION_OLD, 'rev_comment', [
],
],
],
+ 'Revision, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rev_comment', [
+ 'tables' => [],
+ 'fields' => [
+ 'rev_comment_text' => 'rev_comment',
+ 'rev_comment_data' => 'NULL',
+ 'rev_comment_cid' => 'NULL',
+ ],
+ 'joins' => [],
+ ],
+ ],
+ 'Revision, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rev_comment', [
+ 'tables' => [
+ 'temp_rev_comment' => 'revision_comment_temp',
+ 'comment_rev_comment' => 'comment',
+ ],
+ 'fields' => [
+ 'rev_comment_text' => 'comment_rev_comment.comment_text',
+ 'rev_comment_data' => 'comment_rev_comment.comment_data',
+ 'rev_comment_cid' => 'comment_rev_comment.comment_id',
+ ],
+ 'joins' => [
+ 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ],
+ 'comment_rev_comment' => [ 'JOIN',
+ 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ],
+ ],
+ ],
+ ],
'Image, old' => [
MIGRATION_OLD, 'img_description', [
],
],
],
+ 'Image, write-both/read-old' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'img_description', [
+ 'tables' => [],
+ 'fields' => [
+ 'img_description_text' => 'img_description',
+ 'img_description_data' => 'NULL',
+ 'img_description_cid' => 'NULL',
+ ],
+ 'joins' => [],
+ ],
+ ],
+ 'Image, write-both/read-new' => [
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'img_description', [
+ 'tables' => [
+ 'comment_img_description' => 'comment',
+ ],
+ 'fields' => [
+ 'img_description_text' => 'comment_img_description.comment_text',
+ 'img_description_data' => 'comment_img_description.comment_data',
+ 'img_description_cid' => 'comment_img_description.comment_id',
+ ],
+ 'joins' => [
+ 'comment_img_description' => [ 'JOIN',
+ 'comment_img_description.comment_id = img_description_id',
+ ],
+ ],
+ ],
+ ],
];
}
MIGRATION_NEW ],
MIGRATION_WRITE_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW, MIGRATION_NEW ],
MIGRATION_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW, MIGRATION_NEW ],
+
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD => [
+ MIGRATION_OLD, SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, MIGRATION_NEW
+ ],
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW => [
+ MIGRATION_OLD, SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, MIGRATION_NEW
+ ],
];
foreach ( $stages as $writeStage => $possibleReadStages ) {
$fields = $wstore->insert( $this->db, $key, $comment, $data );
}
- if ( $writeStage <= MIGRATION_WRITE_BOTH ) {
+ if ( $writeStage & SCHEMA_COMPAT_WRITE_OLD ) {
$this->assertSame( $expect['text'], $fields[$key], "old field, stage=$writeStage" );
} else {
$this->assertArrayNotHasKey( $key, $fields, "old field, stage=$writeStage" );
}
- if ( $writeStage >= MIGRATION_WRITE_BOTH && !$usesTemp ) {
+ if ( ( $writeStage & SCHEMA_COMPAT_WRITE_NEW ) && !$usesTemp ) {
$this->assertArrayHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
} else {
$this->assertArrayNotHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
$queryInfo['joins']
);
+ $expectForCombination = (
+ ( $writeStage & SCHEMA_COMPAT_WRITE_BOTH ) === SCHEMA_COMPAT_WRITE_OLD ||
+ ( $readStage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD
+ ) ? $expectOld : $expect;
$this->assertComment(
- $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+ $expectForCombination,
$rstore->getCommentLegacy( $this->db, $key, $fieldRow ),
"w=$writeStage, r=$readStage, from getFields()"
);
$this->assertComment(
- $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+ $expectForCombination,
$rstore->getComment( $key, $joinRow ),
"w=$writeStage, r=$readStage, from getJoin()"
);
MIGRATION_NEW ],
MIGRATION_WRITE_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW, MIGRATION_NEW ],
MIGRATION_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW, MIGRATION_NEW ],
+
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD => [
+ MIGRATION_OLD, SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, MIGRATION_NEW
+ ],
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW => [
+ MIGRATION_OLD, SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, MIGRATION_NEW
+ ],
];
foreach ( $stages as $writeStage => $possibleReadStages ) {
$fields = $wstore->insert( $this->db, $comment, $data );
}
- if ( $writeStage <= MIGRATION_WRITE_BOTH ) {
+ if ( $writeStage & SCHEMA_COMPAT_WRITE_OLD ) {
$this->assertSame( $expect['text'], $fields[$key], "old field, stage=$writeStage" );
} else {
$this->assertArrayNotHasKey( $key, $fields, "old field, stage=$writeStage" );
}
- if ( $writeStage >= MIGRATION_WRITE_BOTH && !$usesTemp ) {
+ if ( ( $writeStage & SCHEMA_COMPAT_WRITE_NEW ) && !$usesTemp ) {
$this->assertArrayHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
} else {
$this->assertArrayNotHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
$queryInfo['joins']
);
+ $expectForCombination = (
+ ( $writeStage & SCHEMA_COMPAT_WRITE_BOTH ) === SCHEMA_COMPAT_WRITE_OLD ||
+ ( $readStage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_OLD
+ ) ? $expectOld : $expect;
$this->assertComment(
- $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+ $expectForCombination,
$rstore->getCommentLegacy( $this->db, $fieldRow ),
"w=$writeStage, r=$readStage, from getFields()"
);
$this->assertComment(
- $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+ $expectForCombination,
$rstore->getComment( $joinRow ),
"w=$writeStage, r=$readStage, from getJoin()"
);
'MIGRATION_WRITE_BOTH' => [ MIGRATION_WRITE_BOTH ],
'MIGRATION_WRITE_NEW' => [ MIGRATION_WRITE_NEW ],
'MIGRATION_NEW' => [ MIGRATION_NEW ],
+
+ 'SCHEMA_COMPAT write-both/read-old' => [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD ],
+ 'SCHEMA_COMPAT write-both/read-new' => [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW ],
];
}
/** @var Revision $rev1 */
$rev1 = $editStatus->getValue()['revision'];
- $this->setExpectedException( InvalidArgumentException::class );
- MediaWikiServices::getInstance()->getRevisionStore()
+ $status = MediaWikiServices::getInstance()->getRevisionStore()
->newRevisionsFromBatch( [ $this->revisionToRow( $rev1 ), $this->revisionToRow( $rev1 ) ] );
+
+ $this->assertFalse( $status->isGood() );
+ $this->assertTrue( $status->hasMessage( 'internalerror' ) );
}
}