Index: trunk/phase3/maintenance/archives/patch-page_props.sql
===================================================================
--- trunk/phase3/maintenance/archives/patch-page_props.sql (revision 0)
+++ trunk/phase3/maintenance/archives/patch-page_props.sql (revision 31113)
@@ -0,0 +1,9 @@
+-- Name/value pairs indexed by page_id
+CREATE TABLE /*$wgDBprefix*/page_props (
+ pp_page int NOT NULL,
+ pp_propname varbinary(60) NOT NULL,
+ pp_value blob NOT NULL,
+
+ PRIMARY KEY (pp_page,pp_propname)
+);
+
Property changes on: trunk/phase3/maintenance/archives/patch-page_props.sql
___________________________________________________________________
Name: svn:eol-style
+ native
Index: trunk/phase3/maintenance/updaters.inc
===================================================================
--- trunk/phase3/maintenance/updaters.inc (revision 31112)
+++ trunk/phase3/maintenance/updaters.inc (revision 31113)
@@ -39,6 +39,7 @@
array( 'querycachetwo', 'patch-querycachetwo.sql' ),
array( 'redirect', 'patch-redirect.sql' ),
array( 'protected_titles', 'patch-protected_titles.sql' ),
+ array( 'page_props', 'patch-page_props.sql' ),
);
$wgNewFields = array(
Index: trunk/phase3/maintenance/tables.sql
===================================================================
--- trunk/phase3/maintenance/tables.sql (revision 31112)
+++ trunk/phase3/maintenance/tables.sql (revision 31113)
@@ -1184,4 +1184,13 @@
KEY pt_timestamp (pt_timestamp)
) /*$wgDBTableOptions*/;
+-- Name/value pairs indexed by page_id
+CREATE TABLE /*$wgDBprefix*/page_props (
+ pp_page int NOT NULL,
+ pp_propname varbinary(60) NOT NULL,
+ pp_value blob NOT NULL,
+
+ PRIMARY KEY (pp_page,pp_propname)
+);
+
-- vim: sw=2 sts=2 et
Index: trunk/phase3/includes/ParserOutput.php
===================================================================
--- trunk/phase3/includes/ParserOutput.php (revision 31112)
+++ trunk/phase3/includes/ParserOutput.php (revision 31113)
@@ -22,8 +22,9 @@
$mHeadItems, # Items to put in the <head> section
$mOutputHooks, # Hook tags as per $wgParserOutputHooks
$mWarnings, # Warning text to be returned to the user. Wikitext formatted.
- $mSections; # Table of contents
-
+ $mSections, # Table of contents
+ $mProperties; # Name/value pairs to be cached in the DB
+
/**
* Overridden title for display
*/
@@ -50,6 +51,7 @@
$this->mTemplateIds = array();
$this->mOutputHooks = array();
$this->mWarnings = array();
+ $this->mProperties = array();
}
function getText() { return $this->mText; }
@@ -183,7 +185,24 @@
public function getFlag( $flag ) {
return isset( $this->mFlags[$flag] );
}
-
+
+ /**
+ * Set a property to be cached in the DB
+ */
+ public function setProperty( $name, $value ) {
+ $this->mProperties[$name] = $value;
+ }
+
+ public function getProperty( $name ){
+ return isset( $this->mProperties[$name] ) ? $this->mProperties[$name] : false;
+ }
+
+ public function getProperties() {
+ if ( !isset( $this->mProperties ) ) {
+ $this->mProperties = array();
+ }
+ return $this->mProperties;
+ }
}
Index: trunk/phase3/includes/LinkBatch.php
===================================================================
--- trunk/phase3/includes/LinkBatch.php (revision 31112)
+++ trunk/phase3/includes/LinkBatch.php (revision 31113)
@@ -73,12 +73,18 @@
* Return an array mapping PDBK to ID
*/
function executeInto( &$cache ) {
- $fname = 'LinkBatch::executeInto';
- wfProfileIn( $fname );
- // Do query
+ wfProfileIn( __METHOD__ );
$res = $this->doQuery();
+ $ids = $this->addResultToCache( $cache, $res );
+ wfProfileOut( __METHOD__ );
+ return $ids;
+ }
+
+ /**
+ * Add a ResultWrapper containing IDs and titles to a LinkCache object
+ */
+ function addResultToCache( $cache, $res ) {
if ( !$res ) {
- wfProfileOut( $fname );
return array();
}
@@ -92,7 +98,6 @@
$ids[$title->getPrefixedDBkey()] = $row->page_id;
unset( $remaining[$row->page_namespace][$row->page_title] );
}
- $res->free();
// The remaining links in $data are bad links, register them as such
foreach ( $remaining as $ns => $dbkeys ) {
@@ -102,7 +107,6 @@
$ids[$title->getPrefixedDBkey()] = 0;
}
}
- wfProfileOut( $fname );
return $ids;
}
@@ -110,12 +114,10 @@
* Perform the existence test query, return a ResultWrapper with page_id fields
*/
function doQuery() {
- $fname = 'LinkBatch::doQuery';
-
if ( $this->isEmpty() ) {
return false;
}
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
// Construct query
// This is very similar to Parser::replaceLinkHolders
@@ -123,22 +125,21 @@
$page = $dbr->tableName( 'page' );
$set = $this->constructSet( 'page', $dbr );
if ( $set === false ) {
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return false;
}
$sql = "SELECT page_id, page_namespace, page_title FROM $page WHERE $set";
// Do query
- $res = new ResultWrapper( $dbr, $dbr->query( $sql, $fname ) );
- wfProfileOut( $fname );
+ $res = new ResultWrapper( $dbr, $dbr->query( $sql, __METHOD__ ) );
+ wfProfileOut( __METHOD__ );
return $res;
}
/**
* Construct a WHERE clause which will match all the given titles.
- * Give the appropriate table's field name prefix ('page', 'pl', etc).
*
- * @param $prefix String: ??
+ * @param string $prefix the appropriate table's field name prefix ('page', 'pl', etc)
* @return string
* @public
*/
Index: trunk/phase3/includes/Parser.php
===================================================================
--- trunk/phase3/includes/Parser.php (revision 31112)
+++ trunk/phase3/includes/Parser.php (revision 31113)
@@ -98,7 +98,7 @@
var $mInterwikiLinkHolders, $mLinkHolders;
var $mIncludeSizes, $mPPNodeCount, $mDefaultSort;
var $mTplExpandCache; // empty-frame expansion cache
- var $mTplRedirCache, $mTplDomCache, $mHeadings;
+ var $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores;
# Temporary
# These are variables reset at least once per parse regardless of $clearState
@@ -147,51 +147,9 @@
$this->mFirstCall = false;
wfProfileIn( __METHOD__ );
- global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions;
$this->setHook( 'pre', array( $this, 'renderPreTag' ) );
-
- # Syntax for arguments (see self::setFunctionHook):
- # "name for lookup in localized magic words array",
- # function callback,
- # optional SFH_NO_HASH to omit the hash from calls (e.g. {{int:...}
- # instead of {{#int:...}})
- $this->setFunctionHook( 'int', array( 'CoreParserFunctions', 'intFunction' ), SFH_NO_HASH );
- $this->setFunctionHook( 'ns', array( 'CoreParserFunctions', 'ns' ), SFH_NO_HASH );
- $this->setFunctionHook( 'urlencode', array( 'CoreParserFunctions', 'urlencode' ), SFH_NO_HASH );
- $this->setFunctionHook( 'lcfirst', array( 'CoreParserFunctions', 'lcfirst' ), SFH_NO_HASH );
- $this->setFunctionHook( 'ucfirst', array( 'CoreParserFunctions', 'ucfirst' ), SFH_NO_HASH );
- $this->setFunctionHook( 'lc', array( 'CoreParserFunctions', 'lc' ), SFH_NO_HASH );
- $this->setFunctionHook( 'uc', array( 'CoreParserFunctions', 'uc' ), SFH_NO_HASH );
- $this->setFunctionHook( 'localurl', array( 'CoreParserFunctions', 'localurl' ), SFH_NO_HASH );
- $this->setFunctionHook( 'localurle', array( 'CoreParserFunctions', 'localurle' ), SFH_NO_HASH );
- $this->setFunctionHook( 'fullurl', array( 'CoreParserFunctions', 'fullurl' ), SFH_NO_HASH );
- $this->setFunctionHook( 'fullurle', array( 'CoreParserFunctions', 'fullurle' ), SFH_NO_HASH );
- $this->setFunctionHook( 'formatnum', array( 'CoreParserFunctions', 'formatnum' ), SFH_NO_HASH );
- $this->setFunctionHook( 'grammar', array( 'CoreParserFunctions', 'grammar' ), SFH_NO_HASH );
- $this->setFunctionHook( 'plural', array( 'CoreParserFunctions', 'plural' ), SFH_NO_HASH );
- $this->setFunctionHook( 'numberofpages', array( 'CoreParserFunctions', 'numberofpages' ), SFH_NO_HASH );
- $this->setFunctionHook( 'numberofusers', array( 'CoreParserFunctions', 'numberofusers' ), SFH_NO_HASH );
- $this->setFunctionHook( 'numberofarticles', array( 'CoreParserFunctions', 'numberofarticles' ), SFH_NO_HASH );
- $this->setFunctionHook( 'numberoffiles', array( 'CoreParserFunctions', 'numberoffiles' ), SFH_NO_HASH );
- $this->setFunctionHook( 'numberofadmins', array( 'CoreParserFunctions', 'numberofadmins' ), SFH_NO_HASH );
- $this->setFunctionHook( 'numberofedits', array( 'CoreParserFunctions', 'numberofedits' ), SFH_NO_HASH );
- $this->setFunctionHook( 'language', array( 'CoreParserFunctions', 'language' ), SFH_NO_HASH );
- $this->setFunctionHook( 'padleft', array( 'CoreParserFunctions', 'padleft' ), SFH_NO_HASH );
- $this->setFunctionHook( 'padright', array( 'CoreParserFunctions', 'padright' ), SFH_NO_HASH );
- $this->setFunctionHook( 'anchorencode', array( 'CoreParserFunctions', 'anchorencode' ), SFH_NO_HASH );
- $this->setFunctionHook( 'special', array( 'CoreParserFunctions', 'special' ) );
- $this->setFunctionHook( 'defaultsort', array( 'CoreParserFunctions', 'defaultsort' ), SFH_NO_HASH );
- $this->setFunctionHook( 'filepath', array( 'CoreParserFunctions', 'filepath' ), SFH_NO_HASH );
- $this->setFunctionHook( 'tag', array( 'CoreParserFunctions', 'tagObj' ), SFH_OBJECT_ARGS );
-
- if ( $wgAllowDisplayTitle ) {
- $this->setFunctionHook( 'displaytitle', array( 'CoreParserFunctions', 'displaytitle' ), SFH_NO_HASH );
- }
- if ( $wgAllowSlowParserFunctions ) {
- $this->setFunctionHook( 'pagesinnamespace', array( 'CoreParserFunctions', 'pagesinnamespace' ), SFH_NO_HASH );
- }
-
+ CoreParserFunctions::register( $this );
$this->initialiseVariables();
wfRunHooks( 'ParserFirstCallInit', array( &$this ) );
@@ -256,6 +214,7 @@
$this->mPPNodeCount = 0;
$this->mDefaultSort = false;
$this->mHeadings = array();
+ $this->mDoubleUnderscores = array();
# Fix cloning
if ( isset( $this->mPreprocessor ) && $this->mPreprocessor->parser !== $this ) {
@@ -991,8 +950,7 @@
$text = preg_replace( '/(^|\n)-----*/', '\\1<hr />', $text );
- $text = $this->stripToc( $text );
- $this->stripNoGallery( $text );
+ $text = $this->doDoubleUnderscore( $text );
$text = $this->doHeadings( $text );
if($this->mOptions->getUseDynamicDates()) {
$df =& DateFormatter::getInstance();
@@ -3302,32 +3260,11 @@
}
/**
- * Detect __NOGALLERY__ magic word and set a placeholder
+ * Strip double-underscore items like __NOGALLERY__ and __NOTOC__
+ * Fills $this->mDoubleUnderscores, returns the modified text
*/
- function stripNoGallery( &$text ) {
- # if the string __NOGALLERY__ (not case-sensitive) occurs in the HTML,
- # do not add TOC
- $mw = MagicWord::get( 'nogallery' );
- $this->mOutput->mNoGallery = $mw->matchAndRemove( $text ) ;
- }
-
- /**
- * Find the first __TOC__ magic word and set a <!--MWTOC-->
- * placeholder that will then be replaced by the real TOC in
- * ->formatHeadings, this works because at this points real
- * comments will have already been discarded by the sanitizer.
- *
- * Any additional __TOC__ magic words left over will be discarded
- * as there can only be one TOC on the page.
- */
- function stripToc( $text ) {
- # if the string __NOTOC__ (not case-sensitive) occurs in the HTML,
- # do not add TOC
- $mw = MagicWord::get( 'notoc' );
- if( $mw->matchAndRemove( $text ) ) {
- $this->mShowToc = false;
- }
-
+ function doDoubleUnderscore( $text ) {
+ // The position of __TOC__ needs to be recorded
$mw = MagicWord::get( 'toc' );
if( $mw->match( $text ) ) {
$this->mShowToc = true;
@@ -3339,6 +3276,20 @@
// Only keep the first one.
$text = $mw->replace( '', $text );
}
+
+ // Now match and remove the rest of them
+ $mwa = MagicWord::getDoubleUnderscoreArray();
+ $this->mDoubleUnderscores = $mwa->matchAndRemove( $text );
+
+ if ( isset( $this->mDoubleUnderscores['nogallery'] ) ) {
+ $this->mOutput->mNoGallery = true;
+ }
+ if ( isset( $this->mDoubleUnderscores['notoc'] ) && !$this->mForceTocPosition ) {
+ $this->mShowToc = false;
+ }
+ if ( isset( $this->mDoubleUnderscores['hiddencat'] ) ) {
+ $this->mOutput->setProperty( 'hiddencat', 'y' );
+ }
return $text;
}
@@ -3367,8 +3318,7 @@
}
# Inhibit editsection links if requested in the page
- $esw =& MagicWord::get( 'noeditsection' );
- if( $esw->matchAndRemove( $text ) ) {
+ if ( isset( $this->mDoubleUnderscores['noeditsection'] ) ) {
$showEditLink = 0;
}
@@ -3384,14 +3334,13 @@
# Allow user to stipulate that a page should have a "new section"
# link added via __NEWSECTIONLINK__
- $mw =& MagicWord::get( 'newsectionlink' );
- if( $mw->matchAndRemove( $text ) )
+ if ( isset( $this->mDoubleUnderscores['newsectionlink'] ) ) {
$this->mOutput->setNewSection( true );
+ }
# if the string __FORCETOC__ (not case-sensitive) occurs in the HTML,
# override above conditions and always show TOC above first header
- $mw =& MagicWord::get( 'forcetoc' );
- if ($mw->matchAndRemove( $text ) ) {
+ if ( isset( $this->mDoubleUnderscores['forcetoc'] ) ) {
$this->mShowToc = true;
$enoughToc = true;
}
Index: trunk/phase3/includes/OutputPage.php
===================================================================
--- trunk/phase3/includes/OutputPage.php (revision 31112)
+++ trunk/phase3/includes/OutputPage.php (revision 31113)
@@ -270,18 +270,40 @@
/**
* Add an array of categories, with names in the keys
*/
- public function addCategoryLinks($categories) {
+ public function addCategoryLinks( $categories ) {
global $wgUser, $wgContLang;
if ( !is_array( $categories ) ) {
return;
}
- # Add the links to the link cache in a batch
+ if ( count( $categories ) == 0 ) {
+ return;
+ }
+ # Add the links to a LinkBatch
$arr = array( NS_CATEGORY => $categories );
$lb = new LinkBatch;
$lb->setArray( $arr );
- $lb->execute();
+ # Fetch existence plus the hiddencat property
+ $dbr = wfGetDB( DB_SLAVE );
+ $pageTable = $dbr->tableName( 'page' );
+ $propsTable = $dbr->tableName( 'page_props' );
+ $where = $lb->constructSet( 'page', $dbr );
+ $sql = "SELECT page_id, page_namespace, page_title, pp_value FROM $pageTable LEFT JOIN $propsTable " .
+ " ON pp_page=page_id WHERE ($where) AND pp_propname='hiddencat'";
+ $res = $dbr->query( $sql, __METHOD__ );
+
+ # Add the results to the link cache
+ $lb->addResultToCache( LinkCache::singleton(), $res );
+
+ # Remove categories with hiddencat
+ foreach ( $res as $row ) {
+ if ( isset( $row->pp_value ) ) {
+ unset( $categories[$row->page_title] );
+ }
+ }
+
+ # Add the remaining categories to the skin
$sk = $wgUser->getSkin();
foreach ( $categories as $category => $unused ) {
$title = Title::makeTitleSafe( NS_CATEGORY, $category );
@@ -389,11 +411,11 @@
// Versioning...
$this->mTemplateIds += (array)$parserOutput->mTemplateIds;
- # Display title
+ // Display title
if( ( $dt = $parserOutput->getDisplayTitle() ) !== false )
$this->setPageTitle( $dt );
- # Hooks registered in the object
+ // Hooks registered in the object
global $wgParserOutputHooks;
foreach ( $parserOutput->getOutputHooks() as $hookInfo ) {
list( $hookName, $data ) = $hookInfo;
Index: trunk/phase3/includes/LinksUpdate.php
===================================================================
--- trunk/phase3/includes/LinksUpdate.php (revision 31112)
+++ trunk/phase3/includes/LinksUpdate.php (revision 31113)
@@ -17,6 +17,7 @@
$mExternals, //!< URLs of external links, array key only
$mCategories, //!< Map of category names to sort keys
$mInterlangs, //!< Map of language codes to titles
+ $mProperties, //!< Map of arbitrary name to value
$mDb, //!< Database connection reference
$mOptions, //!< SELECT options to be used (array)
$mRecursive; //!< Whether to queue jobs for recursive updates
@@ -51,6 +52,7 @@
$this->mTemplates = $parserOutput->getTemplates();
$this->mExternals = $parserOutput->getExternalLinks();
$this->mCategories = $parserOutput->getCategories();
+ $this->mProperties = $parserOutput->getProperties();
# Convert the format of the interlanguage links
# I didn't want to change it in the ParserOutput, because that array is passed all
@@ -85,8 +87,7 @@
}
function doIncrementalUpdate() {
- $fname = 'LinksUpdate::doIncrementalUpdate';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
# Page links
$existing = $this->getExistingLinks();
@@ -126,13 +127,22 @@
$categoryUpdates = array_diff_assoc( $existing, $this->mCategories ) + array_diff_assoc( $this->mCategories, $existing );
$this->invalidateCategories( $categoryUpdates );
+ # Page properties
+ $existing = $this->getExistingProperties();
+ $this->incrTableUpdate( 'page_props', 'pp', $this->getPropertyDeletions( $existing ),
+ $this->getPropertyInsertions( $existing ) );
+
+ # Invalidate the necessary pages
+ $changed = array_diff_assoc( $existing, $this->mProperties ) + array_diff_assoc( $this->mProperties, $existing );
+ $this->invalidateProperties( $changed );
+
# Refresh links of all pages including this page
# This will be in a separate transaction
if ( $this->mRecursive ) {
$this->queueRecursiveJobs();
}
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
}
/**
@@ -141,8 +151,7 @@
* Also useful where link table corruption needs to be repaired, e.g. in refreshLinks.php
*/
function doDumbUpdate() {
- $fname = 'LinksUpdate::doDumbUpdate';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
# Refresh category pages and image description pages
$existing = $this->getExistingCategories();
@@ -156,6 +165,7 @@
$this->dumbTableUpdate( 'templatelinks', $this->getTemplateInsertions(), 'tl_from' );
$this->dumbTableUpdate( 'externallinks', $this->getExternalInsertions(), 'el_from' );
$this->dumbTableUpdate( 'langlinks', $this->getInterlangInsertions(), 'll_from' );
+ $this->dumbTableUpdate( 'page_props', $this->getPropertyInsertions(), 'pp_page' );
# Update the cache of all the category pages and image description pages which were changed
$this->invalidateCategories( $categoryUpdates );
@@ -167,7 +177,7 @@
$this->queueRecursiveJobs();
}
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
}
function queueRecursiveJobs() {
@@ -209,8 +219,6 @@
* @param array $dbkeys
*/
function invalidatePages( $namespace, $dbkeys ) {
- $fname = 'LinksUpdate::invalidatePages';
-
if ( !count( $dbkeys ) ) {
return;
}
@@ -227,7 +235,7 @@
'page_namespace' => $namespace,
'page_title IN (' . $this->mDb->makeList( $dbkeys ) . ')',
'page_touched < ' . $this->mDb->addQuotes( $now )
- ), $fname
+ ), __METHOD__
);
while ( $row = $this->mDb->fetchObject( $res ) ) {
$ids[] = $row->page_id;
@@ -245,7 +253,7 @@
array(
'page_id IN (' . $this->mDb->makeList( $ids ) . ')',
'page_touched < ' . $this->mDb->addQuotes( $now )
- ), $fname
+ ), __METHOD__
);
}
@@ -258,13 +266,12 @@
}
function dumbTableUpdate( $table, $insertions, $fromField ) {
- $fname = 'LinksUpdate::dumbTableUpdate';
- $this->mDb->delete( $table, array( $fromField => $this->mId ), $fname );
+ $this->mDb->delete( $table, array( $fromField => $this->mId ), __METHOD__ );
if ( count( $insertions ) ) {
# The link array was constructed without FOR UPDATE, so there may be collisions
# This may cause minor link table inconsistencies, which is better than
# crippling the site with lock contention.
- $this->mDb->insert( $table, $insertions, $fname, array( 'IGNORE' ) );
+ $this->mDb->insert( $table, $insertions, __METHOD__, array( 'IGNORE' ) );
}
}
@@ -285,8 +292,12 @@
* @private
*/
function incrTableUpdate( $table, $prefix, $deletions, $insertions ) {
- $fname = 'LinksUpdate::incrTableUpdate';
- $where = array( "{$prefix}_from" => $this->mId );
+ if ( $table == 'page_props' ) {
+ $fromField = 'pp_page';
+ } else {
+ $fromField = "{$prefix}_from";
+ }
+ $where = array( $fromField => $this->mId );
if ( $table == 'pagelinks' || $table == 'templatelinks' ) {
$clause = $this->makeWhereFrom2d( $deletions, $prefix );
if ( $clause ) {
@@ -297,6 +308,8 @@
} else {
if ( $table == 'langlinks' ) {
$toField = 'll_lang';
+ } elseif ( $table == 'page_props' ) {
+ $toField = 'pp_propname';
} else {
$toField = $prefix . '_to';
}
@@ -307,10 +320,10 @@
}
}
if ( $where ) {
- $this->mDb->delete( $table, $where, $fname );
+ $this->mDb->delete( $table, $where, __METHOD__ );
}
if ( count( $insertions ) ) {
- $this->mDb->insert( $table, $insertions, $fname, 'IGNORE' );
+ $this->mDb->insert( $table, $insertions, __METHOD__, 'IGNORE' );
}
}
@@ -429,6 +442,23 @@
}
/**
+ * Get an array of page property insertions
+ */
+ function getPropertyInsertions( $existing = array() ) {
+ $diffs = array_diff_assoc( $this->mProperties, $existing );
+ $arr = array();
+ foreach ( $diffs as $name => $value ) {
+ $arr[] = array(
+ 'pp_page' => $this->mId,
+ 'pp_propname' => $name,
+ 'pp_value' => $value,
+ );
+ }
+ return $arr;
+ }
+
+
+ /**
* Given an array of existing links, returns those links which are not in $this
* and thus should be deleted.
* @private
@@ -499,13 +529,20 @@
}
/**
+ * Get array of properties which should be deleted.
+ * @private
+ */
+ function getPropertyDeletions( $existing ) {
+ return array_diff_assoc( $existing, $this->mProperties );
+ }
+
+ /**
* Get an array of existing links, as a 2-D array
* @private
*/
function getExistingLinks() {
- $fname = 'LinksUpdate::getExistingLinks';
$res = $this->mDb->select( 'pagelinks', array( 'pl_namespace', 'pl_title' ),
- array( 'pl_from' => $this->mId ), $fname, $this->mOptions );
+ array( 'pl_from' => $this->mId ), __METHOD__, $this->mOptions );
$arr = array();
while ( $row = $this->mDb->fetchObject( $res ) ) {
if ( !isset( $arr[$row->pl_namespace] ) ) {
@@ -522,9 +559,8 @@
* @private
*/
function getExistingTemplates() {
- $fname = 'LinksUpdate::getExistingTemplates';
$res = $this->mDb->select( 'templatelinks', array( 'tl_namespace', 'tl_title' ),
- array( 'tl_from' => $this->mId ), $fname, $this->mOptions );
+ array( 'tl_from' => $this->mId ), __METHOD__, $this->mOptions );
$arr = array();
while ( $row = $this->mDb->fetchObject( $res ) ) {
if ( !isset( $arr[$row->tl_namespace] ) ) {
@@ -541,9 +577,8 @@
* @private
*/
function getExistingImages() {
- $fname = 'LinksUpdate::getExistingImages';
$res = $this->mDb->select( 'imagelinks', array( 'il_to' ),
- array( 'il_from' => $this->mId ), $fname, $this->mOptions );
+ array( 'il_from' => $this->mId ), __METHOD__, $this->mOptions );
$arr = array();
while ( $row = $this->mDb->fetchObject( $res ) ) {
$arr[$row->il_to] = 1;
@@ -557,9 +592,8 @@
* @private
*/
function getExistingExternals() {
- $fname = 'LinksUpdate::getExistingExternals';
$res = $this->mDb->select( 'externallinks', array( 'el_to' ),
- array( 'el_from' => $this->mId ), $fname, $this->mOptions );
+ array( 'el_from' => $this->mId ), __METHOD__, $this->mOptions );
$arr = array();
while ( $row = $this->mDb->fetchObject( $res ) ) {
$arr[$row->el_to] = 1;
@@ -573,9 +607,8 @@
* @private
*/
function getExistingCategories() {
- $fname = 'LinksUpdate::getExistingCategories';
$res = $this->mDb->select( 'categorylinks', array( 'cl_to', 'cl_sortkey' ),
- array( 'cl_from' => $this->mId ), $fname, $this->mOptions );
+ array( 'cl_from' => $this->mId ), __METHOD__, $this->mOptions );
$arr = array();
while ( $row = $this->mDb->fetchObject( $res ) ) {
$arr[$row->cl_to] = $row->cl_sortkey;
@@ -590,15 +623,30 @@
* @private
*/
function getExistingInterlangs() {
- $fname = 'LinksUpdate::getExistingInterlangs';
$res = $this->mDb->select( 'langlinks', array( 'll_lang', 'll_title' ),
- array( 'll_from' => $this->mId ), $fname, $this->mOptions );
+ array( 'll_from' => $this->mId ), __METHOD__, $this->mOptions );
$arr = array();
while ( $row = $this->mDb->fetchObject( $res ) ) {
$arr[$row->ll_lang] = $row->ll_title;
}
return $arr;
}
+
+ /**
+ * Get an array of existing categories, with the name in the key and sort key in the value.
+ * @private
+ */
+ function getExistingProperties() {
+ $res = $this->mDb->select( 'page_props', array( 'pp_propname', 'pp_value' ),
+ array( 'pp_page' => $this->mId ), __METHOD__, $this->mOptions );
+ $arr = array();
+ while ( $row = $this->mDb->fetchObject( $res ) ) {
+ $arr[$row->pp_propname] = $row->pp_value;
+ }
+ $this->mDb->freeResult( $res );
+ return $arr;
+ }
+
/**
* Return the title object of the page being updated
@@ -606,5 +654,25 @@
function getTitle() {
return $this->mTitle;
}
+
+ /**
+ * Invalidate any necessary link lists related to page property changes
+ */
+ function invalidateProperties( $changed ) {
+ global $wgPagePropLinkInvalidations;
+
+ foreach ( $changed as $name => $value ) {
+ if ( isset( $wgPagePropLinkInvalidations[$name] ) ) {
+ $inv = $wgPagePropLinkInvalidations[$name];
+ if ( !is_array( $inv ) ) {
+ $inv = array( $inv );
+ }
+ foreach ( $inv as $table ) {
+ $update = new HTMLCacheUpdate( $this->mTitle, $table );
+ $update->doUpdate();
+ }
+ }
+ }
+ }
}
Index: trunk/phase3/includes/MagicWord.php
===================================================================
--- trunk/phase3/includes/MagicWord.php (revision 31112)
+++ trunk/phase3/includes/MagicWord.php (revision 31113)
@@ -140,7 +140,19 @@
'numberofadmins' => 3600,
);
+ static public $mDoubleUnderscoreIDs = array(
+ 'notoc',
+ 'nogallery',
+ 'forcetoc',
+ 'toc',
+ 'noeditsection',
+ 'newsectionlink',
+ 'hiddencat',
+ );
+
+
static public $mObjects = array();
+ static public $mDoubleUnderscoreArray = null;
/**#@-*/
@@ -197,8 +209,15 @@
return -1;
}
}
+
+ /** Get a MagicWordArray of double-underscore entities */
+ static function getDoubleUnderscoreArray() {
+ if ( is_null( self::$mDoubleUnderscoreArray ) ) {
+ self::$mDoubleUnderscoreArray = new MagicWordArray( self::$mDoubleUnderscoreIDs );
+ }
+ return self::$mDoubleUnderscoreArray;
+ }
-
# Initialises this object with an ID
function load( $id ) {
global $wgContLang;
@@ -449,6 +468,7 @@
var $names = array();
var $hash;
var $baseRegex, $regex;
+ var $matches;
function __construct( $names = array() ) {
$this->names = $names;
@@ -555,6 +575,8 @@
/**
* Parse a match array from preg_match
+ * Returns array(magic word ID, parameter value)
+ * If there is no parameter value, that element will be false.
*/
function parseMatch( $m ) {
reset( $m );
@@ -613,4 +635,25 @@
}
return false;
}
+
+ /**
+ * Returns an associative array, ID => param value, for all items that match
+ * Removes the matched items from the input string (passed by reference)
+ */
+ public function matchAndRemove( &$text ) {
+ $found = array();
+ $regexes = $this->getRegex();
+ foreach ( $regexes as $regex ) {
+ if ( $regex === '' ) {
+ continue;
+ }
+ preg_match_all( $regex, $text, $matches, PREG_SET_ORDER );
+ foreach ( $matches as $m ) {
+ list( $name, $param ) = $this->parseMatch( $m );
+ $found[$name] = $param;
+ }
+ $text = preg_replace( $regex, '', $text );
+ }
+ return $found;
+ }
}
Index: trunk/phase3/includes/DefaultSettings.php
===================================================================
--- trunk/phase3/includes/DefaultSettings.php (revision 31112)
+++ trunk/phase3/includes/DefaultSettings.php (revision 31113)
@@ -2937,3 +2937,11 @@
* Hooks should return strings or false
*/
$wgExceptionHooks = array();
+
+/**
+ * Page property link table invalidation lists.
+ * Should only be set by extensions.
+ */
+$wgPagePropLinkInvalidations = array(
+ 'hiddencat' => 'categorylinks',
+);
Index: trunk/phase3/includes/CoreParserFunctions.php
===================================================================
--- trunk/phase3/includes/CoreParserFunctions.php (revision 31112)
+++ trunk/phase3/includes/CoreParserFunctions.php (revision 31113)
@@ -5,6 +5,52 @@
* @addtogroup Parser
*/
class CoreParserFunctions {
+ static function register( $parser ) {
+ global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions;
+
+ # Syntax for arguments (see self::setFunctionHook):
+ # "name for lookup in localized magic words array",
+ # function callback,
+ # optional SFH_NO_HASH to omit the hash from calls (e.g. {{int:...}
+ # instead of {{#int:...}})
+
+ $parser->setFunctionHook( 'int', array( __CLASS__, 'intFunction' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'ns', array( __CLASS__, 'ns' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'urlencode', array( __CLASS__, 'urlencode' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'lcfirst', array( __CLASS__, 'lcfirst' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'ucfirst', array( __CLASS__, 'ucfirst' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'lc', array( __CLASS__, 'lc' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'uc', array( __CLASS__, 'uc' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'localurl', array( __CLASS__, 'localurl' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'localurle', array( __CLASS__, 'localurle' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'fullurl', array( __CLASS__, 'fullurl' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'fullurle', array( __CLASS__, 'fullurle' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'formatnum', array( __CLASS__, 'formatnum' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'grammar', array( __CLASS__, 'grammar' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'plural', array( __CLASS__, 'plural' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'numberofpages', array( __CLASS__, 'numberofpages' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'numberofusers', array( __CLASS__, 'numberofusers' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'numberofarticles', array( __CLASS__, 'numberofarticles' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'numberoffiles', array( __CLASS__, 'numberoffiles' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'numberofadmins', array( __CLASS__, 'numberofadmins' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'numberofedits', array( __CLASS__, 'numberofedits' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'language', array( __CLASS__, 'language' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'padleft', array( __CLASS__, 'padleft' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'padright', array( __CLASS__, 'padright' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'anchorencode', array( __CLASS__, 'anchorencode' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'special', array( __CLASS__, 'special' ) );
+ $parser->setFunctionHook( 'defaultsort', array( __CLASS__, 'defaultsort' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'filepath', array( __CLASS__, 'filepath' ), SFH_NO_HASH );
+ $parser->setFunctionHook( 'tag', array( __CLASS__, 'tagObj' ), SFH_OBJECT_ARGS );
+
+ if ( $wgAllowDisplayTitle ) {
+ $parser->setFunctionHook( 'displaytitle', array( __CLASS__, 'displaytitle' ), SFH_NO_HASH );
+ }
+ if ( $wgAllowSlowParserFunctions ) {
+ $parser->setFunctionHook( 'pagesinnamespace', array( __CLASS__, 'pagesinnamespace' ), SFH_NO_HASH );
+ }
+ }
+
static function intFunction( $parser, $part1 = '' /*, ... */ ) {
if ( strval( $part1 ) !== '' ) {
$args = array_slice( func_get_args(), 2 );
Index: trunk/phase3/languages/messages/MessagesEn.php
===================================================================
--- trunk/phase3/languages/messages/MessagesEn.php (revision 31112)
+++ trunk/phase3/languages/messages/MessagesEn.php (revision 31113)
@@ -337,6 +337,7 @@
'defaultsort' => array( 1, 'DEFAULTSORT:', 'DEFAULTSORTKEY:', 'DEFAULTCATEGORYSORT:' ),
'filepath' => array( 0, 'FILEPATH:' ),
'tag' => array( 0, 'tag' ),
+ 'hiddencat' => array( 1, '__HIDDENCAT__' ),
);
/**