Index: trunk/phase3/includes/Defines.php
===================================================================
--- trunk/phase3/includes/Defines.php (revision 15030)
+++ trunk/phase3/includes/Defines.php (revision 15031)
@@ -4,6 +4,11 @@
* @package MediaWiki
*/
+/**
+ * Version constants for the benefit of extensions
+ */
+define( 'MW_SPECIALPAGE_VERSION', 2 );
+
/**#@+
* Database related constants
*/
Index: trunk/phase3/includes/GlobalFunctions.php
===================================================================
--- trunk/phase3/includes/GlobalFunctions.php (revision 15030)
+++ trunk/phase3/includes/GlobalFunctions.php (revision 15031)
@@ -1937,4 +1937,31 @@
return strrev( $outChars );
}
+/**
+ * Create an object with a given name and an array of construct parameters
+ * @param string $name
+ * @param array $p parameters
+ */
+function wfCreateObject( $name, $p ){
+ $p = array_values( $p );
+ switch ( count( $p ) ) {
+ case 0:
+ return new $name;
+ case 1:
+ return new $name( $p[0] );
+ case 2:
+ return new $name( $p[0], $p[1] );
+ case 3:
+ return new $name( $p[0], $p[1], $p[2] );
+ case 4:
+ return new $name( $p[0], $p[1], $p[2], $p[3] );
+ case 5:
+ return new $name( $p[0], $p[1], $p[2], $p[3], $p[4] );
+ case 6:
+ return new $name( $p[0], $p[1], $p[2], $p[3], $p[4], $p[5] );
+ default:
+ throw new MWException( "Too many arguments to construtor in wfCreateObject" );
+ }
+}
+
?>
Index: trunk/phase3/includes/MessageCache.php
===================================================================
--- trunk/phase3/includes/MessageCache.php (revision 15030)
+++ trunk/phase3/includes/MessageCache.php (revision 15031)
@@ -315,6 +315,11 @@
$this->mCache[$uckey] = false;
}
}
+
+ # Make sure all extension messages are available
+ wfLoadAllExtensions();
+
+ # Add them to the cache
foreach ( $this->mExtensionMessages as $key => $value ) {
$uckey = $wgLang->ucfirst( $key );
if ( !array_key_exists( $uckey, $this->mCache ) ) {
Index: trunk/phase3/includes/Setup.php
===================================================================
--- trunk/phase3/includes/Setup.php (revision 15030)
+++ trunk/phase3/includes/Setup.php (revision 15031)
@@ -66,7 +66,6 @@
require_once( 'HistoryBlob.php' );
require_once( 'ProxyTools.php' );
require_once( 'ObjectCache.php' );
-require_once( 'SpecialPage.php' );
if ( $wgUseDynamicDates ) {
require_once( 'DateFormatter.php' );
Index: trunk/phase3/includes/AutoLoader.php
===================================================================
--- trunk/phase3/includes/AutoLoader.php (revision 15030)
+++ trunk/phase3/includes/AutoLoader.php (revision 15031)
@@ -1,8 +1,10 @@
<?php
/* This defines autoloading handler for whole MediaWiki framework */
-function __autoload($class_name) {
- $classes = array(
+function __autoload($className) {
+ global $wgAutoloadClasses;
+
+ static $localClasses = array(
'AjaxDispatcher' => 'AjaxDispatcher.php',
'AjaxCachePolicy' => 'AjaxFunctions.php',
'Article' => 'Article.php',
@@ -218,11 +220,22 @@
'memcached' => 'memcached-client.php',
'UtfNormal' => 'normal/UtfNormal.php'
);
- if (array_key_exists($class_name, $classes)) {
- require($classes[$class_name]);
+ if ( isset( $localClasses[$className] ) ) {
+ require($localClasses[$className]);
+ } elseif ( isset( $wgAutoloadClasses[$className] ) ) {
+ require( $wgAutoloadClasses[$className] );
} else {
return false;
}
}
+function wfLoadAllExtensions() {
+ global $wgAutoloadClasses;
+ foreach( $wgAutoloadClasses as $class => $file ) {
+ if ( ! class_exists( $class ) ) {
+ require( $file );
+ }
+ }
+}
+
?>
Index: trunk/phase3/includes/SpecialAllmessages.php
===================================================================
--- trunk/phase3/includes/SpecialAllmessages.php (revision 15030)
+++ trunk/phase3/includes/SpecialAllmessages.php (revision 15031)
@@ -26,6 +26,8 @@
$navText = wfMsg( 'allmessagestext' );
+ # Make sure all extension messages are available
+ wfLoadAllExtensions();
$first = true;
$sortedArray = array_merge( $wgAllMessagesEn, $wgMessageCache->mExtensionMessages );
Index: trunk/phase3/includes/DefaultSettings.php
===================================================================
--- trunk/phase3/includes/DefaultSettings.php (revision 15030)
+++ trunk/phase3/includes/DefaultSettings.php (revision 15031)
@@ -1535,10 +1535,34 @@
/** Use XML parser? */
$wgUseXMLparser = false ;
-/** Extensions */
-$wgSkinExtensionFunctions = array();
+/*****************************************************************************
+ * Extensions
+ */
+
+/**
+ * A list of callback functions which are called once MediaWiki is fully initialised
+ */
$wgExtensionFunctions = array();
+
/**
+ * Extension functions for initialisation of skins. This is called somewhat earlier
+ * than $wgExtensionFunctions.
+ */
+$wgSkinExtensionFunctions = array();
+
+
+/**
+ * Special page list.
+ * See the top of SpecialPage.php for documentation.
+ */
+$wgSpecialPages = array();
+
+/**
+ * Array mapping class names to filenames, for autoloading.
+ */
+$wgAutoloadClasses = array();
+
+/**
* An array of extension types and inside that their names, versions, authors
* and urls, note that the version and url key can be omitted.
*
@@ -1554,6 +1578,9 @@
* Where $type is 'specialpage', 'parserhook', or 'other'.
*/
$wgExtensionCredits = array();
+/*
+ * end extensions
+ ******************************************************************************/
/**
* Allow user Javascript page?
Index: trunk/phase3/includes/SpecialPage.php
===================================================================
--- trunk/phase3/includes/SpecialPage.php (revision 15030)
+++ trunk/phase3/includes/SpecialPage.php (revision 15031)
@@ -1,101 +1,30 @@
<?php
/**
- * SpecialPage: handling special pages and lists thereof
- * $wgSpecialPages is a list of all SpecialPage objects. These objects are
- * either instances of SpecialPage or a sub-class thereof. They have an
- * execute() method, which sends the HTML for the special page to $wgOut.
- * The parent class has an execute() method which distributes the call to
- * the historical global functions. Additionally, execute() also checks if the
- * user has the necessary access privileges and bails out if not.
+ * SpecialPage: handling special pages and lists thereof.
*
- * To add a special page at run-time, use SpecialPage::addPage().
- * DO NOT manipulate this array at run-time.
+ * To add a special page in an extension, add to $wgSpecialPages either
+ * an object instance or an array containing the name and constructor
+ * parameters. The latter is preferred for performance reasons.
*
+ * The object instantiated must be either an instance of SpecialPage or a
+ * sub-class thereof. It must have an execute() method, which sends the HTML
+ * for the special page to $wgOut. The parent class has an execute() method
+ * which distributes the call to the historical global functions. Additionally,
+ * execute() also checks if the user has the necessary access privileges
+ * and bails out if not.
+ *
+ * To add a core special page, use the similar static list in
+ * SpecialPage::$mList. To remove a core static special page at runtime, use
+ * a SpecialPage_initList hook.
+ *
* @package MediaWiki
* @subpackage SpecialPage
*/
-
/**
* @access private
*/
-$wgSpecialPages = array(
- 'DoubleRedirects' => new SpecialPage ( 'DoubleRedirects' ),
- 'BrokenRedirects' => new SpecialPage ( 'BrokenRedirects' ),
- 'Disambiguations' => new SpecialPage ( 'Disambiguations' ),
- 'Userlogin' => new SpecialPage( 'Userlogin' ),
- 'Userlogout' => new UnlistedSpecialPage( 'Userlogout' ),
- 'Preferences' => new SpecialPage( 'Preferences' ),
- 'Watchlist' => new SpecialPage( 'Watchlist' ),
-
- 'Recentchanges' => new IncludableSpecialPage( 'Recentchanges' ),
- 'Upload' => new SpecialPage( 'Upload' ),
- 'Imagelist' => new SpecialPage( 'Imagelist' ),
- 'Newimages' => new IncludableSpecialPage( 'Newimages' ),
- 'Listusers' => new SpecialPage( 'Listusers' ),
- 'Statistics' => new SpecialPage( 'Statistics' ),
- 'Random' => new SpecialPage( 'Randompage' ),
- 'Lonelypages' => new SpecialPage( 'Lonelypages' ),
- 'Uncategorizedpages'=> new SpecialPage( 'Uncategorizedpages' ),
- 'Uncategorizedcategories'=> new SpecialPage( 'Uncategorizedcategories' ),
- 'Uncategorizedimages' => new SpecialPage( 'Uncategorizedimages' ),
- 'Unusedcategories' => new SpecialPage( 'Unusedcategories' ),
- 'Unusedimages' => new SpecialPage( 'Unusedimages' ),
- 'Wantedpages' => new IncludableSpecialPage( 'Wantedpages' ),
- 'Wantedcategories' => new SpecialPage( 'Wantedcategories' ),
- 'Mostlinked' => new SpecialPage( 'Mostlinked' ),
- 'Mostlinkedcategories' => new SpecialPage( 'Mostlinkedcategories' ),
- 'Mostcategories' => new SpecialPage( 'Mostcategories' ),
- 'Mostimages' => new SpecialPage( 'Mostimages' ),
- 'Mostrevisions' => new SpecialPage( 'Mostrevisions' ),
- 'Shortpages' => new SpecialPage( 'Shortpages' ),
- 'Longpages' => new SpecialPage( 'Longpages' ),
- 'Newpages' => new IncludableSpecialPage( 'Newpages' ),
- 'Ancientpages' => new SpecialPage( 'Ancientpages' ),
- 'Deadendpages' => new SpecialPage( 'Deadendpages' ),
- 'Allpages' => new IncludableSpecialPage( 'Allpages' ),
- 'Prefixindex' => new IncludableSpecialPage( 'Prefixindex' ) ,
- 'Ipblocklist' => new SpecialPage( 'Ipblocklist' ),
- 'Specialpages' => new UnlistedSpecialPage( 'Specialpages' ),
- 'Contributions' => new UnlistedSpecialPage( 'Contributions' ),
- 'Emailuser' => new UnlistedSpecialPage( 'Emailuser' ),
- 'Whatlinkshere' => new UnlistedSpecialPage( 'Whatlinkshere' ),
- 'Recentchangeslinked' => new UnlistedSpecialPage( 'Recentchangeslinked' ),
- 'Movepage' => new UnlistedSpecialPage( 'Movepage' ),
- 'Blockme' => new UnlistedSpecialPage( 'Blockme' ),
- 'Booksources' => new SpecialPage( 'Booksources' ),
- 'Categories' => new SpecialPage( 'Categories' ),
- 'Export' => new SpecialPage( 'Export' ),
- 'Version' => new SpecialPage( 'Version' ),
- 'Allmessages' => new SpecialPage( 'Allmessages' ),
- 'Log' => new SpecialPage( 'Log' ),
- 'Blockip' => new SpecialPage( 'Blockip', 'block' ),
- 'Undelete' => new SpecialPage( 'Undelete', 'deletedhistory' ),
- "Import" => new SpecialPage( "Import", 'import' ),
- 'Lockdb' => new SpecialPage( 'Lockdb', 'siteadmin' ),
- 'Unlockdb' => new SpecialPage( 'Unlockdb', 'siteadmin' ),
- 'Userrights' => new SpecialPage( 'Userrights', 'userrights' ),
- 'MIMEsearch' => new SpecialPage( 'MIMEsearch' ),
- 'Unwatchedpages' => new SpecialPage( 'Unwatchedpages', 'unwatchedpages' ),
- 'Listredirects' => new SpecialPage( 'Listredirects' ),
- 'Revisiondelete' => new SpecialPage( 'Revisiondelete', 'deleterevision' ),
- 'Unusedtemplates' => new SpecialPage( 'Unusedtemplates' ),
- 'Randomredirect' => new SpecialPage( 'Randomredirect' ),
-);
-
-if( !$wgDisableCounters ) {
- $wgSpecialPages['Popularpages'] = new SpecialPage( 'Popularpages' );
-}
-
-if( !$wgDisableInternalSearch ) {
- $wgSpecialPages['Search'] = new SpecialPage( 'Search' );
-}
-
-if( $wgEmailAuthentication ) {
- $wgSpecialPages['Confirmemail'] = new UnlistedSpecialPage( 'Confirmemail' );
-}
-
/**
* Parent special page class, also static functions for handling the special
* page list
@@ -137,29 +66,144 @@
*/
var $mIncludable;
+ static public $mList = array(
+ 'DoubleRedirects' => array( 'SpecialPage', 'DoubleRedirects' ),
+ 'BrokenRedirects' => array( 'SpecialPage', 'BrokenRedirects' ),
+ 'Disambiguations' => array( 'SpecialPage', 'Disambiguations' ),
+ 'Userlogin' => array( 'SpecialPage', 'Userlogin' ),
+ 'Userlogout' => array( 'UnlistedSpecialPage', 'Userlogout' ),
+ 'Preferences' => array( 'SpecialPage', 'Preferences' ),
+ 'Watchlist' => array( 'SpecialPage', 'Watchlist' ),
+
+ 'Recentchanges' => array( 'IncludableSpecialPage', 'Recentchanges' ),
+ 'Upload' => array( 'SpecialPage', 'Upload' ),
+ 'Imagelist' => array( 'SpecialPage', 'Imagelist' ),
+ 'Newimages' => array( 'IncludableSpecialPage', 'Newimages' ),
+ 'Listusers' => array( 'SpecialPage', 'Listusers' ),
+ 'Statistics' => array( 'SpecialPage', 'Statistics' ),
+ 'Random' => array( 'SpecialPage', 'Randompage' ),
+ 'Lonelypages' => array( 'SpecialPage', 'Lonelypages' ),
+ 'Uncategorizedpages'=> array( 'SpecialPage', 'Uncategorizedpages' ),
+ 'Uncategorizedcategories'=> array( 'SpecialPage', 'Uncategorizedcategories' ),
+ 'Uncategorizedimages' => array( 'SpecialPage', 'Uncategorizedimages' ),
+ 'Unusedcategories' => array( 'SpecialPage', 'Unusedcategories' ),
+ 'Unusedimages' => array( 'SpecialPage', 'Unusedimages' ),
+ 'Wantedpages' => array( 'IncludableSpecialPage', 'Wantedpages' ),
+ 'Wantedcategories' => array( 'SpecialPage', 'Wantedcategories' ),
+ 'Mostlinked' => array( 'SpecialPage', 'Mostlinked' ),
+ 'Mostlinkedcategories' => array( 'SpecialPage', 'Mostlinkedcategories' ),
+ 'Mostcategories' => array( 'SpecialPage', 'Mostcategories' ),
+ 'Mostimages' => array( 'SpecialPage', 'Mostimages' ),
+ 'Mostrevisions' => array( 'SpecialPage', 'Mostrevisions' ),
+ 'Shortpages' => array( 'SpecialPage', 'Shortpages' ),
+ 'Longpages' => array( 'SpecialPage', 'Longpages' ),
+ 'Newpages' => array( 'IncludableSpecialPage', 'Newpages' ),
+ 'Ancientpages' => array( 'SpecialPage', 'Ancientpages' ),
+ 'Deadendpages' => array( 'SpecialPage', 'Deadendpages' ),
+ 'Allpages' => array( 'IncludableSpecialPage', 'Allpages' ),
+ 'Prefixindex' => array( 'IncludableSpecialPage', 'Prefixindex' ) ,
+ 'Ipblocklist' => array( 'SpecialPage', 'Ipblocklist' ),
+ 'Specialpages' => array( 'UnlistedSpecialPage', 'Specialpages' ),
+ 'Contributions' => array( 'UnlistedSpecialPage', 'Contributions' ),
+ 'Emailuser' => array( 'UnlistedSpecialPage', 'Emailuser' ),
+ 'Whatlinkshere' => array( 'UnlistedSpecialPage', 'Whatlinkshere' ),
+ 'Recentchangeslinked' => array( 'UnlistedSpecialPage', 'Recentchangeslinked' ),
+ 'Movepage' => array( 'UnlistedSpecialPage', 'Movepage' ),
+ 'Blockme' => array( 'UnlistedSpecialPage', 'Blockme' ),
+ 'Booksources' => array( 'SpecialPage', 'Booksources' ),
+ 'Categories' => array( 'SpecialPage', 'Categories' ),
+ 'Export' => array( 'SpecialPage', 'Export' ),
+ 'Version' => array( 'SpecialPage', 'Version' ),
+ 'Allmessages' => array( 'SpecialPage', 'Allmessages' ),
+ 'Log' => array( 'SpecialPage', 'Log' ),
+ 'Blockip' => array( 'SpecialPage', 'Blockip', 'block' ),
+ 'Undelete' => array( 'SpecialPage', 'Undelete', 'deletedhistory' ),
+ "Import" => array( 'SpecialPage', "Import", 'import' ),
+ 'Lockdb' => array( 'SpecialPage', 'Lockdb', 'siteadmin' ),
+ 'Unlockdb' => array( 'SpecialPage', 'Unlockdb', 'siteadmin' ),
+ 'Userrights' => array( 'SpecialPage', 'Userrights', 'userrights' ),
+ 'MIMEsearch' => array( 'SpecialPage', 'MIMEsearch' ),
+ 'Unwatchedpages' => array( 'SpecialPage', 'Unwatchedpages', 'unwatchedpages' ),
+ 'Listredirects' => array( 'SpecialPage', 'Listredirects' ),
+ 'Revisiondelete' => array( 'SpecialPage', 'Revisiondelete', 'deleterevision' ),
+ 'Unusedtemplates' => array( 'SpecialPage', 'Unusedtemplates' ),
+ 'Randomredirect' => array( 'SpecialPage', 'Randomredirect' ),
+ );
+
+ static public $mListInitialised = false;
+
/**#@-*/
+ /**
+ * Initialise the special page list
+ * This must be called before accessing SpecialPage::$mList
+ */
+ static function initList() {
+ global $wgSpecialPages;
+ global $wgDisableCounters, $wgDisableInternalSearch, $wgEmailAuthentication;
+ #throw new MWException( __METHOD__ );
+
+ if ( self::$mListInitialised ) {
+ return;
+ }
+ wfProfileIn( __METHOD__ );
+
+ if( !$wgDisableCounters ) {
+ self::$mList['Popularpages'] = array( 'SpecialPage', 'Popularpages' );
+ }
+
+ if( !$wgDisableInternalSearch ) {
+ self::$mList['Search'] = array( 'SpecialPage', 'Search' );
+ }
+
+ if( $wgEmailAuthentication ) {
+ self::$mList['Confirmemail'] = array( 'UnlistedSpecialPage', 'Confirmemail' );
+ }
+
+ # Add extension special pages
+ self::$mList = array_merge( self::$mList, $wgSpecialPages );
+
+ # Better to set this now, to avoid infinite recursion in carelessly written hooks
+ self::$mListInitialised = true;
+
+ # Run hooks
+ # This hook can be used to remove undesired built-in special pages
+ wfRunHooks( 'SpecialPage_initList', array( &self::$mList ) );
+ wfProfileOut( __METHOD__ );
+ }
+
/**
- * Add a page to the list of valid special pages
- * $obj->execute() must send HTML to $wgOut then return
- * Use this for a special page extension
+ * Add a page to the list of valid special pages. This used to be the preferred
+ * method for adding special pages in extensions. It's now suggested that you add
+ * an associative record to $wgSpecialPages. This avoids autoloading SpecialPage.
+ *
+ * @param mixed $page Must either be an array specifying a class name and
+ * constructor parameters, or an object. The object,
+ * when constructed, must have an execute() method which
+ * sends HTML to $wgOut.
* @static
*/
- static function addPage( &$obj ) {
- global $wgSpecialPages;
- $wgSpecialPages[$obj->mName] = $obj;
+ static function addPage( &$page ) {
+ if ( !self::$mListInitialised ) {
+ self::initList();
+ }
+ self::$mList[$page->mName] = $page;
}
/**
* Remove a special page from the list
- * Occasionally used to disable expensive or dangerous special pages
+ * Formerly used to disable expensive or dangerous special pages. The
+ * preferred method is now to add a SpecialPage_initList hook.
+ *
* @static
*/
static function removePage( $name ) {
- global $wgSpecialPages;
- unset( $wgSpecialPages[$name] );
+ if ( !self::$mListInitialised ) {
+ self::initList();
+ }
+ unset( self::$mList[$name] );
}
/**
@@ -168,14 +212,25 @@
* @param string $name
*/
static function getPage( $name ) {
- global $wgSpecialPages;
- if ( array_key_exists( $name, $wgSpecialPages ) ) {
- return $wgSpecialPages[$name];
+ if ( !self::$mListInitialised ) {
+ self::initList();
+ }
+ if ( array_key_exists( $name, self::$mList ) ) {
+ $rec = self::$mList[$name];
+ if ( is_string( $rec ) ) {
+ $className = $rec;
+ self::$mList[$name] = new $className;
+ } elseif ( is_array( $rec ) ) {
+ $className = array_shift( $rec );
+ self::$mList[$name] = wfCreateObject( $className, $rec );
+ }
+ return self::$mList[$name];
} else {
return NULL;
}
}
+
/**
* @static
* @param string $name
@@ -231,16 +286,19 @@
* @static
*/
static function getPages() {
- global $wgSpecialPages;
+ if ( !self::$mListInitialised ) {
+ self::initList();
+ }
$pages = array(
'' => array(),
'sysop' => array(),
'developer' => array()
);
- foreach ( $wgSpecialPages as $name => $page ) {
+ foreach ( self::$mList as $name => $rec ) {
+ $page = self::getPage( $name );
if ( $page->isListed() ) {
- $pages[$page->getRestriction()][$page->getName()] =& $wgSpecialPages[$name];
+ $pages[$page->getRestriction()][$page->getName()] = $page;
}
}
return $pages;