r69730 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r69729‎ | r69730 | r69731 >
Date:14:14, 22 July 2010
Author:peter17
Status:resolved (Comments)
Tags:
Comment:
iwtransclusion code updated according to the remarks about r69723, except about caching (will come later)
Modified paths:
  • /branches/iwtransclusion/phase3/includes/Interwiki.php (modified) (history)
  • /branches/iwtransclusion/phase3/includes/Revision.php (modified) (history)
  • /branches/iwtransclusion/phase3/includes/parser/Parser.php (modified) (history)

Diff [purge]

Index: branches/iwtransclusion/phase3/includes/Interwiki.php
@@ -261,16 +261,9 @@
262262
263263 /**
264264 * Transclude an interwiki link.
265 - * TODO: separate in interwikiTranscludeFromDB & interwikiTranscludeFromAPI according to the iw type
266265 */
267266 public static function interwikiTransclude( $title ) {
268 -
269 - global $wgEnableScaryTranscluding;
270 -
271 - if ( !$wgEnableScaryTranscluding ) {
272 - return wfMsg('scarytranscludedisabled');
273 - }
274 -
 267+
275268 // If we have a wikiID, we will use it to get an access to the remote database
276269 // if not, we will use the API URL to retrieve the data through a HTTP Get
277270
@@ -279,25 +272,20 @@
280273
281274 if ( $wikiID !== '') {
282275
283 - $finalText = self::fetchTemplateFromDB( $wikiID, $title->getNamespace(), $title->getDBkey());
284 - $subTemplates = self::fetchSubTemplatesListFromDB( $wikiID, $title->getNamespace(), $title->getDBkey());
285 -
286 - foreach ($subTemplates as $template) {
287 - $listSubTemplates.=$template['namespace'].':'.$template['title']."\n";
288 - $list2.="<h2>".$template['title']."</h2>\n<pre>".self::fetchTemplateFromDB( $wikiID, $template['namespace'], $template['title'])."</pre>";
289 - }
 276+ $finalText = self::fetchTemplateFromDB( $wikiID, $title );
 277+ return $finalText;
290278
291279 } else if( $transAPI !== '' ) {
 280+
 281+ $fullTitle = $title->getNsText().':'.$title->getText();
292282
293283 $url1 = $transAPI."?action=query&prop=revisions&titles=$fullTitle&rvprop=content&format=json";
294284
295285 if ( strlen( $url1 ) > 255 ) {
296 - return wfMsg( 'Interwiki-transclusion-url-too-long' );
 286+ return false;
297287 }
298288
299 - $text = self::fetchTemplateHTTPMaybeFromCache( $url1 );
300 -
301 - $fullTitle = $title->getNsText().':'.$title->getText();
 289+ $finalText = self::fetchTemplateHTTPMaybeFromCache( $url1 );
302290
303291 $url2 = $transAPI."?action=parse&text={{".$fullTitle."}}&prop=templates&format=json";
304292
@@ -308,98 +296,35 @@
309297 $templates = $myArray['parse']['templates'];
310298 }
311299
312 -
313 - // TODO: The templates are retrieved one by one.
314 - // We should split the templates in two groups: up-to-date and out-of-date
315 - // Only the second group would be retrieved through the API or DB request
 300+ // TODO: The templates are retrieved one by one. We should get them all in 1 request
 301+ // Here, we preload and cache the subtemplates
316302 for ($i = 0 ; $i < count( $templates ) ; $i++) {
317303 $newTitle = $templates[$i]['*'];
318304
319305 $url = $transAPI."?action=query&prop=revisions&titles=$newTitle&rvprop=content&format=json";
320306
321 - $listSubTemplates.= $newTitle."\n";
322 - $list2.="<h2>".$newTitle."</h2>\n<pre>".self::fetchTemplateHTTPMaybeFromCache( $url )."</pre>";
 307+ // $newText is unused, but requesting it will put the template in the cache
 308+ $newText = self::fetchTemplateHTTPMaybeFromCache( $url );
323309
324310 }
 311+ return $finalText;
325312
326 - $finalText = "$url1\n$url2\n$text";
327 -
328 - } else {
329 - return wfMsg( 'Interwiki-transclusion-failed' );
330313 }
331 -
332 - return "<h2>$fullTitle</h2><pre>$finalText</pre> List of templates: <pre>".$listSubTemplates.'</pre>' . $list2;
 314+ return false;
333315 }
334316
335 - public static function fetchTemplateFromDB ( $wikiID, $namespace, $DBkey ) {
 317+ public static function fetchTemplateFromDB ( $wikiID, $title ) {
336318
337 - try {
338 - $dbr = wfGetDb( DB_SLAVE, array(), $wikiID );
339 - } catch (Exception $e) {
340 - return wfMsg( 'Failed-to-connect-the-distant-DB' );
341 - }
 319+ $revision = Revision::loadFromTitleForeignWiki( $wikiID, $title );
342320
343 - $fields = array('old_text', 'page_id');
344 - $res = $dbr->select(
345 - array( 'page', 'revision', 'text' ),
346 - $fields,
347 - array( 'rev_id=page_latest',
348 - 'page_namespace' => $namespace,
349 - 'page_title' => $DBkey,
350 - 'page_id=rev_page',
351 - 'rev_text_id=old_id'),
352 - null,
353 - array( 'LIMIT' => 1 )
354 - );
355 -
356 - $obj = $dbr->resultObject( $res );
357 -
358 - if ( $obj ) {
359 - $row = $obj->fetchObject();
360 - $obj->free();
361 -
362 - if( $row ) {
363 - $res = new Revision( $row );
364 - $articleID = $res->mTextRow->page_id;
365 - $text = $articleID."\n".$res->mTextRow->old_text;
366 - }
 321+ if ( $revision ) {
 322+ $text = $revision->getText();
 323+ return $text;
367324 }
368325
369 - return $text;
 326+ return false;
370327 }
371328
372 - public static function fetchSubTemplatesListFromDB ( $wikiID, $namespace, $DBkey ) {
373 -
374 - try {
375 - $dbr = wfGetDb( DB_SLAVE, array(), $wikiID );
376 - } catch (Exception $e) {
377 - return wfMsg( 'Failed-to-connect-the-distant-DB' );
378 - }
379 -
380 - $fields = array('tl_namespace', 'tl_title');
381 - $res = $dbr->select(
382 - array( 'page', 'templatelinks' ),
383 - $fields,
384 - array( 'page_namespace' => $namespace,
385 - 'page_title' => $DBkey,
386 - 'tl_from=page_id' )
387 - );
388 -
389 - $obj = $dbr->resultObject( $res );
390 -
391 - if ( $obj ) {
392 -
393 - $listTemplates = array();
394 -
395 - while ($row = $obj->fetchObject() ) {
396 - $listTemplates[] = array( 'namespace' => $row->tl_namespace, 'title' => $row->tl_title );
397 - }
398 - $obj->free();
399 - }
400 -
401 - return $listTemplates;
402 - }
403 -
404329 public static function fetchTemplateHTTPMaybeFromCache( $url ) {
405330 global $wgTranscludeCacheExpiry;
406331 $dbr = wfGetDB( DB_SLAVE );
@@ -429,7 +354,7 @@
430355 $dbw = wfGetDB( DB_MASTER );
431356 $dbw->replace( 'transcache', array('tc_url'), array(
432357 'tc_url' => $url,
433 - 'tc_time' => $dbw->timestamp( time() ),
 358+ 'tc_time' => $dbw->timestamp( ),
434359 'tc_contents' => $text)
435360 );
436361
Index: branches/iwtransclusion/phase3/includes/Revision.php
@@ -121,6 +121,30 @@
122122 }
123123
124124 /**
 125+ * Stores the origin wiki of a revision in case it is a foreign wiki
 126+ */
 127+ function setWikiID( $wikiID ) {
 128+ $this->mWikiID = $wikiID;
 129+ }
 130+
 131+ /**
 132+ * Load the current revision of a given page of a foreign wiki.
 133+ * The WikiID is stored for further use, such as loadText() and getTimestampFromId()
 134+ */
 135+ public static function loadFromTitleForeignWiki( $wikiID, $title ) {
 136+ $dbr = wfGetDB( DB_SLAVE, array(), $wikiID );
 137+
 138+ $revision = self::loadFromTitle( $dbr, $title );
 139+
 140+ if( $revision ) {
 141+ $revision->setWikiID( $wikiID );
 142+ }
 143+
 144+ return $revision;
 145+
 146+ }
 147+
 148+ /**
125149 * Load either the current, or a specified, revision
126150 * that's attached to a given page. If not attached
127151 * to that page, will return null.
@@ -358,6 +382,7 @@
359383 throw new MWException( 'Revision constructor passed invalid row format.' );
360384 }
361385 $this->mUnpatrolled = null;
 386+ $this->mWikiID = false;
362387 }
363388
364389 /**
@@ -405,7 +430,8 @@
406431 if( isset( $this->mTitle ) ) {
407432 return $this->mTitle;
408433 }
409 - $dbr = wfGetDB( DB_SLAVE );
 434+ $dbr = wfGetDB( DB_SLAVE, array(), $this->mWikiID );
 435+
410436 $row = $dbr->selectRow(
411437 array( 'page', 'revision' ),
412438 array( 'page_namespace', 'page_title' ),
@@ -545,7 +571,7 @@
546572 if( $this->mUnpatrolled !== null ) {
547573 return $this->mUnpatrolled;
548574 }
549 - $dbr = wfGetDB( DB_SLAVE );
 575+ $dbr = wfGetDB( DB_SLAVE, array(), $this->mWikiID );
550576 $this->mUnpatrolled = $dbr->selectField( 'recentchanges',
551577 'rc_id',
552578 array( // Add redundant user,timestamp condition so we can use the existing index
@@ -899,7 +925,7 @@
900926
901927 if( !$row ) {
902928 // Text data is immutable; check slaves first.
903 - $dbr = wfGetDB( DB_SLAVE );
 929+ $dbr = wfGetDB( DB_SLAVE, array(), $this->mWikiID );
904930 $row = $dbr->selectRow( 'text',
905931 array( 'old_text', 'old_flags' ),
906932 array( 'old_id' => $this->getTextId() ),
@@ -908,7 +934,7 @@
909935
910936 if( !$row && wfGetLB()->getServerCount() > 1 ) {
911937 // Possible slave lag!
912 - $dbw = wfGetDB( DB_MASTER );
 938+ $dbw = wfGetDB( DB_MASTER, array(), $this->mWikiID );
913939 $row = $dbw->selectRow( 'text',
914940 array( 'old_text', 'old_flags' ),
915941 array( 'old_id' => $this->getTextId() ),
@@ -1020,7 +1046,7 @@
10211047 * @return String
10221048 */
10231049 static function getTimestampFromId( $title, $id ) {
1024 - $dbr = wfGetDB( DB_SLAVE );
 1050+ $dbr = wfGetDB( DB_SLAVE, array(), $this->mWikiID );
10251051 // Casting fix for DB2
10261052 if ( $id == '' ) {
10271053 $id = 0;
@@ -1030,7 +1056,7 @@
10311057 $timestamp = $dbr->selectField( 'revision', 'rev_timestamp', $conds, __METHOD__ );
10321058 if ( $timestamp === false && wfGetLB()->getServerCount() > 1 ) {
10331059 # Not in slave, try master
1034 - $dbw = wfGetDB( DB_MASTER );
 1060+ $dbw = wfGetDB( DB_MASTER, array(), $this->mWikiID );
10351061 $timestamp = $dbw->selectField( 'revision', 'rev_timestamp', $conds, __METHOD__ );
10361062 }
10371063 return wfTimestamp( TS_MW, $timestamp );
Index: branches/iwtransclusion/phase3/includes/parser/Parser.php
@@ -3167,12 +3167,15 @@
31683168 } elseif ( $title->isTrans() ) {
31693169 // TODO: Work by Peter17 in progress
31703170
3171 - $text = Interwiki::interwikiTransclude( $title );
 3171+ $text = Interwiki::interwikiTransclude( $title );
 3172+
 3173+ if ( $text !== false ) {
31723174 # Preprocess it like a template
31733175 $text = $this->preprocessToDom( $text, self::PTD_FOR_INCLUSION );
 3176+ $found = true;
31743177 $isChildObj = true;
 3178+ }
31753179
3176 - $found = true;
31773180 }
31783181
31793182 # Do infinite loop check

Follow-up revisions

RevisionCommit summaryAuthorDate
r69746Batch caching for API-retrieved templates, as requested in r69730peter1719:43, 22 July 2010
r69781Negative caching of API-retrieved templates (as requested in r69746) + prefix...peter1709:11, 23 July 2010
r87105Merge r69541, r69723, r69730reedy00:25, 29 April 2011
r92986Merge r87105, Which is a merge of r69541, r69723, r69730reedy17:23, 24 July 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r69723iwtransclusion code moved from Parser.php to Interwiki.php; now able to retri...peter1709:48, 22 July 2010

Comments

#Comment by Catrope (talk | contribs)   15:27, 22 July 2010
 			if ( strlen( $url1 ) > 255 ) {
-				return wfMsg( 'Interwiki-transclusion-url-too-long' );
+				return false;
 			}

Now that you're no longer using the transcache table with a varchar(255) field for the URL, you no longer need to do this.

+			$fullTitle = $title->getNsText().':'.$title->getText();

There's $title->getPrefixedText() for this, which also doesn't have the flaw of putting in the : for titles in the main namespace.

 			$url2 = $transAPI."?action=parse&text={{".$fullTitle."}}&prop=templates&format=json";

That's a rather nasty way to get templates, because it forces the parser to parse the template on the remote wiki. You should use ?action=query&prop=templates instead because that uses the templatelinks table. There's Title::getPrefixedText() for this, which also doesn't have the flaw of returning an extra : for pages in the main namespace.

 			$url1 = $transAPI."?action=query&prop=revisions&titles=$fullTitle&rvprop=content&format=json";

It would be good style (and prevent escaping nightmares) to build the query string with wfArrayToCGI().

 			for ($i = 0 ; $i < count( $templates ) ; $i++) {

You can use foreach ( $templates as $template ) in PHP.

+				// $newText is unused, but requesting it will put the template in the cache
+				$newText = self::fetchTemplateHTTPMaybeFromCache( $url );

So this requests each template separately. It would be nicer to request them in batches of 50 with &titles=Foo|Bar|Baz syntax. That'd need a little refactoring here and there though (of fetchTemplateHTTPMaybeFromCache, for instance). Batched fetching is the only way prefetching is gonna help at all: otherwise you might as well delay this until the moment the parser finds out it needs a template.

+		$this->mWikiID = $wikiID;

Please declare private $mWikiID; as a member explicitly near the top of the class.

#Comment by Peter17 (talk | contribs)   19:43, 22 July 2010

> There's $title->getPrefixedText() for this, which also doesn't have the flaw of putting in the : for titles in the main namespace.

$title->getPrefixedText() will also include the interwiki prefix, which I don't want...

> Please declare private $mWikiID; as a member explicitly near the top of the class.

Ok to do this, but I can't find the list of the members of this class... They seem to be declared only in the constructor, Revision(). Weird.

#Comment by Catrope (talk | contribs)   20:08, 22 July 2010

Right, $title is interwiki. In that case getText() will include the namespace prefix and getNsText() willl be empty.

Oh, so they're not declared. No problem then, as long as your field is declared in the constructor.

#Comment by Peter17 (talk | contribs)   21:41, 22 July 2010

For $title->getNsText().':'.$title->getText():

  • {{mediawikiwiki::User:Peter17}} gives ":User:Peter17" (correct, except the initial ':')
  • {{wikipedia:Paris-geo-stub}} gives "Template:Paris-geo-stub" (correct)

For $title->getText():

  • {{mediawikiwiki::User:Peter17}} gives "User:Peter17" (correct)
  • {{wikipedia:Paris-geo-stub}} gives "Paris-geo-stub" (incorrect)
#Comment by Catrope (talk | contribs)   05:35, 23 July 2010

Meh. Title doesn't seem to have an appropriate method for this, so I guess the best way to handle this is something like ( $title->getNamespace() != NS_MAIN ? '' : $title->getNsText() . ':' ) . $title->getText(). Probably worth creating a Title method for, something like getPrefixedTextWithoutInterwiki() but with a less horrible name.

Status & tagging log