MediaWiki  REL1_20
LinksUpdate.php
Go to the documentation of this file.
00001 <?php
00028 class LinksUpdate extends SqlDataUpdate {
00029 
00030         // @todo: make members protected, but make sure extensions don't break
00031 
00032         public $mId,         
00033                 $mTitle,         
00034                 $mParserOutput,  
00035                 $mLinks,         
00036                 $mImages,        
00037                 $mTemplates,     
00038                 $mExternals,     
00039                 $mCategories,    
00040                 $mInterlangs,    
00041                 $mProperties,    
00042                 $mDb,            
00043                 $mOptions,       
00044                 $mRecursive;     
00045 
00053         function __construct( $title, $parserOutput, $recursive = true ) {
00054                 parent::__construct( false ); // no implicit transaction
00055 
00056                 if ( !( $title instanceof Title ) ) {
00057                         throw new MWException( "The calling convention to LinksUpdate::LinksUpdate() has changed. " .
00058                                 "Please see Article::editUpdates() for an invocation example.\n" );
00059                 }
00060 
00061                 if ( !( $parserOutput instanceof ParserOutput ) ) {
00062                         throw new MWException( "The calling convention to LinksUpdate::__construct() has changed. " .
00063                                 "Please see WikiPage::doEditUpdates() for an invocation example.\n" );
00064                 }
00065 
00066                 $this->mTitle = $title;
00067                 $this->mId = $title->getArticleID();
00068 
00069                 if ( !$this->mId ) {
00070                         throw new MWException( "The Title object did not provide an article ID. Perhaps the page doesn't exist?" );
00071                 }
00072 
00073                 $this->mParserOutput = $parserOutput;
00074                 $this->mLinks = $parserOutput->getLinks();
00075                 $this->mImages = $parserOutput->getImages();
00076                 $this->mTemplates = $parserOutput->getTemplates();
00077                 $this->mExternals = $parserOutput->getExternalLinks();
00078                 $this->mCategories = $parserOutput->getCategories();
00079                 $this->mProperties = $parserOutput->getProperties();
00080                 $this->mInterwikis = $parserOutput->getInterwikiLinks();
00081 
00082                 # Convert the format of the interlanguage links
00083                 # I didn't want to change it in the ParserOutput, because that array is passed all
00084                 # the way back to the skin, so either a skin API break would be required, or an
00085                 # inefficient back-conversion.
00086                 $ill = $parserOutput->getLanguageLinks();
00087                 $this->mInterlangs = array();
00088                 foreach ( $ill as $link ) {
00089                         list( $key, $title ) = explode( ':', $link, 2 );
00090                         $this->mInterlangs[$key] = $title;
00091                 }
00092 
00093                 foreach ( $this->mCategories as &$sortkey ) {
00094                         # If the sortkey is longer then 255 bytes,
00095                         # it truncated by DB, and then doesn't get
00096                         # matched when comparing existing vs current
00097                         # categories, causing bug 25254.
00098                         # Also. substr behaves weird when given "".
00099                         if ( $sortkey !== '' ) {
00100                                 $sortkey = substr( $sortkey, 0, 255 );
00101                         }
00102                 }
00103 
00104                 $this->mRecursive = $recursive;
00105 
00106                 wfRunHooks( 'LinksUpdateConstructed', array( &$this ) );
00107         }
00108 
00112         public function doUpdate() {
00113                 global $wgUseDumbLinkUpdate;
00114 
00115                 wfRunHooks( 'LinksUpdate', array( &$this ) );
00116                 if ( $wgUseDumbLinkUpdate ) {
00117                         $this->doDumbUpdate();
00118                 } else {
00119                         $this->doIncrementalUpdate();
00120                 }
00121                 wfRunHooks( 'LinksUpdateComplete', array( &$this ) );
00122         }
00123 
00124         protected function doIncrementalUpdate() {
00125                 wfProfileIn( __METHOD__ );
00126 
00127                 # Page links
00128                 $existing = $this->getExistingLinks();
00129                 $this->incrTableUpdate( 'pagelinks', 'pl', $this->getLinkDeletions( $existing ),
00130                         $this->getLinkInsertions( $existing ) );
00131 
00132                 # Image links
00133                 $existing = $this->getExistingImages();
00134 
00135                 $imageDeletes = $this->getImageDeletions( $existing );
00136                 $this->incrTableUpdate( 'imagelinks', 'il', $imageDeletes,
00137                         $this->getImageInsertions( $existing ) );
00138 
00139                 # Invalidate all image description pages which had links added or removed
00140                 $imageUpdates = $imageDeletes + array_diff_key( $this->mImages, $existing );
00141                 $this->invalidateImageDescriptions( $imageUpdates );
00142 
00143                 # External links
00144                 $existing = $this->getExistingExternals();
00145                 $this->incrTableUpdate( 'externallinks', 'el', $this->getExternalDeletions( $existing ),
00146                         $this->getExternalInsertions( $existing ) );
00147 
00148                 # Language links
00149                 $existing = $this->getExistingInterlangs();
00150                 $this->incrTableUpdate( 'langlinks', 'll', $this->getInterlangDeletions( $existing ),
00151                         $this->getInterlangInsertions( $existing ) );
00152 
00153                 # Inline interwiki links
00154                 $existing = $this->getExistingInterwikis();
00155                 $this->incrTableUpdate( 'iwlinks', 'iwl', $this->getInterwikiDeletions( $existing ),
00156                         $this->getInterwikiInsertions( $existing ) );
00157 
00158                 # Template links
00159                 $existing = $this->getExistingTemplates();
00160                 $this->incrTableUpdate( 'templatelinks', 'tl', $this->getTemplateDeletions( $existing ),
00161                         $this->getTemplateInsertions( $existing ) );
00162 
00163                 # Category links
00164                 $existing = $this->getExistingCategories();
00165 
00166                 $categoryDeletes = $this->getCategoryDeletions( $existing );
00167 
00168                 $this->incrTableUpdate( 'categorylinks', 'cl', $categoryDeletes,
00169                         $this->getCategoryInsertions( $existing ) );
00170 
00171                 # Invalidate all categories which were added, deleted or changed (set symmetric difference)
00172                 $categoryInserts = array_diff_assoc( $this->mCategories, $existing );
00173                 $categoryUpdates = $categoryInserts + $categoryDeletes;
00174                 $this->invalidateCategories( $categoryUpdates );
00175                 $this->updateCategoryCounts( $categoryInserts, $categoryDeletes );
00176 
00177                 # Page properties
00178                 $existing = $this->getExistingProperties();
00179 
00180                 $propertiesDeletes = $this->getPropertyDeletions( $existing );
00181 
00182                 $this->incrTableUpdate( 'page_props', 'pp', $propertiesDeletes,
00183                         $this->getPropertyInsertions( $existing ) );
00184 
00185                 # Invalidate the necessary pages
00186                 $changed = $propertiesDeletes + array_diff_assoc( $this->mProperties, $existing );
00187                 $this->invalidateProperties( $changed );
00188 
00189                 # Refresh links of all pages including this page
00190                 # This will be in a separate transaction
00191                 if ( $this->mRecursive ) {
00192                         $this->queueRecursiveJobs();
00193                 }
00194 
00195                 wfProfileOut( __METHOD__ );
00196         }
00197 
00203         protected function doDumbUpdate() {
00204                 wfProfileIn( __METHOD__ );
00205 
00206                 # Refresh category pages and image description pages
00207                 $existing = $this->getExistingCategories();
00208                 $categoryInserts = array_diff_assoc( $this->mCategories, $existing );
00209                 $categoryDeletes = array_diff_assoc( $existing, $this->mCategories );
00210                 $categoryUpdates = $categoryInserts + $categoryDeletes;
00211                 $existing = $this->getExistingImages();
00212                 $imageUpdates = array_diff_key( $existing, $this->mImages ) + array_diff_key( $this->mImages, $existing );
00213 
00214                 $this->dumbTableUpdate( 'pagelinks',     $this->getLinkInsertions(),     'pl_from' );
00215                 $this->dumbTableUpdate( 'imagelinks',    $this->getImageInsertions(),    'il_from' );
00216                 $this->dumbTableUpdate( 'categorylinks', $this->getCategoryInsertions(), 'cl_from' );
00217                 $this->dumbTableUpdate( 'templatelinks', $this->getTemplateInsertions(), 'tl_from' );
00218                 $this->dumbTableUpdate( 'externallinks', $this->getExternalInsertions(), 'el_from' );
00219                 $this->dumbTableUpdate( 'langlinks',     $this->getInterlangInsertions(),'ll_from' );
00220                 $this->dumbTableUpdate( 'iwlinks',       $this->getInterwikiInsertions(),'iwl_from' );
00221                 $this->dumbTableUpdate( 'page_props',    $this->getPropertyInsertions(), 'pp_page' );
00222 
00223                 # Update the cache of all the category pages and image description
00224                 # pages which were changed, and fix the category table count
00225                 $this->invalidateCategories( $categoryUpdates );
00226                 $this->updateCategoryCounts( $categoryInserts, $categoryDeletes );
00227                 $this->invalidateImageDescriptions( $imageUpdates );
00228 
00229                 # Refresh links of all pages including this page
00230                 # This will be in a separate transaction
00231                 if ( $this->mRecursive ) {
00232                         $this->queueRecursiveJobs();
00233                 }
00234 
00235                 wfProfileOut( __METHOD__ );
00236         }
00237 
00238         function queueRecursiveJobs() {
00239                 global $wgUpdateRowsPerJob;
00240                 wfProfileIn( __METHOD__ );
00241 
00242                 $cache = $this->mTitle->getBacklinkCache();
00243                 $batches = $cache->partition( 'templatelinks', $wgUpdateRowsPerJob );
00244                 if ( !$batches ) {
00245                         wfProfileOut( __METHOD__ );
00246                         return;
00247                 }
00248                 $jobs = array();
00249                 foreach ( $batches as $batch ) {
00250                         list( $start, $end ) = $batch;
00251                         $params = array(
00252                                 'table' => 'templatelinks',
00253                                 'start' => $start,
00254                                 'end' => $end,
00255                         );
00256                         $jobs[] = new RefreshLinksJob2( $this->mTitle, $params );
00257                 }
00258                 Job::batchInsert( $jobs );
00259 
00260                 wfProfileOut( __METHOD__ );
00261         }
00262 
00266         function invalidateCategories( $cats ) {
00267                 $this->invalidatePages( NS_CATEGORY, array_keys( $cats ) );
00268         }
00269 
00275         function updateCategoryCounts( $added, $deleted ) {
00276                 $a = WikiPage::factory( $this->mTitle );
00277                 $a->updateCategoryCounts(
00278                         array_keys( $added ), array_keys( $deleted )
00279                 );
00280         }
00281 
00285         function invalidateImageDescriptions( $images ) {
00286                 $this->invalidatePages( NS_FILE, array_keys( $images ) );
00287         }
00288 
00294         private function dumbTableUpdate( $table, $insertions, $fromField ) {
00295                 $this->mDb->delete( $table, array( $fromField => $this->mId ), __METHOD__ );
00296                 if ( count( $insertions ) ) {
00297                         # The link array was constructed without FOR UPDATE, so there may
00298                         # be collisions.  This may cause minor link table inconsistencies,
00299                         # which is better than crippling the site with lock contention.
00300                         $this->mDb->insert( $table, $insertions, __METHOD__, array( 'IGNORE' ) );
00301                 }
00302         }
00303 
00311         function incrTableUpdate( $table, $prefix, $deletions, $insertions ) {
00312                 if ( $table == 'page_props' ) {
00313                         $fromField = 'pp_page';
00314                 } else {
00315                         $fromField = "{$prefix}_from";
00316                 }
00317                 $where = array( $fromField => $this->mId );
00318                 if ( $table == 'pagelinks' || $table == 'templatelinks' || $table == 'iwlinks' ) {
00319                         if ( $table == 'iwlinks' ) {
00320                                 $baseKey = 'iwl_prefix';
00321                         } else {
00322                                 $baseKey = "{$prefix}_namespace";
00323                         }
00324                         $clause = $this->mDb->makeWhereFrom2d( $deletions, $baseKey, "{$prefix}_title" );
00325                         if ( $clause ) {
00326                                 $where[] = $clause;
00327                         } else {
00328                                 $where = false;
00329                         }
00330                 } else {
00331                         if ( $table == 'langlinks' ) {
00332                                 $toField = 'll_lang';
00333                         } elseif ( $table == 'page_props' ) {
00334                                 $toField = 'pp_propname';
00335                         } else {
00336                                 $toField = $prefix . '_to';
00337                         }
00338                         if ( count( $deletions ) ) {
00339                                 $where[] = "$toField IN (" . $this->mDb->makeList( array_keys( $deletions ) ) . ')';
00340                         } else {
00341                                 $where = false;
00342                         }
00343                 }
00344                 if ( $where ) {
00345                         $this->mDb->delete( $table, $where, __METHOD__ );
00346                 }
00347                 if ( count( $insertions ) ) {
00348                         $this->mDb->insert( $table, $insertions, __METHOD__, 'IGNORE' );
00349                 }
00350         }
00351 
00358         private function getLinkInsertions( $existing = array() ) {
00359                 $arr = array();
00360                 foreach( $this->mLinks as $ns => $dbkeys ) {
00361                         $diffs = isset( $existing[$ns] )
00362                                 ? array_diff_key( $dbkeys, $existing[$ns] )
00363                                 : $dbkeys;
00364                         foreach ( $diffs as $dbk => $id ) {
00365                                 $arr[] = array(
00366                                         'pl_from'      => $this->mId,
00367                                         'pl_namespace' => $ns,
00368                                         'pl_title'     => $dbk
00369                                 );
00370                         }
00371                 }
00372                 return $arr;
00373         }
00374 
00380         private function getTemplateInsertions( $existing = array() ) {
00381                 $arr = array();
00382                 foreach( $this->mTemplates as $ns => $dbkeys ) {
00383                         $diffs = isset( $existing[$ns] ) ? array_diff_key( $dbkeys, $existing[$ns] ) : $dbkeys;
00384                         foreach ( $diffs as $dbk => $id ) {
00385                                 $arr[] = array(
00386                                         'tl_from'      => $this->mId,
00387                                         'tl_namespace' => $ns,
00388                                         'tl_title'     => $dbk
00389                                 );
00390                         }
00391                 }
00392                 return $arr;
00393         }
00394 
00401         private function getImageInsertions( $existing = array() ) {
00402                 $arr = array();
00403                 $diffs = array_diff_key( $this->mImages, $existing );
00404                 foreach( $diffs as $iname => $dummy ) {
00405                         $arr[] = array(
00406                                 'il_from' => $this->mId,
00407                                 'il_to'   => $iname
00408                         );
00409                 }
00410                 return $arr;
00411         }
00412 
00418         private function getExternalInsertions( $existing = array() ) {
00419                 $arr = array();
00420                 $diffs = array_diff_key( $this->mExternals, $existing );
00421                 foreach( $diffs as $url => $dummy ) {
00422                         foreach( wfMakeUrlIndexes( $url ) as $index ) {
00423                                 $arr[] = array(
00424                                         'el_from'   => $this->mId,
00425                                         'el_to'     => $url,
00426                                         'el_index'  => $index,
00427                                 );
00428                         }
00429                 }
00430                 return $arr;
00431         }
00432 
00441         private function getCategoryInsertions( $existing = array() ) {
00442                 global $wgContLang, $wgCategoryCollation;
00443                 $diffs = array_diff_assoc( $this->mCategories, $existing );
00444                 $arr = array();
00445                 foreach ( $diffs as $name => $prefix ) {
00446                         $nt = Title::makeTitleSafe( NS_CATEGORY, $name );
00447                         $wgContLang->findVariantLink( $name, $nt, true );
00448 
00449                         if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
00450                                 $type = 'subcat';
00451                         } elseif ( $this->mTitle->getNamespace() == NS_FILE ) {
00452                                 $type = 'file';
00453                         } else {
00454                                 $type = 'page';
00455                         }
00456 
00457                         # Treat custom sortkeys as a prefix, so that if multiple
00458                         # things are forced to sort as '*' or something, they'll
00459                         # sort properly in the category rather than in page_id
00460                         # order or such.
00461                         $sortkey = Collation::singleton()->getSortKey(
00462                                 $this->mTitle->getCategorySortkey( $prefix ) );
00463 
00464                         $arr[] = array(
00465                                 'cl_from'    => $this->mId,
00466                                 'cl_to'      => $name,
00467                                 'cl_sortkey' => $sortkey,
00468                                 'cl_timestamp' => $this->mDb->timestamp(),
00469                                 'cl_sortkey_prefix' => $prefix,
00470                                 'cl_collation' => $wgCategoryCollation,
00471                                 'cl_type' => $type,
00472                         );
00473                 }
00474                 return $arr;
00475         }
00476 
00484         private function getInterlangInsertions( $existing = array() ) {
00485                 $diffs = array_diff_assoc( $this->mInterlangs, $existing );
00486                 $arr = array();
00487                 foreach( $diffs as $lang => $title ) {
00488                         $arr[] = array(
00489                                 'll_from'  => $this->mId,
00490                                 'll_lang'  => $lang,
00491                                 'll_title' => $title
00492                         );
00493                 }
00494                 return $arr;
00495         }
00496 
00502         function getPropertyInsertions( $existing = array() ) {
00503                 $diffs = array_diff_assoc( $this->mProperties, $existing );
00504                 $arr = array();
00505                 foreach ( $diffs as $name => $value ) {
00506                         $arr[] = array(
00507                                 'pp_page'      => $this->mId,
00508                                 'pp_propname'  => $name,
00509                                 'pp_value'     => $value,
00510                         );
00511                 }
00512                 return $arr;
00513         }
00514 
00521         private function getInterwikiInsertions( $existing = array() ) {
00522                 $arr = array();
00523                 foreach( $this->mInterwikis as $prefix => $dbkeys ) {
00524                         $diffs = isset( $existing[$prefix] ) ? array_diff_key( $dbkeys, $existing[$prefix] ) : $dbkeys;
00525                         foreach ( $diffs as $dbk => $id ) {
00526                                 $arr[] = array(
00527                                         'iwl_from'   => $this->mId,
00528                                         'iwl_prefix' => $prefix,
00529                                         'iwl_title'  => $dbk
00530                                 );
00531                         }
00532                 }
00533                 return $arr;
00534         }
00535 
00542         private function getLinkDeletions( $existing ) {
00543                 $del = array();
00544                 foreach ( $existing as $ns => $dbkeys ) {
00545                         if ( isset( $this->mLinks[$ns] ) ) {
00546                                 $del[$ns] = array_diff_key( $existing[$ns], $this->mLinks[$ns] );
00547                         } else {
00548                                 $del[$ns] = $existing[$ns];
00549                         }
00550                 }
00551                 return $del;
00552         }
00553 
00560         private function getTemplateDeletions( $existing ) {
00561                 $del = array();
00562                 foreach ( $existing as $ns => $dbkeys ) {
00563                         if ( isset( $this->mTemplates[$ns] ) ) {
00564                                 $del[$ns] = array_diff_key( $existing[$ns], $this->mTemplates[$ns] );
00565                         } else {
00566                                 $del[$ns] = $existing[$ns];
00567                         }
00568                 }
00569                 return $del;
00570         }
00571 
00578         private function getImageDeletions( $existing ) {
00579                 return array_diff_key( $existing, $this->mImages );
00580         }
00581 
00588         private function getExternalDeletions( $existing ) {
00589                 return array_diff_key( $existing, $this->mExternals );
00590         }
00591 
00598         private function getCategoryDeletions( $existing ) {
00599                 return array_diff_assoc( $existing, $this->mCategories );
00600         }
00601 
00608         private function getInterlangDeletions( $existing ) {
00609                 return array_diff_assoc( $existing, $this->mInterlangs );
00610         }
00611 
00617         function getPropertyDeletions( $existing ) {
00618                 return array_diff_assoc( $existing, $this->mProperties );
00619         }
00620 
00627         private function getInterwikiDeletions( $existing ) {
00628                 $del = array();
00629                 foreach ( $existing as $prefix => $dbkeys ) {
00630                         if ( isset( $this->mInterwikis[$prefix] ) ) {
00631                                 $del[$prefix] = array_diff_key( $existing[$prefix], $this->mInterwikis[$prefix] );
00632                         } else {
00633                                 $del[$prefix] = $existing[$prefix];
00634                         }
00635                 }
00636                 return $del;
00637         }
00638 
00644         private function getExistingLinks() {
00645                 $res = $this->mDb->select( 'pagelinks', array( 'pl_namespace', 'pl_title' ),
00646                         array( 'pl_from' => $this->mId ), __METHOD__, $this->mOptions );
00647                 $arr = array();
00648                 foreach ( $res as $row ) {
00649                         if ( !isset( $arr[$row->pl_namespace] ) ) {
00650                                 $arr[$row->pl_namespace] = array();
00651                         }
00652                         $arr[$row->pl_namespace][$row->pl_title] = 1;
00653                 }
00654                 return $arr;
00655         }
00656 
00662         private function getExistingTemplates() {
00663                 $res = $this->mDb->select( 'templatelinks', array( 'tl_namespace', 'tl_title' ),
00664                         array( 'tl_from' => $this->mId ), __METHOD__, $this->mOptions );
00665                 $arr = array();
00666                 foreach ( $res as $row ) {
00667                         if ( !isset( $arr[$row->tl_namespace] ) ) {
00668                                 $arr[$row->tl_namespace] = array();
00669                         }
00670                         $arr[$row->tl_namespace][$row->tl_title] = 1;
00671                 }
00672                 return $arr;
00673         }
00674 
00680         private function getExistingImages() {
00681                 $res = $this->mDb->select( 'imagelinks', array( 'il_to' ),
00682                         array( 'il_from' => $this->mId ), __METHOD__, $this->mOptions );
00683                 $arr = array();
00684                 foreach ( $res as $row ) {
00685                         $arr[$row->il_to] = 1;
00686                 }
00687                 return $arr;
00688         }
00689 
00695         private function getExistingExternals() {
00696                 $res = $this->mDb->select( 'externallinks', array( 'el_to' ),
00697                         array( 'el_from' => $this->mId ), __METHOD__, $this->mOptions );
00698                 $arr = array();
00699                 foreach ( $res as $row ) {
00700                         $arr[$row->el_to] = 1;
00701                 }
00702                 return $arr;
00703         }
00704 
00710         private function getExistingCategories() {
00711                 $res = $this->mDb->select( 'categorylinks', array( 'cl_to', 'cl_sortkey_prefix' ),
00712                         array( 'cl_from' => $this->mId ), __METHOD__, $this->mOptions );
00713                 $arr = array();
00714                 foreach ( $res as $row ) {
00715                         $arr[$row->cl_to] = $row->cl_sortkey_prefix;
00716                 }
00717                 return $arr;
00718         }
00719 
00726         private function getExistingInterlangs() {
00727                 $res = $this->mDb->select( 'langlinks', array( 'll_lang', 'll_title' ),
00728                         array( 'll_from' => $this->mId ), __METHOD__, $this->mOptions );
00729                 $arr = array();
00730                 foreach ( $res as $row ) {
00731                         $arr[$row->ll_lang] = $row->ll_title;
00732                 }
00733                 return $arr;
00734         }
00735 
00740         protected function getExistingInterwikis() {
00741                 $res = $this->mDb->select( 'iwlinks', array( 'iwl_prefix', 'iwl_title' ),
00742                         array( 'iwl_from' => $this->mId ), __METHOD__, $this->mOptions );
00743                 $arr = array();
00744                 foreach ( $res as $row ) {
00745                         if ( !isset( $arr[$row->iwl_prefix] ) ) {
00746                                 $arr[$row->iwl_prefix] = array();
00747                         }
00748                         $arr[$row->iwl_prefix][$row->iwl_title] = 1;
00749                 }
00750                 return $arr;
00751         }
00752 
00758         private function getExistingProperties() {
00759                 $res = $this->mDb->select( 'page_props', array( 'pp_propname', 'pp_value' ),
00760                         array( 'pp_page' => $this->mId ), __METHOD__, $this->mOptions );
00761                 $arr = array();
00762                 foreach ( $res as $row ) {
00763                         $arr[$row->pp_propname] = $row->pp_value;
00764                 }
00765                 return $arr;
00766         }
00767 
00772         public function getTitle() {
00773                 return $this->mTitle;
00774         }
00775 
00781         public function getParserOutput() {
00782                 return $this->mParserOutput;
00783         }
00784 
00789         public function getImages() {
00790                 return $this->mImages;
00791         }
00792 
00797         private function invalidateProperties( $changed ) {
00798                 global $wgPagePropLinkInvalidations;
00799 
00800                 foreach ( $changed as $name => $value ) {
00801                         if ( isset( $wgPagePropLinkInvalidations[$name] ) ) {
00802                                 $inv = $wgPagePropLinkInvalidations[$name];
00803                                 if ( !is_array( $inv ) ) {
00804                                         $inv = array( $inv );
00805                                 }
00806                                 foreach ( $inv as $table ) {
00807                                         $update = new HTMLCacheUpdate( $this->mTitle, $table );
00808                                         $update->doUpdate();
00809                                 }
00810                         }
00811                 }
00812         }
00813 }
00814 
00818 class LinksDeletionUpdate extends SqlDataUpdate {
00819 
00820         protected $mPage;     
00821 
00827         function __construct( WikiPage $page ) {
00828                 parent::__construct( false ); // no implicit transaction
00829 
00830                 $this->mPage = $page;
00831         }
00832 
00836         public function doUpdate() {
00837                 $title = $this->mPage->getTitle();
00838                 $id = $this->mPage->getId();
00839 
00840                 # Delete restrictions for it
00841                 $this->mDb->delete( 'page_restrictions', array ( 'pr_page' => $id ), __METHOD__ );
00842 
00843                 # Fix category table counts
00844                 $cats = array();
00845                 $res = $this->mDb->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ );
00846 
00847                 foreach ( $res as $row ) {
00848                         $cats [] = $row->cl_to;
00849                 }
00850 
00851                 $this->mPage->updateCategoryCounts( array(), $cats );
00852 
00853                 # If using cascading deletes, we can skip some explicit deletes
00854                 if ( !$this->mDb->cascadingDeletes() ) {
00855                         $this->mDb->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
00856 
00857                         # Delete outgoing links
00858                         $this->mDb->delete( 'pagelinks', array( 'pl_from' => $id ), __METHOD__ );
00859                         $this->mDb->delete( 'imagelinks', array( 'il_from' => $id ), __METHOD__ );
00860                         $this->mDb->delete( 'categorylinks', array( 'cl_from' => $id ), __METHOD__ );
00861                         $this->mDb->delete( 'templatelinks', array( 'tl_from' => $id ), __METHOD__ );
00862                         $this->mDb->delete( 'externallinks', array( 'el_from' => $id ), __METHOD__ );
00863                         $this->mDb->delete( 'langlinks', array( 'll_from' => $id ), __METHOD__ );
00864                         $this->mDb->delete( 'iwlinks', array( 'iwl_from' => $id ), __METHOD__ );
00865                         $this->mDb->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ );
00866                         $this->mDb->delete( 'page_props', array( 'pp_page' => $id ), __METHOD__ );
00867                 }
00868 
00869                 # If using cleanup triggers, we can skip some manual deletes
00870                 if ( !$this->mDb->cleanupTriggers() ) {
00871                         # Clean up recentchanges entries...
00872                         $this->mDb->delete( 'recentchanges',
00873                                 array( 'rc_type != ' . RC_LOG,
00874                                         'rc_namespace' => $title->getNamespace(),
00875                                         'rc_title' => $title->getDBkey() ),
00876                                 __METHOD__ );
00877                         $this->mDb->delete( 'recentchanges',
00878                                 array( 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ),
00879                                 __METHOD__ );
00880                 }
00881         }
00882 }