MediaWiki
REL1_24
|
00001 <?php 00028 class LinksUpdate extends SqlDataUpdate { 00029 // @todo make members protected, but make sure extensions don't break 00030 00032 public $mId; 00033 00035 public $mTitle; 00036 00038 public $mParserOutput; 00039 00041 public $mLinks; 00042 00044 public $mImages; 00045 00047 public $mTemplates; 00048 00050 public $mExternals; 00051 00053 public $mCategories; 00054 00056 public $mInterlangs; 00057 00059 public $mProperties; 00060 00062 public $mDb; 00063 00065 public $mOptions; 00066 00068 public $mRecursive; 00069 00073 private $linkInsertions = null; 00074 00078 private $linkDeletions = null; 00079 00088 function __construct( $title, $parserOutput, $recursive = true ) { 00089 parent::__construct( false ); // no implicit transaction 00090 00091 if ( !( $title instanceof Title ) ) { 00092 throw new MWException( "The calling convention to LinksUpdate::LinksUpdate() has changed. " . 00093 "Please see Article::editUpdates() for an invocation example.\n" ); 00094 } 00095 00096 if ( !( $parserOutput instanceof ParserOutput ) ) { 00097 throw new MWException( "The calling convention to LinksUpdate::__construct() has changed. " . 00098 "Please see WikiPage::doEditUpdates() for an invocation example.\n" ); 00099 } 00100 00101 $this->mTitle = $title; 00102 $this->mId = $title->getArticleID(); 00103 00104 if ( !$this->mId ) { 00105 throw new MWException( "The Title object did not provide an article " . 00106 "ID. Perhaps the page doesn't exist?" ); 00107 } 00108 00109 $this->mParserOutput = $parserOutput; 00110 00111 $this->mLinks = $parserOutput->getLinks(); 00112 $this->mImages = $parserOutput->getImages(); 00113 $this->mTemplates = $parserOutput->getTemplates(); 00114 $this->mExternals = $parserOutput->getExternalLinks(); 00115 $this->mCategories = $parserOutput->getCategories(); 00116 $this->mProperties = $parserOutput->getProperties(); 00117 $this->mInterwikis = $parserOutput->getInterwikiLinks(); 00118 00119 # Convert the format of the interlanguage links 00120 # I didn't want to change it in the ParserOutput, because that array is passed all 00121 # the way back to the skin, so either a skin API break would be required, or an 00122 # inefficient back-conversion. 00123 $ill = $parserOutput->getLanguageLinks(); 00124 $this->mInterlangs = array(); 00125 foreach ( $ill as $link ) { 00126 list( $key, $title ) = explode( ':', $link, 2 ); 00127 $this->mInterlangs[$key] = $title; 00128 } 00129 00130 foreach ( $this->mCategories as &$sortkey ) { 00131 # If the sortkey is longer then 255 bytes, 00132 # it truncated by DB, and then doesn't get 00133 # matched when comparing existing vs current 00134 # categories, causing bug 25254. 00135 # Also. substr behaves weird when given "". 00136 if ( $sortkey !== '' ) { 00137 $sortkey = substr( $sortkey, 0, 255 ); 00138 } 00139 } 00140 00141 $this->mRecursive = $recursive; 00142 00143 wfRunHooks( 'LinksUpdateConstructed', array( &$this ) ); 00144 } 00145 00149 public function doUpdate() { 00150 wfRunHooks( 'LinksUpdate', array( &$this ) ); 00151 $this->doIncrementalUpdate(); 00152 wfRunHooks( 'LinksUpdateComplete', array( &$this ) ); 00153 } 00154 00155 protected function doIncrementalUpdate() { 00156 wfProfileIn( __METHOD__ ); 00157 00158 # Page links 00159 $existing = $this->getExistingLinks(); 00160 $this->linkDeletions = $this->getLinkDeletions( $existing ); 00161 $this->linkInsertions = $this->getLinkInsertions( $existing ); 00162 $this->incrTableUpdate( 'pagelinks', 'pl', $this->linkDeletions, $this->linkInsertions ); 00163 00164 # Image links 00165 $existing = $this->getExistingImages(); 00166 00167 $imageDeletes = $this->getImageDeletions( $existing ); 00168 $this->incrTableUpdate( 'imagelinks', 'il', $imageDeletes, 00169 $this->getImageInsertions( $existing ) ); 00170 00171 # Invalidate all image description pages which had links added or removed 00172 $imageUpdates = $imageDeletes + array_diff_key( $this->mImages, $existing ); 00173 $this->invalidateImageDescriptions( $imageUpdates ); 00174 00175 # External links 00176 $existing = $this->getExistingExternals(); 00177 $this->incrTableUpdate( 'externallinks', 'el', $this->getExternalDeletions( $existing ), 00178 $this->getExternalInsertions( $existing ) ); 00179 00180 # Language links 00181 $existing = $this->getExistingInterlangs(); 00182 $this->incrTableUpdate( 'langlinks', 'll', $this->getInterlangDeletions( $existing ), 00183 $this->getInterlangInsertions( $existing ) ); 00184 00185 # Inline interwiki links 00186 $existing = $this->getExistingInterwikis(); 00187 $this->incrTableUpdate( 'iwlinks', 'iwl', $this->getInterwikiDeletions( $existing ), 00188 $this->getInterwikiInsertions( $existing ) ); 00189 00190 # Template links 00191 $existing = $this->getExistingTemplates(); 00192 $this->incrTableUpdate( 'templatelinks', 'tl', $this->getTemplateDeletions( $existing ), 00193 $this->getTemplateInsertions( $existing ) ); 00194 00195 # Category links 00196 $existing = $this->getExistingCategories(); 00197 00198 $categoryDeletes = $this->getCategoryDeletions( $existing ); 00199 00200 $this->incrTableUpdate( 'categorylinks', 'cl', $categoryDeletes, 00201 $this->getCategoryInsertions( $existing ) ); 00202 00203 # Invalidate all categories which were added, deleted or changed (set symmetric difference) 00204 $categoryInserts = array_diff_assoc( $this->mCategories, $existing ); 00205 $categoryUpdates = $categoryInserts + $categoryDeletes; 00206 $this->invalidateCategories( $categoryUpdates ); 00207 $this->updateCategoryCounts( $categoryInserts, $categoryDeletes ); 00208 00209 # Page properties 00210 $existing = $this->getExistingProperties(); 00211 00212 $propertiesDeletes = $this->getPropertyDeletions( $existing ); 00213 00214 $this->incrTableUpdate( 'page_props', 'pp', $propertiesDeletes, 00215 $this->getPropertyInsertions( $existing ) ); 00216 00217 # Invalidate the necessary pages 00218 $changed = $propertiesDeletes + array_diff_assoc( $this->mProperties, $existing ); 00219 $this->invalidateProperties( $changed ); 00220 00221 # Update the links table freshness for this title 00222 $this->updateLinksTimestamp(); 00223 00224 # Refresh links of all pages including this page 00225 # This will be in a separate transaction 00226 if ( $this->mRecursive ) { 00227 $this->queueRecursiveJobs(); 00228 } 00229 00230 wfProfileOut( __METHOD__ ); 00231 } 00232 00239 function queueRecursiveJobs() { 00240 self::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks' ); 00241 if ( $this->mTitle->getNamespace() == NS_FILE ) { 00242 // Process imagelinks in case the title is or was a redirect 00243 self::queueRecursiveJobsForTable( $this->mTitle, 'imagelinks' ); 00244 } 00245 } 00246 00253 public static function queueRecursiveJobsForTable( Title $title, $table ) { 00254 wfProfileIn( __METHOD__ ); 00255 if ( $title->getBacklinkCache()->hasLinks( $table ) ) { 00256 $job = new RefreshLinksJob( 00257 $title, 00258 array( 00259 'table' => $table, 00260 'recursive' => true, 00261 ) + Job::newRootJobParams( // "overall" refresh links job info 00262 "refreshlinks:{$table}:{$title->getPrefixedText()}" 00263 ) 00264 ); 00265 JobQueueGroup::singleton()->push( $job ); 00266 JobQueueGroup::singleton()->deduplicateRootJob( $job ); 00267 } 00268 wfProfileOut( __METHOD__ ); 00269 } 00270 00274 function invalidateCategories( $cats ) { 00275 $this->invalidatePages( NS_CATEGORY, array_keys( $cats ) ); 00276 } 00277 00283 function updateCategoryCounts( $added, $deleted ) { 00284 $a = WikiPage::factory( $this->mTitle ); 00285 $a->updateCategoryCounts( 00286 array_keys( $added ), array_keys( $deleted ) 00287 ); 00288 } 00289 00293 function invalidateImageDescriptions( $images ) { 00294 $this->invalidatePages( NS_FILE, array_keys( $images ) ); 00295 } 00296 00304 function incrTableUpdate( $table, $prefix, $deletions, $insertions ) { 00305 if ( $table == 'page_props' ) { 00306 $fromField = 'pp_page'; 00307 } else { 00308 $fromField = "{$prefix}_from"; 00309 } 00310 $where = array( $fromField => $this->mId ); 00311 if ( $table == 'pagelinks' || $table == 'templatelinks' || $table == 'iwlinks' ) { 00312 if ( $table == 'iwlinks' ) { 00313 $baseKey = 'iwl_prefix'; 00314 } else { 00315 $baseKey = "{$prefix}_namespace"; 00316 } 00317 $clause = $this->mDb->makeWhereFrom2d( $deletions, $baseKey, "{$prefix}_title" ); 00318 if ( $clause ) { 00319 $where[] = $clause; 00320 } else { 00321 $where = false; 00322 } 00323 } else { 00324 if ( $table == 'langlinks' ) { 00325 $toField = 'll_lang'; 00326 } elseif ( $table == 'page_props' ) { 00327 $toField = 'pp_propname'; 00328 } else { 00329 $toField = $prefix . '_to'; 00330 } 00331 if ( count( $deletions ) ) { 00332 $where[$toField] = array_keys( $deletions ); 00333 } else { 00334 $where = false; 00335 } 00336 } 00337 if ( $where ) { 00338 $this->mDb->delete( $table, $where, __METHOD__ ); 00339 } 00340 if ( count( $insertions ) ) { 00341 $this->mDb->insert( $table, $insertions, __METHOD__, 'IGNORE' ); 00342 wfRunHooks( 'LinksUpdateAfterInsert', array( $this, $table, $insertions ) ); 00343 } 00344 } 00345 00352 private function getLinkInsertions( $existing = array() ) { 00353 $arr = array(); 00354 foreach ( $this->mLinks as $ns => $dbkeys ) { 00355 $diffs = isset( $existing[$ns] ) 00356 ? array_diff_key( $dbkeys, $existing[$ns] ) 00357 : $dbkeys; 00358 foreach ( $diffs as $dbk => $id ) { 00359 $arr[] = array( 00360 'pl_from' => $this->mId, 00361 'pl_from_namespace' => $this->mTitle->getNamespace(), 00362 'pl_namespace' => $ns, 00363 'pl_title' => $dbk 00364 ); 00365 } 00366 } 00367 00368 return $arr; 00369 } 00370 00376 private function getTemplateInsertions( $existing = array() ) { 00377 $arr = array(); 00378 foreach ( $this->mTemplates as $ns => $dbkeys ) { 00379 $diffs = isset( $existing[$ns] ) ? array_diff_key( $dbkeys, $existing[$ns] ) : $dbkeys; 00380 foreach ( $diffs as $dbk => $id ) { 00381 $arr[] = array( 00382 'tl_from' => $this->mId, 00383 'tl_from_namespace' => $this->mTitle->getNamespace(), 00384 'tl_namespace' => $ns, 00385 'tl_title' => $dbk 00386 ); 00387 } 00388 } 00389 00390 return $arr; 00391 } 00392 00399 private function getImageInsertions( $existing = array() ) { 00400 $arr = array(); 00401 $diffs = array_diff_key( $this->mImages, $existing ); 00402 foreach ( $diffs as $iname => $dummy ) { 00403 $arr[] = array( 00404 'il_from' => $this->mId, 00405 'il_from_namespace' => $this->mTitle->getNamespace(), 00406 'il_to' => $iname 00407 ); 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_id' => $this->mDb->nextSequenceValue( 'externallinks_el_id_seq' ), 00425 'el_from' => $this->mId, 00426 'el_to' => $url, 00427 'el_index' => $index, 00428 ); 00429 } 00430 } 00431 00432 return $arr; 00433 } 00434 00443 private function getCategoryInsertions( $existing = array() ) { 00444 global $wgContLang, $wgCategoryCollation; 00445 $diffs = array_diff_assoc( $this->mCategories, $existing ); 00446 $arr = array(); 00447 foreach ( $diffs as $name => $prefix ) { 00448 $nt = Title::makeTitleSafe( NS_CATEGORY, $name ); 00449 $wgContLang->findVariantLink( $name, $nt, true ); 00450 00451 if ( $this->mTitle->getNamespace() == NS_CATEGORY ) { 00452 $type = 'subcat'; 00453 } elseif ( $this->mTitle->getNamespace() == NS_FILE ) { 00454 $type = 'file'; 00455 } else { 00456 $type = 'page'; 00457 } 00458 00459 # Treat custom sortkeys as a prefix, so that if multiple 00460 # things are forced to sort as '*' or something, they'll 00461 # sort properly in the category rather than in page_id 00462 # order or such. 00463 $sortkey = Collation::singleton()->getSortKey( 00464 $this->mTitle->getCategorySortkey( $prefix ) ); 00465 00466 $arr[] = array( 00467 'cl_from' => $this->mId, 00468 'cl_to' => $name, 00469 'cl_sortkey' => $sortkey, 00470 'cl_timestamp' => $this->mDb->timestamp(), 00471 'cl_sortkey_prefix' => $prefix, 00472 'cl_collation' => $wgCategoryCollation, 00473 'cl_type' => $type, 00474 ); 00475 } 00476 00477 return $arr; 00478 } 00479 00487 private function getInterlangInsertions( $existing = array() ) { 00488 $diffs = array_diff_assoc( $this->mInterlangs, $existing ); 00489 $arr = array(); 00490 foreach ( $diffs as $lang => $title ) { 00491 $arr[] = array( 00492 'll_from' => $this->mId, 00493 'll_lang' => $lang, 00494 'll_title' => $title 00495 ); 00496 } 00497 00498 return $arr; 00499 } 00500 00506 function getPropertyInsertions( $existing = array() ) { 00507 $diffs = array_diff_assoc( $this->mProperties, $existing ); 00508 00509 $arr = array(); 00510 foreach ( array_keys( $diffs ) as $name ) { 00511 $arr[] = $this->getPagePropRowData( $name ); 00512 } 00513 00514 return $arr; 00515 } 00516 00533 private function getPagePropRowData( $prop ) { 00534 global $wgPagePropsHaveSortkey; 00535 00536 $value = $this->mProperties[$prop]; 00537 00538 $row = array( 00539 'pp_page' => $this->mId, 00540 'pp_propname' => $prop, 00541 'pp_value' => $value, 00542 ); 00543 00544 if ( $wgPagePropsHaveSortkey ) { 00545 $row['pp_sortkey'] = $this->getPropertySortKeyValue( $value ); 00546 } 00547 00548 return $row; 00549 } 00550 00563 private function getPropertySortKeyValue( $value ) { 00564 if ( is_int( $value ) || is_float( $value ) || is_bool( $value ) ) { 00565 return floatval( $value ); 00566 } 00567 00568 return null; 00569 } 00570 00577 private function getInterwikiInsertions( $existing = array() ) { 00578 $arr = array(); 00579 foreach ( $this->mInterwikis as $prefix => $dbkeys ) { 00580 $diffs = isset( $existing[$prefix] ) 00581 ? array_diff_key( $dbkeys, $existing[$prefix] ) 00582 : $dbkeys; 00583 00584 foreach ( $diffs as $dbk => $id ) { 00585 $arr[] = array( 00586 'iwl_from' => $this->mId, 00587 'iwl_prefix' => $prefix, 00588 'iwl_title' => $dbk 00589 ); 00590 } 00591 } 00592 00593 return $arr; 00594 } 00595 00602 private function getLinkDeletions( $existing ) { 00603 $del = array(); 00604 foreach ( $existing as $ns => $dbkeys ) { 00605 if ( isset( $this->mLinks[$ns] ) ) { 00606 $del[$ns] = array_diff_key( $existing[$ns], $this->mLinks[$ns] ); 00607 } else { 00608 $del[$ns] = $existing[$ns]; 00609 } 00610 } 00611 00612 return $del; 00613 } 00614 00621 private function getTemplateDeletions( $existing ) { 00622 $del = array(); 00623 foreach ( $existing as $ns => $dbkeys ) { 00624 if ( isset( $this->mTemplates[$ns] ) ) { 00625 $del[$ns] = array_diff_key( $existing[$ns], $this->mTemplates[$ns] ); 00626 } else { 00627 $del[$ns] = $existing[$ns]; 00628 } 00629 } 00630 00631 return $del; 00632 } 00633 00640 private function getImageDeletions( $existing ) { 00641 return array_diff_key( $existing, $this->mImages ); 00642 } 00643 00650 private function getExternalDeletions( $existing ) { 00651 return array_diff_key( $existing, $this->mExternals ); 00652 } 00653 00660 private function getCategoryDeletions( $existing ) { 00661 return array_diff_assoc( $existing, $this->mCategories ); 00662 } 00663 00670 private function getInterlangDeletions( $existing ) { 00671 return array_diff_assoc( $existing, $this->mInterlangs ); 00672 } 00673 00679 function getPropertyDeletions( $existing ) { 00680 return array_diff_assoc( $existing, $this->mProperties ); 00681 } 00682 00689 private function getInterwikiDeletions( $existing ) { 00690 $del = array(); 00691 foreach ( $existing as $prefix => $dbkeys ) { 00692 if ( isset( $this->mInterwikis[$prefix] ) ) { 00693 $del[$prefix] = array_diff_key( $existing[$prefix], $this->mInterwikis[$prefix] ); 00694 } else { 00695 $del[$prefix] = $existing[$prefix]; 00696 } 00697 } 00698 00699 return $del; 00700 } 00701 00707 private function getExistingLinks() { 00708 $res = $this->mDb->select( 'pagelinks', array( 'pl_namespace', 'pl_title' ), 00709 array( 'pl_from' => $this->mId ), __METHOD__, $this->mOptions ); 00710 $arr = array(); 00711 foreach ( $res as $row ) { 00712 if ( !isset( $arr[$row->pl_namespace] ) ) { 00713 $arr[$row->pl_namespace] = array(); 00714 } 00715 $arr[$row->pl_namespace][$row->pl_title] = 1; 00716 } 00717 00718 return $arr; 00719 } 00720 00726 private function getExistingTemplates() { 00727 $res = $this->mDb->select( 'templatelinks', array( 'tl_namespace', 'tl_title' ), 00728 array( 'tl_from' => $this->mId ), __METHOD__, $this->mOptions ); 00729 $arr = array(); 00730 foreach ( $res as $row ) { 00731 if ( !isset( $arr[$row->tl_namespace] ) ) { 00732 $arr[$row->tl_namespace] = array(); 00733 } 00734 $arr[$row->tl_namespace][$row->tl_title] = 1; 00735 } 00736 00737 return $arr; 00738 } 00739 00745 private function getExistingImages() { 00746 $res = $this->mDb->select( 'imagelinks', array( 'il_to' ), 00747 array( 'il_from' => $this->mId ), __METHOD__, $this->mOptions ); 00748 $arr = array(); 00749 foreach ( $res as $row ) { 00750 $arr[$row->il_to] = 1; 00751 } 00752 00753 return $arr; 00754 } 00755 00761 private function getExistingExternals() { 00762 $res = $this->mDb->select( 'externallinks', array( 'el_to' ), 00763 array( 'el_from' => $this->mId ), __METHOD__, $this->mOptions ); 00764 $arr = array(); 00765 foreach ( $res as $row ) { 00766 $arr[$row->el_to] = 1; 00767 } 00768 00769 return $arr; 00770 } 00771 00777 private function getExistingCategories() { 00778 $res = $this->mDb->select( 'categorylinks', array( 'cl_to', 'cl_sortkey_prefix' ), 00779 array( 'cl_from' => $this->mId ), __METHOD__, $this->mOptions ); 00780 $arr = array(); 00781 foreach ( $res as $row ) { 00782 $arr[$row->cl_to] = $row->cl_sortkey_prefix; 00783 } 00784 00785 return $arr; 00786 } 00787 00794 private function getExistingInterlangs() { 00795 $res = $this->mDb->select( 'langlinks', array( 'll_lang', 'll_title' ), 00796 array( 'll_from' => $this->mId ), __METHOD__, $this->mOptions ); 00797 $arr = array(); 00798 foreach ( $res as $row ) { 00799 $arr[$row->ll_lang] = $row->ll_title; 00800 } 00801 00802 return $arr; 00803 } 00804 00809 protected function getExistingInterwikis() { 00810 $res = $this->mDb->select( 'iwlinks', array( 'iwl_prefix', 'iwl_title' ), 00811 array( 'iwl_from' => $this->mId ), __METHOD__, $this->mOptions ); 00812 $arr = array(); 00813 foreach ( $res as $row ) { 00814 if ( !isset( $arr[$row->iwl_prefix] ) ) { 00815 $arr[$row->iwl_prefix] = array(); 00816 } 00817 $arr[$row->iwl_prefix][$row->iwl_title] = 1; 00818 } 00819 00820 return $arr; 00821 } 00822 00828 private function getExistingProperties() { 00829 $res = $this->mDb->select( 'page_props', array( 'pp_propname', 'pp_value' ), 00830 array( 'pp_page' => $this->mId ), __METHOD__, $this->mOptions ); 00831 $arr = array(); 00832 foreach ( $res as $row ) { 00833 $arr[$row->pp_propname] = $row->pp_value; 00834 } 00835 00836 return $arr; 00837 } 00838 00843 public function getTitle() { 00844 return $this->mTitle; 00845 } 00846 00852 public function getParserOutput() { 00853 return $this->mParserOutput; 00854 } 00855 00860 public function getImages() { 00861 return $this->mImages; 00862 } 00863 00868 private function invalidateProperties( $changed ) { 00869 global $wgPagePropLinkInvalidations; 00870 00871 foreach ( $changed as $name => $value ) { 00872 if ( isset( $wgPagePropLinkInvalidations[$name] ) ) { 00873 $inv = $wgPagePropLinkInvalidations[$name]; 00874 if ( !is_array( $inv ) ) { 00875 $inv = array( $inv ); 00876 } 00877 foreach ( $inv as $table ) { 00878 $update = new HTMLCacheUpdate( $this->mTitle, $table ); 00879 $update->doUpdate(); 00880 } 00881 } 00882 } 00883 } 00884 00890 public function getAddedLinks() { 00891 if ( $this->linkInsertions === null ) { 00892 return null; 00893 } 00894 $result = array(); 00895 foreach ( $this->linkInsertions as $insertion ) { 00896 $result[] = Title::makeTitle( $insertion['pl_namespace'], $insertion['pl_title'] ); 00897 } 00898 00899 return $result; 00900 } 00901 00907 public function getRemovedLinks() { 00908 if ( $this->linkDeletions === null ) { 00909 return null; 00910 } 00911 $result = array(); 00912 foreach ( $this->linkDeletions as $ns => $titles ) { 00913 foreach ( $titles as $title => $unused ) { 00914 $result[] = Title::makeTitle( $ns, $title ); 00915 } 00916 } 00917 00918 return $result; 00919 } 00920 00924 protected function updateLinksTimestamp() { 00925 if ( $this->mId ) { 00926 // The link updates made here only reflect the freshness of the parser output 00927 $timestamp = $this->mParserOutput->getCacheTime(); 00928 $this->mDb->update( 'page', 00929 array( 'page_links_updated' => $this->mDb->timestamp( $timestamp ) ), 00930 array( 'page_id' => $this->mId ), 00931 __METHOD__ 00932 ); 00933 } 00934 } 00935 } 00936 00940 class LinksDeletionUpdate extends SqlDataUpdate { 00942 protected $mPage; 00943 00950 function __construct( WikiPage $page ) { 00951 parent::__construct( false ); // no implicit transaction 00952 00953 $this->mPage = $page; 00954 00955 if ( !$page->exists() ) { 00956 throw new MWException( "Page ID not known, perhaps the page doesn't exist?" ); 00957 } 00958 } 00959 00963 public function doUpdate() { 00964 $title = $this->mPage->getTitle(); 00965 $id = $this->mPage->getId(); 00966 00967 # Delete restrictions for it 00968 $this->mDb->delete( 'page_restrictions', array( 'pr_page' => $id ), __METHOD__ ); 00969 00970 # Fix category table counts 00971 $cats = array(); 00972 $res = $this->mDb->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ ); 00973 00974 foreach ( $res as $row ) { 00975 $cats[] = $row->cl_to; 00976 } 00977 00978 $this->mPage->updateCategoryCounts( array(), $cats ); 00979 00980 # If using cascading deletes, we can skip some explicit deletes 00981 if ( !$this->mDb->cascadingDeletes() ) { 00982 # Delete outgoing links 00983 $this->mDb->delete( 'pagelinks', array( 'pl_from' => $id ), __METHOD__ ); 00984 $this->mDb->delete( 'imagelinks', array( 'il_from' => $id ), __METHOD__ ); 00985 $this->mDb->delete( 'categorylinks', array( 'cl_from' => $id ), __METHOD__ ); 00986 $this->mDb->delete( 'templatelinks', array( 'tl_from' => $id ), __METHOD__ ); 00987 $this->mDb->delete( 'externallinks', array( 'el_from' => $id ), __METHOD__ ); 00988 $this->mDb->delete( 'langlinks', array( 'll_from' => $id ), __METHOD__ ); 00989 $this->mDb->delete( 'iwlinks', array( 'iwl_from' => $id ), __METHOD__ ); 00990 $this->mDb->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ ); 00991 $this->mDb->delete( 'page_props', array( 'pp_page' => $id ), __METHOD__ ); 00992 } 00993 00994 # If using cleanup triggers, we can skip some manual deletes 00995 if ( !$this->mDb->cleanupTriggers() ) { 00996 # Clean up recentchanges entries... 00997 $this->mDb->delete( 'recentchanges', 00998 array( 'rc_type != ' . RC_LOG, 00999 'rc_namespace' => $title->getNamespace(), 01000 'rc_title' => $title->getDBkey() ), 01001 __METHOD__ ); 01002 $this->mDb->delete( 'recentchanges', 01003 array( 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ), 01004 __METHOD__ ); 01005 } 01006 } 01007 01013 function updateCategoryCounts( $added, $deleted ) { 01014 $a = WikiPage::factory( $this->mTitle ); 01015 $a->updateCategoryCounts( 01016 array_keys( $added ), array_keys( $deleted ) 01017 ); 01018 } 01019 }