r68579 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r68578‎ | r68579 | r68580 >
Date:18:43, 25 June 2010
Author:nikerabbit
Status:ok
Tags:
Comment:
Add untested maintenance script to check contents of page translation tables
Modified paths:
  • /trunk/extensions/Translate/scripts/pagetranslation-check-database.php (added) (history)

Diff [purge]

Index: trunk/extensions/Translate/scripts/pagetranslation-check-database.php
@@ -0,0 +1,209 @@
 2+<?php
 3+/**
 4+ * Script to check the consistency of the databases of the page translation
 5+ * feature and fix problems.
 6+ *
 7+ * @author Niklas Laxstrom
 8+ * @copyright Copyright © 2010, Niklas Laxström
 9+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 10+ * @file
 11+ */
 12+
 13+// Standard boilerplate to define $IP
 14+if ( getenv( 'MW_INSTALL_PATH' ) !== false ) {
 15+ $IP = getenv( 'MW_INSTALL_PATH' );
 16+} else {
 17+ $dir = dirname( __FILE__ ); $IP = "$dir/../../..";
 18+}
 19+require_once( "$IP/maintenance/Maintenance.php" );
 20+
 21+class PTCheckDB extends Maintenance {
 22+ public function __construct() {
 23+ parent::__construct();
 24+ $this->mDescription = 'Check the consistency of the databases of the page translation feature and fix problems.';
 25+ $this->addOption( 'fix', 'Fix the found problems if possible' );
 26+ }
 27+
 28+ public function execute() {
 29+ $fixes = $this->checkSectionTable();
 30+ $fixes += $this->checkRevTagTable();
 31+
 32+ $dbw = wfGetDB( DB_MASTER );
 33+ if ( $this->getOption( 'fix' ) ) {
 34+ $this->output( "Performing the following fixes:\n" );
 35+ foreach ( $fixes as $name => $data ) {
 36+ $this->output( "$name: $data[0]...", $name );
 37+ $dbw->delete( $data[1], '*', $data[2], __METHOD__ );
 38+ }
 39+ } else {
 40+ $this->output( "Use --fix to perform following fixes:\n" );
 41+ foreach ( $fixes as $name => $data ) {
 42+ $sql = $dbw->selectSQLtext( $data[1], '*', $data[2] );
 43+ $sql = preg_replace( '~^SELECT~', 'DELETE', $sql );
 44+ $this->output( "$name: $data[0] - $sql\n" );
 45+
 46+ }
 47+ }
 48+ }
 49+
 50+ protected function checkSectionTable() {
 51+ $fixes = array();
 52+
 53+ $dbr = wfGetDB( DB_SLAVE );
 54+ $pages = $dbr->select( 'translate_sections', 'trs_page', null, __METHOD__, array( 'GROUP BY' => 'trs_page' ) );
 55+ $this->output( "Found {$pages->numRows()} pages in the section table\n" );
 56+ $this->output( "Checking that they match a valid translatable page...\n\n" );
 57+ foreach ( $pages as $row ) {
 58+ $id = $row->trs_page;
 59+ $sections = $dbr->select( 'translate_sections', 'trs_key', array( 'trs_page' => $id ), __METHOD__ );
 60+ $title = Title::newFromID( $id );
 61+ $sectionNames = $this->getSectionNames( $sections );
 62+
 63+ $name = $title ? $title->getPrefixedText() : "#$id";
 64+ $this->output( "Page $name has {$sections->numRows()} sections [$sectionNames]\n" );
 65+
 66+ if ( !$title ) {
 67+ $name = "#$id";
 68+ $deleted = $this->findDeletedPage( $id );
 69+ if ( $deleted === false ) {
 70+ $this->output( "Page id $id does not correspond to any page\n" );
 71+ } else {
 72+ $name .= "<$deleted>";
 73+ $this->output( "Page id $id corresponds to a deleted page $deleted\n" );
 74+ }
 75+ $fixes["$name <sections>"] = array( 'delete sections', 'translate_section', array( 'trs_page' => $id ) );
 76+ } else {
 77+ $name = $title->getPrefixedText();
 78+ $page = TranslatablePage::newFromTitle( $title );
 79+ $tagged = $page->getReadyTag();
 80+ $marked = $page->getMarkedTag();
 81+ $latest = $title->getLatestRevId();
 82+ $this->output( "Revision numbers: <tagged, marked, latest> <$tagged, $marked, $latest>\n" );
 83+ if ( strval($marked) === '' ) {
 84+ $this->output( "These sections do not belong the current page (anymore?)\n" );
 85+ $fixes["$name <sections>"] = array( 'delete sections', 'translate_section', array( 'trs_page' => $id ) );
 86+ }
 87+ }
 88+
 89+ $this->output( "\n" );
 90+ }
 91+ return $fixes;
 92+ }
 93+
 94+ protected function checkRevTagTable() {
 95+ $fixes = array();
 96+
 97+ $dbr = wfGetDB( DB_SLAVE );
 98+
 99+ $result = $dbr->select( 'revtag_type', '*', null, __METHOD__ );
 100+ $idToTag = array();
 101+ foreach ( $result as $_ ) $idToTag[$_->rtt_id] = $_->rtt_name;
 102+ $tagToId = array_flip($idToTag);
 103+
 104+ $pages = $dbr->select( 'revtag', 'rt_page', null, __METHOD__, array( 'GROUP BY' => 'rt_page' ) );
 105+ $this->output( "Checking that tags match a valid page...\n\n" );
 106+ foreach ( $pages as $row ) {
 107+ $id = $row->rt_page;
 108+ $title = Title::newFromID( $id );
 109+ $name = $title ? $title->getPrefixedText() : "#$id";
 110+
 111+
 112+ if ( !$title ) {
 113+ $name = "#$id";
 114+ $deleted = $this->findDeletedPage( $id );
 115+ if ( $deleted === false ) {
 116+ $this->output( "Page id $id does not correspond to any page\n" );
 117+ $fixes["$name <revtag>"] = array( 'delete tags', 'revtag', array( 'rt_page' => $id ) );
 118+ } else {
 119+ $name .= "<$deleted>";
 120+ }
 121+ }
 122+ }
 123+
 124+ $this->output( "Checked {$pages->numRows()} pages in the revtag table\n" );
 125+ $this->output( "\n\nValidating tags...\n" );
 126+
 127+ $result = $dbr->select( 'revtag', '*', null, __METHOD__ );
 128+ $transver = $tagToId['tp:transver'];
 129+
 130+ foreach ( $result as $_ ) {
 131+ if ( !isset( $idToTag[$_->rt_type] ) ) {
 132+ $name = $this->idToName( $_->rt_page );
 133+ $this->output( "Page $name has unknown tag {$_->rt_type}\n" );
 134+ $fixes["$name <revtag:unknown:{$_->rt_type}>"] =
 135+ array( 'delete tag', 'revtag', array( 'rt_page' => $id, 'rt_type' => $_->rt_type ) );
 136+ continue;
 137+ } elseif ( $_->rt_type === $transver ) {
 138+ $check = $this->checkTransrevRevision( $rev );
 139+ if ( $check !== true ) {
 140+ $name = $this->idToName( $_->rt_page );
 141+ $this->output( "Page $name has invalid tp:transver: $check\n" );
 142+ $fixes["$name <revtag:transver>"] =
 143+ array( 'delete tag', 'revtag', array( 'rt_page' => $id, 'rt_type' => $_->rt_type ) );
 144+ }
 145+ }
 146+ }
 147+
 148+ $this->output( "Checked {$result->numRows()} tags in the revtag table\n\n\n" );
 149+ return $fixes;
 150+ }
 151+
 152+ protected function idToName( $id ) {
 153+ $title = Title::newFromID( $id );
 154+ $name = $title ? $title->getPrefixedText() : "#$id";
 155+ if ( !$title ) {
 156+ $name .= $this->findDeletedPage( $id );
 157+ }
 158+
 159+ return $name;
 160+ }
 161+
 162+ protected function getSectionNames( $result ) {
 163+ $names = array();
 164+ foreach ( $result as $section ) {
 165+ $names[] = $section->trs_key;
 166+ }
 167+
 168+ return implode( ', ', $names );
 169+ }
 170+
 171+ protected function findDeletedPage( $id ) {
 172+ $dbr = wfGetDB( DB_SLAVE );
 173+ $page = $dbr->selectRow( 'archive', array( 'ar_namespace', 'ar_title' ),
 174+ array( 'ar_page_id' => $id ), __METHOD__ );
 175+ if ( $page ) {
 176+ $title = Title::makeTitleSafe( $page->ar_namespace, $page->ar_title );
 177+ if ( $title ) {
 178+ return $title->getPrefixedText();
 179+ }
 180+ }
 181+ return false;
 182+ }
 183+
 184+ protected function checkTransrevRevision( $revId ) {
 185+ static $cache = array();
 186+ if ( isset( $cache[$revId] ) ) return $cache[$revId];
 187+
 188+ $revision = Revision::newFromId( $revId );
 189+ if ( !$revision ) {
 190+ $cache[$revId] = 'no such revision';
 191+ } else {
 192+ $title = $revision->getTitle();
 193+ if ( !$title ) {
 194+ $cache[$revId] = 'no title for the revision';
 195+ } else {
 196+ $page = TranslatablePage::newFromTitle( $title );
 197+ if ( $page->getMarkedTag() === false ) {
 198+ $cache[$revId] = 'revision belongs to a page that is not marked for translation';
 199+ } else {
 200+ $cache[$revId] = true;
 201+ }
 202+ }
 203+ }
 204+
 205+ return $cache[$revId];
 206+ }
 207+}
 208+
 209+$maintClass = 'PTCheckDB';
 210+require_once( DO_MAINTENANCE );
Property changes on: trunk/extensions/Translate/scripts/pagetranslation-check-database.php
___________________________________________________________________
Name: svn:eol-style
1211 + native

Status & tagging log