MediaWiki r31113 - Code Review

Jump to: navigation, search
Repository:MediaWiki
Revision:r31112‎ | r31113 (on ViewVC)‎ | r31114 >
Date:08:53, 20 February 2008
Author:tstarling
Status:old
Tags:
Comment:
* Added __HIDDENCAT__ feature, to hide categories from the box at the bottom of the member pages depending on special text on the category page.
* Added page_props backend, generic parser-driven page properties which, when changed, invalidate the cache of backlinked pages on any links table. Could be used to add overlays to images depending on their deletion status, or to add icons to articles based on category membership.
* Refactored double-underscore handling in the parser.
* Moved CoreParserFunctions registration to CoreParserFunctions.
Modified paths:

Diff [purge]

Index: trunk/phase3/maintenance/archives/patch-page_props.sql
@@ -0,0 +1,9 @@
 2+-- Name/value pairs indexed by page_id
 3+CREATE TABLE /*$wgDBprefix*/page_props (
 4+ pp_page int NOT NULL,
 5+ pp_propname varbinary(60) NOT NULL,
 6+ pp_value blob NOT NULL,
 7+
 8+ PRIMARY KEY (pp_page,pp_propname)
 9+);
 10+
Property changes on: trunk/phase3/maintenance/archives/patch-page_props.sql
___________________________________________________________________
Added: svn:eol-style
111 + native
Index: trunk/phase3/maintenance/updaters.inc
@@ -39,6 +39,7 @@
4040 array( 'querycachetwo', 'patch-querycachetwo.sql' ),
4141 array( 'redirect', 'patch-redirect.sql' ),
4242 array( 'protected_titles', 'patch-protected_titles.sql' ),
 43+ array( 'page_props', 'patch-page_props.sql' ),
4344 );
4445
4546 $wgNewFields = array(
Index: trunk/phase3/maintenance/tables.sql
@@ -1184,4 +1184,13 @@
11851185 KEY pt_timestamp (pt_timestamp)
11861186 ) /*$wgDBTableOptions*/;
11871187
 1188+-- Name/value pairs indexed by page_id
 1189+CREATE TABLE /*$wgDBprefix*/page_props (
 1190+ pp_page int NOT NULL,
 1191+ pp_propname varbinary(60) NOT NULL,
 1192+ pp_value blob NOT NULL,
 1193+
 1194+ PRIMARY KEY (pp_page,pp_propname)
 1195+);
 1196+
11881197 -- vim: sw=2 sts=2 et
Index: trunk/phase3/includes/ParserOutput.php
@@ -22,8 +22,9 @@
2323 $mHeadItems, # Items to put in the <head> section
2424 $mOutputHooks, # Hook tags as per $wgParserOutputHooks
2525 $mWarnings, # Warning text to be returned to the user. Wikitext formatted.
26 - $mSections; # Table of contents
27 -
 26+ $mSections, # Table of contents
 27+ $mProperties; # Name/value pairs to be cached in the DB
 28+
2829 /**
2930 * Overridden title for display
3031 */
@@ -50,6 +51,7 @@
5152 $this->mTemplateIds = array();
5253 $this->mOutputHooks = array();
5354 $this->mWarnings = array();
 55+ $this->mProperties = array();
5456 }
5557
5658 function getText() { return $this->mText; }
@@ -183,7 +185,24 @@
184186 public function getFlag( $flag ) {
185187 return isset( $this->mFlags[$flag] );
186188 }
187 -
 189+
 190+ /**
 191+ * Set a property to be cached in the DB
 192+ */
 193+ public function setProperty( $name, $value ) {
 194+ $this->mProperties[$name] = $value;
 195+ }
 196+
 197+ public function getProperty( $name ){
 198+ return isset( $this->mProperties[$name] ) ? $this->mProperties[$name] : false;
 199+ }
 200+
 201+ public function getProperties() {
 202+ if ( !isset( $this->mProperties ) ) {
 203+ $this->mProperties = array();
 204+ }
 205+ return $this->mProperties;
 206+ }
188207 }
189208
190209
Index: trunk/phase3/includes/LinkBatch.php
@@ -73,12 +73,18 @@
7474 * Return an array mapping PDBK to ID
7575 */
7676 function executeInto( &$cache ) {
77 - $fname = 'LinkBatch::executeInto';
78 - wfProfileIn( $fname );
79 - // Do query
 77+ wfProfileIn( __METHOD__ );
8078 $res = $this->doQuery();
 79+ $ids = $this->addResultToCache( $cache, $res );
 80+ wfProfileOut( __METHOD__ );
 81+ return $ids;
 82+ }
 83+
 84+ /**
 85+ * Add a ResultWrapper containing IDs and titles to a LinkCache object
 86+ */
 87+ function addResultToCache( $cache, $res ) {
8188 if ( !$res ) {
82 - wfProfileOut( $fname );
8389 return array();
8490 }
8591
@@ -92,7 +98,6 @@
9399 $ids[$title->getPrefixedDBkey()] = $row->page_id;
94100 unset( $remaining[$row->page_namespace][$row->page_title] );
95101 }
96 - $res->free();
97102
98103 // The remaining links in $data are bad links, register them as such
99104 foreach ( $remaining as $ns => $dbkeys ) {
@@ -102,7 +107,6 @@
103108 $ids[$title->getPrefixedDBkey()] = 0;
104109 }
105110 }
106 - wfProfileOut( $fname );
107111 return $ids;
108112 }
109113
@@ -110,12 +114,10 @@
111115 * Perform the existence test query, return a ResultWrapper with page_id fields
112116 */
113117 function doQuery() {
114 - $fname = 'LinkBatch::doQuery';
115 -
116118 if ( $this->isEmpty() ) {
117119 return false;
118120 }
119 - wfProfileIn( $fname );
 121+ wfProfileIn( __METHOD__ );
120122
121123 // Construct query
122124 // This is very similar to Parser::replaceLinkHolders
@@ -123,22 +125,21 @@
124126 $page = $dbr->tableName( 'page' );
125127 $set = $this->constructSet( 'page', $dbr );
126128 if ( $set === false ) {
127 - wfProfileOut( $fname );
 129+ wfProfileOut( __METHOD__ );
128130 return false;
129131 }
130132 $sql = "SELECT page_id, page_namespace, page_title FROM $page WHERE $set";
131133
132134 // Do query
133 - $res = new ResultWrapper( $dbr, $dbr->query( $sql, $fname ) );
134 - wfProfileOut( $fname );
 135+ $res = new ResultWrapper( $dbr, $dbr->query( $sql, __METHOD__ ) );
 136+ wfProfileOut( __METHOD__ );
135137 return $res;
136138 }
137139
138140 /**
139141 * Construct a WHERE clause which will match all the given titles.
140 - * Give the appropriate table's field name prefix ('page', 'pl', etc).
141142 *
142 - * @param $prefix String: ??
 143+ * @param string $prefix the appropriate table's field name prefix ('page', 'pl', etc)
143144 * @return string
144145 * @public
145146 */
Index: trunk/phase3/includes/Parser.php
@@ -98,7 +98,7 @@
9999 var $mInterwikiLinkHolders, $mLinkHolders;
100100 var $mIncludeSizes, $mPPNodeCount, $mDefaultSort;
101101 var $mTplExpandCache; // empty-frame expansion cache
102 - var $mTplRedirCache, $mTplDomCache, $mHeadings;
 102+ var $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores;
103103
104104 # Temporary
105105 # These are variables reset at least once per parse regardless of $clearState
@@ -147,51 +147,9 @@
148148 $this->mFirstCall = false;
149149
150150 wfProfileIn( __METHOD__ );
151 - global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions;
152151
153152 $this->setHook( 'pre', array( $this, 'renderPreTag' ) );
154 -
155 - # Syntax for arguments (see self::setFunctionHook):
156 - # "name for lookup in localized magic words array",
157 - # function callback,
158 - # optional SFH_NO_HASH to omit the hash from calls (e.g. {{int:...}
159 - # instead of {{#int:...}})
160 - $this->setFunctionHook( 'int', array( 'CoreParserFunctions', 'intFunction' ), SFH_NO_HASH );
161 - $this->setFunctionHook( 'ns', array( 'CoreParserFunctions', 'ns' ), SFH_NO_HASH );
162 - $this->setFunctionHook( 'urlencode', array( 'CoreParserFunctions', 'urlencode' ), SFH_NO_HASH );
163 - $this->setFunctionHook( 'lcfirst', array( 'CoreParserFunctions', 'lcfirst' ), SFH_NO_HASH );
164 - $this->setFunctionHook( 'ucfirst', array( 'CoreParserFunctions', 'ucfirst' ), SFH_NO_HASH );
165 - $this->setFunctionHook( 'lc', array( 'CoreParserFunctions', 'lc' ), SFH_NO_HASH );
166 - $this->setFunctionHook( 'uc', array( 'CoreParserFunctions', 'uc' ), SFH_NO_HASH );
167 - $this->setFunctionHook( 'localurl', array( 'CoreParserFunctions', 'localurl' ), SFH_NO_HASH );
168 - $this->setFunctionHook( 'localurle', array( 'CoreParserFunctions', 'localurle' ), SFH_NO_HASH );
169 - $this->setFunctionHook( 'fullurl', array( 'CoreParserFunctions', 'fullurl' ), SFH_NO_HASH );
170 - $this->setFunctionHook( 'fullurle', array( 'CoreParserFunctions', 'fullurle' ), SFH_NO_HASH );
171 - $this->setFunctionHook( 'formatnum', array( 'CoreParserFunctions', 'formatnum' ), SFH_NO_HASH );
172 - $this->setFunctionHook( 'grammar', array( 'CoreParserFunctions', 'grammar' ), SFH_NO_HASH );
173 - $this->setFunctionHook( 'plural', array( 'CoreParserFunctions', 'plural' ), SFH_NO_HASH );
174 - $this->setFunctionHook( 'numberofpages', array( 'CoreParserFunctions', 'numberofpages' ), SFH_NO_HASH );
175 - $this->setFunctionHook( 'numberofusers', array( 'CoreParserFunctions', 'numberofusers' ), SFH_NO_HASH );
176 - $this->setFunctionHook( 'numberofarticles', array( 'CoreParserFunctions', 'numberofarticles' ), SFH_NO_HASH );
177 - $this->setFunctionHook( 'numberoffiles', array( 'CoreParserFunctions', 'numberoffiles' ), SFH_NO_HASH );
178 - $this->setFunctionHook( 'numberofadmins', array( 'CoreParserFunctions', 'numberofadmins' ), SFH_NO_HASH );
179 - $this->setFunctionHook( 'numberofedits', array( 'CoreParserFunctions', 'numberofedits' ), SFH_NO_HASH );
180 - $this->setFunctionHook( 'language', array( 'CoreParserFunctions', 'language' ), SFH_NO_HASH );
181 - $this->setFunctionHook( 'padleft', array( 'CoreParserFunctions', 'padleft' ), SFH_NO_HASH );
182 - $this->setFunctionHook( 'padright', array( 'CoreParserFunctions', 'padright' ), SFH_NO_HASH );
183 - $this->setFunctionHook( 'anchorencode', array( 'CoreParserFunctions', 'anchorencode' ), SFH_NO_HASH );
184 - $this->setFunctionHook( 'special', array( 'CoreParserFunctions', 'special' ) );
185 - $this->setFunctionHook( 'defaultsort', array( 'CoreParserFunctions', 'defaultsort' ), SFH_NO_HASH );
186 - $this->setFunctionHook( 'filepath', array( 'CoreParserFunctions', 'filepath' ), SFH_NO_HASH );
187 - $this->setFunctionHook( 'tag', array( 'CoreParserFunctions', 'tagObj' ), SFH_OBJECT_ARGS );
188 -
189 - if ( $wgAllowDisplayTitle ) {
190 - $this->setFunctionHook( 'displaytitle', array( 'CoreParserFunctions', 'displaytitle' ), SFH_NO_HASH );
191 - }
192 - if ( $wgAllowSlowParserFunctions ) {
193 - $this->setFunctionHook( 'pagesinnamespace', array( 'CoreParserFunctions', 'pagesinnamespace' ), SFH_NO_HASH );
194 - }
195 -
 153+ CoreParserFunctions::register( $this );
196154 $this->initialiseVariables();
197155
198156 wfRunHooks( 'ParserFirstCallInit', array( &$this ) );
@@ -256,6 +214,7 @@
257215 $this->mPPNodeCount = 0;
258216 $this->mDefaultSort = false;
259217 $this->mHeadings = array();
 218+ $this->mDoubleUnderscores = array();
260219
261220 # Fix cloning
262221 if ( isset( $this->mPreprocessor ) && $this->mPreprocessor->parser !== $this ) {
@@ -991,8 +950,7 @@
992951
993952 $text = preg_replace( '/(^|\n)-----*/', '\\1<hr />', $text );
994953
995 - $text = $this->stripToc( $text );
996 - $this->stripNoGallery( $text );
 954+ $text = $this->doDoubleUnderscore( $text );
997955 $text = $this->doHeadings( $text );
998956 if($this->mOptions->getUseDynamicDates()) {
999957 $df =& DateFormatter::getInstance();
@@ -3302,32 +3260,11 @@
33033261 }
33043262
33053263 /**
3306 - * Detect __NOGALLERY__ magic word and set a placeholder
 3264+ * Strip double-underscore items like __NOGALLERY__ and __NOTOC__
 3265+ * Fills $this->mDoubleUnderscores, returns the modified text
33073266 */
3308 - function stripNoGallery( &$text ) {
3309 - # if the string __NOGALLERY__ (not case-sensitive) occurs in the HTML,
3310 - # do not add TOC
3311 - $mw = MagicWord::get( 'nogallery' );
3312 - $this->mOutput->mNoGallery = $mw->matchAndRemove( $text ) ;
3313 - }
3314 -
3315 - /**
3316 - * Find the first __TOC__ magic word and set a <!--MWTOC-->
3317 - * placeholder that will then be replaced by the real TOC in
3318 - * ->formatHeadings, this works because at this points real
3319 - * comments will have already been discarded by the sanitizer.
3320 - *
3321 - * Any additional __TOC__ magic words left over will be discarded
3322 - * as there can only be one TOC on the page.
3323 - */
3324 - function stripToc( $text ) {
3325 - # if the string __NOTOC__ (not case-sensitive) occurs in the HTML,
3326 - # do not add TOC
3327 - $mw = MagicWord::get( 'notoc' );
3328 - if( $mw->matchAndRemove( $text ) ) {
3329 - $this->mShowToc = false;
3330 - }
3331 -
 3267+ function doDoubleUnderscore( $text ) {
 3268+ // The position of __TOC__ needs to be recorded
33323269 $mw = MagicWord::get( 'toc' );
33333270 if( $mw->match( $text ) ) {
33343271 $this->mShowToc = true;
@@ -3339,6 +3276,20 @@
33403277 // Only keep the first one.
33413278 $text = $mw->replace( '', $text );
33423279 }
 3280+
 3281+ // Now match and remove the rest of them
 3282+ $mwa = MagicWord::getDoubleUnderscoreArray();
 3283+ $this->mDoubleUnderscores = $mwa->matchAndRemove( $text );
 3284+
 3285+ if ( isset( $this->mDoubleUnderscores['nogallery'] ) ) {
 3286+ $this->mOutput->mNoGallery = true;
 3287+ }
 3288+ if ( isset( $this->mDoubleUnderscores['notoc'] ) && !$this->mForceTocPosition ) {
 3289+ $this->mShowToc = false;
 3290+ }
 3291+ if ( isset( $this->mDoubleUnderscores['hiddencat'] ) ) {
 3292+ $this->mOutput->setProperty( 'hiddencat', 'y' );
 3293+ }
33433294 return $text;
33443295 }
33453296
@@ -3367,8 +3318,7 @@
33683319 }
33693320
33703321 # Inhibit editsection links if requested in the page
3371 - $esw =& MagicWord::get( 'noeditsection' );
3372 - if( $esw->matchAndRemove( $text ) ) {
 3322+ if ( isset( $this->mDoubleUnderscores['noeditsection'] ) ) {
33733323 $showEditLink = 0;
33743324 }
33753325
@@ -3384,14 +3334,13 @@
33853335
33863336 # Allow user to stipulate that a page should have a "new section"
33873337 # link added via __NEWSECTIONLINK__
3388 - $mw =& MagicWord::get( 'newsectionlink' );
3389 - if( $mw->matchAndRemove( $text ) )
 3338+ if ( isset( $this->mDoubleUnderscores['newsectionlink'] ) ) {
33903339 $this->mOutput->setNewSection( true );
 3340+ }
33913341
33923342 # if the string __FORCETOC__ (not case-sensitive) occurs in the HTML,
33933343 # override above conditions and always show TOC above first header
3394 - $mw =& MagicWord::get( 'forcetoc' );
3395 - if ($mw->matchAndRemove( $text ) ) {
 3344+ if ( isset( $this->mDoubleUnderscores['forcetoc'] ) ) {
33963345 $this->mShowToc = true;
33973346 $enoughToc = true;
33983347 }
Index: trunk/phase3/includes/OutputPage.php
@@ -270,18 +270,40 @@
271271 /**
272272 * Add an array of categories, with names in the keys
273273 */
274 - public function addCategoryLinks($categories) {
 274+ public function addCategoryLinks( $categories ) {
275275 global $wgUser, $wgContLang;
276276
277277 if ( !is_array( $categories ) ) {
278278 return;
279279 }
280 - # Add the links to the link cache in a batch
 280+ if ( count( $categories ) == 0 ) {
 281+ return;
 282+ }
 283+ # Add the links to a LinkBatch
281284 $arr = array( NS_CATEGORY => $categories );
282285 $lb = new LinkBatch;
283286 $lb->setArray( $arr );
284 - $lb->execute();
285287
 288+ # Fetch existence plus the hiddencat property
 289+ $dbr = wfGetDB( DB_SLAVE );
 290+ $pageTable = $dbr->tableName( 'page' );
 291+ $propsTable = $dbr->tableName( 'page_props' );
 292+ $where = $lb->constructSet( 'page', $dbr );
 293+ $sql = "SELECT page_id, page_namespace, page_title, pp_value FROM $pageTable LEFT JOIN $propsTable " .
 294+ " ON pp_page=page_id WHERE ($where) AND pp_propname='hiddencat'";
 295+ $res = $dbr->query( $sql, __METHOD__ );
 296+
 297+ # Add the results to the link cache
 298+ $lb->addResultToCache( LinkCache::singleton(), $res );
 299+
 300+ # Remove categories with hiddencat
 301+ foreach ( $res as $row ) {
 302+ if ( isset( $row->pp_value ) ) {
 303+ unset( $categories[$row->page_title] );
 304+ }
 305+ }
 306+
 307+ # Add the remaining categories to the skin
286308 $sk = $wgUser->getSkin();
287309 foreach ( $categories as $category => $unused ) {
288310 $title = Title::makeTitleSafe( NS_CATEGORY, $category );
@@ -389,11 +411,11 @@
390412 // Versioning...
391413 $this->mTemplateIds += (array)$parserOutput->mTemplateIds;
392414
393 - # Display title
 415+ // Display title
394416 if( ( $dt = $parserOutput->getDisplayTitle() ) !== false )
395417 $this->setPageTitle( $dt );
396418
397 - # Hooks registered in the object
 419+ // Hooks registered in the object
398420 global $wgParserOutputHooks;
399421 foreach ( $parserOutput->getOutputHooks() as $hookInfo ) {
400422 list( $hookName, $data ) = $hookInfo;
Index: trunk/phase3/includes/LinksUpdate.php
@@ -17,6 +17,7 @@
1818 $mExternals, //!< URLs of external links, array key only
1919 $mCategories, //!< Map of category names to sort keys
2020 $mInterlangs, //!< Map of language codes to titles
 21+ $mProperties, //!< Map of arbitrary name to value
2122 $mDb, //!< Database connection reference
2223 $mOptions, //!< SELECT options to be used (array)
2324 $mRecursive; //!< Whether to queue jobs for recursive updates
@@ -51,6 +52,7 @@
5253 $this->mTemplates = $parserOutput->getTemplates();
5354 $this->mExternals = $parserOutput->getExternalLinks();
5455 $this->mCategories = $parserOutput->getCategories();
 56+ $this->mProperties = $parserOutput->getProperties();
5557
5658 # Convert the format of the interlanguage links
5759 # I didn't want to change it in the ParserOutput, because that array is passed all
@@ -85,8 +87,7 @@
8688 }
8789
8890 function doIncrementalUpdate() {
89 - $fname = 'LinksUpdate::doIncrementalUpdate';
90 - wfProfileIn( $fname );
 91+ wfProfileIn( __METHOD__ );
9192
9293 # Page links
9394 $existing = $this->getExistingLinks();
@@ -126,13 +127,22 @@
127128 $categoryUpdates = array_diff_assoc( $existing, $this->mCategories ) + array_diff_assoc( $this->mCategories, $existing );
128129 $this->invalidateCategories( $categoryUpdates );
129130
 131+ # Page properties
 132+ $existing = $this->getExistingProperties();
 133+ $this->incrTableUpdate( 'page_props', 'pp', $this->getPropertyDeletions( $existing ),
 134+ $this->getPropertyInsertions( $existing ) );
 135+
 136+ # Invalidate the necessary pages
 137+ $changed = array_diff_assoc( $existing, $this->mProperties ) + array_diff_assoc( $this->mProperties, $existing );
 138+ $this->invalidateProperties( $changed );
 139+
130140 # Refresh links of all pages including this page
131141 # This will be in a separate transaction
132142 if ( $this->mRecursive ) {
133143 $this->queueRecursiveJobs();
134144 }
135145
136 - wfProfileOut( $fname );
 146+ wfProfileOut( __METHOD__ );
137147 }
138148
139149 /**
@@ -141,8 +151,7 @@
142152 * Also useful where link table corruption needs to be repaired, e.g. in refreshLinks.php
143153 */
144154 function doDumbUpdate() {
145 - $fname = 'LinksUpdate::doDumbUpdate';
146 - wfProfileIn( $fname );
 155+ wfProfileIn( __METHOD__ );
147156
148157 # Refresh category pages and image description pages
149158 $existing = $this->getExistingCategories();
@@ -156,6 +165,7 @@
157166 $this->dumbTableUpdate( 'templatelinks', $this->getTemplateInsertions(), 'tl_from' );
158167 $this->dumbTableUpdate( 'externallinks', $this->getExternalInsertions(), 'el_from' );
159168 $this->dumbTableUpdate( 'langlinks', $this->getInterlangInsertions(), 'll_from' );
 169+ $this->dumbTableUpdate( 'page_props', $this->getPropertyInsertions(), 'pp_page' );
160170
161171 # Update the cache of all the category pages and image description pages which were changed
162172 $this->invalidateCategories( $categoryUpdates );
@@ -167,7 +177,7 @@
168178 $this->queueRecursiveJobs();
169179 }
170180
171 - wfProfileOut( $fname );
 181+ wfProfileOut( __METHOD__ );
172182 }
173183
174184 function queueRecursiveJobs() {
@@ -209,8 +219,6 @@
210220 * @param array $dbkeys
211221 */
212222 function invalidatePages( $namespace, $dbkeys ) {
213 - $fname = 'LinksUpdate::invalidatePages';
214 -
215223 if ( !count( $dbkeys ) ) {
216224 return;
217225 }
@@ -227,7 +235,7 @@
228236 'page_namespace' => $namespace,
229237 'page_title IN (' . $this->mDb->makeList( $dbkeys ) . ')',
230238 'page_touched < ' . $this->mDb->addQuotes( $now )
231 - ), $fname
 239+ ), __METHOD__
232240 );
233241 while ( $row = $this->mDb->fetchObject( $res ) ) {
234242 $ids[] = $row->page_id;
@@ -245,7 +253,7 @@
246254 array(
247255 'page_id IN (' . $this->mDb->makeList( $ids ) . ')',
248256 'page_touched < ' . $this->mDb->addQuotes( $now )
249 - ), $fname
 257+ ), __METHOD__
250258 );
251259 }
252260
@@ -258,13 +266,12 @@
259267 }
260268
261269 function dumbTableUpdate( $table, $insertions, $fromField ) {
262 - $fname = 'LinksUpdate::dumbTableUpdate';
263 - $this->mDb->delete( $table, array( $fromField => $this->mId ), $fname );
 270+ $this->mDb->delete( $table, array( $fromField => $this->mId ), __METHOD__ );
264271 if ( count( $insertions ) ) {
265272 # The link array was constructed without FOR UPDATE, so there may be collisions
266273 # This may cause minor link table inconsistencies, which is better than
267274 # crippling the site with lock contention.
268 - $this->mDb->insert( $table, $insertions, $fname, array( 'IGNORE' ) );
 275+ $this->mDb->insert( $table, $insertions, __METHOD__, array( 'IGNORE' ) );
269276 }
270277 }
271278
@@ -285,8 +292,12 @@
286293 * @private
287294 */
288295 function incrTableUpdate( $table, $prefix, $deletions, $insertions ) {
289 - $fname = 'LinksUpdate::incrTableUpdate';
290 - $where = array( "{$prefix}_from" => $this->mId );
 296+ if ( $table == 'page_props' ) {
 297+ $fromField = 'pp_page';
 298+ } else {
 299+ $fromField = "{$prefix}_from";
 300+ }
 301+ $where = array( $fromField => $this->mId );
291302 if ( $table == 'pagelinks' || $table == 'templatelinks' ) {
292303 $clause = $this->makeWhereFrom2d( $deletions, $prefix );
293304 if ( $clause ) {
@@ -297,6 +308,8 @@
298309 } else {
299310 if ( $table == 'langlinks' ) {
300311 $toField = 'll_lang';
 312+ } elseif ( $table == 'page_props' ) {
 313+ $toField = 'pp_propname';
301314 } else {
302315 $toField = $prefix . '_to';
303316 }
@@ -307,10 +320,10 @@
308321 }
309322 }
310323 if ( $where ) {
311 - $this->mDb->delete( $table, $where, $fname );
 324+ $this->mDb->delete( $table, $where, __METHOD__ );
312325 }
313326 if ( count( $insertions ) ) {
314 - $this->mDb->insert( $table, $insertions, $fname, 'IGNORE' );
 327+ $this->mDb->insert( $table, $insertions, __METHOD__, 'IGNORE' );
315328 }
316329 }
317330
@@ -429,6 +442,23 @@
430443 }
431444
432445 /**
 446+ * Get an array of page property insertions
 447+ */
 448+ function getPropertyInsertions( $existing = array() ) {
 449+ $diffs = array_diff_assoc( $this->mProperties, $existing );
 450+ $arr = array();
 451+ foreach ( $diffs as $name => $value ) {
 452+ $arr[] = array(
 453+ 'pp_page' => $this->mId,
 454+ 'pp_propname' => $name,
 455+ 'pp_value' => $value,
 456+ );
 457+ }
 458+ return $arr;
 459+ }
 460+
 461+
 462+ /**
433463 * Given an array of existing links, returns those links which are not in $this
434464 * and thus should be deleted.
435465 * @private
@@ -499,13 +529,20 @@
500530 }
501531
502532 /**
 533+ * Get array of properties which should be deleted.
 534+ * @private
 535+ */
 536+ function getPropertyDeletions( $existing ) {
 537+ return array_diff_assoc( $existing, $this->mProperties );
 538+ }
 539+
 540+ /**
503541 * Get an array of existing links, as a 2-D array
504542 * @private
505543 */
506544 function getExistingLinks() {
507 - $fname = 'LinksUpdate::getExistingLinks';
508545 $res = $this->mDb->select( 'pagelinks', array( 'pl_namespace', 'pl_title' ),
509 - array( 'pl_from' => $this->mId ), $fname, $this->mOptions );
 546+ array( 'pl_from' => $this->mId ), __METHOD__, $this->mOptions );
510547 $arr = array();
511548 while ( $row = $this->mDb->fetchObject( $res ) ) {
512549 if ( !isset( $arr[$row->pl_namespace] ) ) {
@@ -522,9 +559,8 @@
523560 * @private
524561 */
525562 function getExistingTemplates() {
526 - $fname = 'LinksUpdate::getExistingTemplates';
527563 $res = $this->mDb->select( 'templatelinks', array( 'tl_namespace', 'tl_title' ),
528 - array( 'tl_from' => $this->mId ), $fname, $this->mOptions );
 564+ array( 'tl_from' => $this->mId ), __METHOD__, $this->mOptions );
529565 $arr = array();
530566 while ( $row = $this->mDb->fetchObject( $res ) ) {
531567 if ( !isset( $arr[$row->tl_namespace] ) ) {
@@ -541,9 +577,8 @@
542578 * @private
543579 */
544580 function getExistingImages() {
545 - $fname = 'LinksUpdate::getExistingImages';
546581 $res = $this->mDb->select( 'imagelinks', array( 'il_to' ),
547 - array( 'il_from' => $this->mId ), $fname, $this->mOptions );
 582+ array( 'il_from' => $this->mId ), __METHOD__, $this->mOptions );
548583 $arr = array();
549584 while ( $row = $this->mDb->fetchObject( $res ) ) {
550585 $arr[$row->il_to] = 1;
@@ -557,9 +592,8 @@
558593 * @private
559594 */
560595 function getExistingExternals() {
561 - $fname = 'LinksUpdate::getExistingExternals';
562596 $res = $this->mDb->select( 'externallinks', array( 'el_to' ),
563 - array( 'el_from' => $this->mId ), $fname, $this->mOptions );
 597+ array( 'el_from' => $this->mId ), __METHOD__, $this->mOptions );
564598 $arr = array();
565599 while ( $row = $this->mDb->fetchObject( $res ) ) {
566600 $arr[$row->el_to] = 1;
@@ -573,9 +607,8 @@
574608 * @private
575609 */
576610 function getExistingCategories() {
577 - $fname = 'LinksUpdate::getExistingCategories';
578611 $res = $this->mDb->select( 'categorylinks', array( 'cl_to', 'cl_sortkey' ),
579 - array( 'cl_from' => $this->mId ), $fname, $this->mOptions );
 612+ array( 'cl_from' => $this->mId ), __METHOD__, $this->mOptions );
580613 $arr = array();
581614 while ( $row = $this->mDb->fetchObject( $res ) ) {
582615 $arr[$row->cl_to] = $row->cl_sortkey;
@@ -590,15 +623,30 @@
591624 * @private
592625 */
593626 function getExistingInterlangs() {
594 - $fname = 'LinksUpdate::getExistingInterlangs';
595627 $res = $this->mDb->select( 'langlinks', array( 'll_lang', 'll_title' ),
596 - array( 'll_from' => $this->mId ), $fname, $this->mOptions );
 628+ array( 'll_from' => $this->mId ), __METHOD__, $this->mOptions );
597629 $arr = array();
598630 while ( $row = $this->mDb->fetchObject( $res ) ) {
599631 $arr[$row->ll_lang] = $row->ll_title;
600632 }
601633 return $arr;
602634 }
 635+
 636+ /**
 637+ * Get an array of existing categories, with the name in the key and sort key in the value.
 638+ * @private
 639+ */
 640+ function getExistingProperties() {
 641+ $res = $this->mDb->select( 'page_props', array( 'pp_propname', 'pp_value' ),
 642+ array( 'pp_page' => $this->mId ), __METHOD__, $this->mOptions );
 643+ $arr = array();
 644+ while ( $row = $this->mDb->fetchObject( $res ) ) {
 645+ $arr[$row->pp_propname] = $row->pp_value;
 646+ }
 647+ $this->mDb->freeResult( $res );
 648+ return $arr;
 649+ }
 650+
603651
604652 /**
605653 * Return the title object of the page being updated
@@ -606,5 +654,25 @@
607655 function getTitle() {
608656 return $this->mTitle;
609657 }
 658+
 659+ /**
 660+ * Invalidate any necessary link lists related to page property changes
 661+ */
 662+ function invalidateProperties( $changed ) {
 663+ global $wgPagePropLinkInvalidations;
 664+
 665+ foreach ( $changed as $name => $value ) {
 666+ if ( isset( $wgPagePropLinkInvalidations[$name] ) ) {
 667+ $inv = $wgPagePropLinkInvalidations[$name];
 668+ if ( !is_array( $inv ) ) {
 669+ $inv = array( $inv );
 670+ }
 671+ foreach ( $inv as $table ) {
 672+ $update = new HTMLCacheUpdate( $this->mTitle, $table );
 673+ $update->doUpdate();
 674+ }
 675+ }
 676+ }
 677+ }
610678 }
611679
Index: trunk/phase3/includes/MagicWord.php
@@ -140,7 +140,19 @@
141141 'numberofadmins' => 3600,
142142 );
143143
 144+ static public $mDoubleUnderscoreIDs = array(
 145+ 'notoc',
 146+ 'nogallery',
 147+ 'forcetoc',
 148+ 'toc',
 149+ 'noeditsection',
 150+ 'newsectionlink',
 151+ 'hiddencat',
 152+ );
 153+
 154+
144155 static public $mObjects = array();
 156+ static public $mDoubleUnderscoreArray = null;
145157
146158 /**#@-*/
147159
@@ -197,8 +209,15 @@
198210 return -1;
199211 }
200212 }
 213+
 214+ /** Get a MagicWordArray of double-underscore entities */
 215+ static function getDoubleUnderscoreArray() {
 216+ if ( is_null( self::$mDoubleUnderscoreArray ) ) {
 217+ self::$mDoubleUnderscoreArray = new MagicWordArray( self::$mDoubleUnderscoreIDs );
 218+ }
 219+ return self::$mDoubleUnderscoreArray;
 220+ }
201221
202 -
203222 # Initialises this object with an ID
204223 function load( $id ) {
205224 global $wgContLang;
@@ -449,6 +468,7 @@
450469 var $names = array();
451470 var $hash;
452471 var $baseRegex, $regex;
 472+ var $matches;
453473
454474 function __construct( $names = array() ) {
455475 $this->names = $names;
@@ -555,6 +575,8 @@
556576
557577 /**
558578 * Parse a match array from preg_match
 579+ * Returns array(magic word ID, parameter value)
 580+ * If there is no parameter value, that element will be false.
559581 */
560582 function parseMatch( $m ) {
561583 reset( $m );
@@ -613,4 +635,25 @@
614636 }
615637 return false;
616638 }
 639+
 640+ /**
 641+ * Returns an associative array, ID => param value, for all items that match
 642+ * Removes the matched items from the input string (passed by reference)
 643+ */
 644+ public function matchAndRemove( &$text ) {
 645+ $found = array();
 646+ $regexes = $this->getRegex();
 647+ foreach ( $regexes as $regex ) {
 648+ if ( $regex === '' ) {
 649+ continue;
 650+ }
 651+ preg_match_all( $regex, $text, $matches, PREG_SET_ORDER );
 652+ foreach ( $matches as $m ) {
 653+ list( $name, $param ) = $this->parseMatch( $m );
 654+ $found[$name] = $param;
 655+ }
 656+ $text = preg_replace( $regex, '', $text );
 657+ }
 658+ return $found;
 659+ }
617660 }
Index: trunk/phase3/includes/DefaultSettings.php
@@ -2937,3 +2937,11 @@
29382938 * Hooks should return strings or false
29392939 */
29402940 $wgExceptionHooks = array();
 2941+
 2942+/**
 2943+ * Page property link table invalidation lists.
 2944+ * Should only be set by extensions.
 2945+ */
 2946+$wgPagePropLinkInvalidations = array(
 2947+ 'hiddencat' => 'categorylinks',
 2948+);
Index: trunk/phase3/includes/CoreParserFunctions.php
@@ -5,6 +5,52 @@
66 * @addtogroup Parser
77 */
88 class CoreParserFunctions {
 9+ static function register( $parser ) {
 10+ global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions;
 11+
 12+ # Syntax for arguments (see self::setFunctionHook):
 13+ # "name for lookup in localized magic words array",
 14+ # function callback,
 15+ # optional SFH_NO_HASH to omit the hash from calls (e.g. {{int:...}
 16+ # instead of {{#int:...}})
 17+
 18+ $parser->setFunctionHook( 'int', array( __CLASS__, 'intFunction' ), SFH_NO_HASH );
 19+ $parser->setFunctionHook( 'ns', array( __CLASS__, 'ns' ), SFH_NO_HASH );
 20+ $parser->setFunctionHook( 'urlencode', array( __CLASS__, 'urlencode' ), SFH_NO_HASH );
 21+ $parser->setFunctionHook( 'lcfirst', array( __CLASS__, 'lcfirst' ), SFH_NO_HASH );
 22+ $parser->setFunctionHook( 'ucfirst', array( __CLASS__, 'ucfirst' ), SFH_NO_HASH );
 23+ $parser->setFunctionHook( 'lc', array( __CLASS__, 'lc' ), SFH_NO_HASH );
 24+ $parser->setFunctionHook( 'uc', array( __CLASS__, 'uc' ), SFH_NO_HASH );
 25+ $parser->setFunctionHook( 'localurl', array( __CLASS__, 'localurl' ), SFH_NO_HASH );
 26+ $parser->setFunctionHook( 'localurle', array( __CLASS__, 'localurle' ), SFH_NO_HASH );
 27+ $parser->setFunctionHook( 'fullurl', array( __CLASS__, 'fullurl' ), SFH_NO_HASH );
 28+ $parser->setFunctionHook( 'fullurle', array( __CLASS__, 'fullurle' ), SFH_NO_HASH );
 29+ $parser->setFunctionHook( 'formatnum', array( __CLASS__, 'formatnum' ), SFH_NO_HASH );
 30+ $parser->setFunctionHook( 'grammar', array( __CLASS__, 'grammar' ), SFH_NO_HASH );
 31+ $parser->setFunctionHook( 'plural', array( __CLASS__, 'plural' ), SFH_NO_HASH );
 32+ $parser->setFunctionHook( 'numberofpages', array( __CLASS__, 'numberofpages' ), SFH_NO_HASH );
 33+ $parser->setFunctionHook( 'numberofusers', array( __CLASS__, 'numberofusers' ), SFH_NO_HASH );
 34+ $parser->setFunctionHook( 'numberofarticles', array( __CLASS__, 'numberofarticles' ), SFH_NO_HASH );
 35+ $parser->setFunctionHook( 'numberoffiles', array( __CLASS__, 'numberoffiles' ), SFH_NO_HASH );
 36+ $parser->setFunctionHook( 'numberofadmins', array( __CLASS__, 'numberofadmins' ), SFH_NO_HASH );
 37+ $parser->setFunctionHook( 'numberofedits', array( __CLASS__, 'numberofedits' ), SFH_NO_HASH );
 38+ $parser->setFunctionHook( 'language', array( __CLASS__, 'language' ), SFH_NO_HASH );
 39+ $parser->setFunctionHook( 'padleft', array( __CLASS__, 'padleft' ), SFH_NO_HASH );
 40+ $parser->setFunctionHook( 'padright', array( __CLASS__, 'padright' ), SFH_NO_HASH );
 41+ $parser->setFunctionHook( 'anchorencode', array( __CLASS__, 'anchorencode' ), SFH_NO_HASH );
 42+ $parser->setFunctionHook( 'special', array( __CLASS__, 'special' ) );
 43+ $parser->setFunctionHook( 'defaultsort', array( __CLASS__, 'defaultsort' ), SFH_NO_HASH );
 44+ $parser->setFunctionHook( 'filepath', array( __CLASS__, 'filepath' ), SFH_NO_HASH );
 45+ $parser->setFunctionHook( 'tag', array( __CLASS__, 'tagObj' ), SFH_OBJECT_ARGS );
 46+
 47+ if ( $wgAllowDisplayTitle ) {
 48+ $parser->setFunctionHook( 'displaytitle', array( __CLASS__, 'displaytitle' ), SFH_NO_HASH );
 49+ }
 50+ if ( $wgAllowSlowParserFunctions ) {
 51+ $parser->setFunctionHook( 'pagesinnamespace', array( __CLASS__, 'pagesinnamespace' ), SFH_NO_HASH );
 52+ }
 53+ }
 54+
955 static function intFunction( $parser, $part1 = '' /*, ... */ ) {
1056 if ( strval( $part1 ) !== '' ) {
1157 $args = array_slice( func_get_args(), 2 );
Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -337,6 +337,7 @@
338338 'defaultsort' => array( 1, 'DEFAULTSORT:', 'DEFAULTSORTKEY:', 'DEFAULTCATEGORYSORT:' ),
339339 'filepath' => array( 0, 'FILEPATH:' ),
340340 'tag' => array( 0, 'tag' ),
 341+ 'hiddencat' => array( 1, '__HIDDENCAT__' ),
341342 );
342343
343344 /**

Status & tagging log

  • 15:24, 12 September 2011 Meno25 (talk | contribs) changed the status of r31113 [removed: ok added: old]