X-Git-Url: http://git.cyclocoop.org/%22%20.%20generer_url_ecrire%28%22upgrade%22%2C%22reinstall=non%22%29%20.%20%22?a=blobdiff_plain;f=includes%2FWikiPage.php;h=6063a5136643c8f76767af2771d61adc1800f1e1;hb=01f36b721f6fb60000b625fd681993d50ebd0e40;hp=1c28d11b12d2957270a040e8bf277382988c085a;hpb=8bf6ca1d1860ae924b21860578ced36d2d037b66;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/WikiPage.php b/includes/WikiPage.php index 1c28d11b12..6063a51366 100644 --- a/includes/WikiPage.php +++ b/includes/WikiPage.php @@ -1,4 +1,25 @@ selectRow( 'page', self::selectFields(), array( 'page_id' => $id ), __METHOD__ ); + public static function newFromID( $id, $from = 'fromdb' ) { + $from = self::convertSelectType( $from ); + $db = wfGetDB( $from === self::DATA_FROM_MASTER ? DB_MASTER : DB_SLAVE ); + $row = $db->selectRow( 'page', self::selectFields(), array( 'page_id' => $id ), __METHOD__ ); if ( !$row ) { return null; } - return self::newFromRow( $row ); + return self::newFromRow( $row, $from ); } /** @@ -135,14 +187,38 @@ class WikiPage extends Page { * @since 1.20 * @param $row object: database row containing at least fields returned * by selectFields(). + * @param $from string|int: source of $data: + * - "fromdb" or self::DATA_FROM_SLAVE: from a slave DB + * - "fromdbmaster" or self::DATA_FROM_MASTER: from the master DB + * - "forupdate" or self::DATA_FOR_UPDATE: from the master DB using SELECT FOR UPDATE * @return WikiPage */ - public static function newFromRow( $row ) { + public static function newFromRow( $row, $from = 'fromdb' ) { $page = self::factory( Title::newFromRow( $row ) ); - $page->loadFromRow( $row ); + $page->loadFromRow( $row, $from ); return $page; } + /** + * Convert 'fromdb', 'fromdbmaster' and 'forupdate' to DATA_* constants. + * + * @param $type object|string|int + * @return mixed + */ + private static function convertSelectType( $type ) { + switch ( $type ) { + case 'fromdb': + return self::DATA_FROM_SLAVE; + case 'fromdbmaster': + return self::DATA_FROM_MASTER; + case 'forupdate': + return self::DATA_FOR_UPDATE; + default: + // It may already be an integer or whatever else + return $type; + } + } + /** * Returns overrides for action handlers. * Classes listed here will be used instead of the default one when @@ -184,6 +260,7 @@ class WikiPage extends Page { */ public function clear() { $this->mDataLoaded = false; + $this->mDataLoadedFrom = self::DATA_NOT_LOADED; $this->mCounter = null; $this->mRedirectTarget = null; # Title object if set @@ -229,14 +306,15 @@ class WikiPage extends Page { * Fetch a page record with the given conditions * @param $dbr DatabaseBase object * @param $conditions Array + * @param $options Array * @return mixed Database result resource, or false on failure */ - protected function pageData( $dbr, $conditions ) { + protected function pageData( $dbr, $conditions, $options = array() ) { $fields = self::selectFields(); wfRunHooks( 'ArticlePageDataBefore', array( &$this, &$fields ) ); - $row = $dbr->selectRow( 'page', $fields, $conditions, __METHOD__ ); + $row = $dbr->selectRow( 'page', $fields, $conditions, __METHOD__, $options ); wfRunHooks( 'ArticlePageDataAfter', array( &$this, &$row ) ); @@ -249,12 +327,13 @@ class WikiPage extends Page { * * @param $dbr DatabaseBase object * @param $title Title object + * @param $options Array * @return mixed Database result resource, or false on failure */ - public function pageDataFromTitle( $dbr, $title ) { + public function pageDataFromTitle( $dbr, $title, $options = array() ) { return $this->pageData( $dbr, array( 'page_namespace' => $title->getNamespace(), - 'page_title' => $title->getDBkey() ) ); + 'page_title' => $title->getDBkey() ), $options ); } /** @@ -262,38 +341,54 @@ class WikiPage extends Page { * * @param $dbr DatabaseBase * @param $id Integer + * @param $options Array * @return mixed Database result resource, or false on failure */ - public function pageDataFromId( $dbr, $id ) { - return $this->pageData( $dbr, array( 'page_id' => $id ) ); + public function pageDataFromId( $dbr, $id, $options = array() ) { + return $this->pageData( $dbr, array( 'page_id' => $id ), $options ); } /** * Set the general counter, title etc data loaded from * some source. * - * @param $data Object|String One of the following: - * A DB query result object or... - * "fromdb" to get from a slave DB or... - * "fromdbmaster" to get from the master DB + * @param $from object|string|int One of the following: + * - A DB query result object + * - "fromdb" or self::DATA_FROM_SLAVE to get from a slave DB + * - "fromdbmaster" or self::DATA_FROM_MASTER to get from the master DB + * - "forupdate" or self::DATA_FOR_UPDATE to get from the master DB using SELECT FOR UPDATE + * * @return void */ - public function loadPageData( $data = 'fromdb' ) { - if ( $data === 'fromdbmaster' ) { + public function loadPageData( $from = 'fromdb' ) { + $from = self::convertSelectType( $from ); + if ( is_int( $from ) && $from <= $this->mDataLoadedFrom ) { + // We already have the data from the correct location, no need to load it twice. + return; + } + + if ( $from === self::DATA_FOR_UPDATE ) { + $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle, array( 'FOR UPDATE' ) ); + } elseif ( $from === self::DATA_FROM_MASTER ) { $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle ); - } elseif ( $data === 'fromdb' ) { // slave + } elseif ( $from === self::DATA_FROM_SLAVE ) { $data = $this->pageDataFromTitle( wfGetDB( DB_SLAVE ), $this->mTitle ); # Use a "last rev inserted" timestamp key to dimish the issue of slave lag. # Note that DB also stores the master position in the session and checks it. $touched = $this->getCachedLastEditTime(); if ( $touched ) { // key set if ( !$data || $touched > wfTimestamp( TS_MW, $data->page_touched ) ) { + $from = self::DATA_FROM_MASTER; $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle ); } } + } else { + // No idea from where the caller got this data, assume slave database. + $data = $from; + $from = self::DATA_FROM_SLAVE; } - $this->loadFromRow( $data ); + $this->loadFromRow( $data, $from ); } /** @@ -302,8 +397,13 @@ class WikiPage extends Page { * @since 1.20 * @param $data object: database row containing at least fields returned * by selectFields() + * @param $from string|int One of the following: + * - "fromdb" or self::DATA_FROM_SLAVE if the data comes from a slave DB + * - "fromdbmaster" or self::DATA_FROM_MASTER if the data comes from the master DB + * - "forupdate" or self::DATA_FOR_UPDATE if the data comes from from + * the master DB using SELECT FOR UPDATE */ - public function loadFromRow( $data ) { + public function loadFromRow( $data, $from ) { $lc = LinkCache::singleton(); if ( $data ) { @@ -325,6 +425,7 @@ class WikiPage extends Page { } $this->mDataLoaded = true; + $this->mDataLoadedFrom = self::convertSelectType( $from ); } /** @@ -438,6 +539,49 @@ class WikiPage extends Page { return (int)$this->mLatest; } + /** + * Get the Revision object of the oldest revision + * @return Revision|null + */ + public function getOldestRevision() { + wfProfileIn( __METHOD__ ); + + // Try using the slave database first, then try the master + $continue = 2; + $db = wfGetDB( DB_SLAVE ); + $revSelectFields = Revision::selectFields(); + + while ( $continue ) { + $row = $db->selectRow( + array( 'page', 'revision' ), + $revSelectFields, + array( + 'page_namespace' => $this->mTitle->getNamespace(), + 'page_title' => $this->mTitle->getDBkey(), + 'rev_page = page_id' + ), + __METHOD__, + array( + 'ORDER BY' => 'rev_timestamp ASC' + ) + ); + + if ( $row ) { + $continue = 0; + } else { + $db = wfGetDB( DB_MASTER ); + $continue--; + } + } + + wfProfileOut( __METHOD__ ); + if ( $row ) { + return Revision::newFromRow( $row ); + } else { + return null; + } + } + /** * Loads everything except the text * This isn't necessary for all uses, so it's only done if needed. @@ -566,6 +710,24 @@ class WikiPage extends Page { } } + /** + * Get the User object of the user who created the page + * @param $audience Integer: one of: + * Revision::FOR_PUBLIC to be displayed to all users + * Revision::FOR_THIS_USER to be displayed to $wgUser + * Revision::RAW get the text regardless of permissions + * @return User|null + */ + public function getCreator( $audience = Revision::FOR_PUBLIC ) { + $revision = $this->getOldestRevision(); + if ( $revision ) { + $userName = $revision->getUserText( $audience ); + return User::newFromName( $userName, false ); + } else { + return null; + } + } + /** * @param $audience Integer: one of: * Revision::FOR_PUBLIC to be displayed to all users @@ -1431,7 +1593,9 @@ class WikiPage extends Page { $user = is_null( $user ) ? $wgUser : $user; $status = Status::newGood( array() ); - # Load $this->mTitle->getArticleID() and $this->mLatest if it's not already + // Load the data from the master database if needed. + // The caller may already loaded it from the master or even loaded it using + // SELECT FOR UPDATE, so do not override that using clear(). $this->loadPageData( 'fromdbmaster' ); $flags = $this->checkFlags( $flags ); @@ -1960,7 +2124,7 @@ class WikiPage extends Page { * @param &$cascade Integer. Set to false if cascading protection isn't allowed. * @param $expiry Array: per restriction type expiration * @param $user User The user updating the restrictions - * @return bool true on success + * @return Status */ public function doUpdateRestrictions( array $limit, array $expiry, &$cascade, $reason, User $user ) { global $wgContLang; @@ -2226,19 +2390,24 @@ class WikiPage extends Page { $reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null ) { global $wgUser, $wgContentHandlerUseDB; - $user = is_null( $user ) ? $wgUser : $user; wfDebug( __METHOD__ . "\n" ); + if ( $this->mTitle->getDBkey() === '' ) { + return WikiPage::DELETE_NO_PAGE; + } + + $user = is_null( $user ) ? $wgUser : $user; if ( ! wfRunHooks( 'ArticleDelete', array( &$this, &$user, &$reason, &$error ) ) ) { return WikiPage::DELETE_HOOK_ABORTED; } - $dbw = wfGetDB( DB_MASTER ); - $t = $this->mTitle->getDBkey(); - $id = $id ? $id : $this->mTitle->getArticleID( Title::GAID_FOR_UPDATE ); - if ( $t === '' || $id == 0 ) { - return WikiPage::DELETE_NO_PAGE; + if ( $id == 0 ) { + $this->loadPageData( 'forupdate' ); + $id = $this->getID(); + if ( $id == 0 ) { + return WikiPage::DELETE_NO_PAGE; + } } // Bitfields to further suppress the content @@ -2253,6 +2422,7 @@ class WikiPage extends Page { $bitfield = 'rev_deleted'; } + $dbw = wfGetDB( DB_MASTER ); $dbw->begin( __METHOD__ ); // For now, shunt the revision data into the archive table. // Text is *not* removed from the text table; bulk storage