X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FArticle.php;h=68290a6291b48a3e209900e53bd65888b4700d28;hb=bbd225e01312fd56845d8fbf650aa3cd184bb731;hp=8290f21da026961984c45fd9f70c7f0ef66b3162;hpb=33f66d157b96ee10db0c18122179db8ca89627a7;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Article.php b/includes/Article.php index 8290f21da0..68290a6291 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -17,7 +17,12 @@ class Article { /**@{{ * @private */ - var $mComment = ''; // !< + + /** + * @var RequestContext + */ + protected $mContext; + var $mContent; // !< var $mContentLoaded = false; // !< var $mCounter = -1; // !< Not loaded @@ -26,22 +31,50 @@ class Article { var $mGoodAdjustment = 0; // !< var $mIsRedirect = false; // !< var $mLatest = false; // !< - var $mMinorEdit; // !< var $mOldId; // !< - var $mPreparedEdit = false; // !< Title object if set - var $mRedirectedFrom = null; // !< Title object if set - var $mRedirectTarget = null; // !< Title object if set + var $mPreparedEdit = false; + + /** + * @var Title + */ + var $mRedirectedFrom = null; + + /** + * @var Title + */ + var $mRedirectTarget = null; + + /** + * @var Title + */ var $mRedirectUrl = false; // !< var $mRevIdFetched = 0; // !< - var $mRevision = null; // !< Revision object if set + + /** + * @var Revision + */ + var $mLastRevision = null; + + /** + * @var Revision + */ + var $mRevision = null; + var $mTimestamp = ''; // !< var $mTitle; // !< Title object var $mTotalAdjustment = 0; // !< var $mTouched = '19700101000000'; // !< - var $mUser = -1; // !< Not loaded - var $mUserText = ''; // !< username from Revision if set - var $mParserOptions; // !< ParserOptions object for $wgUser articles - var $mParserOutput; // !< ParserCache object if set + + /** + * @var ParserOptions + */ + var $mParserOptions; + + /** + * @var ParserOutput + */ + var $mParserOutput; + /**@}}*/ /** @@ -159,7 +192,7 @@ class Article { * * @param $text string article content containing redirect info * @return mixed false, Title of in-wiki target, or string with URL - * @deprecated @since 1.17 + * @deprecated since 1.17 */ public function followRedirectText( $text ) { // recurse through to only get the final target @@ -223,11 +256,11 @@ class Article { $this->mDataLoaded = false; $this->mContentLoaded = false; - $this->mUser = $this->mCounter = -1; # Not loaded + $this->mCounter = -1; # Not loaded $this->mRedirectedFrom = null; # Title object if set $this->mRedirectTarget = null; # Title object if set - $this->mUserText = - $this->mTimestamp = $this->mComment = ''; + $this->mLastRevision = null; # Latest revision + $this->mTimestamp = ''; $this->mGoodAdjustment = $this->mTotalAdjustment = 0; $this->mTouched = '19700101000000'; $this->mForUpdate = false; @@ -292,23 +325,6 @@ class Article { return $text; } - /** - * This function returns the text of a section, specified by a number ($section). - * A section is text under a heading like == Heading == or \Heading\, or - * the first section before any such heading (section 0). - * - * If a section contains subsections, these are also returned. - * - * @param $text String: text to look in - * @param $section Integer: section number - * @return string text of the requested section - * @deprecated - */ - public function getSection( $text, $section ) { - global $wgParser; - return $wgParser->getSection( $text, $section ); - } - /** * Get the text that needs to be saved in order to undo all revisions * between $undo and $undoafter. Revisions must belong to the same page, @@ -403,26 +419,34 @@ class Article { wfProfileOut( __METHOD__ ); } + /** + * Return the list of revision fields that should be selected to create + * a new page. + */ + public static function selectFields() { + return array( + 'page_id', + 'page_namespace', + 'page_title', + 'page_restrictions', + 'page_counter', + 'page_is_redirect', + 'page_is_new', + 'page_random', + 'page_touched', + 'page_latest', + 'page_len', + ); + } + /** * Fetch a page record with the given conditions - * @param $dbr Database object + * @param $dbr DatabaseBase object * @param $conditions Array * @return mixed Database result resource, or false on failure */ protected function pageData( $dbr, $conditions ) { - $fields = array( - 'page_id', - 'page_namespace', - 'page_title', - 'page_restrictions', - 'page_counter', - 'page_is_redirect', - 'page_is_new', - 'page_random', - 'page_touched', - 'page_latest', - 'page_len', - ); + $fields = self::selectFields(); wfRunHooks( 'ArticlePageDataBefore', array( &$this, &$fields ) ); @@ -437,11 +461,11 @@ class Article { * Fetch a page record matching the Title object's namespace and title * using a sanitized title string * - * @param $dbr Database object + * @param $dbr DatabaseBase object * @param $title Title object * @return mixed Database result resource, or false on failure */ - public function pageDataFromTitle( $dbr, $title ) { + protected function pageDataFromTitle( $dbr, $title ) { return $this->pageData( $dbr, array( 'page_namespace' => $title->getNamespace(), 'page_title' => $title->getDBkey() ) ); @@ -450,8 +474,9 @@ class Article { /** * Fetch a page record matching the requested ID * - * @param $dbr Database + * @param $dbr DatabaseBase * @param $id Integer + * @return mixed Database result resource, or false on failure */ protected function pageDataFromId( $dbr, $id ) { return $this->pageData( $dbr, array( 'page_id' => $id ) ); @@ -461,7 +486,7 @@ class Article { * Set the general counter, title etc data loaded from * some source. * - * @param $data Database row object or "fromdb" + * @param $data Object|String $res->fetchObject() object or the string "fromdb" to reload */ public function loadPageData( $data = 'fromdb' ) { if ( $data === 'fromdb' ) { @@ -563,33 +588,16 @@ class Article { /** * Read/write accessor to select FOR UPDATE + * @deprecated since 1.18 * * @param $x Mixed: FIXME * @return mixed value of $x, or value stored in Article::mForUpdate */ public function forUpdate( $x = null ) { + wfDeprecated( __METHOD__ ); return wfSetVar( $this->mForUpdate, $x ); } - /** - * Get options for all SELECT statements - * - * @param $options Array: an optional options array which'll be appended to - * the default - * @return Array: options - */ - protected function getSelectOptions( $options = '' ) { - if ( $this->mForUpdate ) { - if ( is_array( $options ) ) { - $options[] = 'FOR UPDATE'; - } else { - $options = 'FOR UPDATE'; - } - } - - return $options; - } - /** * @return int Page ID */ @@ -630,8 +638,7 @@ class Article { $this->mCounter = $dbr->selectField( 'page', 'page_counter', array( 'page_id' => $id ), - __METHOD__, - $this->getSelectOptions() + __METHOD__ ); } } @@ -691,8 +698,8 @@ class Article { * This isn't necessary for all uses, so it's only done if needed. */ protected function loadLastEdit() { - if ( -1 != $this->mUser ) { - return; + if ( $this->mLastRevision !== null ) { + return; // already loaded } # New or non-existent articles have no user information @@ -702,7 +709,7 @@ class Article { } $revision = Revision::loadFromPageId( wfGetDB( DB_MASTER ), $id ); - if ( !is_null( $revision ) ) { + if ( $revision ) { $this->setLastEdit( $revision ); } } @@ -712,11 +719,7 @@ class Article { */ protected function setLastEdit( Revision $revision ) { $this->mLastRevision = $revision; - $this->mUser = $revision->getUser(); - $this->mUserText = $revision->getUserText(); $this->mTimestamp = $revision->getTimestamp(); - $this->mComment = $revision->getComment(); - $this->mMinorEdit = $revision->isMinor(); } /** @@ -727,32 +730,55 @@ class Article { if ( !$this->mTimestamp ) { $this->loadLastEdit(); } - return wfTimestamp( TS_MW, $this->mTimestamp ); } /** + * @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 int user ID for the user that made the last article revision */ - public function getUser() { + public function getUser( $audience = Revision::FOR_PUBLIC ) { $this->loadLastEdit(); - return $this->mUser; + if ( $this->mLastRevision ) { + return $this->mLastRevision->getUser( $audience ); + } else { + return -1; + } } /** + * @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 string username of the user that made the last article revision */ - public function getUserText() { + public function getUserText( $audience = Revision::FOR_PUBLIC ) { $this->loadLastEdit(); - return $this->mUserText; + if ( $this->mLastRevision ) { + return $this->mLastRevision->getUserText( $audience ); + } else { + return ''; + } } /** + * @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 string Comment stored for the last article revision */ - public function getComment() { + public function getComment( $audience = Revision::FOR_PUBLIC ) { $this->loadLastEdit(); - return $this->mComment; + if ( $this->mLastRevision ) { + return $this->mLastRevision->getComment( $audience ); + } else { + return ''; + } } /** @@ -762,7 +788,11 @@ class Article { */ public function getMinorEdit() { $this->loadLastEdit(); - return $this->mMinorEdit; + if ( $this->mLastRevision ) { + return $this->mLastRevision->isMinor(); + } else { + return false; + } } /** @@ -779,46 +809,54 @@ class Article { } /** - * FIXME: this does what? - * @param $limit Integer: default 0. - * @param $offset Integer: default 0. - * @return UserArrayFromResult object with User objects of article contributors for requested range + * Get a list of users who have edited this article, not including the user who made + * the most recent revision, which you can get from $article->getUser() if you want it + * @return UserArray */ - public function getContributors( $limit = 0, $offset = 0 ) { + public function getContributors() { # FIXME: this is expensive; cache this info somewhere. $dbr = wfGetDB( DB_SLAVE ); - $revTable = $dbr->tableName( 'revision' ); $userTable = $dbr->tableName( 'user' ); - $pageId = $this->getId(); - - $user = $this->getUser(); - - if ( $user ) { - $excludeCond = "AND rev_user != $user"; + if ( $dbr->implicitGroupby() ) { + $realNameField = 'user_real_name'; } else { - $userText = $dbr->addQuotes( $this->getUserText() ); - $excludeCond = "AND rev_user_text != $userText"; + $realNameField = 'FIRST(user_real_name) AS user_real_name'; } - $deletedBit = $dbr->bitAnd( 'rev_deleted', Revision::DELETED_USER ); // username hidden? + $tables = array( 'revision', 'user' ); - $sql = "SELECT {$userTable}.*, rev_user_text as user_name, MAX(rev_timestamp) as timestamp - FROM $revTable LEFT JOIN $userTable ON rev_user = user_id - WHERE rev_page = $pageId - $excludeCond - AND $deletedBit = 0 - GROUP BY rev_user, rev_user_text - ORDER BY timestamp DESC"; + $fields = array( + 'rev_user as user_id', + 'rev_user_text AS user_name', + $realNameField, + 'MAX(rev_timestamp) AS timestamp', + ); - if ( $limit > 0 ) { - $sql = $dbr->limitResult( $sql, $limit, $offset ); + $conds = array( 'rev_page' => $this->getId() ); + + // The user who made the top revision gets credited as "this page was last edited by + // John, based on contributions by Tom, Dick and Harry", so don't include them twice. + $user = $this->getUser(); + if ( $user ) { + $conds[] = "rev_user != $user"; + } else { + $conds[] = "rev_user_text != {$dbr->addQuotes( $this->getUserText() )}"; } - $sql .= ' ' . $this->getSelectOptions(); - $res = $dbr->query( $sql, __METHOD__ ); + $conds[] = "{$dbr->bitAnd( 'rev_deleted', Revision::DELETED_USER )} = 0"; // username hidden? + + $jconds = array( + 'user' => array( 'LEFT JOIN', 'rev_user = user_id' ), + ); + $options = array( + 'GROUP BY' => array( 'rev_user', 'rev_user_text' ), + 'ORDER BY' => 'timestamp DESC', + ); + + $res = $dbr->select( $tables, $fields, $conds, __METHOD__, $options, $jconds ); return new UserArrayFromResult( $res ); } @@ -1115,8 +1153,7 @@ class Article { if ( $ns == NS_USER || $ns == NS_USER_TALK ) { # Don't index user and user talk pages for blocked users (bug 11443) if ( !$this->mTitle->isSubpage() ) { - $block = new Block(); - if ( $block->load( $this->mTitle->getText() ) ) { + if ( Block::newFromTarget( null, $this->mTitle->getText() ) instanceof Block ) { return array( 'index' => 'noindex', 'follow' => 'nofollow' @@ -1212,7 +1249,7 @@ class Article { * @return boolean */ public function showRedirectedFromHeader() { - global $wgOut, $wgUser, $wgRequest, $wgRedirectSources; + global $wgOut, $wgRequest, $wgRedirectSources; $rdfrom = $wgRequest->getVal( 'rdfrom' ); @@ -1220,7 +1257,7 @@ class Article { // This is an internally redirected page view. // We'll need a backlink to the source page for navigation. if ( wfRunHooks( 'ArticleViewRedirect', array( &$this ) ) ) { - $redir = $wgUser->getSkin()->link( + $redir = Linker::link( $this->mRedirectedFrom, null, array(), @@ -1248,7 +1285,7 @@ class Article { // This is an externally redirected view, from some other wiki. // If it was reported from a trusted site, supply a backlink. if ( $wgRedirectSources && preg_match( $wgRedirectSources, $rdfrom ) ) { - $redir = $wgUser->getSkin()->makeExternalLink( $rdfrom, $rdfrom ); + $redir = Linker::makeExternalLink( $rdfrom, $rdfrom ); $s = wfMsgExt( 'redirectedfrom', array( 'parseinline', 'replaceafter' ), $redir ); $wgOut->setSubtitle( $s ); @@ -1311,7 +1348,6 @@ class Article { return; } - $sk = $wgUser->getSkin(); $token = $wgUser->editToken( $rcid ); $wgOut->preventClickjacking(); @@ -1319,7 +1355,7 @@ class Article { "' ); @@ -4165,8 +4053,7 @@ class Article { 'watchlist', 'COUNT(*)', $wl_clause, - __METHOD__, - $this->getSelectOptions() ); + __METHOD__ ); $pageInfo = $this->pageCountInfo( $page ); $talkInfo = $this->pageCountInfo( $page->getTalkPage() ); @@ -4210,15 +4097,13 @@ class Article { 'revision', 'COUNT(rev_page)', $rev_clause, - __METHOD__, - $this->getSelectOptions() + __METHOD__ ); $authors = $dbr->selectField( 'revision', 'COUNT(DISTINCT rev_user_text)', $rev_clause, - __METHOD__, - $this->getSelectOptions() + __METHOD__ ); return array( 'edits' => $edits, 'authors' => $authors ); @@ -4395,34 +4280,33 @@ class Article { /** * Get parser options suitable for rendering the primary article wikitext - * @param $canonical boolean Determines that the generated must not depend on user preferences (see bug 14404) - * @return mixed ParserOptions object or boolean false + * @return ParserOptions object */ - public function getParserOptions( $canonical = false ) { - global $wgUser, $wgLanguageCode; - - if ( !$this->mParserOptions || $canonical ) { - $user = !$canonical ? $wgUser : new User; - $parserOptions = new ParserOptions( $user ); - $parserOptions->setTidy( true ); - $parserOptions->enableLimitReport(); - - if ( $canonical ) { - $parserOptions->setUserLang( $wgLanguageCode ); # Must be set explicitely - return $parserOptions; - } - $this->mParserOptions = $parserOptions; + public function getParserOptions() { + global $wgUser; + if ( !$this->mParserOptions ) { + $this->mParserOptions = $this->makeParserOptions( $wgUser ); } - - // Clone to allow modifications of the return value without affecting - // the cache + // Clone to allow modifications of the return value without affecting cache return clone $this->mParserOptions; } + /** + * Get parser options suitable for rendering the primary article wikitext + * @param User $user + * @return ParserOptions + */ + public function makeParserOptions( User $user ) { + $options = ParserOptions::newFromUser( $user ); + $options->enableLimitReport(); // show inclusion/loop reports + $options->setTidy( true ); // fix bad HTML + return $options; + } + /** * Updates cascading protections * - * @param $parserOutput mixed ParserOptions object, or boolean false + * @param $parserOutput ParserOutput object, or boolean false **/ protected function doCascadeProtectionUpdates( $parserOutput ) { if ( !$this->isCurrent() || wfReadOnly() || !$this->mTitle->areRestrictionsCascading() ) { @@ -4579,9 +4463,38 @@ class Article { return $this->getOutputFromWikitext( $text, $useParserCache ); } + /** + * Sets the context this Article is executed in + * + * @param $context RequestContext + * @since 1.18 + */ + public function setContext( $context ) { + $this->mContext = $context; + } + + /** + * Gets the context this Article is executed in + * + * @return RequestContext + * @since 1.18 + */ + public function getContext() { + if ( $this->mContext instanceof RequestContext ) { + return $this->mContext; + } else { + wfDebug( __METHOD__ . " called and \$mContext is null. Return RequestContext::getMain(); for sanity\n" ); + return RequestContext::getMain(); + } + } + } class PoolWorkArticleView extends PoolCounterWork { + + /** + * @var Article + */ private $mArticle; function __construct( $article, $key, $useParserCache, $parserOptions ) { @@ -4616,6 +4529,9 @@ class PoolWorkArticleView extends PoolCounterWork { return $this->mArticle->tryDirtyCache(); } + /** + * @param $status Status + */ function error( $status ) { global $wgOut;