* Recent Changes improvements: object oriented back end, move page annotation and...
authorTim Starling <tstarling@users.mediawiki.org>
Sat, 17 Jan 2004 05:49:39 +0000 (05:49 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Sat, 17 Jan 2004 05:49:39 +0000 (05:49 +0000)
* Misc. bugs fixed in DatabaseFunctions.php and Skin.php.
* install-utils, install and update utilise Database objects instead of handling their own connections
* schema change for RC improvement -- added rc_type, rc_moved_to_title and rc_moved_to_ns

19 files changed:
includes/Article.php
includes/Database.php
includes/DatabaseFunctions.php
includes/DefaultSettings.php
includes/DifferenceEngine.php
includes/LogPage.php
includes/RecentChange.php [new file with mode: 0644]
includes/Setup.php
includes/Skin.php
includes/SpecialMovepage.php
includes/SpecialRecentchanges.php
includes/SpecialUserlogin.php
includes/Title.php
install-utils.inc
install.php
maintenance/archives/patch-rc_type.sql [new file with mode: 0644]
maintenance/tables.sql
update.php
wiki.phtml

index 522616d..807007f 100644 (file)
@@ -20,16 +20,17 @@ class Article {
        /* private */ var $mCounter, $mComment, $mCountAdjustment;
        /* private */ var $mMinorEdit, $mRedirectedFrom;
        /* private */ var $mTouched, $mFileCache, $mTitle;
-
+       /* private */ var $mId, $mTable;
+       
        function Article( &$title ) {
                $this->mTitle =& $title;
                $this->clear();
        }
-
+       
        /* private */ function clear()
        {
                $this->mContentLoaded = false;
-               $this->mUser = $this->mCounter = -1; # Not loaded
+               $this->mCurID = $this->mUser = $this->mCounter = -1; # Not loaded
                $this->mRedirectedFrom = $this->mUserText =
                $this->mTimestamp = $this->mComment = $this->mFileCache = "";
                $this->mCountAdjustment = 0;
@@ -67,6 +68,7 @@ class Article {
        # Note that getContent/loadContent may follow redirects if
        # not told otherwise, and so may cause a change to mTitle.
 
+       # Return the text of this revision
        function getContent( $noredir = false )
        {
                global $action,$section,$count; # From query string
@@ -117,7 +119,8 @@ class Article {
                        }
                }
        }
-
+       
+       # Load the revision (including cur_text) into this object
        function loadContent( $noredir = false )
        {
                global $wgOut, $wgMwRedir;
@@ -125,21 +128,8 @@ class Article {
 
                if ( $this->mContentLoaded ) return;
                $fname = "Article::loadContent";
-
-               # Pre-fill content with error message so that if something
-               # fails we'll have something telling us what we intended.
-
-               $t = $this->mTitle->getPrefixedText();
-               if ( isset( $oldid ) ) {
-                       $oldid = IntVal( $oldid );
-                       $t .= ",oldid={$oldid}";
-               }
-               if ( isset( $redirect ) ) {
-                       $redirect = ($redirect == "no") ? "no" : "yes";
-                       $t .= ",redirect={$redirect}";
-               }
-               $this->mContent = wfMsg( "missingarticle", $t );
-
+               $success = true;
+               
                if ( ! $oldid ) {       # Retrieve current version
                        $id = $this->getID();
                        if ( 0 == $id ) return;
@@ -212,6 +202,22 @@ class Article {
                        $this->mTimestamp = $s->old_timestamp;
                        wfFreeResult( $res );
                }
+
+               # Return error message :P
+               # Horrible, confusing UI and data. I think this should return false on error -- TS
+               if ( !$success ) {
+                       $t = $this->mTitle->getPrefixedText();
+                       if ( isset( $oldid ) ) {
+                               $oldid = IntVal( $oldid );
+                               $t .= ",oldid={$oldid}";
+                       }
+                       if ( isset( $redirect ) ) {
+                               $redirect = ($redirect == "no") ? "no" : "yes";
+                               $t .= ",redirect={$redirect}";
+                       }
+                       $this->mContent = wfMsg( "missingarticle", $t );
+               }
+
                $this->mContentLoaded = true;
        }
 
@@ -246,7 +252,7 @@ class Article {
                return 1;
        }
 
-       # Load the field related to the last edit time of the article.
+       # Loads everything from cur except cur_text
        # This isn't necessary for all uses, so it's only done if needed.
 
        /* private */ function loadLastEdit()
@@ -399,16 +405,8 @@ class Article {
                $this->mTitle->resetArticleID( $newid );
 
                Article::onArticleCreate( $this->mTitle );
+               RecentChange::notifyNew( $now, $this->mTitle, $isminor, $wgUser, $summary );
                
-               $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time," .
-                 "rc_namespace,rc_title,rc_new,rc_minor,rc_cur_id,rc_user," .
-                 "rc_user_text,rc_comment,rc_this_oldid,rc_last_oldid,rc_bot) VALUES (" .
-                 "'{$now}','{$now}',{$ns},'" . wfStrencode( $ttl ) . "',1," .
-                 ( $isminor ? 1 : 0 ) . ",{$newid}," . $wgUser->getID() . ",'" .
-                 wfStrencode( $wgUser->getName() ) . "','" .
-                 wfStrencode( $summary ) . "',0,0," .
-                 ( $wgUser->isBot() ? 1 : 0 ) . ")";
-               wfQuery( $sql, DB_WRITE, $fname );
                if ($watchthis) {               
                        if(!$this->mTitle->userIsWatching()) $this->watch(); 
                } else {
@@ -505,27 +503,8 @@ class Article {
                        $oldid = wfInsertID( $res );
 
                        $bot = (int)($wgUser->isBot() || $forceBot);
-                       
-                       $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time," .
-                         "rc_namespace,rc_title,rc_new,rc_minor,rc_bot,rc_cur_id,rc_user," .
-                         "rc_user_text,rc_comment,rc_this_oldid,rc_last_oldid) VALUES (" .
-                         "'{$now}','{$now}'," . $this->mTitle->getNamespace() . ",'" .
-                         wfStrencode( $this->mTitle->getDBkey() ) . "',0,{$me2}," .
-                         "$bot," . $this->getID() . "," . $wgUser->getID() . ",'" .
-                         wfStrencode( $wgUser->getName() ) . "','" .
-                         wfStrencode( $summary ) . "',0,{$oldid})";
-                       wfQuery( $sql, DB_WRITE, $fname );
-
-                       $sql = "UPDATE recentchanges SET rc_this_oldid={$oldid} " .
-                         "WHERE rc_namespace=" . $this->mTitle->getNamespace() . " AND " .
-                         "rc_title='" . wfStrencode( $this->mTitle->getDBkey() ) . "' AND " .
-                         "rc_timestamp='" . $this->getTimestamp() . "'";
-                       wfQuery( $sql, DB_WRITE, $fname );
-
-                       $sql = "UPDATE recentchanges SET rc_cur_time='{$now}' " .
-                         "WHERE rc_cur_id=" . $this->getID();
-                       wfQuery( $sql, DB_WRITE, $fname );
-
+                       RecentChange::notifyEdit( $now, $this->mTitle, $me2, $wgUser, $this->getComment(), 
+                               $oldid, $this->getTimestamp() );
                        Article::onArticleEdit( $this->mTitle );
                }
 
index c243b5d..8e6282e 100644 (file)
@@ -6,6 +6,9 @@ define( "DB_READ", -1 );
 define( "DB_WRITE", -2 );
 define( "DB_LAST", -3 );
 
+define( "LIST_COMMA", 0 );
+define( "LIST_AND", 1 );
+
 class Database {
 
 #------------------------------------------------------------------------------
@@ -16,7 +19,7 @@ class Database {
        /* private */ var $mIgnoreErrors = false;
        
        /* private */ var $mServer, $mUser, $mPassword, $mConn, $mDBname;
-       /* private */ var $mOut, $mDebug;
+       /* private */ var $mOut, $mDebug, $mOpened = false;
        
        /* private */ var $mFailFunction; 
 
@@ -51,7 +54,8 @@ class Database {
        # Get functions
        
        function lastQuery() { return $this->mLastQuery; }
-               
+       function isOpen() { return $this->mOpened; }
+
 #------------------------------------------------------------------------------
 # Other functions
 #------------------------------------------------------------------------------
@@ -84,12 +88,12 @@ class Database {
                $this->mServer = $server;
                $this->mUser = $user;
                $this->mPassword = $password;
-               $this->mDbName = $dbName;
+               $this->mDBname = $dbName;
                
                $success = false;
                
                @$this->mConn = mysql_connect( $server, $user, $password );
-               if ( $this->mConn !== false ) {
+               if ( $this->mConn !== false && $dbName != "" ) {
                        $success = @mysql_select_db( $dbName, $this->mConn );
                        if ( !$success ) {
                                wfDebug( "Error selecting database \"$dbName\": " . $this->lastError() . "\n" );
@@ -105,6 +109,7 @@ class Database {
                        $this->reportConnectionError();
                        $this->close();
                }
+               $this->mOpened = $success;
                return $success;
        }
        
@@ -112,6 +117,7 @@ class Database {
        # Returns success, true if already closed
        function close()
        {
+               $this->mOpened = false;
                if ( $this->mConn ) {
                        return mysql_close( $this->mConn );
                } else {
@@ -132,7 +138,7 @@ class Database {
        
        # Usually aborts on failure
        # If errors are explicitly ignored, returns success
-       function query( $sql, $db, $fname = "" )
+       function query( $sql, $fname = "" )
        {
                global $wgProfiling;
                
@@ -211,6 +217,23 @@ class Database {
                return $ret;
        }
        
+       # More complex SELECT wrapper, single row only
+       # Aborts or returns FALSE on error
+       # Takes an array of selected variables, and a condition map, which is ANDed
+       # e.g. getArray( "cur", array( "cur_id" ), array( "cur_namespace" => 0, "cur_title" => "Astronomy" ) )
+       #   would return an object where $obj->cur_id is the ID of the Astronomy article
+       function getArray( $table, $vars, $conds, $fname = "Database::getArray" )
+       {
+               $vars = implode( ",", $vars );
+               $where = Database::makeList( $conds, LIST_AND );
+               $sql = "SELECT $vars FROM $table WHERE $where";
+               $res = $this->query( $sql, $fname );
+               if ( $res === false || !$this->numRows( $res ) ) {
+                       return false;
+               }
+               return $this->fetchObject( $res );
+       }
+       
        # Removes most variables from an SQL query and replaces them with X or N for numbers.
        # It's only slightly flawed. Don't use for anything important.
        /* static */ function generalizeSQL( $sql )
@@ -277,6 +300,32 @@ class Database {
                return $found;
        }
        
+       function tableExists( $table )
+       {
+               $res = mysql_list_tables( $this->mDBname );
+               if( !$res ) {
+                       echo "** " . $this->lastError() . "\n";
+                       return false;
+               }
+               for( $i = $this->numRows( $res ) - 1; $i--; $i > 0 ) {
+                       if( mysql_tablename( $res, $i ) == $table ) return true;
+               }
+               return false;
+       }
+
+       function fieldInfo( $table, $field )
+       {
+               $res = $this->query( "SELECT * FROM $table LIMIT 1" );
+               $n = mysql_num_fields( $res );
+               for( $i = 0; $i < $n; $i++ ) {
+                       $meta = mysql_fetch_field( $res, $i );
+                       if( $field == $meta->name ) {
+                               return $meta;
+                       }
+               }
+               return false;
+       }
+
        # INSERT wrapper, inserts an array into a table
        # Keys are field names, values are values
        # Usually aborts on failure
@@ -284,23 +333,52 @@ class Database {
        function insertArray( $table, $a, $fname = "Database::insertArray" )
        {
                $sql1 = "INSERT INTO $table (";
-               $sql2 = "VALUES (";
+               $sql2 = "VALUES (" . Database::makeList( $a );
                $first = true;
                foreach ( $a as $field => $value ) {
-                       if ( $first ) {
+                       if ( !$first ) {
                                $sql1 .= ",";
-                               $sql2 .= ",";
-                               $first = false;
                        }
+                       $first = false;
                        $sql1 .= $field;
+               }
+               $sql = "$sql1) $sql2)";
+               return !!$this->query( $sql, $fname );
+       }
+       
+       # Makes a wfStrencoded list from an array
+       # $mode: LIST_COMMA - comma separated
+       #        LIST_AND   - ANDed WHERE clause (without the WHERE)
+       /* static */ function makeList( $a, $mode = LIST_COMMA)
+       {
+               $first = true;
+               $list = "";
+               foreach ( $a as $field => $value ) {
+                       if ( !$first ) {
+                               if ( $mode == LIST_AND ) {
+                                       $list .= " AND ";
+                               } else {
+                                       $list .= ",";
+                               }
+                       } else {
+                               $first = false;
+                       }
+                       if ( $mode == LIST_AND ) {
+                               $list .= "$field=";
+                       }
                        if ( is_string( $value ) ) {
-                               $sql2 .= "'" . wfStrencode( $value ) . "'";
+                               $list .= "'" . wfStrencode( $value ) . "'";
                        } else {
-                               $sql2 .= $value;
+                               $list .= $value;
                        }
                }
-               $sql = "$sql1) $sql2)";
-               return !!$this->query( $sql, DB_WRITE, $fname );
+               return $list;
+       }
+       
+       function selectDB( $db ) 
+       {
+               $this->mDatabase = $db;
+               mysql_select_db( $db, $this->mConn );
        }
 }
 
index b3208e1..0add9fd 100644 (file)
@@ -2,8 +2,16 @@
 
 # Backwards compatibility wrapper for Database.php
 
+# I imagine this file will eventually become a backwards
+# compatibility wrapper around a load balancer object, and
+# the load balancer will finally call Database, which will
+# represent a single connection
+
 # NB: This file follows a connect on demand scheme. Do 
-# not access the $wgDatabase variable directly, use wfGetDB()
+# not access the $wgDatabase variable directly unless
+# you intend to set it. Use wfGetDB().
+
+include_once( "Database.php" );
 
 # Query the database
 # $db: DB_READ  = -1    read from slave (or only server)
@@ -12,9 +20,6 @@
 # Replication is not actually implemented just yet
 # Usually aborts on failure
 # If errors are explicitly ignored, returns success
-
-include_once( "Database.php" );
-
 function wfQuery( $sql, $db, $fname = "" )
 {
        global $wgDatabase, $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, 
@@ -25,12 +30,12 @@ function wfQuery( $sql, $db, $fname = "" )
                $wgOut->fatalError( wfMsgNoDB( "wrong_wfQuery_params", $db, $sql ) );
        }
 
-       $db = wfGetDB();
-       return $db->query( $sql, $db, $fname );
+       $db = wfGetDB();
+       return $db->query( $sql, $fname );
 }
 
 # Connect on demand
-function wfGetDB()
+function &wfGetDB()
 {
        global $wgDatabase, $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, 
                $wgDebugDumpSql, $wgBufferSQLResults, $wgIgnoreSQLErrors;
@@ -47,7 +52,7 @@ function wfGetDB()
 
 function wfBufferSQLResults( $newstate )
 {
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->setBufferResults( $newstate );
 }
 
@@ -60,97 +65,109 @@ function wfBufferSQLResults( $newstate )
 
 function wfIgnoreSQLErrors( $newstate )
 {
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->setIgnoreErrors( $newstate );
 }
 
 function wfFreeResult( $res ) 
 { 
-       $db = wfGetDB();
+       $db =& wfGetDB();
        $db->freeResult( $res ); 
 }
 
 function wfFetchObject( $res ) 
 { 
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->fetchObject( $res ); 
 }
 
 function wfNumRows( $res ) 
 { 
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->numRows( $res ); 
 }
 
 function wfNumFields( $res ) 
 { 
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->numFields( $res ); 
 }
 
 function wfFieldName( $res, $n ) 
 { 
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->fieldName( $res, $n ); 
 }
 
 function wfInsertId() 
 { 
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->insertId(); 
 }
 function wfDataSeek( $res, $row ) 
 { 
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->dataSeek( $res, $row ); 
 }
 
 function wfLastErrno()  
 { 
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->lastErrno(); 
 }
 
 function wfLastError()  
 { 
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->lastError(); 
 }
 
 function wfAffectedRows()
 { 
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->affectedRows(); 
 }
 
 function wfLastDBquery()
 {
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->lastQuery();
 }
 
 function wfSetSQL( $table, $var, $value, $cond )
 {
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->set( $table, $var, $value, $cond );
 }
 
 function wfGetSQL( $table, $var, $cond )
 {
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->get( $table, $var, $cond );
 }
 
 function wfFieldExists( $table, $field )
 {
-       $db = wfGetDB();
+       $db =& wfGetDB();
        return $db->fieldExists( $table, $field );
 }
 
 function wfIndexExists( $table, $index ) 
 {
-       $db = wfGetDB();
-       return $wgDatabase->indexExists( $table, $index );
+       $db =& wfGetDB();
+       return $db->indexExists( $table, $index );
+}
+
+function wfInsertArray( $table, $array ) 
+{
+       $db =& wfGetDB();
+       return $db->insertArray( $table, $array );
+}
+
+function wfGetArray( $table, $vars, $conds, $fname = "wfGetArray" )
+{
+       $db =& wfGetDB();
+       return $db->getArray( $table, $vars, $conds, $fname );
 }
 
 ?>
index 7e40447..f226f2e 100644 (file)
@@ -64,6 +64,7 @@ $wgAmericanDates    = false; # Enable for English module to print dates
                                                         # as eg 'May 12' instead of '12 May'
 $wgLocalInterwiki   = "w";
 $wgShowIPinHeader      = true; # For non-logged in users
+$wgMaxNameChars     = 32; # Maximum number of bytes in username
 
 # Translation using MediaWiki: namespace
 # Not recommended unless memcached is installed
index 30af4a2..c3188c7 100644 (file)
@@ -5,7 +5,8 @@ class DifferenceEngine {
        /* private */ var $mOldid, $mNewid;
        /* private */ var $mOldtitle, $mNewtitle;
        /* private */ var $mOldtext, $mNewtext;
-
+       /* private */ var $mOldUser, $mNewUser;
+       
        function DifferenceEngine( $old, $new )
        {
                $this->mOldid = $old;
@@ -29,9 +30,17 @@ class DifferenceEngine {
                $wgOut->supressQuickbar();
                $wgOut->setSubtitle( wfMsg( "difference" ) );
                $wgOut->setRobotpolicy( "noindex,follow" );
+               
+               $sk = $wgUser->getSkin();
+               $oldUserTitle = Title::makeTitle( NS_USER, $this->mOldUser );
+               $newUserTitle = Title::makeTitle( NS_USER, $this->mNewUser );
+               $oldUserLink = $sk->makeLinkObj( $oldUserTitle, $this->mOldUser );
+               $newUserLink = $sk->makeLinkObj( $newUserTitle, $this->mNewUser );
+               $oldHeader = "<strong>{$this->mOldtitle}</strong><br>$oldUserLink";
+               $newHeader = "<strong>{$this->mNewtitle}</strong><br>$newUserLink";
 
                DifferenceEngine::showDiff( $this->mOldtext, $this->mNewtext,
-                 $this->mOldtitle, $this->mNewtitle );
+                 $oldHeader, $newHeader );
                $wgOut->addHTML( "<hr><h2>{$this->mNewtitle}</h2>\n" );
                $wgOut->addWikiText( $this->mNewtext );
        }
@@ -48,9 +57,9 @@ class DifferenceEngine {
                $wgOut->addHTML( "<table width='98%' border=0
 cellpadding=0 cellspacing='4px'><tr>
 <td colspan=2 width='50%' align=center bgcolor='#cccccc'>
-<strong>{$otitle}</strong></td>
+{$otitle}</td>
 <td colspan=2 width='50%' align=center bgcolor='#cccccc'>
-<strong>{$ntitle}</strong></td>
+{$ntitle}</td>
 </tr>\n" );
 
                $diffs = new Diff( $ota, $nta );
@@ -68,20 +77,21 @@ cellpadding=0 cellspacing='4px'><tr>
        {
                global $wgTitle, $wgOut, $wgLang;
                $fname = "DifferenceEngine::loadText";
-
+               
                if ( 0 == $this->mNewid || 0 == $this->mOldid ) {
                        $wgOut->setArticleFlag( true );
                        $this->mNewtitle = wfMsg( "currentrev" );
                        $id = $wgTitle->getArticleID();
-
-                       $sql = "SELECT cur_text FROM cur WHERE cur_id={$id}";
+                       
+                       $sql = "SELECT cur_text, cur_user_text FROM cur WHERE cur_id={$id}";
                        $res = wfQuery( $sql, DB_READ, $fname );
                        if ( 0 == wfNumRows( $res ) ) { return false; }
 
                        $s = wfFetchObject( $res );
                        $this->mNewtext = $s->cur_text;
+                       $this->mNewUser = $s->cur_user_text;
                } else {
-                       $sql = "SELECT old_timestamp,old_text,old_flags FROM old WHERE " .
+                       $sql = "SELECT old_timestamp,old_text,old_flags,old_user_text FROM old WHERE " .
                          "old_id={$this->mNewid}";
 
                        $res = wfQuery( $sql, DB_READ, $fname );
@@ -92,15 +102,17 @@ cellpadding=0 cellspacing='4px'><tr>
 
                        $t = $wgLang->timeanddate( $s->old_timestamp, true );
                        $this->mNewtitle = wfMsg( "revisionasof", $t );
+                       $this->mNewUser = $s->old_user_text;
                }
                if ( 0 == $this->mOldid ) {
-                       $sql = "SELECT old_timestamp,old_text,old_flags FROM old USE INDEX (name_title_timestamp) WHERE " .
+                       $sql = "SELECT old_timestamp,old_text,old_flags,old_user_text " .
+                         "FROM old USE INDEX (name_title_timestamp) WHERE " .
                          "old_namespace=" . $wgTitle->getNamespace() . " AND " .
                          "old_title='" . wfStrencode( $wgTitle->getDBkey() ) .
                          "' ORDER BY inverse_timestamp LIMIT 1";
                        $res = wfQuery( $sql, DB_READ, $fname );
                } else {
-                       $sql = "SELECT old_timestamp,old_text,old_flags FROM old WHERE " .
+                       $sql = "SELECT old_timestamp,old_text,old_flags,old_user_text FROM old WHERE " .
                          "old_id={$this->mOldid}";
                        $res = wfQuery( $sql, DB_READ, $fname );
                }
@@ -111,7 +123,8 @@ cellpadding=0 cellspacing='4px'><tr>
 
                $t = $wgLang->timeanddate( $s->old_timestamp, true );
                $this->mOldtitle = wfMsg( "revisionasof", $t );
-
+               $this->mOldUser = $s->old_user_text;
+               
                return true;
        }
 }
index 0faeab6..371820e 100644 (file)
@@ -81,13 +81,9 @@ class LogPage {
                
                # And update recentchanges
                if ( $this->mUpdateRecentChanges ) {
-                       $sql = "INSERT INTO recentchanges (rc_timestamp,rc_cur_time,
-                       rc_user,rc_user_text,rc_namespace,rc_title,rc_comment,
-                       rc_cur_id) VALUES ('{$now}','{$now}',{$uid},'{$ut}',4,'" .
-                               wfStrencode( $this->mTitle ) . "','" .
-                               wfStrencode( $this->mComment ) . "',{$this->mId})";
-                       wfQuery( $sql, DB_WRITE, $fname );
-                       }
+                       $titleObj = Title::makeTitle( Namespace::getWikipedia(), $this->mTitle );
+                       RecentChange::notifyLog( $now, $titleObj, $wgUser, $this->mComment );
+               }
                return true;
        }
 
diff --git a/includes/RecentChange.php b/includes/RecentChange.php
new file mode 100644 (file)
index 0000000..d7e8a6d
--- /dev/null
@@ -0,0 +1,263 @@
+<?
+# Utility class for creating new RC entries
+
+define( "RC_EDIT", 0);
+define( "RC_NEW", 1);
+define( "RC_MOVE", 2);
+define( "RC_LOG", 3);
+
+/*
+mAttributes:
+       rc_timestamp    time the entry was made
+       rc_cur_time     timestamp on the cur row
+       rc_namespace    namespace #
+       rc_title        non-prefixed db key
+       rc_type          is new entry, used to determine whether updating is necessary
+       rc_minor        is minor
+       rc_cur_id       id of associated cur entry
+       rc_user         user id who made the entry
+       rc_user_text    user name who made the entry
+       rc_comment      edit summary
+       rc_this_oldid   old_id associated with this entry (or zero)
+       rc_last_oldid   old_id associated with the entry before this one (or zero)
+       rc_bot          is bot, hidden
+
+mExtra:
+       prefixedDBkey   prefixed db key, used by external app via msg queue
+       lastTimestamp   timestamp of previous entry, used in WHERE clause during update
+       lang            the interwiki prefix, automatically set in save()
+*/
+
+class RecentChange
+{
+       var $mAttribs = array(), $mExtra = array();
+       var $mTitle = false, $mMovedToTitle = false;
+
+       # Factory methods
+       
+       /* static */ function newFromRow( $row ) 
+       {
+               $rc = new RecentChange;
+               $rc->loadFromRow( $row );
+               return $rc;
+       }
+       
+       # Accessors
+       
+       function setAttribs( $attribs ) 
+       {
+               $this->mAttribs = $attribs;
+       }
+       
+       function setExtra( $extra )
+       {
+               $this->mExtra = $extra;
+       }
+       
+       function getTitle()
+       {
+               if ( $this->mTitle === false ) {
+                       $this->mTitle = Title::makeTitle( $this->mAttribs['rc_namespace'], $this->mAttribs['rc_title'] );
+               }
+               return $this->mTitle;
+       }
+
+       function getMovedToTitle()
+       {
+               if ( $this->mMovedToTitle === false ) {
+                       $this->mMovedToTitle = Title::makeTitle( $this->mAttribs['rc_moved_to_ns'], 
+                               $this->mAttribs['rc_moved_to_title'] );
+               }
+               return $this->mMovedToTitle;
+       }
+
+       # Writes the data in this object to the database
+       function save() 
+       {
+               global $wgUseRCQueue, $wgRCQueueID, $wgLocalInterwiki;
+               $fname = "RecentChange::save";
+               
+               if ( !is_array($this->mExtra) ) {
+                       $this->mExtra = array();
+               }
+               $this->mExtra['lang'] = $wgLocalInterwiki;
+               
+               # Insert new row
+               wfInsertArray( "recentchanges", $this->mAttribs, $fname );
+               
+               # Update old rows, if necessary
+               if ( $this->mAttribs['rc_type'] == RC_EDIT ) {
+                       $oldid = $this->mAttribs['rc_last_oldid'];
+                       $ns = $this->mAttribs['rc_namespace'];
+                       $title = wfStrencode($this->mAttribs['rc_title']);
+                       $lastTime = $this->mExtra['lastTimestamp'];
+                       $now = $this->mAttribs['rc_timestamp'];
+                       $curId = $this->mAttribs['rc_cur_id'];
+                       
+                       # Update rc_this_oldid for the entries which were current
+                       $sql = "UPDATE recentchanges SET rc_this_oldid={$oldid} " .
+                               "WHERE rc_namespace=$ns AND rc_title='$title' AND rc_timestamp='$lastTime'";
+                       wfQuery( $sql, DB_WRITE, $fname );
+
+                       # Update rc_cur_time
+                       $sql = "UPDATE recentchanges SET rc_cur_time='{$now}' " .
+                         "WHERE rc_cur_id=" . $curId;
+                       wfQuery( $sql, DB_WRITE, $fname );
+               }
+               
+               # Notify external application
+               if ( $wgUseRCQueue ) {
+                       $queue = msg_get_queue( $wgRCQueueID );
+                       if (!msg_send( $queue, array_merge( $this->mAttribs, 1, $this->mExtra ), 
+                               true, false, $error )) 
+                       {
+                               wfDebug( "Error sending message to RC queue, code $error\n" );
+                       }
+               }
+       }
+       
+       # Makes an entry in the database corresponding to an edit
+       /*static*/ function notifyEdit( $timestamp, &$title, $minor, &$user, $comment, 
+               $oldId, $lastTimestamp ) 
+       {
+               $rc = new RecentChange;
+               $rc->mAttribs = array(
+                       'rc_timestamp'  => $timestamp,
+                       'rc_cur_time'   => $timestamp,
+                       'rc_namespace'  => $title->getNamespace(),
+                       'rc_title'      => $title->getDBkey(),
+                       'rc_type'       => RC_EDIT,
+                       'rc_minor'      => $minor ? 1 : 0,
+                       'rc_cur_id'     => $title->getArticleID(),
+                       'rc_user'       => $user->getID(),
+                       'rc_user_text'  => $user->getName(),
+                       'rc_comment'    => $comment,
+                       'rc_this_oldid' => 0,
+                       'rc_last_oldid' => $oldId,
+                       'rc_bot'        => $user->isBot() ? 1 : 0,
+                       'rc_moved_to_ns'        => 0,
+                       'rc_moved_to_title'     => ''
+               );
+               
+               $rc->mExtra =  array(
+                       'prefixedDBkey' => $title->getPrefixedDBkey(),
+                       'lastTimestamp' => $lastTimestamp
+               );
+               $rc->save();
+       }
+       
+       # Makes an entry in the database corresponding to page creation
+       # Note: the title object must be loaded with the new id using resetArticleID()
+       /*static*/ function notifyNew( $timestamp, &$title, $minor, &$user, $comment )
+       {
+               $rc = new RecentChange;
+               $rc->mAttribs = array(
+                       'rc_timestamp'  => $timestamp,
+                       'rc_cur_time'   => $timestamp,
+                       'rc_namespace'  => $title->getNamespace(),
+                       'rc_title'      => $title->getDBkey(),
+                       'rc_type'       => RC_NEW,
+                       'rc_minor'      => $minor ? 1 : 0,
+                       'rc_cur_id'     => $title->getArticleID(),
+                       'rc_user'       => $user->getID(),
+                       'rc_user_text'  => $user->getName(),
+                       'rc_comment'    => $comment,
+                       'rc_this_oldid' => 0,
+                       'rc_last_oldid' => 0,
+                       'rc_bot'        => $user->isBot() ? 1 : 0,
+                       'rc_moved_to_ns'        => 0,
+                       'rc_moved_to_title'     => ''
+               );
+               
+               $rc->mExtra =  array(
+                       'prefixedDBkey' => $title->getPrefixedDBkey(),
+                       'lastTimestamp' => 0
+               );
+               $rc->save();
+       }
+       
+       # Makes an entry in the database corresponding to a rename
+       /*static*/ function notifyMove( $timestamp, &$oldTitle, &$newTitle, &$user, $comment )
+       {
+               $rc = new RecentChange;
+               $rc->mAttribs = array(
+                       'rc_timestamp'  => $timestamp,
+                       'rc_cur_time'   => $timestamp,
+                       'rc_namespace'  => $oldTitle->getNamespace(),
+                       'rc_title'      => $oldTitle->getDBkey(),
+                       'rc_type'       => RC_MOVE,
+                       'rc_minor'      => 0,
+                       'rc_cur_id'     => $oldTitle->getArticleID(),
+                       'rc_user'       => $user->getID(),
+                       'rc_user_text'  => $user->getName(),
+                       'rc_comment'    => $comment,
+                       'rc_this_oldid' => 0,
+                       'rc_last_oldid' => 0,
+                       'rc_bot'        => $user->isBot() ? 1 : 0,
+                       'rc_moved_to_ns'        => $newTitle->getNamespace(),
+                       'rc_moved_to_title'     => $newTitle->getDBkey()
+               );
+               
+               $rc->mExtra = array(
+                       'prefixedDBkey' => $oldTitle->getPrefixedDBkey(),
+                       'lastTimestamp' => 0,
+                       'prefixedMoveTo'        => $newTitle->getPrefixedDBkey()
+               );
+               $rc->save();
+       }
+       
+       # A log entry is different to an edit in that previous revisions are 
+       # not kept
+       /*static*/ function notifyLog( $timestamp, &$title, &$user, $comment )
+       {
+               $rc = new RecentChange;
+               $rc->mAttribs = array(
+                       'rc_timestamp'  => $timestamp,
+                       'rc_cur_time'   => $timestamp,
+                       'rc_namespace'  => $title->getNamespace(),
+                       'rc_title'      => $title->getDBkey(),
+                       'rc_type'       => RC_LOG,
+                       'rc_minor'      => 0,
+                       'rc_cur_id'     => $title->getArticleID(),
+                       'rc_user'       => $user->getID(),
+                       'rc_user_text'  => $user->getName(),
+                       'rc_comment'    => $comment,
+                       'rc_this_oldid' => 0,
+                       'rc_last_oldid' => 0,
+                       'rc_bot'        => 0,
+                       'rc_moved_to_ns'        => 0,
+                       'rc_moved_to_title'     => ''
+               );
+               $rc->mExtra =  array(
+                       'prefixedDBkey' => $title->getPrefixedDBkey(),
+                       'lastTimestamp' => 0
+               );
+               $rc->save();
+       }
+
+       # Initialises the members of this object from a mysql row object
+       function loadFromRow( $row )
+       {
+               $this->mAttribs = get_object_vars( $row );
+               $this->mExtra = array();
+       }
+       
+       # Gets the end part of the diff URL assoicated with this object
+       # Blank if no diff link should be displayed
+       function diffLinkTrail( $forceCur )
+       {
+               if ( $this->mAttribs['rc_type'] == RC_EDIT ) {
+                       $trail = "curid=" . (int)($this->mAttribs['rc_cur_id']) .
+                               "&oldid=" . (int)($this->mAttribs['rc_last_oldid']);
+                       if ( $forceCur ) {
+                               $trail .= "&diff=0" ;
+                       } else {
+                               $trail .= "&diff=" . (int)($this->mAttribs['rc_this_oldid']);
+                       }
+               } else {
+                       $trail = "";
+               }
+               return $trail;
+       }
+}
+?>
index dcb5378..29a6004 100644 (file)
@@ -24,6 +24,7 @@ wfProfileIn( "$fname-includes" );
 
 include_once( "GlobalFunctions.php" );
 include_once( "Namespace.php" );
+include_once( "RecentChange.php" ); 
 include_once( "Skin.php" );
 include_once( "OutputPage.php" );
 include_once( "User.php" );
index e0416f4..d15272e 100644 (file)
@@ -9,6 +9,8 @@
        "Standard", "Nostalgia", "CologneBlue" #, "Smarty", "Montparnasse"
 );
 
+include_once( "RecentChange.php" );
+
 # For some odd PHP bug, this function can't be part of a class
 function getCategories ()
 {
@@ -26,20 +28,19 @@ function getCategories ()
   return $s ;
 }
 
-
-class RecentChangesClass {
-       var $secureName , $displayName , $link , $namespace ;
-       var $oldid , $diffid , $timestamp , $curlink , $lastlink , $usertalklink , $versionlink ;
-       var $usercomment , $userlink ;
-       var $isminor , $isnew , $watched , $islog ;
-       } ;
+class RCCacheEntry extends RecentChange
+{
+       var $secureName, $link;
+       var $curlink , $lastlink , $usertalklink , $versionlink ;
+       var $userlink, $timestamp, $watched;
+} ;
 
 class Skin {
 
        /* private */ var $lastdate, $lastline;
 
        var $rc_cache ; # Cache for Enhanced Recent Changes
-       var $rccc ; # Recent Changes Cache Counter for visibility toggle
+       var $rcCacheIndex ; # Recent Changes Cache Counter for visibility toggle
 
 
        function Skin()
@@ -67,16 +68,16 @@ class Skin {
                return $q;
        }
 
-       function initPage()
+       function initPage( &$out )
        {
-               global $wgOut, $wgStyleSheetPath;
+               global $wgStyleSheetPath;
                $fname = "Skin::initPage";
                wfProfileIn( $fname );
-
-               $wgOut->addLink( "shortcut icon", "", "/favicon.ico" );
-               if ( $wgOut->isPrintable() ) { $ss = "wikiprintable.css"; }
+               
+               $out->addLink( "shortcut icon", "", "/favicon.ico" );
+               if ( $out->isPrintable() ) { $ss = "wikiprintable.css"; }
                else { $ss = $this->getStylesheet(); }
-               $wgOut->addLink( "stylesheet", "", "{$wgStyleSheetPath}/{$ss}" );
+               $out->addLink( "stylesheet", "", "{$wgStyleSheetPath}/{$ss}" );
                wfProfileOut( $fname );
        }
        
@@ -84,7 +85,7 @@ class Skin {
                global $wgDebugComments;
                
                wfProfileIn( "Skin::outputPage" );
-               $this->initPage();
+               $this->initPage( $out );
                $out->out( $out->headElement() );
 
                $out->out( "\n<body" );
@@ -1649,10 +1650,11 @@ class Skin {
        # Called by history lists and recent changes
        #
 
+       # Returns text for the start of the tabular part of RC
        function beginRecentChangesList()
        {
-               $rc_cache = array() ;
-               $rccc = 0 ;
+               $this->rc_cache = array() ;
+               $this->rcCacheIndex = 0 ;
                $this->lastdate = "";
                return "";
        }
@@ -1664,6 +1666,8 @@ class Skin {
                return $s;
        }
 
+       # Returns text for the end of RC
+       # If enhanced RC is in use, returns pretty much all the text
        function endRecentChangesList()
        {
                $s = $this->recentChangesBlock() ;
@@ -1671,77 +1675,101 @@ class Skin {
                return $s;
        }
 
-       function endImageHistoryList()
+       # Enhanced RC ungrouped line
+       function recentChangesBlockLine ( $rcObj ) 
        {
-               $s = "</ul>\n";
-               return $s;
-       }
-
-       function recentChangesBlockLine ( $y ) {
                global $wgUploadPath ;
-
-               $M = wfMsg( "minoreditletter" );
-               $N = wfMsg( "newpageletter" );
+               
+               # Get rc_xxxx variables
+               extract( $rcObj->mAttribs ) ;
+               $curIdEq = "curid=$rc_cur_id";
+               
+               # Spacer image
                $r = "" ;
-               $r .= "<img src='{$wgUploadPath}/Arr_.png' width=12 height=12 border=0>" ;
-               $r .= "<tt>" ;
-               if ( $y->isnew ) $r .= $N ;
-               else $r .= "&nbsp;" ;
-               if ( $y->isminor ) $r .= $M ;
-               else $r .= "&nbsp;" ;
-               $r .= " ".$y->timestamp." " ;
+               $r .= "<img src='{$wgUploadPath}/Arr_.png' width=12 height=12 border=0>" ;              $r .= "<tt>" ;
+               
+               if ( $rc_type == RC_MOVE ) {
+                       $r .= "&nbsp;&nbsp;";
+               } else {
+                       # M & N (minor & new)
+                       $M = wfMsg( "minoreditletter" );
+                       $N = wfMsg( "newpageletter" );
+               
+                       if ( $rc_type == RC_NEW ) {
+                               $r .= $N ;
+                       } else {
+                               $r .= "&nbsp;" ;
+                       }
+                       if ( $rc_minor ) {
+                               $r .= $M ;
+                       } else {
+                               $r .= "&nbsp;" ;
+                       }
+               }
+               
+               # Timestamp
+               $r .= " ".$rcObj->timestamp." " ;
                $r .= "</tt>" ;
-               $link = $y->link ;
-               if ( $y->watched ) $link = "<strong>{$link}</strong>" ;
+
+               # Article link
+               $link = $rcObj->link ;
+               if ( $rcObj->watched ) $link = "<strong>{$link}</strong>" ;
                $r .= $link ;
 
+               # Cur
                $r .= " (" ;
-               $r .= $y->curlink ;
+               $r .= $rcObj->curlink ;
                $r .= "; " ;
-               $r .= $this->makeKnownLink( $y->secureName, wfMsg( "hist" ), "action=history" );
+               
+               # Hist
+               $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
 
-               $r .= ") . . ".$y->userlink ;
-               $r .= $y->usertalklink ;
-               if ( $y->usercomment != "" )
-                       $r .= " <em>(".wfEscapeHTML($y->usercomment).")</em>" ;
+               # User/talk
+               $r .= ") . . ".$rcObj->userlink ;
+               $r .= $rcObj->usertalklink ;
+               
+               # Comment
+               if ( $rc_comment != "" && $rc_type != RC_MOVE )
+                       $r .= " <em>(".wfEscapeHTML($rc_comment).")</em>" ;
                $r .= "<br>\n" ;
                return $r ;
-               }
+       }
 
-       function recentChangesBlockGroup ( $y ) {
+       # Enhanced RC group
+       function recentChangesBlockGroup ( $block ) 
+       {
                global $wgUploadPath ;
-
+               
                $r = "" ;
                $M = wfMsg( "minoreditletter" );
                $N = wfMsg( "newpageletter" );
+               
+               # Collate list of users
                $isnew = false ;
                $userlinks = array () ;
-               foreach ( $y AS $x ) {
-                       $oldid = $x->diffid ;
-                       if ( $x->isnew ) $isnew = true ;
-                       $u = $x->userlink ;
+               foreach ( $block AS $rcObj ) {
+                       $oldid = $rcObj->mAttribs['rc_last_oldid'];
+                       if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
+                       $u = $rcObj->userlink ;
                        if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
                        $userlinks[$u]++ ;
-                       }
-
+               }
+               
+               # Sort the list and convert to text
                krsort ( $userlinks ) ;
                asort ( $userlinks ) ;
                $users = array () ;
-               $u = array_keys ( $userlinks ) ;
-               foreach ( $u as $x ) {
-                       $z = $x ;
-                       if ( $userlinks[$x] > 1 ) $z .= " ({$userlinks[$x]}&times;)" ;
-                       array_push ( $users , $z ) ;
-                       }
+               foreach ( $userlinks as $userlink => $count) {
+                       $text = $userlink ;
+                       if ( $count > 1 ) $text .= " ({$count}&times;)" ;
+                       array_push ( $users , $text ) ;
+               }
                $users = " <font size='-1'>[".implode("; ",$users)."]</font>" ;
 
-               $e = $y ;
-               $e = array_shift ( $e ) ;
-
                # Arrow
-               $rci = "RCI{$this->rccc}" ;
-               $rcl = "RCL{$this->rccc}" ;
-               $rcm = "RCM{$this->rccc}" ;
+               $rci = "RCI{$this->rcCacheIndex}" ;
+               $rcl = "RCL{$this->rcCacheIndex}" ;
+               $rcm = "RCM{$this->rcCacheIndex}" ;
                $tl = "<a href='javascript:toggleVisibility(\"{$rci}\",\"{$rcm}\",\"{$rcl}\")'>" ;
                $tl .= "<span id='{$rcm}'><img src='{$wgUploadPath}/Arr_r.png' width=12 height=12 border=0></span>" ;
                $tl .= "<span id='{$rcl}' style='display:none'><img src='{$wgUploadPath}/Arr_d.png' width=12 height=12 border=0></span>" ;
@@ -1749,246 +1777,318 @@ class Skin {
                $r .= $tl ;
 
                # Main line
+               # M/N
                $r .= "<tt>" ;
                if ( $isnew ) $r .= $N ;
                else $r .= "&nbsp;" ;
                $r .= "&nbsp;" ; # Minor
-               $r .= " ".$e->timestamp." " ;
-               $r .= "</tt>" ;
 
-               $link = $e->link ;
-               if ( $e->watched ) $link = "<strong>{$link}</strong>" ;
+               # Timestamp
+               $r .= " ".$block[0]->timestamp." " ;
+               $r .= "</tt>" ;
+               
+               # Article link
+               $link = $block[0]->link ;
+               if ( $block[0]->watched ) $link = "<strong>{$link}</strong>" ;
                $r .= $link ;
-
-               if ( !$e->islog ) {
-                       $r .= " (".count($y)." " ;
+               
+               $curIdEq = "curid=" . $block[0]->mAttribs['rc_cur_id'];
+               if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
+                       # Changes
+                       $r .= " (".count($block)." " ;
                        if ( $isnew ) $r .= wfMsg("changes");
-                       else $r .= $this->makeKnownLink( $e->secureName , wfMsg("changes") , "diff=0&oldid=".$oldid ) ;
+                       else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg("changes") , 
+                               "{$curIdEq}&diff=0&oldid=".$oldid ) ;
                        $r .= "; " ;
-                       $r .= $this->makeKnownLink( $e->secureName, wfMsg( "history" ), "action=history" );
+
+                       # History
+                       $r .= $this->makeKnownLink( $block[0]->getTitle(), wfMsg( "history" ), "{$curIdEq}&action=history" );
                        $r .= ")" ;
-                       }
+               }
 
                $r .= $users ;
                $r .= "<br>\n" ;
 
                # Sub-entries
                $r .= "<div id='{$rci}' style='display:none'>" ;
-               foreach ( $y AS $x )
-                       {
+               foreach ( $block AS $rcObj ) {
+                       # Get rc_xxxx variables
+                       extract( $rcObj->mAttribs );
+                       
                        $r .= "<img src='{$wgUploadPath}/Arr_.png' width=12 height=12 border=0>";
                        $r .= "<tt>&nbsp; &nbsp; &nbsp; &nbsp;" ;
-                       if ( $x->isnew ) $r .= $N ;
+                       if ( $rc_new ) $r .= $N ;
                        else $r .= "&nbsp;" ;
-                       if ( $x->isminor ) $r .= $M ;
+                       if ( $rc_minor ) $r .= $M ;
                        else $r .= "&nbsp;" ;
                        $r .= "</tt>" ;
 
                        $o = "" ;
-                       if ( $x->oldid != 0 ) $o = "oldid=".$x->oldid ;
-                       if ( $x->islog ) $link = $x->timestamp ;
-                       else $link = $this->makeKnownLink( $x->secureName, $x->timestamp , $o ) ;
+                       if ( $rc_last_oldid != 0 ) {
+                               $o = "oldid=".$rc_last_oldid ;
+                       }
+                       if ( $rc_type == RC_LOG ) {
+                               $link = $rcObj->timestamp ;
+                       } else {
+                               $link = $this->makeKnownLink( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
+                       }
                        $link = "<tt>{$link}</tt>" ;
 
-
                        $r .= $link ;
                        $r .= " (" ;
-                       $r .= $x->curlink ;
+                       $r .= $rcObj->curlink ;
                        $r .= "; " ;
-                       $r .= $x->lastlink ;
-                       $r .= ") . . ".$x->userlink ;
-                       $r .= $x->usertalklink ;
-                       if ( $x->usercomment != "" )
-                               $r .= " <em>(".wfEscapeHTML($x->usercomment).")</em>" ;
+                       $r .= $rcObj->lastlink ;
+                       $r .= ") . . ".$rcObj->userlink ;
+                       $r .= $rcObj->usertalklink ;
+                       if ( $rc_comment != "" )
+                               $r .= " <em>(".wfEscapeHTML($rc_comment).")</em>" ;
                        $r .= "<br>\n" ;
-                       }
+               }
                $r .= "</div>\n" ;
 
-               $this->rccc++ ;
+               $this->rcCacheIndex++ ;
                return $r ;
-               }
+       }
 
+       # If enhanced RC is in use, this function takes the previously cached
+       # RC lines, arranges them, and outputs the HTML
        function recentChangesBlock ()
        {
                global $wgUploadPath ;
                if ( count ( $this->rc_cache ) == 0 ) return "" ;
-               $k = array_keys ( $this->rc_cache ) ;
-               foreach ( $k AS $x )
-                       {
-                       $y = $this->rc_cache[$x] ;
-                       if ( count ( $y ) < 2 ) {
-                               $r .= $this->recentChangesBlockLine ( array_shift ( $y ) ) ;
+               #$k = array_keys ( $this->rc_cache ) ;
+               foreach ( $this->rc_cache AS $secureName => $block ) {
+                       if ( count ( $block ) < 2 ) {
+                               $r .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
                        } else {
-                               $r .= $this->recentChangesBlockGroup ( $y ) ;
-                               }
+                               $r .= $this->recentChangesBlockGroup ( $block ) ;
                        }
+               }
 
                return "<div align=left>{$r}</div>" ;
        }
 
-       function recentChangesLine( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
+       # Called in a loop over all displayed RC entries
+       # Either returns the line, or caches it for later use
+       function recentChangesLine( $row, $watched = false )
        {
                global $wgUser ;
                $usenew = $wgUser->getOption( "usenewrc" );
                if ( $usenew )
-                       $r = $this->recentChangesLineNew ( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched , $oldid , $diffid ) ;
+                       $line = $this->recentChangesLineNew ( $row, $watched ) ;
                else
-                       $r = $this->recentChangesLineOld ( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched , $oldid , $diffid ) ;
-               return $r ;
+                       $line = $this->recentChangesLineOld ( $row, $watched ) ;
+               return $line ;
        }
-
-       function recentChangesLineOld( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0, $diffid = 0 )
+       
+       function recentChangesLineOld( $row, $watched = false )
        {
                global $wgTitle, $wgLang, $wgUser;
-
-               $d = $wgLang->date( $ts, true);
+               
+               # Extract DB fields into local scope
+               extract( get_object_vars( $row ) );
+               $rc = RecentChange::newFromRow( $row );
+               $curIdEq = "curid=" . $rc_cur_id;
+               
+               # Make date header if necessary
+               $date = $wgLang->date( $rc_timestamp, true);
                $s = "";
-               if ( $d != $this->lastdate ) {
+               if ( $date != $this->lastdate ) {
                        if ( "" != $this->lastdate ) { $s .= "</ul>\n"; }
-                       $s .= "<h4>{$d}</h4>\n<ul>";
-                       $this->lastdate = $d;
+                       $s .= "<h4>{$date}</h4>\n<ul>";
+                       $this->lastdate = $date;
                }
-               $h = $wgLang->time( $ts, true );
-               $t = Title::makeName( $ns, $ttl );
-               $clink = $this->makeKnownLink( $t , "" );
-               $nt = Title::newFromText( $t );
-
-               if ( $watched ) {
-                       $clink = "<strong>{$clink}</strong>";
-               }
-               $hlink = $this->makeKnownLink( $t, wfMsg( "hist" ), "action=history" );
-               if ( $isnew || $nt->isLog() ) {
-                       $dlink = wfMsg( "diff" );
+               $s .= "<li> ";
+               
+               if ( $rc_type == RC_MOVE ) {
+                       # Diff
+                       $s .= "(" . wfMsg( "diff" ) . ") (";
+                       # Hist
+                       $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( "hist" ), "action=history" ) .
+                               ") . . ";
+                       
+                       # "[[x]] moved to [[y]]"
+                       $s .= $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" );
+                       $s .= " " . wfMsg( "movedto" ). " ";
+                       $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" );
                } else {
-                       $dlink = $this->makeKnownLink( $t, wfMsg( "diff" ),
-                         "diff={$oldid}&oldid={$diffid}" ); # Finagle's law
+                       # Diff link
+                       if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
+                               $diffLink = wfMsg( "diff" );
+                       } else {
+                               $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "diff" ),
+                                 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" );
+                       }
+                       $s .= "($diffLink) (";
+                       
+                       # History link
+                       $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" ); 
+                       $s .= ") . . ";
+
+                       # M and N (minor and new)
+                       $M = wfMsg( "minoreditletter" );
+                       $N = wfMsg( "newpageletter" );
+                       if ( $rc_minor ) { $s .= " <strong>{$M}</strong>"; }
+                       if ( $rc_type == RC_NEW ) { $s .= "<strong>{$N}</strong>"; }
+
+                       # Article link
+                       $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), "" );
+
+                       if ( $watched ) {
+                               $articleLink = "<strong>{$articleLink}</strong>";
+                       }
+                       $s .= " $articleLink";
+
                }
-               if ( 0 == $u ) {
-               $ul = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
-                       $ut, "target=" . $ut );                                 
+               
+               # Timestamp
+               $s .= "; " . $wgLang->time( $rc_timestamp, true ) . " . . ";
+               
+               # User link (or contributions for unregistered users)
+               if ( 0 == $rc_user ) {
+                       $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
+                       $rc_user_text, "target=" . $rc_user_text );                                     
                } else { 
-                       $ul = $this->makeLink( $wgLang->getNsText( Namespace::getUser() ) . ":{$ut}", $ut ); 
+                       $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ":{$rc_user_text}", $rc_user_text ); 
                }
-                 
-               $talkname=$wgLang->getNsText(Namespace::getTalk(0)); # use the shorter name
+               $s .= $userLink;
+               
+               # User talk link
+               $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
                global $wgDisableAnonTalk;
-               if( 0 == $u && $wgDisableAnonTalk ) {
-                       $utl = "";
+               if( 0 == $rc_user && $wgDisableAnonTalk ) {
+                       $userTalkLink = "";
                } else {
-                       $utns=$wgLang->getNsText(Namespace::getTalk(Namespace::getUser()));
-                       $utl= $this->makeLink($utns . ":{$ut}", $talkname );
-               }
-               $cr = wfMsg( "currentrev" );
-
-               $s .= "<li> ({$dlink}) ({$hlink}) . .";
-               $M = wfMsg( "minoreditletter" );
-               $N = wfMsg( "newpageletter" );
-               if ( $isminor ) { $s .= " <strong>{$M}</strong>"; }
-               if ( $isnew ) { $s .= "<strong>{$N}</strong>"; }
-               $s .= " {$clink}; {$h} . . {$ul}";
-
-               $blink="";
-               if ( ( 0 == $u ) && $wgUser->isSysop() ) {
-                       $blink = $this->makeKnownLink( $wgLang->specialPage(
-                         "Blockip" ), wfMsg( "blocklink" ), "ip={$ut}" );
+                       $utns=$wgLang->getNsText(NS_USER_TALK);
+                       $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
+               }
+               # Block link
+               $blockLink="";
+               if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
+                       $blockLink = $this->makeKnownLink( $wgLang->specialPage(
+                         "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
                        
                }
-               if($blink) { 
-                       if($utl) $utl .= " | ";
-                       $utl .= $blink;
+               if($blockLink) { 
+                       if($userTalkLink) $userTalkLink .= " | ";
+                       $userTalkLink .= $blockLink;
                }
-               if($utl) $s.=" ({$utl})";
+               if($userTalkLink) $s.=" ({$userTalkLink})";
 
-               if ( "" != $c && "*" != $c ) {
-                       $s .= " <em>(" . wfEscapeHTML( $c ) . ")</em>";
+               # Add comment
+               if ( "" != $rc_comment && "*" != $rc_comment && $rc_type != RC_MOVE ) {
+                       $s .= " <em>(" . wfEscapeHTML( $rc_comment ) . ")</em>";
                }
                $s .= "</li>\n";
 
                return $s;
        }
-
-       function recentChangesLineNew( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
+       
+#      function recentChangesLineNew( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
+       function recentChangesLineNew( $row, $watched = false )
        {
                global $wgTitle, $wgLang, $wgUser;
 
-               $rc = new RecentChangesClass ;
+               # Fill $rc with all the information from the row
+               $rc = new RCCacheEntry ;
+               $rc->loadFromRow( $row );
 
-               $d = $wgLang->date( $ts, true);
-               $s = "";
+               # Extract fields from DB into the function scope (rc_xxxx variables)
+               extract( $rc->mAttribs );
+               $curIdEq = "curid=" . $rc_cur_id;
+
+               # If it's a new day, add the headline and flush the cache
+               $date = $wgLang->date( $rc_timestamp, true);
                $ret = "" ;
-               if ( $d != $this->lastdate ) {
+               if ( $date != $this->lastdate ) {
+                       # Process current cache
                        $ret = $this->recentChangesBlock () ;
                        $this->rc_cache = array() ;
-                       $ret .= "<h4>{$d}</h4>\n";
-                       $this->lastdate = $d;
-               }
-               $h = $wgLang->time( $ts, true );
-               $t = Title::makeName( $ns, $ttl );
-               $clink = $this->makeKnownLink( $t, "" ) ;
-               if ( $oldid == 0 ) $c2link = $clink ;
-               else $c2link = $this->makeKnownLink( $t, "" , "oldid={$oldid}" );
-               $nt = Title::newFromText( $t );
-
-               $rc->timestamp = $h ;
-               $rc->oldid = $oldid ;
-               $rc->diffid = $diffid ;
+                       $ret .= "<h4>{$date}</h4>\n";
+                       $this->lastdate = $date;
+               }
+               
+               # Make article link
+               if ( $rc_type == RC_MOVE ) {
+                       $clink = $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" );
+                       $clink .= " " . wfMsg("movedto") . " ";
+                       $clink .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" );
+               } else {
+                       $clink = $this->makeKnownLinkObj( $rc->getTitle(), "" ) ;
+               }
+               
+               $time = $wgLang->time( $rc_timestamp, true );
                $rc->watched = $watched ;
-               $rc->isnew = $isnew ;
-               $rc->isminor = $isminor ;
-               $rc->secureName = $t ;
-               $rc->displayName = $nt ;
                $rc->link = $clink ;
-               $rc->usercomment = $c ;
-               $rc->islog = $nt->isLog() ;
-
-               if ( ( $isnew && $oldid == 0 ) || $nt->isLog() ) {
-                       $dlink = wfMsg( "cur" );
+               $rc->timestamp = $time;
+               
+               # Make "cur" link
+               if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE) {
+                       $curLink = wfMsg( "cur" );
                } else {
-                       $dlink = $this->makeKnownLink( $t, wfMsg( "cur" ),
-                         "diff=0&oldid={$oldid}" );
+                       $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "cur" ),
+                         "{$curIdEq}&diff=0&oldid={$rc_this_oldid}" );
                }
 
-               if ( $diffid == 0 || $nt->isLog() ) {
-                       $plink = wfMsg( "last" );
+               # Make "last" link
+               $titleObj = $rc->getTitle();
+               if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE ) {
+                       $lastLink = wfMsg( "last" );
                } else {
-                       $plink = $this->makeKnownLink( $t, wfMsg( "last" ),
-                         "diff={$oldid}&oldid={$diffid}" );
+                       $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "last" ),
+                         "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" );
                }
 
-               if ( 0 == $u ) {
-               $ul = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
-                       $ut, "target=" . $ut );
-               } else { $ul = $this->makeLink( $wgLang->getNsText(
-                 Namespace::getUser() ) . ":{$ut}", $ut ); }
-
-               $rc->userlink = $ul ;
-               $rc->lastlink = $plink ;
-               $rc->curlink = $dlink ;
+               # Make user link (or user contributions for unregistered users)
+               if ( 0 == $rc_user ) {
+               $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
+                       $rc_user_text, "target=" . $rc_user_text );
+               } else { $userLink = $this->makeLink( $wgLang->getNsText(
+                 Namespace::getUser() ) . ":{$rc_user_text}", $rc_user_text ); }
 
-               $utns=$wgLang->getNsText(Namespace::getTalk(Namespace::getUser()));
-               $talkname=$wgLang->getNsText(Namespace::getTalk(0)); # use the shorter name
-               $utl= $this->makeLink($utns . ":{$ut}", $talkname );                                            
+               $rc->userlink = $userLink ;
+               $rc->lastlink = $lastLink ;
+               $rc->curlink = $curLink ;
 
+               # Make user talk link           
+               $utns=$wgLang->getNsText(NS_USER_TALK);
+               $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
+               $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname ); 
+               
                global $wgDisableAnonTalk;
-               if ( ( 0 == $u ) && $wgUser->isSysop() ) {
-                       $blink = $this->makeKnownLink( $wgLang->specialPage(
-                         "Blockip" ), wfMsg( "blocklink" ), "ip={$ut}" );
+               if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
+                       $blockLink = $this->makeKnownLink( $wgLang->specialPage(
+                         "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
                        if( $wgDisableAnonTalk )
-                               $rc->usertalklink = " ({$blink})";
+                               $rc->usertalklink = " ({$blockLink})";
                        else
-                               $rc->usertalklink = " ({$utl} | {$blink})";
+                               $rc->usertalklink = " ({$userTalkLink} | {$blockLink})";
                } else {
-                       if( $wgDisableAnonTalk && ($u == 0) )
+                       if( $wgDisableAnonTalk && ($rc_user == 0) )
                                $rc->usertalklink = "";
                        else
-                               $rc->usertalklink = " ({$utl})";
+                               $rc->usertalklink = " ({$userTalkLink})";
                }
 
-               if ( !isset ( $this->rc_cache[$t] ) ) $this->rc_cache[$t] = array() ;
-               array_push ( $this->rc_cache[$t] , $rc ) ;
+               # Put accumulated information into the cache, for later display
+               # Page moves go on their own line
+               $title = $rc->getTitle();
+               $secureName = $title->getPrefixedDBkey();
+               if ( $rc_type == RC_MOVE ) {
+                       array_push($this->rc_cache, array($rc) );
+               } else {
+                       if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
+                       array_push ( $this->rc_cache[$secureName] , $rc ) ;
+               }
                return $ret;
        }
 
+       function endImageHistoryList()
+       {
+               $s = "</ul>\n";
+               return $s;
+       }
 
        function imageHistoryLine( $iscur, $ts, $img, $u, $ut, $size, $c )
        {
index 5ee0313..b85f382 100644 (file)
@@ -299,21 +299,7 @@ class MovePageForm {
                  "old_namespace={$this->ons} AND old_title='{$this->odt}'";
                wfQuery( $sql, DB_WRITE, $fname );
                
-               $sql = "UPDATE recentchanges SET ".
-                       "rc_namespace={$this->nns}, rc_title='{$this->ndt}' WHERE ".
-                       "rc_cur_id={$this->oldid}";
-        wfQuery( $sql, DB_WRITE, $fname );
-
-               # FIXME: Here we mark the redirect as 'new' in recentchanges,
-               # but as old in cur. Is there a reason for this?
-               $sql = "INSERT INTO recentchanges (rc_namespace,rc_title,
-                       rc_comment,rc_user,rc_user_text,rc_timestamp,
-                       rc_cur_time,rc_cur_id,rc_new)
-                       VALUES ({$this->ons},'{$this->odt}'," .
-                 "'{$mt} \\\"{$this->nft}\\\"','" .
-                 $wgUser->getID() . "','" . wfStrencode( $wgUser->getName() ) .
-          "','{$now}','{$now}',{$this->newid},1)";
-        wfQuery( $sql, DB_WRITE, $fname );
+               RecentChange::notifyMove( $now, $this->ot, $this->nt, $wgUser, $mt );
 
                # The only link from here should be the old redirect
 
@@ -360,10 +346,11 @@ class MovePageForm {
                wfQuery( $sql, DB_WRITE, $fname );
                $wgLinkCache->clearLink( $this->nft );
 
+               $comment = "{$mt} \"{$this->nft}\"";
+               $encComment = wfStrencode( $comment );
                $common = "{$this->ons},'{$this->odt}'," .
-                 "'{$mt} \\\"{$this->nft}\\\"','" .
-                 $wgUser->getID() . "','" . wfStrencode( $wgUser->getName() ) .
-          "','{$now}'";
+                 "'$encComment','" .$wgUser->getID() . "','" . 
+                 wfStrencode( $wgUser->getName() ) ."','{$now}'";
                $sql = "INSERT INTO cur (cur_namespace,cur_title," .
                  "cur_comment,cur_user,cur_user_text,cur_timestamp,inverse_timestamp," .
                  "cur_touched,cur_text,cur_is_redirect,cur_is_new) " .
@@ -377,17 +364,7 @@ class MovePageForm {
                  "old_namespace={$this->ons} AND old_title='{$this->odt}'";
                wfQuery( $sql, DB_WRITE, $fname );
 
-               $sql = "UPDATE recentchanges SET ".
-                       "rc_namespace={$this->nns}, rc_title='{$this->ndt}' WHERE ".
-                       "rc_namespace={$this->ons} AND rc_title='{$this->odt}'";
-               wfQuery( $sql, DB_WRITE, $fname );
-
-               $sql = "INSERT INTO recentchanges (rc_namespace,rc_title,
-                       rc_comment,rc_user,rc_user_text,rc_timestamp,
-                       rc_cur_time,rc_cur_id,rc_new)
-                       VALUES ({$common},'{$now}',{$this->newid},1)";
-               wfQuery( $sql, DB_WRITE, $fname );
-
+               RecentChange::notifyMove( $now, $this->ot, $this->nt, $wgUser, $comment );
                Article::onArticleCreate( $this->nt );
 
                $sql = "UPDATE links SET l_from='{$this->nft}' WHERE l_from='{$this->oft}'";
index 9fce1a5..f775355 100644 (file)
@@ -80,8 +80,7 @@ function wfSpecialRecentchanges( $par )
        }
 
        $uid = $wgUser->getID();
-       $sql2 = "SELECT rc_cur_id,rc_namespace,rc_title,rc_user,rc_new," .
-         "rc_comment,rc_user_text,rc_timestamp,rc_minor,rc_this_oldid,rc_last_oldid,rc_bot" . ($uid ? ",wl_user" : "") . " FROM recentchanges " .
+       $sql2 = "SELECT recentchanges.*" . ($uid ? ",wl_user" : "") . " FROM recentchanges " .
          ($uid ? "LEFT OUTER JOIN watchlist ON wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace & 65534 " : "") .
          "WHERE rc_timestamp > '{$cutoff}' {$hidem} " .
          "ORDER BY rc_timestamp DESC LIMIT {$limit}";
@@ -108,27 +107,15 @@ function wfSpecialRecentchanges( $par )
 
        $s = $sk->beginRecentChangesList();
        while ( $limit ) {
-               if ( ( 0 == $count1 ) ) { break; }
-
-                       $ts = $obj1->rc_timestamp;
-                       $u = $obj1->rc_user;
-                       $ut = $obj1->rc_user_text;
-                       $ns = $obj1->rc_namespace;
-                       $ttl = $obj1->rc_title;
-                       $com = $obj1->rc_comment;
-                       $me = ( $obj1->rc_minor > 0 );
-                       $new = ( $obj1->rc_new > 0 );
-                       $watched = ($obj1->wl_user > 0);
-                       $oldid = $obj1->rc_this_oldid ;
-                       $diffid = $obj1->rc_last_oldid ;
-
-                       $obj1 = wfFetchObject( $res );
-                       --$count1;
-               if ( ! ( $hideminor && $me ) ) {
-                       $s .= $sk->recentChangesLine( $ts, $u, $ut, $ns, $ttl,
-                         $com, $me, $new, $watched, $oldid , $diffid );
+               if ( ( 0 == $count1 ) ) { 
+                       break; 
+               }
+               if ( ! ( $hideminor && $obj1->rc_minor ) ) {
+                       $s .= $sk->recentChangesLine( $obj1, $obj1->wl_user );
                        --$limit;
                }
+               $obj1 = wfFetchObject( $res );
+               --$count1;
        }
        $s .= $sk->endRecentChangesList();
 
index b18e501..7daa17c 100644 (file)
@@ -91,7 +91,7 @@ function wfSpecialUserlogin()
 /* private */ function addNewAccountInternal()
 {
        global $wgUser, $wgOut, $wpPassword, $wpRetype, $wpName, $wpRemember;
-       global $wpEmail;
+       global $wpEmail, $wgMaxNameChars;
 
        if (!$wgUser->isAllowedToCreateAccount()) {
                userNotPrivilegedMessage();
@@ -105,7 +105,8 @@ function wfSpecialUserlogin()
        $wpName = trim( $wpName );
        if ( ( "" == $wpName ) ||
          preg_match( "/\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/", $wpName ) ||
-         (strpos( $wpName, "/" ) !== false) ) 
+         (strpos( $wpName, "/" ) !== false) ||
+         (strlen( $wpName ) > $wgMaxNameChars) ) 
        {
                mainLoginForm( wfMsg( "noname" ) );
                return;
index 5955567..c245bf6 100644 (file)
@@ -88,6 +88,21 @@ class Title {
                        return NULL;
                }
        }
+       
+       # Create a title from a cur id
+       # This is inefficiently implemented
+       function newFromID( $id ) 
+       {
+               $fname = "Title::newFromID";
+               $row = wfGetArray( "cur", array( "cur_namespace", "cur_title" ), 
+                       array( "cur_id" => $id ), $fname );
+               if ( $row !== false ) {
+                       $title = Title::makeTitle( $row->cur_namespace, $row->cur_title );
+               } else {
+                       $title = NULL;
+               }
+               return $title;
+       }
 
        function nameOf( $id )
        {
index f984247..d78b7b0 100644 (file)
@@ -76,7 +76,7 @@ function replacevars( $ins ) {
 #
 # Read and execute SQL commands from a file
 #
-function dbsource( $fname, $conn = false ) {
+function dbsource( $fname, $database = false ) {
        $fp = fopen( $fname, "r" );
        if ( false === $fp ) {
                print "Could not open \"{$fname}\".\n";
@@ -103,8 +103,8 @@ function dbsource( $fname, $conn = false ) {
 
                if ( $done ) {
                        $cmd = replacevars( $cmd );
-                       if( $conn )
-                               $res = mysql_query( $cmd, $conn );
+                       if( $database )
+                               $res = $database->query( $cmd );
                        else
                                $res = mysql_query( $cmd );
 
@@ -120,7 +120,7 @@ function dbsource( $fname, $conn = false ) {
        fclose( $fp );
 }
 
-
+# Obsolete, use Database::fieldExists()
 function field_exists( $table, $field ) {
        $fname = "Update script: field_exists";
        $res = wfQuery( "DESCRIBE $table", $fname );
@@ -135,7 +135,7 @@ function field_exists( $table, $field ) {
        return $found;
 }
 
-
+# Obsolete Database::tableExists()
 function table_exists( $db ) {
        global $wgDBname;
        $res = mysql_list_tables( $wgDBname );
@@ -149,6 +149,7 @@ function table_exists( $db ) {
        return false;
 }
 
+# Obsolete, use Database:fieldInfo()
 function field_info( $table, $field ) {
        $res = mysql_query( "SELECT * FROM $table LIMIT 1" );
        $n = mysql_num_fields( $res );
index 552c603..1348d95 100644 (file)
@@ -96,8 +96,8 @@ print "\nYou should have already created a root password for the database.\n" .
 
 $rootpw = readconsole();
 
-$rconn = mysql_connect( $wgDBserver, "root", $rootpw );
-if ( false === $rconn ) {
+$wgDatabase = Database::newFromParams( $wgDBserver, "root", $rootpw, "", 1 );
+if ( !$wgDatabase->isOpen() ) {
        print "Could not connect to database on \"{$wgDBserver}\" as root.\n";
        exit();
 }
@@ -110,18 +110,18 @@ $wgTitle = Title::newFromText( "Installation script" );
 # Now do the actual database creation
 #
 print "Creating database...\n";
-dbsource( "./maintenance/database.sql", $rconn );
+dbsource( "./maintenance/database.sql", $wgDatabase );
 
-mysql_select_db( $wgDBname, $rconn );
-dbsource( "./maintenance/tables.sql", $rconn );
-dbsource( "./maintenance/users.sql", $rconn );
-dbsource( "./maintenance/initialdata.sql", $rconn );
-dbsource( "./maintenance/interwiki.sql", $rconn );
+$wgDatabase->selectDB( $wgDBname );
+dbsource( "./maintenance/tables.sql", $wgDatabase );
+dbsource( "./maintenance/users.sql", $wgDatabase );
+dbsource( "./maintenance/initialdata.sql", $wgDatabase );
+dbsource( "./maintenance/interwiki.sql", $wgDatabase );
 
 populatedata(); # Needs internationalized messages
 
 print "Adding indexes...\n";
-dbsource( "./maintenance/indexes.sql", $rconn );
+dbsource( "./maintenance/indexes.sql", $wgDatabase );
 
 print "Done.\nBrowse \"{$wgServer}{$wgScript}\" to test.\n";
 exit();
@@ -148,18 +148,18 @@ function makedirectory( $d ) {
 
 
 function populatedata() {
-       global $wgDBadminpassword;
+       global $wgDBadminpassword, $wgDatabase;
        $fname = "Installation script: populatedata()";
 
        $sql = "DELETE FROM site_stats";
-       wfQuery( $sql, DB_WRITE, $fname );
+       $wgDatabase->query( $sql, $fname );
 
        $sql = "INSERT INTO site_stats (ss_row_id,ss_total_views," .
                "ss_total_edits,ss_good_articles) VALUES (1,0,0,0)";
-       wfQuery( $sql, DB_WRITE, $fname );
+       $wgDatabase->query( $sql, $fname );
 
        $sql = "DELETE FROM user";
-       wfQuery( $sql, DB_WRITE, $fname );
+       $wgDatabase->query( $sql, $fname );
 
        $u = User::newFromName( "WikiSysop" );
        if ( 0 == $u->idForName() ) {
@@ -182,7 +182,7 @@ function populatedata() {
        $dlp = addslashes( wfMsgNoDB( "dellogpage" ) );
 
        $sql = "DELETE FROM cur";
-       wfQuery( $sql, DB_WRITE, $fname );
+       $wgDatabase->query( $sql, $fname );
 
        $now = wfTimestampNow();
        $won = wfInvertTimestamp( $now );
@@ -190,19 +190,19 @@ function populatedata() {
        $sql = "INSERT INTO cur (cur_namespace,cur_title,cur_text," .
          "cur_restrictions,cur_timestamp,inverse_timestamp,cur_touched) VALUES ({$wns},'{$ulp}','" .
          wfStrencode( wfMsg( "uploadlogpagetext" ) ) . "','sysop','$now','$won','$now')";
-       wfQuery( $sql, DB_WRITE, $fname );
+       $wgDatabase->query( $sql, $fname );
 
        $sql = "INSERT INTO cur (cur_namespace,cur_title,cur_text," .
          "cur_restrictions,cur_timestamp,inverse_timestamp,cur_touched) VALUES ({$wns},'{$dlp}','" .
          wfStrencode( wfMsg( "dellogpagetext" ) ) . "','sysop','$now','$won','$now')";
-       wfQuery( $sql, DB_WRITE, $fname );
+       $wgDatabase->query( $sql, $fname );
        
        $titleobj = Title::newFromText( wfMsgNoDB( "mainpage" ) );
        $title = $titleobj->getDBkey();
        $sql = "INSERT INTO cur (cur_namespace,cur_title,cur_text,cur_timestamp,inverse_timestamp,cur_touched) " .
          "VALUES (0,'$title','" .
          wfStrencode( wfMsg( "mainpagetext" ) ) . "','$now','$won','$now')";
-       wfQuery( $sql, DB_WRITE, $fname );
+       $wgDatabase->query( $sql, $fname );
        
        initialiseMessages();
 }
diff --git a/maintenance/archives/patch-rc_type.sql b/maintenance/archives/patch-rc_type.sql
new file mode 100644 (file)
index 0000000..abe11f9
--- /dev/null
@@ -0,0 +1,6 @@
+-- recentchanges improvements --
+
+ALTER TABLE recentchanges
+  ADD rc_type tinyint(3) unsigned NOT NULL default '0',
+  ADD rc_moved_to_ns tinyint(3) unsigned NOT NULL default '0',
+  ADD rc_moved_to_title varchar(255) binary NOT NULL default '';
index 9d9b454..8a9d79a 100644 (file)
@@ -164,7 +164,10 @@ CREATE TABLE recentchanges (
   rc_new tinyint(3) unsigned NOT NULL default '0',
   rc_cur_id int(10) unsigned NOT NULL default '0',
   rc_this_oldid int(10) unsigned NOT NULL default '0',
-  rc_last_oldid int(10) unsigned NOT NULL default '0'
+  rc_last_oldid int(10) unsigned NOT NULL default '0',
+  rc_type tinyint(3) unsigned NOT NULL default '0',
+  rc_moved_to_ns tinyint(3) unsigned NOT NULL default '0',
+  rc_moved_to_title varchar(255) binary NOT NULL default '',
 ) TYPE=MyISAM PACK_KEYS=1;
 
 DROP TABLE IF EXISTS watchlist;
index 9e87d3a..477de0f 100644 (file)
@@ -41,22 +41,27 @@ $wgTitle = Title::newFromText( "Update script" );
 #
 # Check the database for things that need to be fixed...
 #
-       print "Checking database for necessary updates...\n";
+print "Checking database for necessary updates...\n";
 
-       $rconn = mysql_connect( $wgDBserver, $wgDBadminuser, $wgDBadminpassword );
-       mysql_select_db( $wgDBname );
+$wgDatabase = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname, 
+       1, false, true, false);
+if ( !$wgDatabase->isOpen() ) {
+       print "Unable to connect to database: " . $wgDatabase->lastError() . "\n";
+       exit();
+}
 
-       do_revision_updates();
-       
-       do_ipblocks_update();
-       do_interwiki_update();
-       do_index_update();
-       do_linkscc_update();
-       do_hitcounter_update();
+do_revision_updates();
+
+do_ipblocks_update();
+do_interwiki_update();
+do_index_update();
+do_linkscc_update();
+do_hitcounter_update();
+do_recentchanges_update();
 
-       initialiseMessages();
+initialiseMessages();
 
-       mysql_close( $rconn );
+$wgDatabase->close();
 
 print "Done.\n";
 exit();
@@ -110,6 +115,7 @@ function do_revision_updates() {
 }
 
 function update_passwords() {
+       global $wgDatabase;
        $fname = "Update script: update_passwords()";
        print "\nIt appears that you need to update the user passwords in your\n" .
          "database. If you have already done this (if you've run this update\n" .
@@ -121,25 +127,26 @@ function update_passwords() {
     if ( ! ( "Y" == $resp{0} || "y" == $resp{0} ) ) { return; }
 
        $sql = "SELECT user_id,user_password FROM user";
-       $source = wfQuery( $sql, DB_READ, fname );
+       $source = $wgDatabase->query( $sql, $fname );
 
-       while ( $row = mysql_fetch_object( $source ) ) {
+       while ( $row = $wgDatabase->fetchObject( $source ) ) {
                $id = $row->user_id;
                $oldpass = $row->user_password;
                $newpass = md5( "{$id}-{$oldpass}" );
 
                $sql = "UPDATE user SET user_password='{$newpass}' " .
                  "WHERE user_id={$id}";
-               wfQuery( $sql, DB_WRITE, $fname );
+               $wgDatabase->query( $sql, $fname );
        }
 }
 
 function do_ipblocks_update() {
-       if ( wfFieldExists( "ipblocks", "ipb_id" ) ) {
+       global $wgDatabase;
+       if ( $wgDatabase->fieldExists( "ipblocks", "ipb_id" ) ) {
                echo "...ipblocks table is up to date.\n";
        } else {
                echo "Updating ipblocks table... ";
-               dbsource( "maintenance/archives/patch-ipblocks.sql" );
+               dbsource( "maintenance/archives/patch-ipblocks.sql", $wgDatabase );
                echo "ok\n";
        }
 }
@@ -147,7 +154,8 @@ function do_ipblocks_update() {
 
 function do_interwiki_update() {
        # Check that interwiki table exists; if it doesn't source it
-       if( table_exists( "interwiki" ) ) {
+       global $wgDatabase;
+       if( $wgDatabase->tableExists( "interwiki" ) ) {
                echo "...already have interwiki table\n";
                return true;
        }
@@ -161,7 +169,8 @@ function do_interwiki_update() {
 
 function do_index_update() {
        # Check that proper indexes are in place
-       $meta = field_info( "recentchanges", "rc_timestamp" );
+       global $wgDatabase;
+       $meta = $wgDatabase->field_info( "recentchanges", "rc_timestamp" );
        if( $meta->multiple_key == 0 ) {
                echo "Updating indexes to 20031107: ";
                dbsource( "maintenance/archives/patch-indexes.sql" );
@@ -174,27 +183,35 @@ function do_index_update() {
 
 function do_linkscc_update() {
        // Create linkscc if necessary
-       global $rconn;
+       global $wgDatabase;
        if( table_exists( "linkscc" ) ) {
                echo "...have linkscc table.\n";
        } else {
                echo "Adding linkscc table... ";
-               dbsource( "maintenance/archives/patch-linkscc.sql" );
+               dbsource( "maintenance/archives/patch-linkscc.sql", $wgDatabase );
                echo "ok\n";
        }
 }
 
 function do_hitcounter_update() {
        // Create hitcounter if necessary
-       global $rconn;
-       if( table_exists( "hitcounter" ) ) {
+       global $wgDatabase;
+       if( $wgDatabase->tableExists( "hitcounter" ) ) {
                echo "...have hitcounter table.\n";
        } else {
                echo "Adding hitcounter table... ";
-               dbsource( "maintenance/archives/patch-hitcounter.sql" );
+               dbsource( "maintenance/archives/patch-hitcounter.sql", $wgDatabase );
                echo "ok\n";
        }
 }
 
+function do_recentchanges_update() {
+       global $wgDatabase;
+       if ( !$wgDatabase->fieldExists( "recentchanges", "rc_type" ) ) {
+               echo "Adding rc_type, rc_moved_to_ns, rc_moved_to_title...";
+               dbsource( "maintenance/archives/patch-rc_type.sql" , $wgDatabase );
+               echo "ok\n";
+       }
+}
 
 ?>
index 8071dfb..86605c8 100644 (file)
@@ -32,7 +32,11 @@ if ( function_exists( "getallheaders" ) ) {
 # Query string fields
 #
 global $action, $title, $search, $go, $target, $printable;
-global $returnto, $diff, $oldid;
+global $returnto, $diff, $oldid, $curid;
+
+# Placeholders in case of DB error
+$wgTitle = Title::newFromText( wfMsg( "badtitle" ) );
+$wgArticle = new Article($wgTitle);
 
 $action = strtolower( trim( $action ) );
 if ( "" == $action ) { $action = "view"; }
@@ -40,6 +44,9 @@ if ( "yes" == $printable ) { $wgOut->setPrintable(); }
 
 if ( "" == $title && "delete" != $action ) {
        $wgTitle = Title::newFromText( wfMsg( "mainpage" ) );
+} elseif ( $curid ) {
+       # URLs like this are generated by RC, because rc_title isn't always accurate
+       $wgTitle = Title::newFromID( $curid );
 } else {
        $wgTitle = Title::newFromURL( $title );
 }