r95396 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r95395‎ | r95396 | r95397 >
Date:13:03, 24 August 2011
Author:reedy
Status:reverted (Comments)
Tags:
Comment:
Merge the iwtransclusion branch back into trunk

Hexmode fixed broken unit tests in revisions after last time
Modified paths:
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/BacklinkCache.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/EditPage.php (modified) (history)
  • /trunk/phase3/includes/GlobalUsageQuery.php (added) (history)
  • /trunk/phase3/includes/Linker.php (modified) (history)
  • /trunk/phase3/includes/LinksUpdate.php (modified) (history)
  • /trunk/phase3/includes/OutputPage.php (modified) (history)
  • /trunk/phase3/includes/Revision.php (modified) (history)
  • /trunk/phase3/includes/SpecialPageFactory.php (modified) (history)
  • /trunk/phase3/includes/Title.php (modified) (history)
  • /trunk/phase3/includes/WikiPage.php (modified) (history)
  • /trunk/phase3/includes/cache/HTMLCacheUpdate.php (modified) (history)
  • /trunk/phase3/includes/db/Database.php (modified) (history)
  • /trunk/phase3/includes/installer/MysqlUpdater.php (modified) (history)
  • /trunk/phase3/includes/installer/SqliteUpdater.php (modified) (history)
  • /trunk/phase3/includes/interwiki/Interwiki.php (modified) (history)
  • /trunk/phase3/includes/parser/Parser.php (modified) (history)
  • /trunk/phase3/includes/parser/ParserOutput.php (modified) (history)
  • /trunk/phase3/includes/parser/Preprocessor_DOM.php (modified) (history)
  • /trunk/phase3/includes/parser/Preprocessor_Hash.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialGlobalFileUsage.php (added) (history)
  • /trunk/phase3/includes/specials/SpecialGlobalTemplateUsage.php (added) (history)
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesQqq.php (modified) (history)
  • /trunk/phase3/maintenance/archives/patch-globalinterwiki.sql (added) (history)
  • /trunk/phase3/maintenance/archives/patch-globalnamespaces.sql (added) (history)
  • /trunk/phase3/maintenance/archives/patch-globaltemplatelinks.sql (added) (history)
  • /trunk/phase3/maintenance/language/messages.inc (modified) (history)
  • /trunk/phase3/maintenance/tables.sql (modified) (history)

Diff [purge]

Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -458,6 +458,8 @@
459459 'Watchlist' => array( 'Watchlist' ),
460460 'Whatlinkshere' => array( 'WhatLinksHere' ),
461461 'Withoutinterwiki' => array( 'WithoutInterwiki' ),
 462+ 'Globalfileusage' => array( 'GlobalFileUsage' ),
 463+ 'Globaltemplateusage' => array( 'GlobalTemplateUsage' ),
462464 );
463465
464466 /**
@@ -1402,6 +1404,9 @@
14031405 'templatesused' => '{{PLURAL:$1|Template|Templates}} used on this page:',
14041406 'templatesusedpreview' => '{{PLURAL:$1|Template|Templates}} used in this preview:',
14051407 'templatesusedsection' => '{{PLURAL:$1|Template|Templates}} used in this section:',
 1408+'distanttemplatesused' => 'Distant {{PLURAL:$1|template|templates}} used on this page:',
 1409+'distanttemplatesusedpreview' => 'Distant {{PLURAL:$1|template|templates}} used in this preview:',
 1410+'distanttemplatesusedsection' => 'Distant {{PLURAL:$1|template|templates}} used in this section:',
14061411 'template-protected' => '(protected)',
14071412 'template-semiprotected' => '(semi-protected)',
14081413 'hiddencategories' => 'This page is a member of {{PLURAL:$1|1 hidden category|$1 hidden categories}}:',
@@ -4582,6 +4587,30 @@
45834588 'compare-title-not-exists' => 'The title you specified does not exist.',
45844589 'compare-revision-not-exists' => 'The revision you specified does not exist.',
45854590
 4591+# Special:GlobalFileUsage
 4592+'globalfileusage' => 'Global file usage',
 4593+'globalfileusage-for' => 'Global file usage for "$1"',
 4594+'globalfileusage-desc' => '[[Special:GlobalFileUsage|Special page]] to view global file usage',
 4595+'globalfileusage-ok' => 'Search',
 4596+'globalfileusage-text' => 'Search global file usage',
 4597+'globalfileusage-no-results' => '[[$1]] is not used on other wikis.',
 4598+'globalfileusage-on-wiki' => 'Usage on $2',
 4599+'globalfileusage-of-file' => 'The following other wikis use this file:',
 4600+'globalfileusage-more' => 'View [[{{#Special:GlobalUsage}}/$1|more global usage]] of this file.',
 4601+'globalfileusage-filterlocal' => 'Do not show local usage',
 4602+
 4603+# Special:GlobalTemplateUsage
 4604+'globaltemplateusage' => 'Global template usage',
 4605+'globaltemplateusage-for' => 'Global template usage for "$1"',
 4606+'globaltemplateusage-desc' => '[[Special:GlobalTemplateUsage|Special page]] to view global template usage',
 4607+'globaltemplateusage-ok' => 'Search',
 4608+'globaltemplateusage-text' => 'Search global template usage',
 4609+'globaltemplateusage-no-results' => '[[$1]] is not used on other wikis.',
 4610+'globaltemplateusage-on-wiki' => 'Usage on $2',
 4611+'globaltemplateusage-of-file' => 'The following other wikis use this template:',
 4612+'globaltemplateusage-more' => 'View [[{{#Special:GlobalUsage}}/$1|more global usage]] of this template.',
 4613+'globaltemplateusage-filterlocal' => 'Do not show local usage',
 4614+
45864615 # Database error messages
45874616 'dberr-header' => 'This wiki has a problem',
45884617 'dberr-problems' => 'Sorry!
Index: trunk/phase3/languages/messages/MessagesQqq.php
@@ -4259,6 +4259,16 @@
42604260
42614261 {{Identical|Other}}',
42624262
 4263+# Special:GlobalFileUsage
 4264+'globalfileusage-for' => '$1 is a file name',
 4265+'globalfileusage-no-results' => '$1 is a file name',
 4266+'globalfileusage-on-wiki' => '$2 is a wiki name',
 4267+
 4268+# Special:GlobalTemplateUsage
 4269+'globaltemplateusage-for' => '$1 is a template name',
 4270+'globaltemplateusage-no-results' => '$1 is a template name',
 4271+'globaltemplateusage-on-wiki' => '$2 is a wiki name',
 4272+
42634273 # SQLite database support
42644274 'sqlite-has-fts' => 'Shown on Special:Version, $1 is version',
42654275 'sqlite-no-fts' => 'Shown on Special:Version, $1 is version',
Index: trunk/phase3/includes/WikiPage.php
@@ -1604,7 +1604,7 @@
16051605 public function doDeleteArticle(
16061606 $reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null
16071607 ) {
1608 - global $wgDeferredUpdateList, $wgUseTrackbacks, $wgUser;
 1608+ global $wgDeferredUpdateList, $wgUseTrackbacks, $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase, $wgUser;
16091609 $user = is_null( $user ) ? $wgUser : $user;
16101610
16111611 wfDebug( __METHOD__ . "\n" );
@@ -1709,7 +1709,15 @@
17101710 $dbw->delete( 'iwlinks', array( 'iwl_from' => $id ), __METHOD__ );
17111711 $dbw->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ );
17121712 $dbw->delete( 'page_props', array( 'pp_page' => $id ), __METHOD__ );
 1713+
 1714+ if ( $wgEnableInterwikiTemplatesTracking && $wgGlobalDatabase ) {
 1715+ $dbw2 = wfGetDB( DB_MASTER, array(), $wgGlobalDatabase );
 1716+ $dbw2->delete( 'globaltemplatelinks',
 1717+ array( 'gtl_from_wiki' => wfGetID(),
 1718+ 'gtl_from_page' => $id )
 1719+ );
17131720 }
 1721+ }
17141722
17151723 # If using cleanup triggers, we can skip some manual deletes
17161724 if ( !$dbw->cleanupTriggers() ) {
@@ -2213,6 +2221,8 @@
22142222 * @param $title Title object
22152223 */
22162224 public static function onArticleCreate( $title ) {
 2225+ global $wgDeferredUpdateList;
 2226+
22172227 # Update existence markers on article/talk tabs...
22182228 if ( $title->isTalkPage() ) {
22192229 $other = $title->getSubjectPage();
@@ -2226,6 +2236,9 @@
22272237 $title->touchLinks();
22282238 $title->purgeSquid();
22292239 $title->deleteTitleProtection();
 2240+
 2241+ # Invalidate caches of distant articles which transclude this page
 2242+ $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'globaltemplatelinks' );
22302243 }
22312244
22322245 /**
@@ -2234,6 +2247,8 @@
22352248 * @param $title Title
22362249 */
22372250 public static function onArticleDelete( $title ) {
 2251+ global $wgMessageCache, $wgDeferredUpdateList;
 2252+
22382253 # Update existence markers on article/talk tabs...
22392254 if ( $title->isTalkPage() ) {
22402255 $other = $title->getSubjectPage();
@@ -2269,6 +2284,9 @@
22702285
22712286 # Image redirects
22722287 RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect( $title );
 2288+
 2289+ # Invalidate caches of distant articles which transclude this page
 2290+ $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'globaltemplatelinks' );
22732291 }
22742292
22752293 /**
@@ -2283,6 +2301,9 @@
22842302 // Invalidate caches of articles which include this page
22852303 $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'templatelinks' );
22862304
 2305+ // Invalidate caches of distant articles which transclude this page
 2306+ $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'globaltemplatelinks' );
 2307+
22872308 // Invalidate the caches of all pages which redirect here
22882309 $wgDeferredUpdateList[] = new HTMLCacheUpdate( $title, 'redirect' );
22892310
@@ -2325,6 +2346,40 @@
23262347 }
23272348
23282349 /**
 2350+ * Return a list of distant templates used by this article.
 2351+ * Uses the globaltemplatelinks table
 2352+ *
 2353+ * @return Array of Title objects
 2354+ */
 2355+ public function getUsedDistantTemplates() {
 2356+ global $wgGlobalDatabase;
 2357+
 2358+ $result = array();
 2359+
 2360+ if ( $wgGlobalDatabase ) {
 2361+ $id = $this->mTitle->getArticleID();
 2362+
 2363+ if ( $id == 0 ) {
 2364+ return array();
 2365+ }
 2366+
 2367+ $dbr = wfGetDB( DB_SLAVE, array(), $wgGlobalDatabase );
 2368+ $res = $dbr->select( 'globaltemplatelinks',
 2369+ array( 'gtl_to_prefix', 'gtl_to_namespace', 'gtl_to_title' ),
 2370+ array( 'gtl_from_wiki' => wfWikiID( ), 'gtl_from_page' => $id ),
 2371+ __METHOD__ );
 2372+
 2373+ if ( $res !== false ) {
 2374+ foreach ( $res as $row ) {
 2375+ $result[] = Title::makeTitle( $row->gtl_to_namespace, $row->gtl_to_title, null, $row->gtl_to_prefix );
 2376+ }
 2377+ }
 2378+ }
 2379+
 2380+ return $result;
 2381+ }
 2382+
 2383+ /**
23292384 * Returns a list of hidden categories this page is a member of.
23302385 * Uses the page_props and categorylinks tables.
23312386 *
Index: trunk/phase3/includes/GlobalUsageQuery.php
@@ -0,0 +1,368 @@
 2+<?php
 3+/**
 4+ * A helper class to query the globalimagelinks table
 5+ *
 6+ */
 7+class GlobalUsageQuery {
 8+ private $limit = 50;
 9+ private $offset;
 10+ private $hasMore = false;
 11+ private $filterLocal = false;
 12+ private $result;
 13+ private $continue;
 14+ private $reversed = false;
 15+ private $target = null;
 16+
 17+ /**
 18+ * @param $target mixed Title or db key, or array of db keys of target(s)
 19+ */
 20+ public function __construct( $target ) {
 21+ global $wgGlobalDatabase;
 22+ $this->db = wfGetDB( DB_SLAVE, array(), $wgGlobalDatabase );
 23+ if ( $target instanceof Title && $target->getNamespace( ) == NS_FILE ) {
 24+ $this->target = $target->getDBKey();
 25+ } else {
 26+ $this->target = $target;
 27+ }
 28+ $this->offset = array();
 29+
 30+ }
 31+
 32+ /**
 33+ * Set the offset parameter
 34+ *
 35+ * @param $offset string offset
 36+ * @param $reversed bool True if this is the upper offset
 37+ */
 38+ public function setOffset( $offset, $reversed = null ) {
 39+ if ( !is_null( $reversed ) ) {
 40+ $this->reversed = $reversed;
 41+ }
 42+
 43+ if ( !is_array( $offset ) ) {
 44+ $offset = explode( '|', $offset );
 45+ }
 46+
 47+ if ( count( $offset ) == 3 ) {
 48+ $this->offset = $offset;
 49+ return true;
 50+ } else {
 51+ return false;
 52+ }
 53+ }
 54+ /**
 55+ * Return the offset set by the user
 56+ *
 57+ * @return array offset
 58+ */
 59+ public function getOffsetString() {
 60+ return implode( '|', $this->offset );
 61+ }
 62+ /**
 63+ * Is the result reversed
 64+ *
 65+ * @return bool
 66+ */
 67+ public function isReversed() {
 68+ return $this->reversed;
 69+ }
 70+
 71+ /**
 72+ * Returns the string used for continuation in a file search
 73+ *
 74+ * @return string
 75+ *
 76+ */
 77+ public function getContinueFileString() {
 78+ if ( $this->hasMore() ) {
 79+ return "{$this->lastRow->gil_to}|{$this->lastRow->gil_wiki}|{$this->lastRow->gil_page}";
 80+ } else {
 81+ return '';
 82+ }
 83+ }
 84+
 85+ /**
 86+ * Returns the string used for continuation in a template search
 87+ *
 88+ * @return string
 89+ *
 90+ */
 91+ public function getContinueTemplateString() {
 92+ if ( $this->hasMore() ) {
 93+ return "{$this->lastRow->gtl_to_title}|{$this->lastRow->gtl_from_wiki}|{$this->lastRow->gtl_from_page}";
 94+ } else {
 95+ return '';
 96+ }
 97+ }
 98+
 99+ /**
 100+ * Set the maximum amount of items to return. Capped at 500.
 101+ *
 102+ * @param $limit int The limit
 103+ */
 104+ public function setLimit( $limit ) {
 105+ $this->limit = min( $limit, 500 );
 106+ }
 107+ /**
 108+ * Returns the user set limit
 109+ */
 110+ public function getLimit() {
 111+ return $this->limit;
 112+ }
 113+
 114+ /**
 115+ * Set whether to filter out the local usage
 116+ */
 117+ public function filterLocal( $value = true ) {
 118+ $this->filterLocal = $value;
 119+ }
 120+
 121+ /**
 122+ * Executes the query for a file search
 123+ */
 124+ public function searchTemplate() {
 125+ global $wgLocalInterwiki;
 126+
 127+ /* Construct a where clause */
 128+ // Add target template(s)
 129+ $where = array( 'gtl_to_prefix' => $wgLocalInterwiki,
 130+ 'gtl_to_namespace' => $this->target->getNamespace( ),
 131+ 'gtl_to_title' => $this->target->getDBkey( )
 132+ );
 133+
 134+ // Set the continuation condition
 135+ $order = 'ASC';
 136+ if ( $this->offset ) {
 137+ $qTo = $this->db->addQuotes( $this->offset[0] );
 138+ $qWiki = $this->db->addQuotes( $this->offset[1] );
 139+ $qPage = intval( $this->offset[2] );
 140+
 141+ // Check which limit we got in order to determine which way to traverse rows
 142+ if ( $this->reversed ) {
 143+ // Reversed traversal; do not include offset row
 144+ $op1 = '<';
 145+ $op2 = '<';
 146+ $order = 'DESC';
 147+ } else {
 148+ // Normal traversal; include offset row
 149+ $op1 = '>';
 150+ $op2 = '>=';
 151+ $order = 'ASC';
 152+ }
 153+
 154+ $where[] = "(gtl_to_title $op1 $qTo) OR " .
 155+ "(gtl_to_title = $qTo AND gtl_from_wiki $op1 $qWiki) OR " .
 156+ "(gtl_to_title = $qTo AND gtl_from_wiki = $qWiki AND gtl_from_page $op2 $qPage)";
 157+ }
 158+
 159+ /* Perform select (Duh.) */
 160+ $res = $this->db->select(
 161+ array(
 162+ 'globaltemplatelinks',
 163+ 'globalnamespaces'
 164+ ),
 165+ array(
 166+ 'gtl_to_title',
 167+ 'gtl_from_wiki',
 168+ 'gtl_from_page',
 169+ 'gtl_from_namespace',
 170+ 'gtl_from_title'
 171+ ),
 172+ $where,
 173+ __METHOD__,
 174+ array(
 175+ 'ORDER BY' => "gtl_to_title $order, gtl_from_wiki $order, gtl_from_page $order",
 176+ // Select an extra row to check whether we have more rows available
 177+ 'LIMIT' => $this->limit + 1,
 178+ ),
 179+ array(
 180+ 'gtl_from_namespace = gn_namespace'
 181+ )
 182+ );
 183+
 184+ /* Process result */
 185+ // Always return the result in the same order; regardless whether reversed was specified
 186+ // reversed is really only used to determine from which direction the offset is
 187+ $rows = array();
 188+ foreach ( $res as $row ) {
 189+ $rows[] = $row;
 190+ }
 191+ if ( $this->reversed ) {
 192+ $rows = array_reverse( $rows );
 193+ }
 194+
 195+ // Build the result array
 196+ $count = 0;
 197+ $this->hasMore = false;
 198+ $this->result = array();
 199+ foreach ( $rows as $row ) {
 200+ $count++;
 201+ if ( $count > $this->limit ) {
 202+ // We've reached the extra row that indicates that there are more rows
 203+ $this->hasMore = true;
 204+ $this->lastRow = $row;
 205+ break;
 206+ }
 207+
 208+ if ( !isset( $this->result[$row->gtl_to_title] ) ) {
 209+ $this->result[$row->gtl_to_title] = array();
 210+ }
 211+ if ( !isset( $this->result[$row->gtl_to_title][$row->gtl_from_wiki] ) ) {
 212+ $this->result[$row->gtl_to_title][$row->gtl_from_wiki] = array();
 213+ }
 214+
 215+ $this->result[$row->gtl_to_title][$row->gtl_from_wiki][] = array(
 216+ 'template' => $row->gtl_to_title,
 217+ 'id' => $row->gtl_from_page,
 218+ 'namespace' => $row->gn_namespacetext,
 219+ 'title' => $row->gtl_from_title,
 220+ 'wiki' => $row->gtl_from_wiki,
 221+ );
 222+ }
 223+ }
 224+
 225+ /**
 226+ * Executes the query for a template search
 227+ */
 228+ public function searchFile() {
 229+ /* Construct a where clause */
 230+ // Add target image(s)
 231+ $where = array( 'gil_to' => $this->target );
 232+
 233+ if ( $this->filterLocal ) {
 234+ // Don't show local file usage
 235+ $where[] = 'gil_wiki != ' . $this->db->addQuotes( wfWikiId() );
 236+ }
 237+
 238+ // Set the continuation condition
 239+ $order = 'ASC';
 240+ if ( $this->offset ) {
 241+ $qTo = $this->db->addQuotes( $this->offset[0] );
 242+ $qWiki = $this->db->addQuotes( $this->offset[1] );
 243+ $qPage = intval( $this->offset[2] );
 244+
 245+ // Check which limit we got in order to determine which way to traverse rows
 246+ if ( $this->reversed ) {
 247+ // Reversed traversal; do not include offset row
 248+ $op1 = '<';
 249+ $op2 = '<';
 250+ $order = 'DESC';
 251+ } else {
 252+ // Normal traversal; include offset row
 253+ $op1 = '>';
 254+ $op2 = '>=';
 255+ $order = 'ASC';
 256+ }
 257+
 258+ $where[] = "(gil_to $op1 $qTo) OR " .
 259+ "(gil_to = $qTo AND gil_wiki $op1 $qWiki) OR " .
 260+ "(gil_to = $qTo AND gil_wiki = $qWiki AND gil_page $op2 $qPage)";
 261+ }
 262+
 263+ /* Perform select (Duh.) */
 264+ $res = $this->db->select( 'globalimagelinks',
 265+ array(
 266+ 'gil_to',
 267+ 'gil_wiki',
 268+ 'gil_page',
 269+ 'gil_page_namespace',
 270+ 'gil_page_title'
 271+ ),
 272+ $where,
 273+ __METHOD__,
 274+ array(
 275+ 'ORDER BY' => "gil_to $order, gil_wiki $order, gil_page $order",
 276+ // Select an extra row to check whether we have more rows available
 277+ 'LIMIT' => $this->limit + 1,
 278+ )
 279+ );
 280+
 281+ /* Process result */
 282+ // Always return the result in the same order; regardless whether reversed was specified
 283+ // reversed is really only used to determine from which direction the offset is
 284+ $rows = array();
 285+ foreach ( $res as $row ) {
 286+ $rows[] = $row;
 287+ }
 288+ if ( $this->reversed ) {
 289+ $rows = array_reverse( $rows );
 290+ }
 291+
 292+ // Build the result array
 293+ $count = 0;
 294+ $this->hasMore = false;
 295+ $this->result = array();
 296+ foreach ( $rows as $row ) {
 297+ $count++;
 298+ if ( $count > $this->limit ) {
 299+ // We've reached the extra row that indicates that there are more rows
 300+ $this->hasMore = true;
 301+ $this->lastRow = $row;
 302+ break;
 303+ }
 304+
 305+ if ( !isset( $this->result[$row->gil_to] ) ) {
 306+ $this->result[$row->gil_to] = array();
 307+ }
 308+ if ( !isset( $this->result[$row->gil_to][$row->gil_wiki] ) ) {
 309+ $this->result[$row->gil_to][$row->gil_wiki] = array();
 310+ }
 311+
 312+ $this->result[$row->gil_to][$row->gil_wiki][] = array(
 313+ 'image' => $row->gil_to,
 314+ 'id' => $row->gil_page,
 315+ 'namespace' => $row->gil_page_namespace,
 316+ 'title' => $row->gil_page_title,
 317+ 'wiki' => $row->gil_wiki,
 318+ );
 319+ }
 320+ }
 321+
 322+ /**
 323+ * Returns the result set. The result is a 4 dimensional array
 324+ * (file, wiki, page), whose items are arrays with keys:
 325+ * - image or template: File name or template name
 326+ * - id: Page id
 327+ * - namespace: Page namespace text
 328+ * - title: Unprefixed page title
 329+ * - wiki: Wiki id
 330+ *
 331+ * @return array Result set
 332+ */
 333+ public function getResult() {
 334+ return $this->result;
 335+ }
 336+ /**
 337+ * Returns a 3 dimensional array with the result of the first file. Useful
 338+ * if only one resource was queried.
 339+ *
 340+ * For further information see documentation of getResult()
 341+ *
 342+ * @return array Result set
 343+ */
 344+ public function getSingleResult() {
 345+ if ( $this->result ) {
 346+ return current( $this->result );
 347+ } else {
 348+ return array();
 349+ }
 350+ }
 351+
 352+ /**
 353+ * Returns whether there are more results
 354+ *
 355+ * @return bool
 356+ */
 357+ public function hasMore() {
 358+ return $this->hasMore;
 359+ }
 360+
 361+ /**
 362+ * Returns the result length
 363+ *
 364+ * @return int
 365+ */
 366+ public function count() {
 367+ return count( $this->result );
 368+ }
 369+}
Property changes on: trunk/phase3/includes/GlobalUsageQuery.php
___________________________________________________________________
Added: svn:eol-style
1370 + native
Index: trunk/phase3/includes/SpecialPageFactory.php
@@ -126,6 +126,8 @@
127127 // Page tools
128128 'ComparePages' => 'SpecialComparePages',
129129 'Export' => 'SpecialExport',
 130+ 'GlobalFileUsage' => 'SpecialGlobalFileUsage',
 131+ 'GlobalTemplateUsage' => 'SpecialGlobalTemplateUsage',
130132 'Import' => 'SpecialImport',
131133 'Undelete' => 'SpecialUndelete',
132134 'Whatlinkshere' => 'SpecialWhatlinkshere',
Property changes on: trunk/phase3/includes/SpecialPageFactory.php
___________________________________________________________________
Modified: svn:mergeinfo
133135 Merged /branches/iwtransclusion/phase3v2/includes/SpecialPageFactory.php:r87111-87112
134136 Merged /branches/iwtransclusion/phase3v3/includes/SpecialPageFactory.php:r92983-95395
135137 Merged /branches/iwtransclusion/phase3/includes/SpecialPageFactory.php:r70966,71049,74205
Index: trunk/phase3/includes/DefaultSettings.php
@@ -2983,13 +2983,35 @@
29842984 $wgPreprocessorCacheThreshold = 1000;
29852985
29862986 /**
2987 - * Enable interwiki transcluding. Only when iw_trans=1.
 2987+ * Enable interwiki transcluding. Only when iw_trans=1 in the interwiki table.
 2988+ * If the interwiki prefix is associated with a wiki ID in the interwiki table,
 2989+ * then the distant templates will be retrieved in the distant DB. If there is
 2990+ * no wiki ID but a API URL for that prefix, the distant templates will be
 2991+ * retrieved using the API and cached in memcached.
29882992 */
2989 -$wgEnableScaryTranscluding = false;
 2993+$wgEnableInterwikiTranscluding = false;
29902994
29912995 /**
2992 - * Expiry time for interwiki transclusion
 2996+ * If $wgEnableInterwikiTranscluding is set to true and if an interwiki prefix
 2997+ * is associated with a wiki ID, then, this option should be set to true to
 2998+ * enable the cache invalidation of the distant pages when the local templates
 2999+ * are edited and also to display the list of the distant templates used by
 3000+ * the local pages. Enabling this requires to set up a global shared database
 3001+ * (see next option $wgGlobalDatabase).
29933002 */
 3003+$wgEnableInterwikiTemplatesTracking = false;
 3004+
 3005+/**
 3006+ * If $wgEnableInterwikiTemplatesTracking is set to true, this option should
 3007+ * contain the wiki ID of the database that hosts the globaltemplatelinks table.
 3008+ */
 3009+$wgGlobalDatabase = '';
 3010+
 3011+/**
 3012+ * If $wgEnableInterwikiTranscluding is set to true and if an interwiki
 3013+ * prefix is associated with an API URL and no wiki ID, this will be
 3014+ * the expiry time for the transcluded templates cached in memcached.
 3015+ */
29943016 $wgTranscludeCacheExpiry = 3600;
29953017
29963018 /** @} */ # end of parser settings }
@@ -5131,6 +5153,8 @@
51325154 'Export' => 'pagetools',
51335155 'Import' => 'pagetools',
51345156 'Whatlinkshere' => 'pagetools',
 5157+ 'GlobalFileUsage' => 'pagetools',
 5158+ 'GlobalTemplateUsage' => 'pagetools',
51355159
51365160 'Statistics' => 'wiki',
51375161 'Version' => 'wiki',
Index: trunk/phase3/includes/installer/SqliteUpdater.php
@@ -63,6 +63,11 @@
6464 // 1.19
6565 array( 'addTable', 'config', 'patch-config.sql' ),
6666 array( 'addIndex', 'logging', 'type_action', 'patch-logging-type-action-index.sql')
 67+
 68+ // 1.19
 69+ array( 'addTable', 'globaltemplatelinks', 'patch-globaltemplatelinks.sql' ),
 70+ array( 'addTable', 'globalnamespaces', 'patch-globalnamespaces.sql' ),
 71+ array( 'addTable', 'globalinterwiki', 'patch-globalinterwiki.sql' ),
6772 );
6873 }
6974
Index: trunk/phase3/includes/installer/MysqlUpdater.php
@@ -185,6 +185,9 @@
186186 // 1.19
187187 array( 'addTable', 'config', 'patch-config.sql' ),
188188 array( 'addIndex', 'logging', 'type_action', 'patch-logging-type-action-index.sql'),
 189+ array( 'addTable', 'globaltemplatelinks', 'patch-globaltemplatelinks.sql' ),
 190+ array( 'addTable', 'globalnamespaces', 'patch-globalnamespaces.sql' ),
 191+ array( 'addTable', 'globalinterwiki', 'patch-globalinterwiki.sql' ),
189192 );
190193 }
191194
Index: trunk/phase3/includes/interwiki/Interwiki.php
@@ -9,6 +9,7 @@
1010 * All information is loaded on creation when called by Interwiki::fetch( $prefix ).
1111 * All work is done on slave, because this should *never* change (except during
1212 * schema updates etc, which aren't wiki-related)
 13+ * This class also contains the functions that allow interwiki templates transclusion.
1314 */
1415 class Interwiki {
1516
@@ -168,6 +169,7 @@
169170 $mc = array(
170171 'iw_url' => $iw->mURL,
171172 'iw_api' => $iw->mAPI,
 173+ 'iw_wikiid' => $iw->mWikiID,
172174 'iw_local' => $iw->mLocal,
173175 'iw_trans' => $iw->mTrans
174176 );
@@ -190,6 +192,7 @@
191193 $iw->mURL = $mc['iw_url'];
192194 $iw->mLocal = isset( $mc['iw_local'] ) ? $mc['iw_local'] : 0;
193195 $iw->mTrans = isset( $mc['iw_trans'] ) ? $mc['iw_trans'] : 0;
 196+ $iw->mAPI = isset( $mc['iw_api'] ) ? $mc['iw_api'] :
194197 $iw->mAPI = isset( $mc['iw_api'] ) ? $mc['iw_api'] : '';
195198 $iw->mWikiID = isset( $mc['iw_wikiid'] ) ? $mc['iw_wikiid'] : '';
196199
@@ -384,4 +387,166 @@
385388 $msg = wfMessage( 'interwiki-desc-' . $this->mPrefix )->inContentLanguage();
386389 return !$msg->exists() ? '' : $msg;
387390 }
 391+
 392+
 393+ /**
 394+ * Transclude an interwiki link.
 395+ */
 396+ public static function interwikiTransclude( $title ) {
 397+
 398+ // If we have a wikiID, we will use it to get an access to the remote database
 399+ // if not, we will use the API URL to retrieve the data through a HTTP Get
 400+
 401+ $wikiID = $title->getTransWikiID( );
 402+ $transAPI = $title->getTransAPI( );
 403+
 404+ if ( $wikiID !== '') {
 405+
 406+ $finalText = self::fetchTemplateFromDB( $wikiID, $title );
 407+ return $finalText;
 408+
 409+ } else if( $transAPI !== '' ) {
 410+
 411+ $interwiki = $title->getInterwiki( );
 412+ $fullTitle = $title->getSemiPrefixedText( );
 413+
 414+ $finalText = self::fetchTemplateFromAPI( $interwiki, $transAPI, $fullTitle );
 415+
 416+ return $finalText;
 417+
388418 }
 419+ return false;
 420+ }
 421+
 422+ /**
 423+ * Retrieve the wikitext of a distant page accessing the foreign DB
 424+ */
 425+ public static function fetchTemplateFromDB ( $wikiID, $title ) {
 426+
 427+ $revision = Revision::loadFromTitleForeignWiki( $wikiID, $title );
 428+
 429+ if ( $revision ) {
 430+ $text = $revision->getText();
 431+ return $text;
 432+ }
 433+
 434+ return false;
 435+ }
 436+
 437+ /**
 438+ * Retrieve the wikitext of a distant page using the API of the foreign wiki
 439+ */
 440+ public static function fetchTemplateFromAPI( $interwiki, $transAPI, $fullTitle ) {
 441+ global $wgMemc, $wgTranscludeCacheExpiry;
 442+
 443+ $key = wfMemcKey( 'iwtransclustiontext', 'textid', $interwiki, $fullTitle );
 444+ $text = $wgMemc->get( $key );
 445+ if( is_array ( $text ) &&
 446+ isset ( $text['missing'] ) &&
 447+ $text['missing'] === true ) {
 448+ return false;
 449+ } else if ( $text ) {
 450+ return $text;
 451+ }
 452+
 453+ $url = wfAppendQuery(
 454+ $transAPI,
 455+ array( 'action' => 'query',
 456+ 'titles' => $fullTitle,
 457+ 'prop' => 'revisions',
 458+ 'rvprop' => 'content',
 459+ 'format' => 'json'
 460+ )
 461+ );
 462+
 463+ $get = Http::get( $url );
 464+ $content = FormatJson::decode( $get, true );
 465+
 466+ if ( isset ( $content['query'] ) &&
 467+ isset ( $content['query']['pages'] ) ) {
 468+ $page = array_pop( $content['query']['pages'] );
 469+ if ( $page && isset( $page['revisions'][0]['*'] ) ) {
 470+ $text = $page['revisions'][0]['*'];
 471+ $wgMemc->set( $key, $text, $wgTranscludeCacheExpiry );
 472+
 473+ // When we cache a template, we also retrieve and cache its subtemplates
 474+ $subtemplates = self::getSubtemplatesListFromAPI( $interwiki, $transAPI, $fullTitle );
 475+ self::cacheTemplatesFromAPI( $interwiki, $transAPI, $subtemplates );
 476+
 477+ return $text;
 478+ } else {
 479+ $wgMemc->set( $key, array ( 'missing' => true ), $wgTranscludeCacheExpiry );
 480+ }
 481+ }
 482+ return false;
 483+ }
 484+
 485+ public static function getSubtemplatesListFromAPI ( $interwiki, $transAPI, $title ) {
 486+ $url = wfAppendQuery( $transAPI,
 487+ array( 'action' => 'query',
 488+ 'titles' => $title,
 489+ 'prop' => 'templates',
 490+ 'format' => 'json'
 491+ )
 492+ );
 493+
 494+ $get = Http::get( $url );
 495+ $myArray = FormatJson::decode($get, true);
 496+
 497+ $templates = array( );
 498+ if ( ! empty( $myArray['query'] )) {
 499+ if ( ! empty( $myArray['query']['pages'] )) {
 500+ $templates = array_pop( $myArray['query']['pages'] );
 501+ if ( ! empty( $templates['templates'] )) {
 502+ $templates = $templates['templates'];
 503+ }
 504+ }
 505+ return $templates;
 506+ }
 507+ }
 508+
 509+ public static function cacheTemplatesFromAPI( $interwiki, $transAPI, $titles ){
 510+ global $wgMemc, $wgTranscludeCacheExpiry;
 511+
 512+ $outdatedTitles = array( );
 513+
 514+ foreach( $titles as $title ){
 515+ if ( isset ( $title['title'] ) ) {
 516+ $key = wfMemcKey( 'iwtransclustiontext', 'textid', $interwiki, $title['title'] );
 517+ $text = $wgMemc->get( $key );
 518+ if( !$text ){
 519+ $outdatedTitles[] = $title['title'];
 520+ }
 521+ }
 522+ }
 523+
 524+ $batches = array_chunk( $outdatedTitles, 50 );
 525+
 526+ foreach( $batches as $batch ){
 527+ $url = wfAppendQuery(
 528+ $transAPI,
 529+ array( 'action' => 'query',
 530+ 'titles' => implode( '|', $batch ),
 531+ 'prop' => 'revisions',
 532+ 'rvprop' => 'content',
 533+ 'format' => 'json'
 534+ )
 535+ );
 536+ $get = Http::get( $url );
 537+ $content = FormatJson::decode( $get, true );
 538+
 539+ if ( isset ( $content['query'] ) &&
 540+ isset ( $content['query']['pages'] ) ) {
 541+ foreach( $content['query']['pages'] as $page ) {
 542+ $key = wfMemcKey( 'iwtransclustiontext', 'textid', $interwiki, $page['title'] );
 543+ if ( isset ( $page['revisions'][0]['*'] ) ) {
 544+ $text = $page['revisions'][0]['*'];
 545+ } else {
 546+ $text = array ( 'missing' => true );
 547+ }
 548+ $wgMemc->set( $key, $text, $wgTranscludeCacheExpiry );
 549+ }
 550+ }
 551+ }
 552+ }
 553+}
Property changes on: trunk/phase3/includes/interwiki/Interwiki.php
___________________________________________________________________
Modified: svn:mergeinfo
389554 Merged /branches/iwtransclusion/phase3/includes/interwiki/Interwiki.php:r69541,69723,69730,69745-69746,69781,69783,69853,69948,70411,70575,70802
390555 Merged /branches/iwtransclusion/phase3v2/includes/interwiki/Interwiki.php:r87105-87107,87109
391556 Merged /branches/iwtransclusion/phase3v3/includes/interwiki/Interwiki.php:r92983-95395
Index: trunk/phase3/includes/BacklinkCache.php
@@ -175,6 +175,25 @@
176176 }
177177
178178 /**
 179+ * Get the distant backtemplatelinks for the table globaltemplatelinks. Cached in process memory only.
 180+ * @return ResultWrapper list of distant pages that use the local title
 181+ */
 182+ public function getDistantTemplateLinks( ) {
 183+ global $wgGlobalDatabase, $wgLocalInterwiki;
 184+
 185+ $dbr = $dbr = wfGetDB( DB_SLAVE, array(), $wgGlobalDatabase );
 186+ $res = $dbr->select(
 187+ array( 'globaltemplatelinks', 'globalinterwiki' ),
 188+ array( 'gtl_from_wiki', 'gtl_from_page', 'gtl_from_title', 'giw_prefix' ),
 189+ array( 'gtl_to_prefix' => $wgLocalInterwiki, 'gtl_to_title' => $this->title->getDBkey( ) ),
 190+ __METHOD__,
 191+ null,
 192+ array( 'gtl_from_wiki = giw_wikiid' )
 193+ );
 194+ return $res;
 195+ }
 196+
 197+ /**
179198 * Get the field name prefix for a given table
180199 * @param $table String
181200 */
@@ -185,6 +204,7 @@
186205 'categorylinks' => 'cl',
187206 'templatelinks' => 'tl',
188207 'redirect' => 'rd',
 208+ 'globaltemplatelinks' => 'gtl',
189209 );
190210
191211 if ( isset( $prefixes[$table] ) ) {
Index: trunk/phase3/includes/parser/ParserOutput.php
@@ -121,6 +121,8 @@
122122 $mLinks = array(), # 2-D map of NS/DBK to ID for the links in the document. ID=zero for broken.
123123 $mTemplates = array(), # 2-D map of NS/DBK to ID for the template references. ID=zero for broken.
124124 $mTemplateIds = array(), # 2-D map of NS/DBK to rev ID for the template references. ID=zero for broken.
 125+ $mDistantTemplates = array(), # 3-D map of WIKIID/NS/DBK to ID for the template references. ID=zero for broken.
 126+ $mDistantTemplateIds = array(), # 3-D map of WIKIID/NS/DBK to rev ID for the template references. ID=zero for broken.
125127 $mImages = array(), # DB keys of the images used, in the array key only
126128 $mImageTimeKeys = array(), # DB keys of the images used mapped to sha1 and MW timestamp
127129 $mExternalLinks = array(), # External link URLs, in the key only
@@ -191,6 +193,8 @@
192194 function getEditSectionTokens() { return $this->mEditSectionTokens; }
193195 function &getLinks() { return $this->mLinks; }
194196 function &getTemplates() { return $this->mTemplates; }
 197+ function &getDistantTemplates() { return $this->mDistantTemplates; }
 198+ function &getDistantTemplateIds() { return $this->mDistantTemplateIds; }
195199 function &getTemplateIds() { return $this->mTemplateIds; }
196200 function &getImages() { return $this->mImages; }
197201 function &getImageTimeKeys() { return $this->mImageTimeKeys; }
@@ -312,6 +316,31 @@
313317 $this->mTemplateIds[$ns][$dbk] = $rev_id; // For versioning
314318 }
315319
 320+ function addDistantTemplate( $title, $page_id, $rev_id ) {
 321+ $prefix = $title->getInterwiki();
 322+ if ( $prefix !=='' ) {
 323+ $ns = $title->getNamespace();
 324+ $dbk = $title->getDBkey();
 325+
 326+ if ( !isset( $this->mDistantTemplates[$prefix] ) ) {
 327+ $this->mDistantTemplates[$prefix] = array();
 328+ }
 329+ if ( !isset( $this->mDistantTemplates[$prefix][$ns] ) ) {
 330+ $this->mDistantTemplates[$prefix][$ns] = array();
 331+ }
 332+ $this->mDistantTemplates[$prefix][$ns][$dbk] = $page_id;
 333+
 334+ // For versioning
 335+ if ( !isset( $this->mDistantTemplateIds[$prefix] ) ) {
 336+ $this->mDistantTemplateIds[$prefix] = array();
 337+ }
 338+ if ( !isset( $this->mDistantTemplateIds[$prefix][$ns] ) ) {
 339+ $this->mDistantTemplateIds[$prefix][$ns] = array();
 340+ }
 341+ $this->mDistantTemplateIds[$prefix][$ns][$dbk] = $rev_id;
 342+ }
 343+ }
 344+
316345 /**
317346 * @param $title Title object, must be an interwiki link
318347 * @throws MWException if given invalid input
Index: trunk/phase3/includes/parser/Preprocessor_DOM.php
@@ -1038,7 +1038,8 @@
10391039 $params = array(
10401040 'title' => new PPNode_DOM( $title ),
10411041 'parts' => new PPNode_DOM( $parts ),
1042 - 'lineStart' => $lineStart );
 1042+ 'lineStart' => $lineStart,
 1043+ 'interwiki' => $this->title->getInterwiki( ) );
10431044 $ret = $this->parser->braceSubstitution( $params, $this );
10441045 if ( isset( $ret['object'] ) ) {
10451046 $newIterator = $ret['object'];
Index: trunk/phase3/includes/parser/Preprocessor_Hash.php
@@ -976,6 +976,7 @@
977977 if ( $flags & PPFrame::NO_TEMPLATES ) {
978978 $newIterator = $this->virtualBracketedImplode( '{{', '|', '}}', $bits['title'], $bits['parts'] );
979979 } else {
 980+ $bits['interwiki'] = $this->title->getInterwiki( );
980981 $ret = $this->parser->braceSubstitution( $bits, $this );
981982 if ( isset( $ret['object'] ) ) {
982983 $newIterator = $ret['object'];
Index: trunk/phase3/includes/parser/Parser.php
@@ -3140,7 +3140,7 @@
31413141 * @private
31423142 */
31433143 function braceSubstitution( $piece, $frame ) {
3144 - global $wgContLang, $wgNonincludableNamespaces;
 3144+ global $wgContLang, $wgNonincludableNamespaces, $wgEnableInterwikiTranscluding, $wgEnableInterwikiTemplatesTracking;
31453145 wfProfileIn( __METHOD__ );
31463146 wfProfileIn( __METHOD__.'-setup' );
31473147
@@ -3148,7 +3148,6 @@
31493149 $found = false; # $text has been filled
31503150 $nowiki = false; # wiki markup in $text should be escaped
31513151 $isHTML = false; # $text is HTML, armour it against wikitext transformation
3152 - $forceRawInterwiki = false; # Force interwiki transclusion to be done in raw mode not rendered
31533152 $isChildObj = false; # $text is a DOM node needing expansion in a child frame
31543153 $isLocalObj = false; # $text is a DOM node needing expansion in the current frame
31553154
@@ -3313,6 +3312,9 @@
33143313 }
33153314 $title = Title::newFromText( $part1, $ns );
33163315 if ( $title ) {
 3316+ if ( !$title->isExternal() && $piece['interwiki'] !== '' ) {
 3317+ $title->setInterwiki( $piece['interwiki'] );
 3318+ }
33173319 $titleText = $title->getPrefixedText();
33183320 # Check for language variants if the template is not found
33193321 if ( $wgContLang->hasVariants() && $title->getArticleID() == 0 ) {
@@ -3375,18 +3377,22 @@
33763378 $text = "[[:$titleText]]";
33773379 $found = true;
33783380 }
3379 - } elseif ( $title->isTrans() ) {
3380 - # Interwiki transclusion
3381 - if ( $this->ot['html'] && !$forceRawInterwiki ) {
3382 - $text = $this->interwikiTransclude( $title, 'render' );
3383 - $isHTML = true;
3384 - } else {
3385 - $text = $this->interwikiTransclude( $title, 'raw' );
 3381+ } elseif ( $wgEnableInterwikiTranscluding && $title->isTrans() ) {
 3382+
 3383+ $text = Interwiki::interwikiTransclude( $title );
 3384+ $this->registerDistantTemplate( $title );
 3385+
 3386+ if ( $wgEnableInterwikiTemplatesTracking ) {
 3387+ $this->registerDistantTemplate( $title );
 3388+ }
 3389+
 3390+ if ( $text !== false ) {
33863391 # Preprocess it like a template
33873392 $text = $this->preprocessToDom( $text, self::PTD_FOR_INCLUSION );
 3393+ $found = true;
33883394 $isChildObj = true;
33893395 }
3390 - $found = true;
 3396+
33913397 }
33923398
33933399 # Do infinite loop check
@@ -3536,10 +3542,19 @@
35373543 }
35383544
35393545 /**
3540 - * Fetch the unparsed text of a template and register a reference to it.
3541 - * @param Title $title
3542 - * @return mixed string or false
 3546+ * Register a distant template as used
35433547 */
 3548+ function registerDistantTemplate( $title ) {
 3549+ $stuff = Parser::distantTemplateCallback( $title, $this );
 3550+ $text = $stuff['text'];
 3551+ $finalTitle = isset( $stuff['finalTitle'] ) ? $stuff['finalTitle'] : $title;
 3552+ if ( isset( $stuff['deps'] ) ) {
 3553+ foreach ( $stuff['deps'] as $dep ) {
 3554+ $this->mOutput->addDistantTemplate( $dep['title'], $dep['page_id'], $dep['rev_id'] );
 3555+ }
 3556+ }
 3557+ }
 3558+
35443559 function fetchTemplate( $title ) {
35453560 $rv = $this->fetchTemplateAndTitle( $title );
35463561 return $rv[0];
@@ -3668,58 +3683,23 @@
36693684 return array( $file, $title );
36703685 }
36713686
3672 - /**
3673 - * Transclude an interwiki link.
3674 - *
3675 - * @param $title Title
3676 - * @param $action
3677 - *
3678 - * @return string
3679 - */
3680 - function interwikiTransclude( $title, $action ) {
3681 - global $wgEnableScaryTranscluding;
 3687+ static function distantTemplateCallback( $title, $parser=false ) {
 3688+ $text = '';
 3689+ $rev_id = null;
 3690+ $deps[] = array(
 3691+ 'title' => $title,
 3692+ 'page_id' => $title->getArticleID(),
 3693+ 'rev_id' => $rev_id );
36823694
3683 - if ( !$wgEnableScaryTranscluding ) {
3684 - return wfMsgForContent('scarytranscludedisabled');
3685 - }
 3695+ $finalTitle = $title;
36863696
3687 - $url = $title->getFullUrl( "action=$action" );
3688 -
3689 - if ( strlen( $url ) > 255 ) {
3690 - return wfMsgForContent( 'scarytranscludetoolong' );
 3697+ return array(
 3698+ 'text' => $text,
 3699+ 'finalTitle' => $finalTitle,
 3700+ 'deps' => $deps );
36913701 }
3692 - return $this->fetchScaryTemplateMaybeFromCache( $url );
3693 - }
36943702
36953703 /**
3696 - * @param $url string
3697 - * @return Mixed|String
3698 - */
3699 - function fetchScaryTemplateMaybeFromCache( $url ) {
3700 - global $wgTranscludeCacheExpiry;
3701 - $dbr = wfGetDB( DB_SLAVE );
3702 - $tsCond = $dbr->timestamp( time() - $wgTranscludeCacheExpiry );
3703 - $obj = $dbr->selectRow( 'transcache', array('tc_time', 'tc_contents' ),
3704 - array( 'tc_url' => $url, "tc_time >= " . $dbr->addQuotes( $tsCond ) ) );
3705 - if ( $obj ) {
3706 - return $obj->tc_contents;
3707 - }
3708 -
3709 - $text = Http::get( $url );
3710 - if ( !$text ) {
3711 - return wfMsgForContent( 'scarytranscludefailed', $url );
3712 - }
3713 -
3714 - $dbw = wfGetDB( DB_MASTER );
3715 - $dbw->replace( 'transcache', array('tc_url'), array(
3716 - 'tc_url' => $url,
3717 - 'tc_time' => $dbw->timestamp( time() ),
3718 - 'tc_contents' => $text)
3719 - );
3720 - return $text;
3721 - }
3722 -
3723 - /**
37243704 * Triple brace replacement -- used for template arguments
37253705 * @private
37263706 *
Index: trunk/phase3/includes/Title.php
@@ -758,6 +758,20 @@
759759 }
760760
761761 /**
 762+ * Return the prefixed title with spaces _without_ the interwiki prefix
 763+ *
 764+ * @return \type{\string} the title, prefixed by the namespace but not by the interwiki prefix, with spaces
 765+ */
 766+ public function getSemiPrefixedText() {
 767+ if ( !isset( $this->mSemiPrefixedText ) ){
 768+ $s = ( $this->mNamespace === NS_MAIN ? '' : $this->getNsText() . ':' ) . $this->mTextform;
 769+ $s = str_replace( '_', ' ', $s );
 770+ $this->mSemiPrefixedText = $s;
 771+ }
 772+ return $this->mSemiPrefixedText;
 773+ }
 774+
 775+ /**
762776 * Get the prefixed title with spaces, plus any fragment
763777 * (part beginning with '#')
764778 *
@@ -1009,8 +1023,12 @@
10101024 * @return String the URL
10111025 */
10121026 public function getInternalURL( $query = '', $variant = false ) {
1013 - global $wgInternalServer, $wgServer;
1014 - $server = $wgInternalServer !== false ? $wgInternalServer : $wgServer;
 1027+ if ( $this->isExternal( ) ) {
 1028+ $server = '';
 1029+ } else {
 1030+ global $wgInternalServer, $wgServer;
 1031+ $server = $wgInternalServer !== false ? $wgInternalServer : $wgServer;
 1032+ }
10151033 $url = wfExpandUrl( $server . $this->getLocalURL( $query, $variant ), PROTO_HTTP );
10161034 wfRunHooks( 'GetInternalURL', array( &$this, &$url, $query ) );
10171035 return $url;
@@ -2836,6 +2854,10 @@
28372855 $this->mFragment = str_replace( '_', ' ', substr( $fragment, 1 ) );
28382856 }
28392857
 2858+ public function setInterwiki( $interwiki ) {
 2859+ $this->mInterwiki = $interwiki;
 2860+ }
 2861+
28402862 /**
28412863 * Get a Title object associated with the talk page of this article
28422864 *
@@ -3140,6 +3162,8 @@
31413163 * @return Mixed true on success, getUserPermissionsErrors()-like array on failure
31423164 */
31433165 public function moveTo( &$nt, $auth = true, $reason = '', $createRedirect = true ) {
 3166+ global $wgContLang, $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase;
 3167+
31443168 $err = $this->isValidMoveOperation( $nt, $auth, $reason );
31453169 if ( is_array( $err ) ) {
31463170 return $err;
@@ -3196,6 +3220,15 @@
31973221 );
31983222 }
31993223
 3224+ if ( $wgEnableInterwikiTemplatesTracking && $wgGlobalDatabase ) {
 3225+ $dbw2 = wfGetDB( DB_MASTER, array(), $wgGlobalDatabase );
 3226+ $dbw2->update( 'globaltemplatelinks',
 3227+ array( 'gtl_from_namespace' => $nt->getNamespace(),
 3228+ 'gtl_from_title' => $nt->getText() ),
 3229+ array ( 'gtl_from_page' => $pageid ),
 3230+ __METHOD__ );
 3231+ }
 3232+
32003233 if ( $protected ) {
32013234 # Protect the redirect title as the title used to be...
32023235 $dbw->insertSelect( 'page_restrictions', 'page_restrictions',
@@ -3289,8 +3322,8 @@
32903323 * @param $createRedirect Bool Whether to leave a redirect at the old title. Ignored
32913324 * if the user doesn't have the suppressredirect right
32923325 */
3293 - private function moveToInternal( &$nt, $reason = '', $createRedirect = true ) {
3294 - global $wgUser, $wgContLang;
 3326+ private function moveOverExistingRedirect( &$nt, $reason = '', $createRedirect = true ) {
 3327+ global $wgUseSquid, $wgUser, $wgContLang, $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase;
32953328
32963329 $moveOverRedirect = $nt->exists();
32973330
@@ -3340,7 +3373,15 @@
33413374 array( 'rc_timestamp' => $rcts, 'rc_namespace' => $newns, 'rc_title' => $newdbk, 'rc_new' => 1 ),
33423375 __METHOD__
33433376 );
 3377+
 3378+ if ( $wgEnableInterwikiTemplatesTracking && $wgGlobalDatabase ) {
 3379+ $dbw2 = wfGetDB( DB_MASTER, array(), $wgGlobalDatabase );
 3380+ $dbw2->delete( 'globaltemplatelinks',
 3381+ array( 'gtl_from_wiki' => wfGetID(),
 3382+ 'gtl_from_page' => $newid ),
 3383+ __METHOD__ );
33443384 }
 3385+ }
33453386
33463387 # Save a null revision in the page's history notifying of the move
33473388 $nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true );
Property changes on: trunk/phase3/includes/Title.php
___________________________________________________________________
Modified: svn:mergeinfo
33483389 Merged /branches/iwtransclusion/phase3v2/includes/Title.php:r87106-87107,87111,87115
33493390 Merged /branches/iwtransclusion/phase3v3/includes/Title.php:r92983-95395
33503391 Merged /branches/iwtransclusion/phase3/includes/Title.php:r69745-69746,69781,69783,69853,69948,70411,70575-70576,70966,71049,76200
Index: trunk/phase3/includes/LinksUpdate.php
@@ -29,6 +29,7 @@
3030 $mLinks, //!< Map of title strings to IDs for the links in the document
3131 $mImages, //!< DB keys of the images used, in the array key only
3232 $mTemplates, //!< Map of title strings to IDs for the template references, including broken ones
 33+ $mDistantTemplates,//!< Map of title strings to IDs for the distant template references, including broken ones
3334 $mExternals, //!< URLs of external links, array key only
3435 $mCategories, //!< Map of category names to sort keys
3536 $mInterlangs, //!< Map of language codes to titles
@@ -66,6 +67,7 @@
6768 $this->mLinks = $parserOutput->getLinks();
6869 $this->mImages = $parserOutput->getImages();
6970 $this->mTemplates = $parserOutput->getTemplates();
 71+ $this->mDistantTemplates = $parserOutput->getDistantTemplates();
7072 $this->mExternals = $parserOutput->getExternalLinks();
7173 $this->mCategories = $parserOutput->getCategories();
7274 $this->mProperties = $parserOutput->getProperties();
@@ -152,6 +154,15 @@
153155 $this->incrTableUpdate( 'templatelinks', 'tl', $this->getTemplateDeletions( $existing ),
154156 $this->getTemplateInsertions( $existing ) );
155157
 158+ # Distant template links
 159+ global $wgGlobalDB;
 160+ if ( $wgGlobalDB ) {
 161+ $existing = $this->getDistantExistingTemplates();
 162+ $this->incrSharedTableUpdate( 'globaltemplatelinks', 'gtl',
 163+ $this->getDistantTemplateDeletions( $existing ),
 164+ $this->getDistantTemplateInsertions( $existing ) );
 165+ }
 166+
156167 # Category links
157168 $existing = $this->getExistingCategories();
158169
@@ -367,12 +378,56 @@
368379 if ( $where ) {
369380 $this->mDb->delete( $table, $where, __METHOD__ );
370381 }
 382+ if ( isset( $insertions['globaltemplatelinks'] ) ) {
 383+ $this->mDb->insert( 'globaltemplatelinks', $insertions['globaltemplatelinks'], __METHOD__, 'IGNORE' );
 384+ unset( $insertions['globaltemplatelinks'] );
 385+ }
 386+ if ( isset( $insertions['globalnamespaces'] ) ) {
 387+ $this->mDb->insert( 'globalnamespaces', $insertions['globalnamespaces'], __METHOD__, 'IGNORE' );
 388+ unset( $insertions['globalnamespaces'] );
 389+ }
 390+ if ( isset( $insertions['globalinterwiki'] ) ) {
 391+ $this->mDb->insert( 'globalinterwiki', $insertions['globalinterwiki'], __METHOD__, 'IGNORE' );
 392+ unset( $insertions['globalinterwiki'] );
 393+ }
371394 if ( count( $insertions ) ) {
372395 $this->mDb->insert( $table, $insertions, __METHOD__, 'IGNORE' );
373396 }
374397 }
375398
 399+ /**
 400+ * Update a shared table by doing a delete query then an insert query
 401+ * @private
 402+ */
 403+ function incrSharedTableUpdate( $table, $prefix, $deletions, $insertions ) {
376404
 405+ global $wgWikiID;
 406+ global $wgGlobalDB;
 407+
 408+ if ( $wgGlobalDB ) {
 409+ $dbw = wfGetDB( DB_MASTER, array(), $wgGlobalDB );
 410+ $where = array( "{$prefix}_from_wiki" => $wgWikiID,
 411+ "{$prefix}_from_page" => $this->mId
 412+ );
 413+ $baseKey = "{$prefix}_to_wiki";
 414+ $middleKey = "{$prefix}_to_namespace";
 415+
 416+ $clause = $dbw->makeWhereFrom3d( $deletions, $baseKey, $middleKey, "{$prefix}_to_title" );
 417+ if ( $clause ) {
 418+ $where[] = $clause;
 419+ } else {
 420+ $where = false;
 421+ }
 422+
 423+ if ( $where ) {
 424+ $dbw->delete( $table, $where, __METHOD__ );
 425+ }
 426+ if ( count( $insertions ) ) {
 427+ $dbw->insert( $table, $insertions, __METHOD__, 'IGNORE' );
 428+ }
 429+ }
 430+ }
 431+
377432 /**
378433 * Get an array of pagelinks insertions for passing to the DB
379434 * Skips the titles specified by the 2-D array $existing
@@ -415,6 +470,45 @@
416471 }
417472
418473 /**
 474+ * Get an array of distant template insertions. Like getLinkInsertions()
 475+ * @private
 476+ */
 477+ function getDistantTemplateInsertions( $existing = array() ) {
 478+ global $wgWikiID;
 479+ $arr = array();
 480+ foreach( $this->mDistantTemplates as $wikiid => $templatesToNS ) {
 481+ foreach( $templatesToNS as $ns => $dbkeys ) {
 482+ $diffs = isset( $existing[$wikiid] ) && isset( $existing[$wikiid][$ns] )
 483+ ? array_diff_key( $dbkeys, $existing[$wikiid][$ns] )
 484+ : $dbkeys;
 485+ $interwiki = Interwiki::fetch( $wikiid );
 486+ $wikiid = $interwiki->getWikiID();
 487+ foreach ( $diffs as $dbk => $id ) {
 488+ $arr['globaltemplatelinks'][] = array(
 489+ 'gtl_from_wiki' => $wgWikiID,
 490+ 'gtl_from_page' => $this->mId,
 491+ 'gtl_from_namespace' => $this->mTitle->getNamespace(),
 492+ 'gtl_from_title' => $this->mTitle->getText(),
 493+ 'gtl_to_wiki' => $wikiid,
 494+ 'gtl_to_namespace' => $ns,
 495+ 'gtl_to_title' => $dbk
 496+ );
 497+ $arr['globalinterwiki'][] = array(
 498+ 'giw_wikiid' => $wikiid,
 499+ 'giw_prefix' => $prefix // FIXME: $prefix ix undefined
 500+ );
 501+ $arr['globalnamespaces'][] = array(
 502+ 'gn_wiki' => wfWikiID( ),
 503+ 'gn_namespace' => $this->mTitle->getNamespace(),
 504+ 'gn_namespacetext' => $this->mTitle->getNsText(),
 505+ );
 506+ }
 507+ }
 508+ }
 509+ return $arr;
 510+ }
 511+
 512+ /**
419513 * Get an array of image insertions
420514 * Skips the names specified in $existing
421515 * @private
@@ -581,6 +675,30 @@
582676 }
583677
584678 /**
 679+ * Given an array of existing templates, returns those templates which are not in $this
 680+ * and thus should be deleted.
 681+ * @private
 682+ */
 683+ function getDistantTemplateDeletions( $existing ) {
 684+ $del = array();
 685+ foreach ( $existing as $wikiid => $templatesForNS ) {
 686+ if ( isset( $this->mDistantTemplates[$wikiid] ) ) {
 687+ $del[$wikiid] = array_diff_key( $existing[$wikiid], $this->mDistantTemplates[$wikiid] );
 688+ } else {
 689+ $del[$wikiid] = $existing[$wikiid];
 690+ }
 691+ foreach ( $templatesForNS as $ns => $dbkeys ) {
 692+ if ( isset( $this->mDistantTemplates[$wikiid][$ns] ) ) {
 693+ $del[$wikiid][$ns] = array_diff_key( $existing[$wikiid][$ns], $this->mDistantTemplates[$wikiid][$ns] );
 694+ } else {
 695+ $del[$wikiid][$ns] = $existing[$wikiid][$ns];
 696+ }
 697+ }
 698+ }
 699+ return $del;
 700+ }
 701+
 702+ /**
585703 * Given an array of existing images, returns those images which are not in $this
586704 * and thus should be deleted.
587705 * @private
@@ -676,6 +794,33 @@
677795 }
678796
679797 /**
 798+ * Get an array of existing distant templates, as a 3-D array
 799+ * @private
 800+ */
 801+ function getDistantExistingTemplates() {
 802+ global $wgWikiID;
 803+ global $wgGlobalDB;
 804+
 805+ $arr = array();
 806+ if ( $wgGlobalDB ) {
 807+ $dbr = wfGetDB( DB_SLAVE, array(), $wgGlobalDB );
 808+ $res = $dbr->select( 'globaltemplatelinks', array( 'gtl_to_wiki', 'gtl_to_namespace', 'gtl_to_title' ),
 809+ array( 'gtl_from_wiki' => $wgWikiID, 'gtl_from_page' => $this->mId ), __METHOD__, $this->mOptions );
 810+ while ( $row = $dbr->fetchObject( $res ) ) {
 811+ if ( !isset( $arr[$row->gtl_to_wiki] ) ) {
 812+ $arr[$row->gtl_to_wiki] = array();
 813+ }
 814+ if ( !isset( $arr[$row->gtl_to_wiki][$row->gtl_to_namespace] ) ) {
 815+ $arr[$row->gtl_to_wiki][$row->gtl_to_namespace] = array();
 816+ }
 817+ $arr[$row->gtl_to_wiki][$row->gtl_to_namespace][$row->gtl_to_title] = 1;
 818+ }
 819+ $dbr->freeResult( $res );
 820+ }
 821+ return $arr;
 822+ }
 823+
 824+ /**
680825 * Get an array of existing images, image names in the keys
681826 * @private
682827 */
Index: trunk/phase3/includes/OutputPage.php
@@ -2048,6 +2048,9 @@
20492049 * @param $action String: action that was denied or null if unknown
20502050 */
20512051 public function readOnlyPage( $source = null, $protected = false, $reasons = array(), $action = null ) {
 2052+ global $wgUser, $wgEnableInterwikiTranscluding, $wgEnableInterwikiTemplatesTracking;
 2053+ $skin = $wgUser->getSkin();
 2054+
20522055 $this->setRobotPolicy( 'noindex,nofollow' );
20532056 $this->setArticleRelated( false );
20542057
@@ -2093,7 +2096,13 @@
20942097 $templates
20952098 </div>
20962099 " );
 2100+ if ( $wgEnableInterwikiTranscluding && $wgEnableInterwikiTemplatesTracking ) {
 2101+ $this->addHTML( "<div class='distantTemplatesUsed'>
 2102+{$skin->formatDistantTemplates( $article->getUsedDistantTemplates( ) )}
 2103+</div>
 2104+" );
20972105 }
 2106+ }
20982107
20992108 # If the title doesn't exist, it's fairly pointless to print a return
21002109 # link to it. After all, you just tried editing it and couldn't, so
Property changes on: trunk/phase3/includes/OutputPage.php
___________________________________________________________________
Modified: svn:mergeinfo
21012110 Merged /branches/iwtransclusion/phase3/includes/OutputPage.php:r70764
21022111 Merged /branches/iwtransclusion/phase3v2/includes/OutputPage.php:r87108
21032112 Merged /branches/iwtransclusion/phase3v3/includes/OutputPage.php:r92983-95395
Index: trunk/phase3/includes/specials/SpecialGlobalTemplateUsage.php
@@ -0,0 +1,207 @@
 2+<?php
 3+/**
 4+ * This file has been copied from Extension:GlobalUsage and adapted
 5+ * to show the usage of a template instead of a file.
 6+ * Special page to show global template usage. Also contains hook functions for
 7+ * showing usage on an template page.
 8+ *
 9+ * @author Bryan Tong Minh <bryan.tongminh@gmail.com>
 10+ * @author Peter Potrowl <peter017@gmail.com>
 11+ */
 12+
 13+class SpecialGlobalTemplateUsage extends SpecialPage {
 14+ public function __construct() {
 15+ parent::__construct( 'GlobalTemplateUsage' );
 16+ }
 17+
 18+ /**
 19+ * Entry point
 20+ */
 21+ public function execute( $par ) {
 22+ global $wgOut, $wgRequest;
 23+
 24+ $target = $par ? $par : $wgRequest->getVal( 'target' );
 25+ $this->target = Title::newFromText( $target );
 26+
 27+ $this->setHeaders();
 28+
 29+ $this->showForm();
 30+
 31+ if ( is_null( $this->target ) ) {
 32+ $wgOut->setPageTitle( wfMsg( 'globaltemplateusage' ) );
 33+ return;
 34+ }
 35+
 36+ $wgOut->setPageTitle( wfMsg( 'globaltemplateusage-for', $this->target->getPrefixedText() ) );
 37+
 38+ $this->showResult();
 39+ }
 40+
 41+ /**
 42+ * Shows the search form
 43+ */
 44+ private function showForm() {
 45+ global $wgScript, $wgOut, $wgRequest;
 46+
 47+ /* Build form */
 48+ $html = Xml::openElement( 'form', array( 'action' => $wgScript ) ) . "\n";
 49+ // Name of SpecialPage
 50+ $html .= Xml::hidden( 'title', $this->getTitle( )->getPrefixedText( ) ) . "\n";
 51+ // Limit
 52+ $html .= Xml::hidden( 'limit', $wgRequest->getInt( 'limit', 50 ) );
 53+ // Input box with target prefilled if available
 54+ $formContent = "\t" . Xml::input( 'target', 40, is_null( $this->target ) ? ''
 55+ : $this->target->getPrefixedText( ) )
 56+ // Submit button
 57+ . "\n\t" . Xml::element( 'input', array(
 58+ 'type' => 'submit',
 59+ 'value' => wfMsg( 'globaltemplateusage-ok' )
 60+ ) );
 61+
 62+ // Wrap the entire form in a nice fieldset
 63+ $html .= Xml::fieldSet( wfMsg( 'globaltemplateusage-text' ), $formContent ) . "\n</form>";
 64+
 65+ $wgOut->addHtml( $html );
 66+ }
 67+
 68+ /**
 69+ * Creates as queryer and executes it based on $wgRequest
 70+ */
 71+ private function showResult() {
 72+ global $wgRequest;
 73+
 74+ $query = new GlobalUsageQuery( $this->target );
 75+
 76+ // Extract params from $wgRequest
 77+ if ( $wgRequest->getText( 'from' ) ) {
 78+ $query->setOffset( $wgRequest->getText( 'from' ) );
 79+ } elseif ( $wgRequest->getText( 'to' ) ) {
 80+ $query->setOffset( $wgRequest->getText( 'to' ), true );
 81+ }
 82+ $query->setLimit( $wgRequest->getInt( 'limit', 50 ) );
 83+
 84+ // Perform query
 85+ $query->searchTemplate();
 86+
 87+ // Show result
 88+ global $wgOut;
 89+
 90+ // Don't show form element if there is no data
 91+ if ( $query->count() == 0 ) {
 92+ $wgOut->addWikiMsg( 'globaltemplateusage-no-results', $this->target->getPrefixedText( ) );
 93+ return;
 94+ }
 95+
 96+ $offset = $query->getOffsetString( );
 97+ $navbar = $this->getNavBar( $query );
 98+ $targetName = $this->target->getPrefixedText( );
 99+
 100+ // Top navbar
 101+ $wgOut->addHtml( $navbar );
 102+
 103+ $wgOut->addHtml( '<div id="mw-globaltemplateusage-result">' );
 104+ foreach ( $query->getSingleResult() as $wiki => $result ) {
 105+ $wgOut->addHtml(
 106+ '<h2>' . wfMsgExt(
 107+ 'globaltemplateusage-on-wiki', 'parseinline',
 108+ $targetName, WikiMap::getWikiName( $wiki ) )
 109+ . "</h2><ul>\n" );
 110+ foreach ( $result as $item ) {
 111+ $wgOut->addHtml( "\t<li>" . self::formatItem( $item ) . "</li>\n" );
 112+ }
 113+ $wgOut->addHtml( "</ul>\n" );
 114+ }
 115+ $wgOut->addHtml( '</div>' );
 116+
 117+ // Bottom navbar
 118+ $wgOut->addHtml( $navbar );
 119+ }
 120+
 121+ /**
 122+ * Helper to format a specific item
 123+ */
 124+ public static function formatItem( $item ) {
 125+ if ( !$item['namespace'] ) {
 126+ $page = $item['title'];
 127+ } else {
 128+ $page = "{$item['namespace']}:{$item['title']}";
 129+ }
 130+
 131+ $link = WikiMap::makeForeignLink( $item['wiki'], $page,
 132+ str_replace( '_', ' ', $page ) );
 133+ // Return only the title if no link can be constructed
 134+ return $link === false ? $page : $link;
 135+ }
 136+
 137+ /**
 138+ * Helper function to create the navbar, stolen from wfViewPrevNext
 139+ *
 140+ * @param $query GlobalTemplateUsageQuery An executed GlobalTemplateUsageQuery object
 141+ * @return string Navbar HTML
 142+ */
 143+ protected function getNavBar( $query ) {
 144+ global $wgLang, $wgUser;
 145+
 146+ $skin = $wgUser->getSkin();
 147+
 148+ $target = $this->target->getPrefixedText();
 149+ $limit = $query->getLimit();
 150+ $fmtLimit = $wgLang->formatNum( $limit );
 151+
 152+ # Find out which strings are for the prev and which for the next links
 153+ $offset = $query->getOffsetString();
 154+ $continue = $query->getContinueTemplateString();
 155+ if ( $query->isReversed() ) {
 156+ $from = $offset;
 157+ $to = $continue;
 158+ } else {
 159+ $from = $continue;
 160+ $to = $offset;
 161+ }
 162+
 163+ # Get prev/next link display text
 164+ $prev = wfMsgExt( 'prevn', array( 'parsemag', 'escape' ), $fmtLimit );
 165+ $next = wfMsgExt( 'nextn', array( 'parsemag', 'escape' ), $fmtLimit );
 166+ # Get prev/next link title text
 167+ $pTitle = wfMsgExt( 'prevn-title', array( 'parsemag', 'escape' ), $fmtLimit );
 168+ $nTitle = wfMsgExt( 'nextn-title', array( 'parsemag', 'escape' ), $fmtLimit );
 169+
 170+ # Fetch the title object
 171+ $title = $this->getTitle();
 172+
 173+ # Make 'previous' link
 174+ if ( $to ) {
 175+ $attr = array( 'title' => $pTitle, 'class' => 'mw-prevlink' );
 176+ $q = array( 'limit' => $limit, 'to' => $to, 'target' => $target );
 177+ $plink = $skin->link( $title, $prev, $attr, $q );
 178+ } else {
 179+ $plink = $prev;
 180+ }
 181+
 182+ # Make 'next' link
 183+ if ( $from ) {
 184+ $attr = array( 'title' => $nTitle, 'class' => 'mw-nextlink' );
 185+ $q = array( 'limit' => $limit, 'from' => $from, 'target' => $target );
 186+ $nlink = $skin->link( $title, $next, $attr, $q );
 187+ } else {
 188+ $nlink = $next;
 189+ }
 190+
 191+ # Make links to set number of items per page
 192+ $numLinks = array();
 193+ foreach ( array( 20, 50, 100, 250, 500 ) as $num ) {
 194+ $fmtLimit = $wgLang->formatNum( $num );
 195+
 196+ $q = array( 'offset' => $offset, 'limit' => $num, 'target' => $target );
 197+ $lTitle = wfMsgExt( 'shown-title', array( 'parsemag', 'escape' ), $num );
 198+ $attr = array( 'title' => $lTitle, 'class' => 'mw-numlink' );
 199+
 200+ $numLinks[] = $skin->link( $title, $fmtLimit, $attr, $q );
 201+ }
 202+ $nums = $wgLang->pipeList( $numLinks );
 203+
 204+ return wfMsgHtml( 'viewprevnext', $plink, $nlink, $nums );
 205+ }
 206+}
 207+
 208+
Property changes on: trunk/phase3/includes/specials/SpecialGlobalTemplateUsage.php
___________________________________________________________________
Added: svn:eol-style
1209 + native
Index: trunk/phase3/includes/specials/SpecialGlobalFileUsage.php
@@ -0,0 +1,224 @@
 2+<?php
 3+/**
 4+ * Special page to show global file usage. Also contains hook functions for
 5+ * showing usage on an image page.
 6+ */
 7+
 8+class SpecialGlobalFileUsage extends SpecialPage {
 9+ public function __construct() {
 10+ parent::__construct( 'GlobalFileUsage' );
 11+ }
 12+
 13+ /**
 14+ * Entry point
 15+ */
 16+ public function execute( $par ) {
 17+ global $wgOut, $wgRequest;
 18+
 19+ $target = $par ? $par : $wgRequest->getVal( 'target' );
 20+ $this->target = Title::makeTitleSafe( NS_FILE, $target );
 21+
 22+ $this->filterLocal = $wgRequest->getCheck( 'filterlocal' );
 23+
 24+ $this->setHeaders();
 25+
 26+ $this->showForm();
 27+
 28+ if ( is_null( $this->target ) ) {
 29+ $wgOut->setPageTitle( wfMsg( 'globalfileusage' ) );
 30+ return;
 31+ }
 32+
 33+ $wgOut->setPageTitle( wfMsg( 'globalfileusage-for', $this->target->getPrefixedText() ) );
 34+
 35+ $this->showResult();
 36+ }
 37+
 38+ /**
 39+ * Shows the search form
 40+ */
 41+ private function showForm() {
 42+ global $wgScript, $wgOut, $wgRequest;
 43+
 44+ /* Build form */
 45+ $html = Xml::openElement( 'form', array( 'action' => $wgScript ) ) . "\n";
 46+ // Name of SpecialPage
 47+ $html .= Xml::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n";
 48+ // Limit
 49+ $html .= Xml::hidden( 'limit', $wgRequest->getInt( 'limit', 50 ) );
 50+ // Input box with target prefilled if available
 51+ $formContent = "\t" . Xml::input( 'target', 40, is_null( $this->target ) ? ''
 52+ : $this->target->getText() )
 53+ // Submit button
 54+ . "\n\t" . Xml::element( 'input', array(
 55+ 'type' => 'submit',
 56+ 'value' => wfMsg( 'globalfileusage-ok' )
 57+ ) )
 58+ // Filter local checkbox
 59+ . "\n\t<p>" . Xml::checkLabel( wfMsg( 'globalfileusage-filterlocal' ),
 60+ 'filterlocal', 'mw-filterlocal', $this->filterLocal ) . '</p>';
 61+
 62+ if ( !is_null( $this->target ) && wfFindFile( $this->target ) ) {
 63+ // Show the image if it exists
 64+ global $wgUser, $wgContLang;
 65+ $skin = $wgUser->getSkin();
 66+
 67+ $html .= $skin->makeImageLinkObj( $this->target,
 68+ $this->target->getPrefixedText(),
 69+ /* $alt */ '', /* $align */ $wgContLang->alignEnd(),
 70+ /* $handlerParams */ array(), /* $framed */ false,
 71+ /* $thumb */ true );
 72+ }
 73+
 74+ // Wrap the entire form in a nice fieldset
 75+ $html .= Xml::fieldSet( wfMsg( 'globalfileusage-text' ), $formContent ) . "\n</form>";
 76+
 77+ $wgOut->addHtml( $html );
 78+ }
 79+
 80+ /**
 81+ * Creates as queryer and executes it based on $wgRequest
 82+ */
 83+ private function showResult() {
 84+ global $wgRequest;
 85+
 86+ $query = new GlobalUsageQuery( $this->target );
 87+
 88+ // Extract params from $wgRequest
 89+ if ( $wgRequest->getText( 'from' ) ) {
 90+ $query->setOffset( $wgRequest->getText( 'from' ) );
 91+ } elseif ( $wgRequest->getText( 'to' ) ) {
 92+ $query->setOffset( $wgRequest->getText( 'to' ), true );
 93+ }
 94+ $query->setLimit( $wgRequest->getInt( 'limit', 50 ) );
 95+ $query->filterLocal( $this->filterLocal );
 96+
 97+ // Perform query
 98+ $query->searchFile();
 99+
 100+ // Show result
 101+ global $wgOut;
 102+
 103+ // Don't show form element if there is no data
 104+ if ( $query->count() == 0 ) {
 105+ $wgOut->addWikiMsg( 'globalfileusage-no-results', $this->target->getPrefixedText() );
 106+ return;
 107+ }
 108+
 109+ $offset = $query->getOffsetString();
 110+ $navbar = $this->getNavBar( $query );
 111+ $targetName = $this->target->getText();
 112+
 113+ // Top navbar
 114+ $wgOut->addHtml( $navbar );
 115+
 116+ $wgOut->addHtml( '<div id="mw-globalfileusage-result">' );
 117+ foreach ( $query->getSingleResult() as $wiki => $result ) {
 118+ $wgOut->addHtml(
 119+ '<h2>' . wfMsgExt(
 120+ 'globalfileusage-on-wiki', 'parseinline',
 121+ $targetName, WikiMap::getWikiName( $wiki ) )
 122+ . "</h2><ul>\n" );
 123+ foreach ( $result as $item ) {
 124+ $wgOut->addHtml( "\t<li>" . self::formatItem( $item ) . "</li>\n" );
 125+ }
 126+ $wgOut->addHtml( "</ul>\n" );
 127+ }
 128+ $wgOut->addHtml( '</div>' );
 129+
 130+ // Bottom navbar
 131+ $wgOut->addHtml( $navbar );
 132+ }
 133+ /**
 134+ * Helper to format a specific item
 135+ */
 136+ public static function formatItem( $item ) {
 137+ if ( !$item['namespace'] ) {
 138+ $page = $item['title'];
 139+ } else {
 140+ $page = "{$item['namespace']}:{$item['title']}";
 141+ }
 142+
 143+ $link = WikiMap::makeForeignLink( $item['wiki'], $page,
 144+ str_replace( '_', ' ', $page ) );
 145+ // Return only the title if no link can be constructed
 146+ return $link === false ? $page : $link;
 147+ }
 148+
 149+ /**
 150+ * Helper function to create the navbar, stolen from wfViewPrevNext
 151+ *
 152+ * @param $query GlobalUsageQuery An executed GlobalUsageQuery object
 153+ * @return string Navbar HTML
 154+ */
 155+ protected function getNavBar( $query ) {
 156+ global $wgLang, $wgUser;
 157+
 158+ $skin = $wgUser->getSkin();
 159+
 160+ $target = $this->target->getText();
 161+ $limit = $query->getLimit();
 162+ $fmtLimit = $wgLang->formatNum( $limit );
 163+
 164+ # Find out which strings are for the prev and which for the next links
 165+ $offset = $query->getOffsetString();
 166+ $continue = $query->getContinueFileString();
 167+ if ( $query->isReversed() ) {
 168+ $from = $offset;
 169+ $to = $continue;
 170+ } else {
 171+ $from = $continue;
 172+ $to = $offset;
 173+ }
 174+
 175+ # Get prev/next link display text
 176+ $prev = wfMsgExt( 'prevn', array( 'parsemag', 'escape' ), $fmtLimit );
 177+ $next = wfMsgExt( 'nextn', array( 'parsemag', 'escape' ), $fmtLimit );
 178+ # Get prev/next link title text
 179+ $pTitle = wfMsgExt( 'prevn-title', array( 'parsemag', 'escape' ), $fmtLimit );
 180+ $nTitle = wfMsgExt( 'nextn-title', array( 'parsemag', 'escape' ), $fmtLimit );
 181+
 182+ # Fetch the title object
 183+ $title = $this->getTitle();
 184+
 185+ # Make 'previous' link
 186+ if ( $to ) {
 187+ $attr = array( 'title' => $pTitle, 'class' => 'mw-prevlink' );
 188+ $q = array( 'limit' => $limit, 'to' => $to, 'target' => $target );
 189+ if ( $this->filterLocal )
 190+ $q['filterlocal'] = '1';
 191+ $plink = $skin->link( $title, $prev, $attr, $q );
 192+ } else {
 193+ $plink = $prev;
 194+ }
 195+
 196+ # Make 'next' link
 197+ if ( $from ) {
 198+ $attr = array( 'title' => $nTitle, 'class' => 'mw-nextlink' );
 199+ $q = array( 'limit' => $limit, 'from' => $from, 'target' => $target );
 200+ if ( $this->filterLocal )
 201+ $q['filterlocal'] = '1';
 202+ $nlink = $skin->link( $title, $next, $attr, $q );
 203+ } else {
 204+ $nlink = $next;
 205+ }
 206+
 207+ # Make links to set number of items per page
 208+ $numLinks = array();
 209+ foreach ( array( 20, 50, 100, 250, 500 ) as $num ) {
 210+ $fmtLimit = $wgLang->formatNum( $num );
 211+
 212+ $q = array( 'offset' => $offset, 'limit' => $num, 'target' => $target );
 213+ if ( $this->filterLocal )
 214+ $q['filterlocal'] = '1';
 215+ $lTitle = wfMsgExt( 'shown-title', array( 'parsemag', 'escape' ), $num );
 216+ $attr = array( 'title' => $lTitle, 'class' => 'mw-numlink' );
 217+
 218+ $numLinks[] = $skin->link( $title, $fmtLimit, $attr, $q );
 219+ }
 220+ $nums = $wgLang->pipeList( $numLinks );
 221+
 222+ return wfMsgHtml( 'viewprevnext', $plink, $nlink, $nums );
 223+ }
 224+}
 225+
Property changes on: trunk/phase3/includes/specials/SpecialGlobalFileUsage.php
___________________________________________________________________
Added: svn:eol-style
1226 + native
Index: trunk/phase3/includes/AutoLoader.php
@@ -539,6 +539,7 @@
540540 'BmpHandler' => 'includes/media/BMP.php',
541541 'DjVuHandler' => 'includes/media/DjVu.php',
542542 'Exif' => 'includes/media/Exif.php',
 543+ 'GlobalUsageQuery' => 'includes/GlobalUsageQuery.php',
543544 'FormatExif' => 'includes/media/FormatMetadata.php',
544545 'FormatMetadata' => 'includes/media/FormatMetadata.php',
545546 'GIFHandler' => 'includes/media/GIF.php',
@@ -752,6 +753,8 @@
753754 'SpecialEmailUser' => 'includes/specials/SpecialEmailuser.php',
754755 'SpecialExport' => 'includes/specials/SpecialExport.php',
755756 'SpecialFilepath' => 'includes/specials/SpecialFilepath.php',
 757+ 'SpecialGlobalFileUsage' => 'includes/specials/SpecialGlobalFileUsage.php',
 758+ 'SpecialGlobalTemplateUsage' => 'includes/specials/SpecialGlobalTemplateUsage.php',
756759 'SpecialImport' => 'includes/specials/SpecialImport.php',
757760 'SpecialListFiles' => 'includes/specials/SpecialListfiles.php',
758761 'SpecialListGroupRights' => 'includes/specials/SpecialListgrouprights.php',
Property changes on: trunk/phase3/includes/AutoLoader.php
___________________________________________________________________
Modified: svn:mergeinfo
759762 Merged /branches/iwtransclusion/phase3v3/includes/AutoLoader.php:r92983-95395
760763 Merged /branches/iwtransclusion/phase3/includes/AutoLoader.php:r70966,71049
761764 Merged /branches/iwtransclusion/phase3v2/includes/AutoLoader.php:r87111-87112
Index: trunk/phase3/includes/EditPage.php
@@ -1313,7 +1313,7 @@
13141314 * during form output near the top, for captchas and the like.
13151315 */
13161316 function showEditForm( $formCallback = null ) {
1317 - global $wgOut, $wgUser;
 1317+ global $wgOut, $wgUser, $wgEnableInterwikiTranscluding, $wgEnableInterwikiTemplatesTracking;
13181318
13191319 wfProfileIn( __METHOD__ );
13201320
@@ -1347,7 +1347,6 @@
13481348 $toolbar = '';
13491349 }
13501350
1351 -
13521351 $wgOut->addHTML( $this->editFormPageTop );
13531352
13541353 if ( $wgUser->getOption( 'previewontop' ) ) {
@@ -1359,6 +1358,9 @@
13601359 $templates = $this->getTemplates();
13611360 $formattedtemplates = Linker::formatTemplates( $templates, $this->preview, $this->section != '');
13621361
 1362+ $distantTemplates = $this->getDistantTemplates();
 1363+ $formattedDistantTemplates = Linker::formatDistantTemplates( $distantTemplates, $this->preview, $this->section != '' );
 1364+
13631365 $hiddencats = $this->mArticle->getHiddenCategories();
13641366 $formattedhiddencats = Linker::formatHiddenCategories( $hiddencats );
13651367
@@ -1457,6 +1459,21 @@
14581460 <div class='templatesUsed'>
14591461 {$formattedtemplates}
14601462 </div>
 1463+HTML
 1464+);
 1465+
 1466+ if ( $wgEnableInterwikiTranscluding && $wgEnableInterwikiTemplatesTracking ) {
 1467+ $wgOut->addHTML( <<<HTML
 1468+{$this->editFormTextAfterTools}
 1469+<div class='distantTemplatesUsed'>
 1470+{$formattedDistantTemplates}
 1471+</div>
 1472+HTML
 1473+);
 1474+ }
 1475+
 1476+ $wgOut->addHTML( <<<HTML
 1477+{$this->editFormTextAfterTools}
14611478 <div class='hiddencats'>
14621479 {$formattedhiddencats}
14631480 </div>
@@ -2118,6 +2135,28 @@
21192136 }
21202137 }
21212138
 2139+ function getDistantTemplates() {
 2140+ global $wgEnableInterwikiTemplatesTracking;
 2141+ if ( !$wgEnableInterwikiTemplatesTracking ) {
 2142+ return array( );
 2143+ }
 2144+ if ( $this->preview || $this->section != '' ) {
 2145+ $templates = array();
 2146+ if ( !isset( $this->mParserOutput ) ) return $templates;
 2147+ $templatesList = $this->mParserOutput->getDistantTemplates();
 2148+ foreach( $templatesList as $prefix => $templatesbyns ) {
 2149+ foreach( $templatesbyns as $ns => $template ) {
 2150+ foreach( array_keys( $template ) as $dbk ) {
 2151+ $templates[] = Title::makeTitle( $ns, $dbk, null, $prefix );
 2152+ }
 2153+ }
 2154+ }
 2155+ return $templates;
 2156+ } else {
 2157+ return $this->mArticle->getUsedDistantTemplates();
 2158+ }
 2159+ }
 2160+
21222161 /**
21232162 * Call the stock "user is blocked" page
21242163 */
Index: trunk/phase3/includes/cache/HTMLCacheUpdate.php
@@ -51,6 +51,16 @@
5252 return;
5353 }
5454
 55+ if ( $this->mTable === 'globaltemplatelinks' ) {
 56+ global $wgEnableInterwikiTemplatesTracking;
 57+
 58+ if ( $wgEnableInterwikiTemplatesTracking ) {
 59+ $distantPageArray = $this->mCache->getDistantTemplateLinks( 'globaltemplatelinks' );
 60+ $this->invalidateDistantTitles( $distantPageArray );
 61+ }
 62+ return;
 63+ }
 64+
5565 # Get an estimate of the number of rows from the BacklinkCache
5666 $numRows = $this->mCache->getNumLinks( $this->mTable );
5767 if ( $numRows > $this->mRowsPerJob * 2 ) {
@@ -68,6 +78,7 @@
6979 $this->invalidateTitles( $titleArray );
7080 }
7181 }
 82+ wfRunHooks( 'HTMLCacheUpdate::doUpdate', array($this->mTitle) );
7283 }
7384
7485 /**
@@ -198,8 +209,46 @@
199210 }
200211 }
201212
 213+ /**
 214+ * Invalidate an array of distant pages, given the wiki ID and page ID of those pages
 215+ */
 216+ protected function invalidateDistantTitles( $distantPageArray ) {
 217+ global $wgUseFileCache, $wgUseSquid, $wgLocalInterwiki;
 218+
 219+ $pagesByWiki = array();
 220+ $titleArray = array();
 221+ # Sort by WikiID in $pagesByWiki
 222+ # Create the distant titles for Squid in $titleArray
 223+ foreach ( $distantPageArray as $row ) {
 224+ $wikiid = $row->gtl_from_wiki;
 225+ if( !isset( $pagesByWiki[$wikiid] ) ) {
 226+ $pagesByWiki[$wikiid] = array();
202227 }
 228+ $pagesByWiki[$wikiid][] = $row->gtl_from_page;
 229+ $titleArray[] = Title::makeTitle( $row->gtl_from_namespace, $row->gtl_from_title, '', $row->gil_interwiki );
 230+ }
203231
 232+ foreach ( $pagesByWiki as $wikiid => $pages ) {
 233+ $dbw = wfGetDB( DB_MASTER, array( ), $wikiid );
 234+ $timestamp = $dbw->timestamp();
 235+ $batches = array_chunk( $pages, $this->mRowsPerQuery );
 236+ foreach ( $batches as $batch ) {
 237+ $dbw->update( 'page',
 238+ array( 'page_touched' => $timestamp ),
 239+ array( 'page_id IN (' . $dbw->makeList( $batch ) . ')' ),
 240+ __METHOD__
 241+ );
 242+ }
 243+ }
 244+
 245+ # Update squid
 246+ if ( $wgUseSquid ) {
 247+ $u = SquidUpdate::newFromTitles( $titleArray );
 248+ $u->doUpdate();
 249+ }
 250+ }
 251+}
 252+
204253 /**
205254 * Job wrapper for HTMLCacheUpdate. Gets run whenever a related
206255 * job gets called from the queue.
Index: trunk/phase3/includes/Linker.php
@@ -1646,6 +1646,42 @@
16471647 }
16481648
16491649 /**
 1650+ * Returns HTML for the "templates used on this page" list.
 1651+ *
 1652+ * @param $templates Array of templates from Article::getUsedTemplate
 1653+ * or similar
 1654+ * @param $preview Boolean: whether this is for a preview
 1655+ * @param $section Boolean: whether this is for a section edit
 1656+ * @return String: HTML output
 1657+ */
 1658+ public static function formatDistantTemplates( $templates, $preview = false, $section = false ) {
 1659+ wfProfileIn( __METHOD__ );
 1660+
 1661+ $outText = '';
 1662+ if ( count( $templates ) > 0 ) {
 1663+
 1664+ # Construct the HTML
 1665+ $outText = '<div class="mw-templatesUsedExplanation">';
 1666+ if ( $preview ) {
 1667+ $outText .= wfMsgExt( 'distanttemplatesusedpreview', array( 'parse' ), count( $templates ) );
 1668+ } elseif ( $section ) {
 1669+ $outText .= wfMsgExt( 'distanttemplatesusedsection', array( 'parse' ), count( $templates ) );
 1670+ } else {
 1671+ $outText .= wfMsgExt( 'distanttemplatesused', array( 'parse' ), count( $templates ) );
 1672+ }
 1673+ $outText .= "</div><ul>\n";
 1674+
 1675+ usort( $templates, array( 'Title', 'compare' ) );
 1676+ foreach ( $templates as $titleObj ) {
 1677+ $outText .= '<li>' . self::link( $titleObj ) . '</li>';
 1678+ }
 1679+ $outText .= '</ul>';
 1680+ }
 1681+ wfProfileOut( __METHOD__ );
 1682+ return $outText;
 1683+ }
 1684+
 1685+ /**
16501686 * Returns HTML for the "hidden categories on this page" list.
16511687 *
16521688 * @param $hiddencats Array of hidden categories from Article::getHiddenCategories
Index: trunk/phase3/includes/Revision.php
@@ -166,6 +166,30 @@
167167 }
168168
169169 /**
 170+ * Stores the origin wiki of a revision in case it is a foreign wiki
 171+ */
 172+ function setWikiID( $wikiID ) {
 173+ $this->mWikiID = $wikiID;
 174+ }
 175+
 176+ /**
 177+ * Load the current revision of a given page of a foreign wiki.
 178+ * The WikiID is stored for further use, such as loadText() and getTimestampFromId()
 179+ */
 180+ public static function loadFromTitleForeignWiki( $wikiID, $title ) {
 181+ $dbr = wfGetDB( DB_SLAVE, array(), $wikiID );
 182+
 183+ $revision = self::loadFromTitle( $dbr, $title );
 184+
 185+ if( $revision ) {
 186+ $revision->setWikiID( $wikiID );
 187+ }
 188+
 189+ return $revision;
 190+
 191+ }
 192+
 193+ /**
170194 * Load either the current, or a specified, revision
171195 * that's attached to a given page. If not attached
172196 * to that page, will return null.
@@ -402,6 +426,7 @@
403427 throw new MWException( 'Revision constructor passed invalid row format.' );
404428 }
405429 $this->mUnpatrolled = null;
 430+ $this->mWikiID = false;
406431 }
407432
408433 /**
@@ -449,7 +474,8 @@
450475 if( isset( $this->mTitle ) ) {
451476 return $this->mTitle;
452477 }
453 - $dbr = wfGetDB( DB_SLAVE );
 478+ $dbr = wfGetDB( DB_SLAVE, array(), $this->mWikiID );
 479+
454480 $row = $dbr->selectRow(
455481 array( 'page', 'revision' ),
456482 array( 'page_namespace', 'page_title' ),
@@ -588,7 +614,7 @@
589615 if( $this->mUnpatrolled !== null ) {
590616 return $this->mUnpatrolled;
591617 }
592 - $dbr = wfGetDB( DB_SLAVE );
 618+ $dbr = wfGetDB( DB_SLAVE, array(), $this->mWikiID );
593619 $this->mUnpatrolled = $dbr->selectField( 'recentchanges',
594620 'rc_id',
595621 array( // Add redundant user,timestamp condition so we can use the existing index
@@ -924,7 +950,11 @@
925951 // Caching may be beneficial for massive use of external storage
926952 global $wgRevisionCacheExpiry, $wgMemc;
927953 $textId = $this->getTextId();
 954+ if( isset( $this->mWikiID ) && $this->mWikiID !== false ) {
 955+ $key = wfForeignMemcKey( $this->mWikiID, null, 'revisiontext', 'textid', $textId );
 956+ } else {
928957 $key = wfMemcKey( 'revisiontext', 'textid', $textId );
 958+ }
929959 if( $wgRevisionCacheExpiry ) {
930960 $text = $wgMemc->get( $key );
931961 if( is_string( $text ) ) {
@@ -944,7 +974,7 @@
945975
946976 if( !$row ) {
947977 // Text data is immutable; check slaves first.
948 - $dbr = wfGetDB( DB_SLAVE );
 978+ $dbr = wfGetDB( DB_SLAVE, array(), $this->mWikiID );
949979 $row = $dbr->selectRow( 'text',
950980 array( 'old_text', 'old_flags' ),
951981 array( 'old_id' => $this->getTextId() ),
@@ -953,7 +983,7 @@
954984
955985 if( !$row && wfGetLB()->getServerCount() > 1 ) {
956986 // Possible slave lag!
957 - $dbw = wfGetDB( DB_MASTER );
 987+ $dbw = wfGetDB( DB_MASTER, array(), $this->mWikiID );
958988 $row = $dbw->selectRow( 'text',
959989 array( 'old_text', 'old_flags' ),
960990 array( 'old_id' => $this->getTextId() ),
@@ -1064,7 +1094,8 @@
10651095 * @return String
10661096 */
10671097 static function getTimestampFromId( $title, $id ) {
1068 - $dbr = wfGetDB( DB_SLAVE );
 1098+ $wikiId = wfWikiID();
 1099+ $dbr = wfGetDB( DB_SLAVE, array(), $wikiId );
10691100 // Casting fix for DB2
10701101 if ( $id == '' ) {
10711102 $id = 0;
@@ -1074,7 +1105,7 @@
10751106 $timestamp = $dbr->selectField( 'revision', 'rev_timestamp', $conds, __METHOD__ );
10761107 if ( $timestamp === false && wfGetLB()->getServerCount() > 1 ) {
10771108 # Not in slave, try master
1078 - $dbw = wfGetDB( DB_MASTER );
 1109+ $dbw = wfGetDB( DB_MASTER, array(), $wikiId );
10791110 $timestamp = $dbw->selectField( 'revision', 'rev_timestamp', $conds, __METHOD__ );
10801111 }
10811112 return wfTimestamp( TS_MW, $timestamp );
Property changes on: trunk/phase3/includes/Revision.php
___________________________________________________________________
Modified: svn:mergeinfo
10821113 Merged /branches/iwtransclusion/phase3/includes/Revision.php:r69730,69745-69746,69781,69783,69853,69948,70411,70575
10831114 Merged /branches/iwtransclusion/phase3v2/includes/Revision.php:r87105-87107
10841115 Merged /branches/iwtransclusion/phase3v3/includes/Revision.php:r92983-95395
Index: trunk/phase3/includes/db/Database.php
@@ -1820,6 +1820,39 @@
18211821 }
18221822
18231823 /**
 1824+ * Build a partial where clause from a 3-d array
 1825+ * The keys on each level may be either integers or strings.
 1826+ *
 1827+ * @param $data Array: organized as 3-d array(baseKeyVal => array(middleKeyVal => array(subKeyVal => <ignored>, ...), ...), ...)
 1828+ * @param $baseKey String: field name to match the base-level keys to (eg 'gtl_to_prefix')
 1829+ * @param $middleKey String: field name to match the middle-level keys to (eg 'gtl_to_namespace')
 1830+ * @param $subKey String: field name to match the sub-level keys to (eg 'gtl_to_title')
 1831+ * @return Mixed: string SQL fragment, or false if no items in array.
 1832+ */
 1833+ function makeWhereFrom3d( $data, $baseKey, $middleKey, $subKey ) {
 1834+ $conds = array();
 1835+ foreach ( $data as $base => $subdata ) {
 1836+ foreach ( $subdata as $middle => $sub ) {
 1837+ if ( count( $sub ) ) {
 1838+ $conds[] = $this->makeList(
 1839+ array( $baseKey => $base,
 1840+ $middleKey => $middle,
 1841+ $subKey => array_keys( $sub ) ),
 1842+ LIST_AND
 1843+ );
 1844+ }
 1845+ }
 1846+ }
 1847+
 1848+ if ( $conds ) {
 1849+ return $this->makeList( $conds, LIST_OR );
 1850+ } else {
 1851+ // Nothing to search for...
 1852+ return false;
 1853+ }
 1854+ }
 1855+
 1856+ /**
18241857 * Bitwise operations
18251858 */
18261859
Property changes on: trunk/phase3/includes/db/Database.php
___________________________________________________________________
Modified: svn:mergeinfo
18271860 Merged /branches/iwtransclusion/phase3/includes/db/Database.php:r70576,70764
18281861 Merged /branches/iwtransclusion/phase3v2/includes/db/Database.php:r87108
18291862 Merged /branches/iwtransclusion/phase3v3/includes/db/Database.php:r92983-95395
Index: trunk/phase3/maintenance/tables.sql
@@ -1480,4 +1480,68 @@
14811481 -- Should cover *most* configuration - strings, ints, bools, etc.
14821482 CREATE INDEX /*i*/cf_name_value ON /*_*/config (cf_name,cf_value(255));
14831483
 1484+-- Table tracking interwiki transclusions in the spirit of templatelinks.
 1485+-- This table tracks transclusions of this wiki's templates on another wiki
 1486+-- The gtl_from_* fields describe the (remote) page the template is transcluded from
 1487+-- The gtl_to_* fields describe the (local) template being transcluded
 1488+CREATE TABLE /*_*/globaltemplatelinks (
 1489+ -- The wiki ID of the remote wiki
 1490+ gtl_from_wiki varchar(64) NOT NULL,
 1491+
 1492+ -- The page ID of the calling page on the remote wiki
 1493+ gtl_from_page int unsigned NOT NULL,
 1494+
 1495+ -- The namespace of the calling page on the remote wiki
 1496+ -- Needed for display purposes, since the foreign namespace ID doesn't necessarily match a local one
 1497+ -- The link between the namespace and the namespace name is made by the globalnamespaces table
 1498+ gtl_from_namespace int NOT NULL,
 1499+
 1500+ -- The title of the calling page on the remote wiki
 1501+ -- Needed for display purposes
 1502+ gtl_from_title varchar(255) binary NOT NULL,
 1503+
 1504+ -- The interwiki prefix of the wiki that hosts the transcluded page
 1505+ gtl_to_prefix varchar(32) NOT NULL,
 1506+
 1507+ -- The namespace of the transcluded page on that wiki
 1508+ gtl_to_namespace int NOT NULL,
 1509+
 1510+ -- The namespace name of transcluded page
 1511+ -- Needed for display purposes, since the local namespace ID doesn't necessarily match a distant one
 1512+ gtl_to_namespacetext varchar(255) NOT NULL,
 1513+
 1514+ -- The title of the transcluded page on that wiki
 1515+ gtl_to_title varchar(255) binary NOT NULL
 1516+) /*$wgDBTableOptions*/;
 1517+
 1518+CREATE UNIQUE INDEX /*i*/gtl_to_from ON /*_*/globaltemplatelinks (gtl_to_prefix, gtl_to_namespace, gtl_to_title, gtl_from_wiki, gtl_from_page);
 1519+CREATE UNIQUE INDEX /*i*/gtl_from_to ON /*_*/globaltemplatelinks (gtl_from_wiki, gtl_from_page, gtl_to_prefix, gtl_to_namespace, gtl_to_title);
 1520+
 1521+-- Table listing distant wiki namespace texts.
 1522+CREATE TABLE /*_*/globalnamespaces (
 1523+ -- The wiki ID of the remote wiki
 1524+ gn_wiki varchar(64) NOT NULL,
 1525+
 1526+ -- The namespace ID of the transcluded page on that wiki
 1527+ gn_namespace int NOT NULL,
 1528+
 1529+ -- The namespace text of transcluded page
 1530+ -- Needed for display purposes, since the local namespace ID doesn't necessarily match a distant one
 1531+ gn_namespacetext varchar(255) NOT NULL
 1532+
 1533+) /*$wgDBTableOptions*/;
 1534+CREATE UNIQUE INDEX /*i*/gn_index ON /*_*/globalnamespaces (gn_wiki, gn_namespace, gn_namespacetext);
 1535+
 1536+-- Table associating distant wiki IDs with their interwiki prefixes.
 1537+CREATE TABLE /*_*/globalinterwiki (
 1538+ -- The wiki ID of the wiki
 1539+ giw_wikiid varchar(64) NOT NULL,
 1540+
 1541+ -- The interwiki prefix of that wiki
 1542+ giw_prefix varchar(32) NOT NULL
 1543+
 1544+) /*$wgDBTableOptions*/;
 1545+CREATE UNIQUE INDEX /*i*/giw_index ON /*_*/globalinterwiki (giw_wikiid, giw_prefix);
 1546+
 1547+
14841548 -- vim: sw=2 sts=2 et
Property changes on: trunk/phase3/maintenance/tables.sql
___________________________________________________________________
Modified: svn:mergeinfo
14851549 Merged /branches/iwtransclusion/phase3v3/maintenance/tables.sql:r92983-95395
Index: trunk/phase3/maintenance/language/messages.inc
@@ -640,6 +640,9 @@
641641 'templatesused',
642642 'templatesusedpreview',
643643 'templatesusedsection',
 644+ 'distanttemplatesused',
 645+ 'distanttemplatesusedpreview',
 646+ 'distanttemplatesusedsection',
644647 'template-protected',
645648 'template-semiprotected',
646649 'hiddencategories',
Index: trunk/phase3/maintenance/archives/patch-globaltemplatelinks.sql
@@ -0,0 +1,36 @@
 2+-- Table tracking interwiki transclusions in the spirit of templatelinks.
 3+-- This table tracks transclusions of this wiki's templates on another wiki
 4+-- The gtl_from_* fields describe the (remote) page the template is transcluded from
 5+-- The gtl_to_* fields describe the (local) template being transcluded
 6+CREATE TABLE /*_*/globaltemplatelinks (
 7+ -- The wiki ID of the remote wiki
 8+ gtl_from_wiki varchar(64) NOT NULL,
 9+
 10+ -- The page ID of the calling page on the remote wiki
 11+ gtl_from_page int unsigned NOT NULL,
 12+
 13+ -- The namespace of the calling page on the remote wiki
 14+ -- Needed for display purposes, since the foreign namespace ID doesn't necessarily match a local one
 15+ -- The link between the namespace and the namespace name is made by the globalnamespaces table
 16+ gtl_from_namespace int NOT NULL,
 17+
 18+ -- The title of the calling page on the remote wiki
 19+ -- Needed for display purposes
 20+ gtl_from_title varchar(255) binary NOT NULL,
 21+
 22+ -- The interwiki prefix of the wiki that hosts the transcluded page
 23+ gtl_to_prefix varchar(32) NOT NULL,
 24+
 25+ -- The namespace of the transcluded page on that wiki
 26+ gtl_to_namespace int NOT NULL,
 27+
 28+ -- The namespace name of transcluded page
 29+ -- Needed for display purposes, since the local namespace ID doesn't necessarily match a distant one
 30+ gtl_to_namespacetext varchar(255) NOT NULL,
 31+
 32+ -- The title of the transcluded page on that wiki
 33+ gtl_to_title varchar(255) binary NOT NULL
 34+) /*$wgDBTableOptions*/;
 35+
 36+CREATE UNIQUE INDEX /*i*/gtl_to_from ON /*_*/globaltemplatelinks (gtl_to_prefix, gtl_to_namespace, gtl_to_title, gtl_from_wiki, gtl_from_page);
 37+CREATE UNIQUE INDEX /*i*/gtl_from_to ON /*_*/globaltemplatelinks (gtl_from_wiki, gtl_from_page, gtl_to_prefix, gtl_to_namespace, gtl_to_title);
Property changes on: trunk/phase3/maintenance/archives/patch-globaltemplatelinks.sql
___________________________________________________________________
Added: svn:eol-style
138 + native
Index: trunk/phase3/maintenance/archives/patch-globalnamespaces.sql
@@ -0,0 +1,14 @@
 2+-- Table listing distant wiki namespace texts.
 3+CREATE TABLE /*_*/globalnamespaces (
 4+ -- The wiki ID of the remote wiki
 5+ gn_wiki varchar(64) NOT NULL,
 6+
 7+ -- The namespace ID of the transcluded page on that wiki
 8+ gn_namespace int NOT NULL,
 9+
 10+ -- The namespace text of transcluded page
 11+ -- Needed for display purposes, since the local namespace ID doesn't necessarily match a distant one
 12+ gn_namespacetext varchar(255) NOT NULL
 13+
 14+) /*$wgDBTableOptions*/;
 15+CREATE UNIQUE INDEX /*i*/gn_index ON /*_*/globalnamespaces (gn_wiki, gn_namespace, gn_namespacetext);
Index: trunk/phase3/maintenance/archives/patch-globalinterwiki.sql
@@ -0,0 +1,10 @@
 2+-- Table associating distant wiki IDs with their interwiki prefixes.
 3+CREATE TABLE /*_*/globalinterwiki (
 4+ -- The wiki ID of the wiki
 5+ giw_wikiid varchar(64) NOT NULL,
 6+
 7+ -- The interwiki prefix of that wiki
 8+ giw_prefix varchar(32) NOT NULL
 9+
 10+) /*$wgDBTableOptions*/;
 11+CREATE UNIQUE INDEX /*i*/giw_index ON /*_*/globalinterwiki (giw_wikiid, giw_prefix);

Follow-up revisions

RevisionCommit summaryAuthorDate
r95397Followup r95396, add missing commareedy13:05, 24 August 2011
r95402Followup r95396...reedy15:31, 24 August 2011
r95438fu r95396: register new message keys in maintenacne fileraymond20:04, 24 August 2011
r95461Fix calls to undefined Xml::hidden...reedy08:28, 25 August 2011
r95462Hopefully fix...reedy08:31, 25 August 2011
r95474Actually do r95462 as intended...reedy10:47, 25 August 2011
r95594fu r95396 Fix function nameraymond08:26, 27 August 2011
r95603Unused variables....platonides18:28, 27 August 2011
r95872Followup r95396...reedy15:00, 31 August 2011
r95947Fix indentation in r95396catrope08:21, 1 September 2011
r96004Followup r95396...reedy15:58, 1 September 2011
r97194Remove unused messages 'globalfileusage-of-file', 'globaltemplateusage-of-fil...siebrand19:34, 15 September 2011
r98467Back out r95396 and friendsreedy22:08, 29 September 2011

Comments

#Comment by Reedy (talk | contribs)   13:17, 24 August 2011

Obviously this really needs RELEASE-NOTES writing up, as wgScaryTransclusion is dead etc...

#Comment by Raymond (talk | contribs)   14:58, 24 August 2011

PHP Notice: Found alias defined for Globaltemplateusage when searching for special page aliases for GlobalTemplateUsage. Case mismatch? [Called from SpecialPage::getTitleFor in /www/w/includes/SpecialPage.php at line 259] in /www/w/includes/GlobalFunctions.php on line 3396

#Comment by Reedy (talk | contribs)   14:55, 31 August 2011

bug 30641 and possibly another...

#Comment by Reedy (talk | contribs)   17:43, 24 August 2011

Other minor thing is getCanonicalUrl() needs fixing in trunk

#Comment by Raymond (talk | contribs)   08:04, 25 August 2011

Seen on Translatewiki:

[25-Aug-2011 08:03:00] PHP Notice:  Found alias defined for Globalfileusage when searching for special page aliases for GlobalFileUsage. Case mismatch? [Called from SpecialPage::getTitleFor in /www/w/includes/SpecialPage.php at line 259] in /www/w/includes/GlobalFunctions.php on line 3396
[25-Aug-2011 08:03:00] PHP Notice:  Found alias defined for Globaltemplateusage when searching for special page aliases for GlobalTemplateUsage. Case mismatch? [Called from SpecialPage::getTitleFor in /www/w/includes/SpecialPage.php at line 259] in /www/w/includes/GlobalFunctions.php on line 3396
[25-Aug-2011 08:03:08] PHP Fatal error:  Call to undefined method Xml::hidden() in /www/w/includes/specials/SpecialGlobalFileUsage.php on line 46
[25-Aug-2011 08:03:09] PHP Fatal error:  Call to undefined method Xml::hidden() in /www/w/includes/specials/SpecialGlobalTemplateUsage.php on line 49
#Comment by NeilK (talk | contribs)   05:07, 26 August 2011

n.b. This change will break wikis that are still using the old GlobalUsage extension -- the classes are redefined in an incompatible way

#Comment by Reedy (talk | contribs)   14:38, 1 September 2011

Class name clashes isn't really a good start...

#Comment by Reedy (talk | contribs)   18:56, 1 September 2011

Logged as bug 30686, and awaiting a response from Peter about it

It seems that the one now in core, is a slightly modified, but otherwise copy of GlobalUsageQuery and SpecialGlobalUsage from the GlobalUsage extension

#Comment by Raymond (talk | contribs)   08:15, 27 August 2011
 PHP Fatal error: Call to undefined method Title::moveToInternal() in /www/w/includes/Title.php on line 3191


-	private function moveToInternal( &$nt, $reason = '', $createRedirect = true ) {
-		global $wgUser, $wgContLang;
+	private function moveOverExistingRedirect( &$nt, $reason = '', $createRedirect = true ) {
+		global $wgUseSquid, $wgUser, $wgContLang, $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase;
#Comment by Raymond (talk | contribs)   08:30, 27 August 2011

On a first glanced fixed with r95594 but it seems the page moves (via JobQueue @ translatewiki.net) do not appear on the move log.

#Comment by Raymond (talk | contribs)   08:34, 27 August 2011

Strike the last comment. Seems fixed, revision status back to new.

#Comment by Platonides (talk | contribs)   15:31, 27 August 2011

Uses undefined globals $wgWikiID and $wgGlobalDB in LinksUpdate.php

#Comment by Reedy (talk | contribs)   15:05, 31 August 2011

Swapped $wgGlobalDB for $wgGlobalDatabase in r95872

$wgWikiID doesn't seem defined anyway, but not sure what it's supposed to be set to.. (in Default Settings)

There's also an undefined $prefix (tagged with a FIXME comment in the code)

Going to try and ping Peter to help tidy this up

#Comment by Duplicatebug (talk | contribs)   19:49, 27 August 2011

Please add some API modules:

  • list=globalimageusage (or add a global parameter to list=imageusage)
  • list=globaltemplateusage/globalembeddedin (or add a global parameter to list=embeddedin)

Please add global="wikiid/wikiname" or imagerepository="wikiid/wikiname" in the output of prop=images/templates when the used image/template came from another wiki.

#Comment by Reedy (talk | contribs)   21:06, 27 August 2011

Log that as a feature request

#Comment by Reedy (talk | contribs)   19:12, 1 September 2011

Actually, this to some extent exists in the GlobalUsage extension...

#Comment by Nikerabbit (talk | contribs)   08:09, 4 September 2011

When trying to search for a global template usage: SQL error ... from within function "GlobalUsageQuery::searchTemplate". Database returned error "1046: No database selected (localhost)".

#Comment by Reedy (talk | contribs)   09:30, 4 September 2011

That just sounds like it needs an if no database set, go away

#Comment by Nikerabbit (talk | contribs)   09:31, 4 September 2011

Which begs the question, why is this in core when wikifarms are rare compared to individual installations?

#Comment by Krinkle (talk | contribs)   23:37, 5 September 2011

I agree, this seems like a perfect thing to go into an extension.

A few side notes:

  • It uses global $wgUser->getSkin();
    • No need for globals here. OutputPage extends ContextSource which means it has both getUser and getSkin on itself.
  • CSS classnames used like distantTemplatesUsed and mw-templatesUsedExplanation should user lowercase and separation by dash, and where needed prefixed with atleast mw-.
#Comment by Reedy (talk | contribs)   00:04, 6 September 2011

Indeed, which was the way when the code was written.

This was a merge into trunk, not a merge and fix every issue ;)

#Comment by Krinkle (talk | contribs)   23:30, 5 September 2011

Another problem is that these two special pages are enabled, accessible and listed on Special:SpecialPages by default. That's not supposed to happen ad 99% of wikis will not have anything global and doesn't need this.

#Comment by Duplicatebug (talk | contribs)   19:22, 11 September 2011

An unused $forceRawInterwiki is leaved in Parser.php

#Comment by Duplicatebug (talk | contribs)   19:44, 11 September 2011

This commit makes Title.php mutable (with Title::setInterwiki), it is called at one place, maybe it is possible to create a new title with one of the factory methods and remove Title::setInterwiki.

The change of Preprocessor_Hash.php should also added to Preprocessor_HipHop. A comment is also nice, to say why the interwiki of the frame/context, and not the interwiki from the templatename, is used. (My understanding: It is used to load the inner templates of a distant template also from the distant wiki).

#Comment by Reedy (talk | contribs)   23:33, 22 September 2011

We should make a decision about this - is it staying in trunk, and if so, needs tidying up

Else we back it out (sooner rather than later, 1.19 is going to be upon us soon...) and cleanup and think about properly extension-i[sz]ing it

#Comment by Bryan (talk | contribs)   14:52, 24 September 2011

It's mostly a human resource question. Is there somebody who is willing to take care of it. If not, then it should be reverted and another gsoc project will bitrot away unfortunately. If there is somebody who is willing to take care of it, then we can have the discussion whether development should be continued in a branch, extension or trunk.

#Comment by Krinkle (talk | contribs)   16:14, 24 September 2011

I think it's stable enough to be usable with MediaWiki trunk, as an extension. Since Wikimedia is likely going to be using this at some point, development will likely not stop completely.

If there are too many things that this project needs that can't be done from an extension (due to lack of configuration variable or hooks), then I suggest simply added them in separate commits with references to the iwtransclusion project, and make follow-ups to that in the extension directory using those hooks. We did the same for the ResourceLoader 2 projects with Gadgets. Develop the feature in an extension and add hooks as needed in separate commits to core.

#Comment by Krinkle (talk | contribs)   20:24, 29 September 2011

The fact that the Title object becomes mutable and that this new feature is enabled by default even when no repository is defined is problematic enough. Before things come dependant on this making merging revisions even harder, please remove this from core as soon as possible.

Status & tagging log