[bug 37746] string ids for content model and format.
[lhc/web/wiklou.git] / includes / LinksUpdate.php
index 1973d95..3e8e362 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * See docs/deferred.txt
+ * Updater for link tracking tables after a page edit.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
+ */
+
+/**
+ * See docs/deferred.txt
+ *
  * @todo document (e.g. one-sentence top-level class description).
  */
-class LinksUpdate extends SecondaryDBDataUpdate {
+class LinksUpdate extends SqlDataUpdate {
 
-       /**@{{
-        * @private
-        */
-       var $mId,            //!< Page ID of the article linked from
-        $mTitle,         //!< Title object of the article linked from
-        $mParserOutput,  //!< Whether to queue jobs for recursive update
-        $mLinks,         //!< Map of title strings to IDs for the links in the document
+       // @todo: make members protected, but make sure extensions don't break
+
+       public $mId,         //!< Page ID of the article linked from
+               $mTitle,         //!< Title object of the article linked from
+               $mParserOutput,  //!< Parser output
+               $mLinks,         //!< Map of title strings to IDs for the links in the document
                $mImages,        //!< DB keys of the images used, in the array key only
                $mTemplates,     //!< Map of title strings to IDs for the template references, including broken ones
                $mExternals,     //!< URLs of external links, array key only
@@ -35,7 +40,6 @@ class LinksUpdate extends SecondaryDBDataUpdate {
                $mInterlangs,    //!< Map of language codes to titles
                $mProperties,    //!< Map of arbitrary name to value
                $mRecursive;     //!< Whether to queue jobs for recursive updates
-       /**@}}*/
 
        /**
         * Constructor
@@ -45,21 +49,26 @@ class LinksUpdate extends SecondaryDBDataUpdate {
         * @param $recursive Boolean: queue jobs for recursive updates?
         */
        function __construct( $title, $parserOutput, $recursive = true ) {
-        parent::__construct( );
+               parent::__construct( );
 
-        if ( !is_object( $title ) ) {
-            throw new MWException( "The calling convention to LinksUpdate::LinksUpdate() has changed. " .
-                "Please see Article::editUpdates() for an invocation example.\n" );
-        }
+               if ( !( $title instanceof Title ) ) {
+                       throw new MWException( "The calling convention to LinksUpdate::LinksUpdate() has changed. " .
+                               "Please see Article::editUpdates() for an invocation example.\n" );
+               }
 
-               if ( !is_object( $title ) ) {
-                       throw new MWException( "The calling convention to LinksUpdate::__construct() has changed. " .
+               if ( !( $parserOutput instanceof ParserOutput ) ) {
+                       throw new MWException( "The calling convention to LinksUpdate::__construct() has changed. " .
                                "Please see WikiPage::doEditUpdates() for an invocation example.\n" );
-               }
-        $this->mTitle = $title;
-        $this->mId = $title->getArticleID();
+               }
+
+               $this->mTitle = $title;
+               $this->mId = $title->getArticleID();
+
+               if ( !$this->mId ) {
+                       throw new MWException( "The Title object did not provide an article ID. Perhaps the page doesn't exist?" );
+               }
 
-        $this->mParserOutput = $parserOutput;
+               $this->mParserOutput = $parserOutput;
 
                $this->mLinks = $parserOutput->getLinks();
                $this->mImages = $parserOutput->getImages();
@@ -276,20 +285,20 @@ class LinksUpdate extends SecondaryDBDataUpdate {
                $this->invalidatePages( NS_FILE, array_keys( $images ) );
        }
 
-    /**
-     * @param $table
-     * @param $insertions
-     * @param $fromField
-     */
-    private function dumbTableUpdate( $table, $insertions, $fromField ) {
-        $this->mDb->delete( $table, array( $fromField => $this->mId ), __METHOD__ );
-        if ( count( $insertions ) ) {
-            # The link array was constructed without FOR UPDATE, so there may
-            # be collisions.  This may cause minor link table inconsistencies,
-            # which is better than crippling the site with lock contention.
-            $this->mDb->insert( $table, $insertions, __METHOD__, array( 'IGNORE' ) );
-        }
-    }
+       /**
+        * @param $table
+        * @param $insertions
+        * @param $fromField
+        */
+       private function dumbTableUpdate( $table, $insertions, $fromField ) {
+               $this->mDb->delete( $table, array( $fromField => $this->mId ), __METHOD__ );
+               if ( count( $insertions ) ) {
+                       # The link array was constructed without FOR UPDATE, so there may
+                       # be collisions.  This may cause minor link table inconsistencies,
+                       # which is better than crippling the site with lock contention.
+                       $this->mDb->insert( $table, $insertions, __METHOD__, array( 'IGNORE' ) );
+               }
+       }
 
        /**
         * Update a table by doing a delete query then an insert query
@@ -755,22 +764,22 @@ class LinksUpdate extends SecondaryDBDataUpdate {
                return $arr;
        }
 
-    /**
-     * Return the title object of the page being updated
-     * @return Title
-     */
-    public function getTitle() {
-        return $this->mTitle;
-    }
+       /**
+        * Return the title object of the page being updated
+        * @return Title
+        */
+       public function getTitle() {
+               return $this->mTitle;
+       }
 
-    /**
-     * Returns parser output
-     * @since 1.19
-     * @return ParserOutput
-     */
-    public function getParserOutput() {
-        return $this->mParserOutput;
-    }
+       /**
+        * Returns parser output
+        * @since 1.19
+        * @return ParserOutput
+        */
+       public function getParserOutput() {
+               return $this->mParserOutput;
+       }
 
        /**
         * Return the list of images used as generated by the parser
@@ -801,3 +810,90 @@ class LinksUpdate extends SecondaryDBDataUpdate {
                }
        }
 }
+
+/**
+ * Update object handling the cleanup of links tables after a page was deleted.
+ **/
+class LinksDeletionUpdate extends SqlDataUpdate {
+
+       protected $mTitle;     //!< Title the title of page that was deleted
+
+       /**
+        * Constructor
+        *
+        * @param $title Title of the page we're updating
+        * @param $parserOutput ParserOutput: output from a full parse of this page
+        * @param $recursive Boolean: queue jobs for recursive updates?
+        */
+       function __construct( Title $title ) {
+               parent::__construct( );
+
+               $this->mTitle = $title;
+
+               if ( !$title->getArticleID() ) {
+                       throw new MWException( "The Title object did not provide an article ID. Perhaps the page doesn't exist?" );
+               }
+       }
+
+       /**
+        * Do some database updates after deletion
+        */
+       public function doUpdate() {
+               $title = $this->mTitle;
+               $id = $title->getArticleID();
+
+               # Delete restrictions for it
+               $this->mDb->delete( 'page_restrictions', array ( 'pr_page' => $id ), __METHOD__ );
+
+               # Fix category table counts
+               $cats = array();
+               $res = $this->mDb->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ );
+
+               foreach ( $res as $row ) {
+                       $cats [] = $row->cl_to;
+               }
+
+               $this->updateCategoryCounts( array(), $cats );
+
+               # If using cascading deletes, we can skip some explicit deletes
+               if ( !$this->mDb->cascadingDeletes() ) {
+                       $this->mDb->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
+
+                       # Delete outgoing links
+                       $this->mDb->delete( 'pagelinks', array( 'pl_from' => $id ), __METHOD__ );
+                       $this->mDb->delete( 'imagelinks', array( 'il_from' => $id ), __METHOD__ );
+                       $this->mDb->delete( 'categorylinks', array( 'cl_from' => $id ), __METHOD__ );
+                       $this->mDb->delete( 'templatelinks', array( 'tl_from' => $id ), __METHOD__ );
+                       $this->mDb->delete( 'externallinks', array( 'el_from' => $id ), __METHOD__ );
+                       $this->mDb->delete( 'langlinks', array( 'll_from' => $id ), __METHOD__ );
+                       $this->mDb->delete( 'iwlinks', array( 'iwl_from' => $id ), __METHOD__ );
+                       $this->mDb->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ );
+                       $this->mDb->delete( 'page_props', array( 'pp_page' => $id ), __METHOD__ );
+               }
+
+               # If using cleanup triggers, we can skip some manual deletes
+               if ( !$this->mDb->cleanupTriggers() ) {
+                       # Clean up recentchanges entries...
+                       $this->mDb->delete( 'recentchanges',
+                               array( 'rc_type != ' . RC_LOG,
+                                       'rc_namespace' => $title->getNamespace(),
+                                       'rc_title' => $title->getDBkey() ),
+                               __METHOD__ );
+                       $this->mDb->delete( 'recentchanges',
+                               array( 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ),
+                               __METHOD__ );
+               }
+       }
+
+       /**
+        * Update all the appropriate counts in the category table.
+        * @param $added array associative array of category name => sort key
+        * @param $deleted array associative array of category name => sort key
+        */
+       function updateCategoryCounts( $added, $deleted ) {
+               $a = WikiPage::factory( $this->mTitle );
+               $a->updateCategoryCounts(
+                       array_keys( $added ), array_keys( $deleted )
+               );
+       }
+}