MediaWiki  REL1_19
LinksUpdate.php
Go to the documentation of this file.
00001 <?php
00022 class LinksUpdate {
00023 
00027         var $mId,            
00028                 $mTitle,         
00029                 $mParserOutput,  
00030                 $mLinks,         
00031                 $mImages,        
00032                 $mTemplates,     
00033                 $mExternals,     
00034                 $mCategories,    
00035                 $mInterlangs,    
00036                 $mProperties,    
00037                 $mDb,            
00038                 $mOptions,       
00039                 $mRecursive;     
00040 
00049         function __construct( $title, $parserOutput, $recursive = true ) {
00050                 global $wgAntiLockFlags;
00051 
00052                 if ( $wgAntiLockFlags & ALF_NO_LINK_LOCK ) {
00053                         $this->mOptions = array();
00054                 } else {
00055                         $this->mOptions = array( 'FOR UPDATE' );
00056                 }
00057                 $this->mDb = wfGetDB( DB_MASTER );
00058 
00059                 if ( !is_object( $title ) ) {
00060                         throw new MWException( "The calling convention to LinksUpdate::LinksUpdate() has changed. " .
00061                                 "Please see Article::editUpdates() for an invocation example.\n" );
00062                 }
00063                 $this->mTitle = $title;
00064                 $this->mId = $title->getArticleID();
00065 
00066                 $this->mParserOutput = $parserOutput;
00067                 $this->mLinks = $parserOutput->getLinks();
00068                 $this->mImages = $parserOutput->getImages();
00069                 $this->mTemplates = $parserOutput->getTemplates();
00070                 $this->mExternals = $parserOutput->getExternalLinks();
00071                 $this->mCategories = $parserOutput->getCategories();
00072                 $this->mProperties = $parserOutput->getProperties();
00073                 $this->mInterwikis = $parserOutput->getInterwikiLinks();
00074 
00075                 # Convert the format of the interlanguage links
00076                 # I didn't want to change it in the ParserOutput, because that array is passed all
00077                 # the way back to the skin, so either a skin API break would be required, or an
00078                 # inefficient back-conversion.
00079                 $ill = $parserOutput->getLanguageLinks();
00080                 $this->mInterlangs = array();
00081                 foreach ( $ill as $link ) {
00082                         list( $key, $title ) = explode( ':', $link, 2 );
00083                         $this->mInterlangs[$key] = $title;
00084                 }
00085 
00086                 foreach ( $this->mCategories as &$sortkey ) {
00087                         # If the sortkey is longer then 255 bytes,
00088                         # it truncated by DB, and then doesn't get
00089                         # matched when comparing existing vs current
00090                         # categories, causing bug 25254.
00091                         # Also. substr behaves weird when given "".
00092                         if ( $sortkey !== '' ) {
00093                                 $sortkey = substr( $sortkey, 0, 255 );
00094                         }
00095                 }
00096 
00097                 $this->mRecursive = $recursive;
00098 
00099                 wfRunHooks( 'LinksUpdateConstructed', array( &$this ) );
00100         }
00101 
00105         public function doUpdate() {
00106                 global $wgUseDumbLinkUpdate;
00107 
00108                 wfRunHooks( 'LinksUpdate', array( &$this ) );
00109                 if ( $wgUseDumbLinkUpdate ) {
00110                         $this->doDumbUpdate();
00111                 } else {
00112                         $this->doIncrementalUpdate();
00113                 }
00114                 wfRunHooks( 'LinksUpdateComplete', array( &$this ) );
00115         }
00116 
00117         protected function doIncrementalUpdate() {
00118                 wfProfileIn( __METHOD__ );
00119 
00120                 # Page links
00121                 $existing = $this->getExistingLinks();
00122                 $this->incrTableUpdate( 'pagelinks', 'pl', $this->getLinkDeletions( $existing ),
00123                         $this->getLinkInsertions( $existing ) );
00124 
00125                 # Image links
00126                 $existing = $this->getExistingImages();
00127 
00128                 $imageDeletes = $this->getImageDeletions( $existing );
00129                 $this->incrTableUpdate( 'imagelinks', 'il', $imageDeletes,
00130                         $this->getImageInsertions( $existing ) );
00131 
00132                 # Invalidate all image description pages which had links added or removed
00133                 $imageUpdates = $imageDeletes + array_diff_key( $this->mImages, $existing );
00134                 $this->invalidateImageDescriptions( $imageUpdates );
00135 
00136                 # External links
00137                 $existing = $this->getExistingExternals();
00138                 $this->incrTableUpdate( 'externallinks', 'el', $this->getExternalDeletions( $existing ),
00139                         $this->getExternalInsertions( $existing ) );
00140 
00141                 # Language links
00142                 $existing = $this->getExistingInterlangs();
00143                 $this->incrTableUpdate( 'langlinks', 'll', $this->getInterlangDeletions( $existing ),
00144                         $this->getInterlangInsertions( $existing ) );
00145 
00146                 # Inline interwiki links
00147                 $existing = $this->getExistingInterwikis();
00148                 $this->incrTableUpdate( 'iwlinks', 'iwl', $this->getInterwikiDeletions( $existing ),
00149                         $this->getInterwikiInsertions( $existing ) );
00150 
00151                 # Template links
00152                 $existing = $this->getExistingTemplates();
00153                 $this->incrTableUpdate( 'templatelinks', 'tl', $this->getTemplateDeletions( $existing ),
00154                         $this->getTemplateInsertions( $existing ) );
00155 
00156                 # Category links
00157                 $existing = $this->getExistingCategories();
00158 
00159                 $categoryDeletes = $this->getCategoryDeletions( $existing );
00160 
00161                 $this->incrTableUpdate( 'categorylinks', 'cl', $categoryDeletes,
00162                         $this->getCategoryInsertions( $existing ) );
00163 
00164                 # Invalidate all categories which were added, deleted or changed (set symmetric difference)
00165                 $categoryInserts = array_diff_assoc( $this->mCategories, $existing );
00166                 $categoryUpdates = $categoryInserts + $categoryDeletes;
00167                 $this->invalidateCategories( $categoryUpdates );
00168                 $this->updateCategoryCounts( $categoryInserts, $categoryDeletes );
00169 
00170                 # Page properties
00171                 $existing = $this->getExistingProperties();
00172 
00173                 $propertiesDeletes = $this->getPropertyDeletions( $existing );
00174 
00175                 $this->incrTableUpdate( 'page_props', 'pp', $propertiesDeletes,
00176                         $this->getPropertyInsertions( $existing ) );
00177 
00178                 # Invalidate the necessary pages
00179                 $changed = $propertiesDeletes + array_diff_assoc( $this->mProperties, $existing );
00180                 $this->invalidateProperties( $changed );
00181 
00182                 # Refresh links of all pages including this page
00183                 # This will be in a separate transaction
00184                 if ( $this->mRecursive ) {
00185                         $this->queueRecursiveJobs();
00186                 }
00187 
00188                 wfProfileOut( __METHOD__ );
00189         }
00190 
00196         protected function doDumbUpdate() {
00197                 wfProfileIn( __METHOD__ );
00198 
00199                 # Refresh category pages and image description pages
00200                 $existing = $this->getExistingCategories();
00201                 $categoryInserts = array_diff_assoc( $this->mCategories, $existing );
00202                 $categoryDeletes = array_diff_assoc( $existing, $this->mCategories );
00203                 $categoryUpdates = $categoryInserts + $categoryDeletes;
00204                 $existing = $this->getExistingImages();
00205                 $imageUpdates = array_diff_key( $existing, $this->mImages ) + array_diff_key( $this->mImages, $existing );
00206 
00207                 $this->dumbTableUpdate( 'pagelinks',     $this->getLinkInsertions(),     'pl_from' );
00208                 $this->dumbTableUpdate( 'imagelinks',    $this->getImageInsertions(),    'il_from' );
00209                 $this->dumbTableUpdate( 'categorylinks', $this->getCategoryInsertions(), 'cl_from' );
00210                 $this->dumbTableUpdate( 'templatelinks', $this->getTemplateInsertions(), 'tl_from' );
00211                 $this->dumbTableUpdate( 'externallinks', $this->getExternalInsertions(), 'el_from' );
00212                 $this->dumbTableUpdate( 'langlinks',     $this->getInterlangInsertions(),'ll_from' );
00213                 $this->dumbTableUpdate( 'iwlinks',       $this->getInterwikiInsertions(),'iwl_from' );
00214                 $this->dumbTableUpdate( 'page_props',    $this->getPropertyInsertions(), 'pp_page' );
00215 
00216                 # Update the cache of all the category pages and image description
00217                 # pages which were changed, and fix the category table count
00218                 $this->invalidateCategories( $categoryUpdates );
00219                 $this->updateCategoryCounts( $categoryInserts, $categoryDeletes );
00220                 $this->invalidateImageDescriptions( $imageUpdates );
00221 
00222                 # Refresh links of all pages including this page
00223                 # This will be in a separate transaction
00224                 if ( $this->mRecursive ) {
00225                         $this->queueRecursiveJobs();
00226                 }
00227 
00228                 wfProfileOut( __METHOD__ );
00229         }
00230 
00231         function queueRecursiveJobs() {
00232                 global $wgUpdateRowsPerJob;
00233                 wfProfileIn( __METHOD__ );
00234 
00235                 $cache = $this->mTitle->getBacklinkCache();
00236                 $batches = $cache->partition( 'templatelinks', $wgUpdateRowsPerJob );
00237                 if ( !$batches ) {
00238                         wfProfileOut( __METHOD__ );
00239                         return;
00240                 }
00241                 $jobs = array();
00242                 foreach ( $batches as $batch ) {
00243                         list( $start, $end ) = $batch;
00244                         $params = array(
00245                                 'table' => 'templatelinks',
00246                                 'start' => $start,
00247                                 'end' => $end,
00248                         );
00249                         $jobs[] = new RefreshLinksJob2( $this->mTitle, $params );
00250                 }
00251                 Job::batchInsert( $jobs );
00252 
00253                 wfProfileOut( __METHOD__ );
00254         }
00255 
00262         function invalidatePages( $namespace, $dbkeys ) {
00263                 if ( !count( $dbkeys ) ) {
00264                         return;
00265                 }
00266 
00272                 $now = $this->mDb->timestamp();
00273                 $ids = array();
00274                 $res = $this->mDb->select( 'page', array( 'page_id' ),
00275                         array(
00276                                 'page_namespace' => $namespace,
00277                                 'page_title IN (' . $this->mDb->makeList( $dbkeys ) . ')',
00278                                 'page_touched < ' . $this->mDb->addQuotes( $now )
00279                         ), __METHOD__
00280                 );
00281                 foreach ( $res as $row ) {
00282                         $ids[] = $row->page_id;
00283                 }
00284                 if ( !count( $ids ) ) {
00285                         return;
00286                 }
00287 
00293                 $this->mDb->update( 'page', array( 'page_touched' => $now ),
00294                         array(
00295                                 'page_id IN (' . $this->mDb->makeList( $ids ) . ')',
00296                                 'page_touched < ' . $this->mDb->addQuotes( $now )
00297                         ), __METHOD__
00298                 );
00299         }
00300 
00304         function invalidateCategories( $cats ) {
00305                 $this->invalidatePages( NS_CATEGORY, array_keys( $cats ) );
00306         }
00307 
00313         function updateCategoryCounts( $added, $deleted ) {
00314                 $a = WikiPage::factory( $this->mTitle );
00315                 $a->updateCategoryCounts(
00316                         array_keys( $added ), array_keys( $deleted )
00317                 );
00318         }
00319 
00323         function invalidateImageDescriptions( $images ) {
00324                 $this->invalidatePages( NS_FILE, array_keys( $images ) );
00325         }
00326 
00332         private function dumbTableUpdate( $table, $insertions, $fromField ) {
00333                 $this->mDb->delete( $table, array( $fromField => $this->mId ), __METHOD__ );
00334                 if ( count( $insertions ) ) {
00335                         # The link array was constructed without FOR UPDATE, so there may
00336                         # be collisions.  This may cause minor link table inconsistencies,
00337                         # which is better than crippling the site with lock contention.
00338                         $this->mDb->insert( $table, $insertions, __METHOD__, array( 'IGNORE' ) );
00339                 }
00340         }
00341 
00349         function incrTableUpdate( $table, $prefix, $deletions, $insertions ) {
00350                 if ( $table == 'page_props' ) {
00351                         $fromField = 'pp_page';
00352                 } else {
00353                         $fromField = "{$prefix}_from";
00354                 }
00355                 $where = array( $fromField => $this->mId );
00356                 if ( $table == 'pagelinks' || $table == 'templatelinks' || $table == 'iwlinks' ) {
00357                         if ( $table == 'iwlinks' ) {
00358                                 $baseKey = 'iwl_prefix';
00359                         } else {
00360                                 $baseKey = "{$prefix}_namespace";
00361                         }
00362                         $clause = $this->mDb->makeWhereFrom2d( $deletions, $baseKey, "{$prefix}_title" );
00363                         if ( $clause ) {
00364                                 $where[] = $clause;
00365                         } else {
00366                                 $where = false;
00367                         }
00368                 } else {
00369                         if ( $table == 'langlinks' ) {
00370                                 $toField = 'll_lang';
00371                         } elseif ( $table == 'page_props' ) {
00372                                 $toField = 'pp_propname';
00373                         } else {
00374                                 $toField = $prefix . '_to';
00375                         }
00376                         if ( count( $deletions ) ) {
00377                                 $where[] = "$toField IN (" . $this->mDb->makeList( array_keys( $deletions ) ) . ')';
00378                         } else {
00379                                 $where = false;
00380                         }
00381                 }
00382                 if ( $where ) {
00383                         $this->mDb->delete( $table, $where, __METHOD__ );
00384                 }
00385                 if ( count( $insertions ) ) {
00386                         $this->mDb->insert( $table, $insertions, __METHOD__, 'IGNORE' );
00387                 }
00388         }
00389 
00396         private function getLinkInsertions( $existing = array() ) {
00397                 $arr = array();
00398                 foreach( $this->mLinks as $ns => $dbkeys ) {
00399                         $diffs = isset( $existing[$ns] )
00400                                 ? array_diff_key( $dbkeys, $existing[$ns] )
00401                                 : $dbkeys;
00402                         foreach ( $diffs as $dbk => $id ) {
00403                                 $arr[] = array(
00404                                         'pl_from'      => $this->mId,
00405                                         'pl_namespace' => $ns,
00406                                         'pl_title'     => $dbk
00407                                 );
00408                         }
00409                 }
00410                 return $arr;
00411         }
00412 
00418         private function getTemplateInsertions( $existing = array() ) {
00419                 $arr = array();
00420                 foreach( $this->mTemplates as $ns => $dbkeys ) {
00421                         $diffs = isset( $existing[$ns] ) ? array_diff_key( $dbkeys, $existing[$ns] ) : $dbkeys;
00422                         foreach ( $diffs as $dbk => $id ) {
00423                                 $arr[] = array(
00424                                         'tl_from'      => $this->mId,
00425                                         'tl_namespace' => $ns,
00426                                         'tl_title'     => $dbk
00427                                 );
00428                         }
00429                 }
00430                 return $arr;
00431         }
00432 
00439         private function getImageInsertions( $existing = array() ) {
00440                 $arr = array();
00441                 $diffs = array_diff_key( $this->mImages, $existing );
00442                 foreach( $diffs as $iname => $dummy ) {
00443                         $arr[] = array(
00444                                 'il_from' => $this->mId,
00445                                 'il_to'   => $iname
00446                         );
00447                 }
00448                 return $arr;
00449         }
00450 
00456         private function getExternalInsertions( $existing = array() ) {
00457                 $arr = array();
00458                 $diffs = array_diff_key( $this->mExternals, $existing );
00459                 foreach( $diffs as $url => $dummy ) {
00460                         foreach( wfMakeUrlIndexes( $url ) as $index ) {
00461                                 $arr[] = array(
00462                                         'el_from'   => $this->mId,
00463                                         'el_to'     => $url,
00464                                         'el_index'  => $index,
00465                                 );
00466                         }
00467                 }
00468                 return $arr;
00469         }
00470 
00479         private function getCategoryInsertions( $existing = array() ) {
00480                 global $wgContLang, $wgCategoryCollation;
00481                 $diffs = array_diff_assoc( $this->mCategories, $existing );
00482                 $arr = array();
00483                 foreach ( $diffs as $name => $prefix ) {
00484                         $nt = Title::makeTitleSafe( NS_CATEGORY, $name );
00485                         $wgContLang->findVariantLink( $name, $nt, true );
00486 
00487                         if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
00488                                 $type = 'subcat';
00489                         } elseif ( $this->mTitle->getNamespace() == NS_FILE ) {
00490                                 $type = 'file';
00491                         } else {
00492                                 $type = 'page';
00493                         }
00494 
00495                         # Treat custom sortkeys as a prefix, so that if multiple
00496                         # things are forced to sort as '*' or something, they'll
00497                         # sort properly in the category rather than in page_id
00498                         # order or such.
00499                         $sortkey = Collation::singleton()->getSortKey(
00500                                 $this->mTitle->getCategorySortkey( $prefix ) );
00501 
00502                         $arr[] = array(
00503                                 'cl_from'    => $this->mId,
00504                                 'cl_to'      => $name,
00505                                 'cl_sortkey' => $sortkey,
00506                                 'cl_timestamp' => $this->mDb->timestamp(),
00507                                 'cl_sortkey_prefix' => $prefix,
00508                                 'cl_collation' => $wgCategoryCollation,
00509                                 'cl_type' => $type,
00510                         );
00511                 }
00512                 return $arr;
00513         }
00514 
00522         private function getInterlangInsertions( $existing = array() ) {
00523                 $diffs = array_diff_assoc( $this->mInterlangs, $existing );
00524                 $arr = array();
00525                 foreach( $diffs as $lang => $title ) {
00526                         $arr[] = array(
00527                                 'll_from'  => $this->mId,
00528                                 'll_lang'  => $lang,
00529                                 'll_title' => $title
00530                         );
00531                 }
00532                 return $arr;
00533         }
00534 
00540         function getPropertyInsertions( $existing = array() ) {
00541                 $diffs = array_diff_assoc( $this->mProperties, $existing );
00542                 $arr = array();
00543                 foreach ( $diffs as $name => $value ) {
00544                         $arr[] = array(
00545                                 'pp_page'      => $this->mId,
00546                                 'pp_propname'  => $name,
00547                                 'pp_value'     => $value,
00548                         );
00549                 }
00550                 return $arr;
00551         }
00552 
00559         private function getInterwikiInsertions( $existing = array() ) {
00560                 $arr = array();
00561                 foreach( $this->mInterwikis as $prefix => $dbkeys ) {
00562                         $diffs = isset( $existing[$prefix] ) ? array_diff_key( $dbkeys, $existing[$prefix] ) : $dbkeys;
00563                         foreach ( $diffs as $dbk => $id ) {
00564                                 $arr[] = array(
00565                                         'iwl_from'   => $this->mId,
00566                                         'iwl_prefix' => $prefix,
00567                                         'iwl_title'  => $dbk
00568                                 );
00569                         }
00570                 }
00571                 return $arr;
00572         }
00573 
00580         private function getLinkDeletions( $existing ) {
00581                 $del = array();
00582                 foreach ( $existing as $ns => $dbkeys ) {
00583                         if ( isset( $this->mLinks[$ns] ) ) {
00584                                 $del[$ns] = array_diff_key( $existing[$ns], $this->mLinks[$ns] );
00585                         } else {
00586                                 $del[$ns] = $existing[$ns];
00587                         }
00588                 }
00589                 return $del;
00590         }
00591 
00598         private function getTemplateDeletions( $existing ) {
00599                 $del = array();
00600                 foreach ( $existing as $ns => $dbkeys ) {
00601                         if ( isset( $this->mTemplates[$ns] ) ) {
00602                                 $del[$ns] = array_diff_key( $existing[$ns], $this->mTemplates[$ns] );
00603                         } else {
00604                                 $del[$ns] = $existing[$ns];
00605                         }
00606                 }
00607                 return $del;
00608         }
00609 
00616         private function getImageDeletions( $existing ) {
00617                 return array_diff_key( $existing, $this->mImages );
00618         }
00619 
00626         private function getExternalDeletions( $existing ) {
00627                 return array_diff_key( $existing, $this->mExternals );
00628         }
00629 
00636         private function getCategoryDeletions( $existing ) {
00637                 return array_diff_assoc( $existing, $this->mCategories );
00638         }
00639 
00646         private function getInterlangDeletions( $existing ) {
00647                 return array_diff_assoc( $existing, $this->mInterlangs );
00648         }
00649 
00655         function getPropertyDeletions( $existing ) {
00656                 return array_diff_assoc( $existing, $this->mProperties );
00657         }
00658 
00665         private function getInterwikiDeletions( $existing ) {
00666                 $del = array();
00667                 foreach ( $existing as $prefix => $dbkeys ) {
00668                         if ( isset( $this->mInterwikis[$prefix] ) ) {
00669                                 $del[$prefix] = array_diff_key( $existing[$prefix], $this->mInterwikis[$prefix] );
00670                         } else {
00671                                 $del[$prefix] = $existing[$prefix];
00672                         }
00673                 }
00674                 return $del;
00675         }
00676 
00682         private function getExistingLinks() {
00683                 $res = $this->mDb->select( 'pagelinks', array( 'pl_namespace', 'pl_title' ),
00684                         array( 'pl_from' => $this->mId ), __METHOD__, $this->mOptions );
00685                 $arr = array();
00686                 foreach ( $res as $row ) {
00687                         if ( !isset( $arr[$row->pl_namespace] ) ) {
00688                                 $arr[$row->pl_namespace] = array();
00689                         }
00690                         $arr[$row->pl_namespace][$row->pl_title] = 1;
00691                 }
00692                 return $arr;
00693         }
00694 
00700         private function getExistingTemplates() {
00701                 $res = $this->mDb->select( 'templatelinks', array( 'tl_namespace', 'tl_title' ),
00702                         array( 'tl_from' => $this->mId ), __METHOD__, $this->mOptions );
00703                 $arr = array();
00704                 foreach ( $res as $row ) {
00705                         if ( !isset( $arr[$row->tl_namespace] ) ) {
00706                                 $arr[$row->tl_namespace] = array();
00707                         }
00708                         $arr[$row->tl_namespace][$row->tl_title] = 1;
00709                 }
00710                 return $arr;
00711         }
00712 
00718         private function getExistingImages() {
00719                 $res = $this->mDb->select( 'imagelinks', array( 'il_to' ),
00720                         array( 'il_from' => $this->mId ), __METHOD__, $this->mOptions );
00721                 $arr = array();
00722                 foreach ( $res as $row ) {
00723                         $arr[$row->il_to] = 1;
00724                 }
00725                 return $arr;
00726         }
00727 
00733         private function getExistingExternals() {
00734                 $res = $this->mDb->select( 'externallinks', array( 'el_to' ),
00735                         array( 'el_from' => $this->mId ), __METHOD__, $this->mOptions );
00736                 $arr = array();
00737                 foreach ( $res as $row ) {
00738                         $arr[$row->el_to] = 1;
00739                 }
00740                 return $arr;
00741         }
00742 
00748         private function getExistingCategories() {
00749                 $res = $this->mDb->select( 'categorylinks', array( 'cl_to', 'cl_sortkey_prefix' ),
00750                         array( 'cl_from' => $this->mId ), __METHOD__, $this->mOptions );
00751                 $arr = array();
00752                 foreach ( $res as $row ) {
00753                         $arr[$row->cl_to] = $row->cl_sortkey_prefix;
00754                 }
00755                 return $arr;
00756         }
00757 
00764         private function getExistingInterlangs() {
00765                 $res = $this->mDb->select( 'langlinks', array( 'll_lang', 'll_title' ),
00766                         array( 'll_from' => $this->mId ), __METHOD__, $this->mOptions );
00767                 $arr = array();
00768                 foreach ( $res as $row ) {
00769                         $arr[$row->ll_lang] = $row->ll_title;
00770                 }
00771                 return $arr;
00772         }
00773 
00778         protected function getExistingInterwikis() {
00779                 $res = $this->mDb->select( 'iwlinks', array( 'iwl_prefix', 'iwl_title' ),
00780                         array( 'iwl_from' => $this->mId ), __METHOD__, $this->mOptions );
00781                 $arr = array();
00782                 foreach ( $res as $row ) {
00783                         if ( !isset( $arr[$row->iwl_prefix] ) ) {
00784                                 $arr[$row->iwl_prefix] = array();
00785                         }
00786                         $arr[$row->iwl_prefix][$row->iwl_title] = 1;
00787                 }
00788                 return $arr;
00789         }
00790 
00796         private function getExistingProperties() {
00797                 $res = $this->mDb->select( 'page_props', array( 'pp_propname', 'pp_value' ),
00798                         array( 'pp_page' => $this->mId ), __METHOD__, $this->mOptions );
00799                 $arr = array();
00800                 foreach ( $res as $row ) {
00801                         $arr[$row->pp_propname] = $row->pp_value;
00802                 }
00803                 return $arr;
00804         }
00805 
00810         public function getTitle() {
00811                 return $this->mTitle;
00812         }
00813 
00819         public function getParserOutput() {
00820                 return $this->mParserOutput;
00821         }
00822 
00827         public function getImages() {
00828                 return $this->mImages;
00829         }
00830 
00835         private function invalidateProperties( $changed ) {
00836                 global $wgPagePropLinkInvalidations;
00837 
00838                 foreach ( $changed as $name => $value ) {
00839                         if ( isset( $wgPagePropLinkInvalidations[$name] ) ) {
00840                                 $inv = $wgPagePropLinkInvalidations[$name];
00841                                 if ( !is_array( $inv ) ) {
00842                                         $inv = array( $inv );
00843                                 }
00844                                 foreach ( $inv as $table ) {
00845                                         $update = new HTMLCacheUpdate( $this->mTitle, $table );
00846                                         $update->doUpdate();
00847                                 }
00848                         }
00849                 }
00850         }
00851 }