r68594 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r68593‎ | r68594 | r68595 >
Date:00:25, 26 June 2010
Author:werdna
Status:resolved (Comments)
Tags:
Comment:
LiquidThreads: Import data from XML dumps
Modified paths:
  • /trunk/extensions/LiquidThreads/LiquidThreads.php (modified) (history)
  • /trunk/extensions/LiquidThreads/classes/Hooks.php (modified) (history)
  • /trunk/extensions/LiquidThreads/classes/Thread.php (modified) (history)
  • /trunk/extensions/LiquidThreads/lqt.sql (modified) (history)

Diff [purge]

Index: trunk/extensions/LiquidThreads/LiquidThreads.php
@@ -66,6 +66,10 @@
6767 $wgHooks['OAIFetchRowsQuery'][] = 'LqtHooks::modifyOAIQuery';
6868 $wgHooks['OAIFetchRecordQuery'][] = 'LqtHooks::modifyOAIQuery';
6969
 70+// Import-related
 71+$wgHooks['ImportHandlePageXMLTag'][] = 'LqtHooks::handlePageXMLTag';
 72+$wgHooks['AfterImportPage'][] = 'LqtHooks::afterImportPage';
 73+
7074 // Deletion
7175 $wgHooks['ArticleDeleteComplete'][] = 'LqtDeletionController::onArticleDeleteComplete';
7276 $wgHooks['ArticleRevisionUndeleted'][] = 'LqtDeletionController::onArticleRevisionUndeleted';
Index: trunk/extensions/LiquidThreads/classes/Thread.php
@@ -41,7 +41,7 @@
4242 protected $rootRevision;
4343
4444 /* Flag about who has edited or replied to this thread. */
45 - protected $editedness;
 45+ public $editedness;
4646 protected $editors = null;
4747
4848 protected $replies;
@@ -122,6 +122,10 @@
123123
124124 function insert() {
125125 $this->dieIfHistorical();
 126+
 127+ if ( $this->id() ) {
 128+ throw new MWException( "Attempt to insert a thread that already exists." );
 129+ }
126130
127131 $dbw = wfGetDB( DB_MASTER );
128132
Index: trunk/extensions/LiquidThreads/classes/Hooks.php
@@ -7,6 +7,18 @@
88 public static $editArticle = null;
99 public static $editTalkpage = null;
1010 public static $scriptVariables = array();
 11+
 12+ public static $editedStati = array(
 13+ Threads::EDITED_NEVER => 'never',
 14+ Threads::EDITED_HAS_REPLY => 'has-reply',
 15+ Threads::EDITED_BY_AUTHOR => 'by-author',
 16+ Threads::EDITED_BY_OTHERS => 'by-others'
 17+ );
 18+ public static $threadTypes = array(
 19+ Threads::TYPE_NORMAL => 'normal',
 20+ Threads::TYPE_MOVED => 'moved',
 21+ Threads::TYPE_DELETED => 'deleted'
 22+ );
1123
1224 static function customizeOldChangesList( &$changeslist, &$s, $rc ) {
1325 if ( $rc->getTitle()->getNamespace() != NS_LQT_THREAD )
@@ -157,44 +169,35 @@
158170 }
159171
160172 static function dumpThreadData( $writer, &$out, $row, $title ) {
161 - $editedStati = array(
162 - Threads::EDITED_NEVER => 'never',
163 - Threads::EDITED_HAS_REPLY => 'has-reply',
164 - Threads::EDITED_BY_AUTHOR => 'by-author',
165 - Threads::EDITED_BY_OTHERS => 'by-others'
166 - );
167 - $threadTypes = array(
168 - Threads::TYPE_NORMAL => 'normal',
169 - Threads::TYPE_MOVED => 'moved',
170 - Threads::TYPE_DELETED => 'deleted'
171 - );
172 -
173173 // Is it a thread
174 - if ( !empty( $row->thread_id ) ) {
175 - $thread = Thread::newFromRow( $row );
176 - $threadInfo = "\n";
177 - $attribs = array();
178 - $attribs['ThreadSubject'] = $thread->subject();
179 - if ( $thread->hasSuperThread() ) {
180 - $attribs['ThreadParent'] = $thread->superThread()->id();
181 - }
182 - $attribs['ThreadAncestor'] = $thread->topmostThread()->id();
183 - $attribs['ThreadPage'] = $thread->getTitle()->getPrefixedText();
184 - $attribs['ThreadID'] = $thread->id();
185 - if ( $thread->hasSummary() && $thread->summary() ) {
186 - $attribs['ThreadSummaryPage'] = $thread->summary()->getId();
187 - }
188 - $attribs['ThreadAuthor'] = $thread->author()->getName();
189 - $attribs['ThreadEditStatus'] = $editedStati[$thread->editedness()];
190 - $attribs['ThreadType'] = $threadTypes[$thread->type()];
 174+ if ( empty( $row->thread_id ) ) {
 175+ return true;
 176+ }
 177+
 178+ $thread = Thread::newFromRow( $row );
 179+ $threadInfo = "\n";
 180+ $attribs = array();
 181+ $attribs['ThreadSubject'] = $thread->subject();
 182+ if ( $thread->hasSuperThread() ) {
 183+ $attribs['ThreadParent'] = $thread->superThread()->title()->getPrefixedText();
 184+ $attribs['ThreadAncestor'] = $thread->topmostThread()->title()->getPrefixedText();
 185+ }
 186+ $attribs['ThreadPage'] = $thread->getTitle()->getPrefixedText();
 187+ $attribs['ThreadID'] = $thread->id();
 188+ if ( $thread->hasSummary() && $thread->summary() ) {
 189+ $attribs['ThreadSummaryPage'] = $thread->summary()->getTitle()->getPrefixedText();
 190+ }
 191+ $attribs['ThreadAuthor'] = $thread->author()->getName();
 192+ $attribs['ThreadEditStatus'] = self::$editedStati[$thread->editedness()];
 193+ $attribs['ThreadType'] = self::$threadTypes[$thread->type()];
 194+ $attribs['ThreadSignature'] = $thread->signature();
191195
192 - foreach ( $attribs as $key => $value ) {
193 - $threadInfo .= "\t" . Xml::element( $key, null, $value ) . "\n";
194 - }
195 -
196 - $out .= Xml::tags( 'DiscussionThreading', null, $threadInfo ) . "\n";
 196+ foreach ( $attribs as $key => $value ) {
 197+ $threadInfo .= "\t" . Xml::element( $key, null, $value ) . "\n";
197198 }
198199
 200+ $out .= Xml::tags( 'DiscussionThreading', null, $threadInfo ) . "\n";
 201+
199202 return true;
200203 }
201204
@@ -573,4 +576,197 @@
574577 return '';
575578 }
576579 }
 580+
 581+ /**
 582+ * Handles tags in Page sections of XML dumps
 583+ */
 584+
 585+ public static function handlePageXMLTag( $reader, &$pageInfo ) {
 586+ if ( !( $reader->nodeType == XmlReader::ELEMENT &&
 587+ $reader->name == 'DiscussionThreading' ) ) {
 588+ return true;
 589+ }
 590+
 591+ $pageInfo['DiscussionThreading'] = array();
 592+ $fields = array(
 593+ 'ThreadSubject',
 594+ 'ThreadParent',
 595+ 'ThreadAncestor',
 596+ 'ThreadPage',
 597+ 'ThreadID',
 598+ 'ThreadSummaryPage',
 599+ 'ThreadAuthor',
 600+ 'ThreadEditStatus',
 601+ 'ThreadType',
 602+ 'ThreadSignature',
 603+ );
 604+
 605+ $skip = false;
 606+
 607+ while ( $skip ? $reader->next() : $reader->read() ) {
 608+ if ( $reader->nodeType == XmlReader::END_ELEMENT &&
 609+ $reader->name == 'DiscussionThreading') {
 610+ break;
 611+ }
 612+
 613+ $tag = $reader->name;
 614+
 615+ if ( in_array( $tag, $fields ) ) {
 616+ $pageInfo['DiscussionThreading'][$tag] = $reader->nodeContents();
 617+ }
 618+ }
 619+
 620+ return false;
 621+ }
 622+
 623+ // Processes discussion threading data in XML dumps (extracted in handlePageXMLTag).
 624+ public static function afterImportPage( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) {
 625+ // in-process cache of pending thread relationships
 626+ static $pendingRelationships = null;
 627+
 628+ if ( $pendingRelationships === null ) {
 629+ $pendingRelationships = self::loadPendingRelationships();
 630+ }
 631+
 632+ $titlePendingRelationships = array();
 633+ if ( isset($pendingRelationships[$title->getPrefixedText()]) ) {
 634+ $titlePendingRelationships = $pendingRelationships[$title->getPrefixedText()];
 635+
 636+ foreach( $titlePendingRelationships as $k => $v ) {
 637+ if ( $v['type'] == 'article' ) {
 638+ self::applyPendingArticleRelationship( $v, $title );
 639+ unset( $titlePendingRelationships[$k] );
 640+ }
 641+ }
 642+ }
 643+
 644+ if ( ! isset( $pageInfo['DiscussionThreading'] ) ) {
 645+ return true;
 646+ }
 647+
 648+ $statusValues = array_flip( self::$editedStati );
 649+ $typeValues = array_flip( self::$threadTypes );
 650+
 651+ $info = $pageInfo['DiscussionThreading'];
 652+
 653+ $root = new Article( $title );
 654+ $article = new Article( Title::newFromText( $info['ThreadPage'] ) );
 655+ $type = $typeValues[$info['ThreadType']];
 656+ $editedness = $statusValues[$info['ThreadEditStatus']];
 657+ $subject = $info['ThreadSubject'];
 658+ $summary = wfMsgForContent( 'lqt-imported' );
 659+
 660+ $signature = null;
 661+ if ( isset( $info['ThreadSignature'] ) ) {
 662+ $signature = $info['ThreadSignature'];
 663+ }
 664+
 665+ $thread = Thread::create( $root, $article, null, $type,
 666+ $subject, $summary, null, $signature );
 667+
 668+ if ( isset( $info['ThreadSummaryPage'] ) ) {
 669+ $summaryPageName = $info['ThreadSummaryPage'];
 670+ $summaryPage = new Article( Title::newFromText( $summaryPageName ) );
 671+ if ( $summaryPage->exists() ) {
 672+ $thread->setSummaryPage( $summaryPage );
 673+ } else {
 674+ self::addPendingRelationship( $thread->id(), 'thread_summary_page',
 675+ $summaryPageName, 'article', $pendingRelationships );
 676+ }
 677+ }
 678+
 679+ if ( isset( $info['ThreadParent'] ) ) {
 680+ $threadPageName = $info['ThreadParent'];
 681+ $parentArticle = new Article( Title::newFromText( $threadPageName ) );
 682+ $superthread = Threads::withRoot( $parentArticle );
 683+
 684+ if ( $superthread ) {
 685+ $thread->setSuperthread( $superthread );
 686+ } else {
 687+ self::addPendingRelationship( $thread->id(), 'thread_parent',
 688+ $threadPageName, 'thread', $pendingRelationships );
 689+ }
 690+ }
 691+
 692+ $thread->save();
 693+
 694+ foreach( $titlePendingRelationships as $k => $v ) {
 695+ if ( $v['type'] == 'thread' ) {
 696+ self::applyPendingThreadRelationship( $pendingRelationship, $thread );
 697+ unset( $titlePendingRelationships[$k] );
 698+ }
 699+ }
 700+
 701+ return true;
 702+ }
 703+
 704+ public static function applyPendingThreadRelationship( $pendingRelationship, $thread ) {
 705+ if ( $pendingRelationship['relationship'] == 'thread_parent' ) {
 706+ $childThread = Threads::withID( $pendingRelationship['thread'] );
 707+
 708+ $childThread->setSuperthread( $thread );
 709+ $childThread->save();
 710+ $thread->save();
 711+ }
 712+ }
 713+
 714+ public static function applyPendingArticleRelationship( $pendingRelationship, $title ) {
 715+ $articleID = $title->getArticleId();
 716+
 717+ $dbw = wfGetDB( DB_MASTER );
 718+
 719+ $dbw->update( 'thread', array( $pendingRelationship['relationship'] => $articleID ),
 720+ array( 'thread_id' => $pendingRelationship['thread'] ),
 721+ __METHOD__ );
 722+
 723+ $dbw->delete( 'thread_pending_relationship',
 724+ array( 'tpr_title' => $pendingRelationship['title'] ), __METHOD__ );
 725+ }
 726+
 727+ public static function loadPendingRelationships() {
 728+ $dbr = wfGetDB( DB_MASTER );
 729+ $arr = array();
 730+
 731+ $res = $dbr->select( 'thread_pending_relationship', '*', array(1), __METHOD__ );
 732+
 733+ foreach( $res as $row ) {
 734+ $entry = array(
 735+ 'thread' => $row->tpr_thread,
 736+ 'relationship' => $row->tpr_relationship,
 737+ 'title' => $row->tpr_title,
 738+ 'type' => $row->tpr_type,
 739+ );
 740+
 741+ if ( !isset($arr[$title]) ) {
 742+ $arr[$title] = array();
 743+ }
 744+
 745+ $arr[$title][] = $entry;
 746+ }
 747+
 748+ return $arr;
 749+ }
 750+
 751+ public static function addPendingRelationship( $thread, $relationship, $title, $type, &$array ) {
 752+ $entry = array(
 753+ 'thread' => $thread,
 754+ 'relationship' => $relationship,
 755+ 'title' => $title,
 756+ 'type' => $type,
 757+ );
 758+
 759+ $row = array();
 760+ foreach( $entry as $k => $v ) {
 761+ $row['tpr_'.$k] = $v;
 762+ }
 763+
 764+ $dbw = wfGetDB( DB_MASTER );
 765+ $dbw->insert( 'thread_pending_relationship', $row, __METHOD__ );
 766+
 767+ if ( !isset( $array[$title] ) ) {
 768+ $array[$title] = array();
 769+ }
 770+
 771+ $array[$title][] = $entry;
 772+ }
577773 }
Index: trunk/extensions/LiquidThreads/lqt.sql
@@ -86,3 +86,12 @@
8787 KEY (th_timestamp,th_thread),
8888 KEY (th_user,th_user_text)
8989 ) /*$wgDBTableOptions*/;
 90+
 91+-- Storage for "pending" relationships from import
 92+CREATE TABLE /*_*/thread_pending_relationship (
 93+ tpr_thread int unsigned NOT NULL,
 94+ tpr_relationship varbinary(64) NOT NULL,
 95+ tpr_title varbinary(1024) NOT NULL,
 96+ tpr_type varbinary(32) NOT NULL,
 97+ PRIMARY KEY (tpr_thread,tpr_relationship)
 98+) /*$wgDBTableOptions*/;

Follow-up revisions

RevisionCommit summaryAuthorDate
r80541Fix FIXME on r68594.werdna00:21, 19 January 2011

Comments

#Comment by Reedy (talk | contribs)   12:26, 27 October 2010
		foreach( $titlePendingRelationships as $k => $v ) {
			if ( $v['type'] == 'thread' ) {
				self::applyPendingThreadRelationship( $pendingRelationship, $thread );
				unset( $titlePendingRelationships[$k] );
			}
		}
</pre?

$pendingRelationship is undefined
#Comment by Reedy (talk | contribs)   21:54, 11 January 2011

Double fixme

2011-01-11 18:21:23 failed First-pass for page XML data dumps Fatal error: Call to a member function getPrefixedText() on a non-object in /usr/local/apache/common-local/wmf-deployment/extensions/LiquidThreads/classes/Hooks.php on line 180

#Comment by Reedy (talk | contribs)   22:08, 11 January 2011

Linking back to the bug logged for this one - bug 26673

#Comment by Werdna (talk | contribs)   00:23, 19 January 2011

Both fixed.

Status & tagging log