* @package MediaWiki
*/
-/**
- * Need the CacheManager to be loaded
- */
-require_once( 'CacheManager.php' );
-require_once( 'Revision.php' );
-
-$wgArticleCurContentFields = false;
-$wgArticleOldContentFields = false;
-
/**
* Class representing a MediaWiki article and history.
*
* @package MediaWiki
*/
class Article {
- /**#@+
- * @access private
- */
- var $mContent, $mContentLoaded;
- var $mUser, $mTimestamp, $mUserText;
- var $mCounter, $mComment, $mGoodAdjustment, $mTotalAdjustment;
- var $mMinorEdit, $mRedirectedFrom;
- var $mTouched, $mFileCache, $mTitle;
- var $mId, $mTable;
- var $mForUpdate;
- var $mOldId;
- var $mRevIdFetched;
- var $mRevision;
- var $mRedirectUrl;
- /**#@-*/
+ /**@{{
+ * @private
+ */
+ var $mComment; //!<
+ var $mContent; //!<
+ var $mContentLoaded; //!<
+ var $mCounter; //!<
+ var $mForUpdate; //!<
+ var $mGoodAdjustment; //!<
+ var $mLatest; //!<
+ var $mMinorEdit; //!<
+ var $mOldId; //!<
+ var $mRedirectedFrom; //!<
+ var $mRedirectUrl; //!<
+ var $mRevIdFetched; //!<
+ var $mRevision; //!<
+ var $mTimestamp; //!<
+ var $mTitle; //!<
+ var $mTotalAdjustment; //!<
+ var $mTouched; //!<
+ var $mUser; //!<
+ var $mUserText; //!<
+ /**@}}*/
/**
* Constructor and clear the article
- * @param Title &$title
- * @param integer $oldId Revision ID, null to fetch from request, zero for current
+ * @param $title Reference to a Title object.
+ * @param $oldId Integer revision ID, null to fetch from request, zero for current
*/
function Article( &$title, $oldId = null ) {
$this->mTitle =& $title;
/**
* Tell the page view functions that this view was redirected
* from another page on the wiki.
- * @param Title $from
+ * @param $from Title object.
*/
function setRedirectedFrom( $from ) {
$this->mRedirectedFrom = $from;
} else {
return $rt->getFullURL();
}
- }
+ }
return $rt;
}
}
/**
* Clear the object
- * @access private
+ * @private
*/
function clear() {
$this->mDataLoaded = false;
$this->mCurID = $this->mUser = $this->mCounter = -1; # Not loaded
$this->mRedirectedFrom = null; # Title object if set
$this->mUserText =
- $this->mTimestamp = $this->mComment = $this->mFileCache = '';
+ $this->mTimestamp = $this->mComment = '';
$this->mGoodAdjustment = $this->mTotalAdjustment = 0;
$this->mTouched = '19700101000000';
$this->mForUpdate = false;
$this->mIsRedirect = false;
$this->mRevIdFetched = 0;
$this->mRedirectUrl = false;
+ $this->mLatest = false;
}
/**
* Note that getContent/loadContent do not follow redirects anymore.
* If you need to fetch redirectable content easily, try
* the shortcut in Article::followContent()
- *
- * @fixme There are still side-effects in this!
+ * FIXME
+ * @todo There are still side-effects in this!
* In general, you should use the Revision class, not Article,
* to fetch text for purposes other than page views.
*
function getContent() {
global $wgRequest, $wgUser, $wgOut;
- # Get variables from query string :P
- $action = $wgRequest->getText( 'action', 'view' );
- $section = $wgRequest->getText( 'section' );
- $preload = $wgRequest->getText( 'preload' );
-
- $fname = 'Article::getContent';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
if ( 0 == $this->getID() ) {
- if ( 'edit' == $action ) {
- wfProfileOut( $fname );
-
- # If requested, preload some text.
- $text=$this->getPreloadedText($preload);
-
- # We used to put MediaWiki:Newarticletext here if
- # $text was empty at this point.
- # This is now shown above the edit box instead.
- return $text;
- }
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
$wgOut->setRobotpolicy( 'noindex,nofollow' );
if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
return "<div class='noarticletext'>$ret</div>";
} else {
$this->loadContent();
- # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
- if ( $this->mTitle->getNamespace() == NS_USER_TALK &&
- $wgUser->isIP($this->mTitle->getText()) &&
- $action=='view'
- ) {
- wfProfileOut( $fname );
- return $this->mContent . "\n" .wfMsg('anontalkpagetext');
- } else {
- if($action=='edit') {
- if($section!='') {
- if($section=='new') {
- wfProfileOut( $fname );
- $text=$this->getPreloadedText($preload);
- return $text;
- }
-
- # strip NOWIKI etc. to avoid confusion (true-parameter causes HTML
- # comments to be stripped as well)
- $rv=$this->getSection($this->mContent,$section);
- wfProfileOut( $fname );
- return $rv;
- }
- }
- wfProfileOut( $fname );
- return $this->mContent;
- }
- }
- }
-
- /**
- * Get the contents of a page from its title and remove includeonly tags
- *
- * @param string The title of the page
- * @return string The contents of the page
- */
- function getPreloadedText($preload) {
- if ( $preload === '' )
- return '';
- else {
- $preloadTitle = Title::newFromText( $preload );
- if ( isset( $preloadTitle ) && $preloadTitle->userCanRead() ) {
- $rev=Revision::newFromTitle($preloadTitle);
- if ( is_object( $rev ) ) {
- $text = $rev->getText();
- // TODO FIXME: AAAAAAAAAAA, this shouldn't be implementing
- // its own mini-parser! -ævar
- $text = preg_replace( '~</?includeonly>~', '', $text );
- return $text;
- } else
- return '';
- }
+ wfProfileOut( __METHOD__ );
+ return $this->mContent;
}
}
/**
* This function returns the text of a section, specified by a number ($section).
- * A section is text under a heading like == Heading == or <h1>Heading</h1>, or
+ * A section is text under a heading like == Heading == or \<h1\>Heading\</h1\>, or
* the first section before any such heading (section 0).
*
* If a section contains subsections, these are also returned.
*
- * @param string $text text to look in
- * @param integer $section section number
+ * @param $text String: text to look in
+ * @param $section Integer: section number
* @return string text of the requested section
+ * @deprecated
*/
function getSection($text,$section) {
-
- # strip NOWIKI etc. to avoid confusion (true-parameter causes HTML
- # comments to be stripped as well)
- $striparray=array();
- $parser=new Parser();
- $parser->mOutputType=OT_WIKI;
- $parser->mOptions = new ParserOptions();
- $striptext=$parser->strip($text, $striparray, true);
-
- # now that we can be sure that no pseudo-sections are in the source,
- # split it up by section
- $secs =
- preg_split(
- '/(^=+.+?=+|^<h[1-6].*?>.*?<\/h[1-6].*?>)(?!\S)/mi',
- $striptext, -1,
- PREG_SPLIT_DELIM_CAPTURE);
- if($section==0) {
- $rv=$secs[0];
- } else {
- $headline=$secs[$section*2-1];
- preg_match( '/^(=+).+?=+|^<h([1-6]).*?>.*?<\/h[1-6].*?>(?!\S)/mi',$headline,$matches);
- $hlevel=$matches[1];
-
- # translate wiki heading into level
- if(strpos($hlevel,'=')!==false) {
- $hlevel=strlen($hlevel);
- }
-
- $rv=$headline. $secs[$section*2];
- $count=$section+1;
-
- $break=false;
- while(!empty($secs[$count*2-1]) && !$break) {
-
- $subheadline=$secs[$count*2-1];
- preg_match( '/^(=+).+?=+|^<h([1-6]).*?>.*?<\/h[1-6].*?>(?!\S)/mi',$subheadline,$matches);
- $subhlevel=$matches[1];
- if(strpos($subhlevel,'=')!==false) {
- $subhlevel=strlen($subhlevel);
- }
- if($subhlevel > $hlevel) {
- $rv.=$subheadline.$secs[$count*2];
- }
- if($subhlevel <= $hlevel) {
- $break=true;
- }
- $count++;
-
- }
- }
- # reinsert stripped tags
- $rv=$parser->unstrip($rv,$striparray);
- $rv=$parser->unstripNoWiki($rv,$striparray);
- $rv=trim($rv);
- return $rv;
-
+ global $wgParser;
+ return $wgParser->getSection( $text, $section );
}
/**
# TODO
}
}
- $lastid = $oldid;
+ # unused:
+ # $lastid = $oldid;
}
+
if ( !$oldid ) {
$oldid = 0;
}
# Query variables :P
$oldid = $this->getOldID();
- $fname = 'Article::loadContent';
-
# Pre-fill content with error message so that if something
# fails we'll have something telling us what we intended.
* Fetch a page record with the given conditions
* @param Database $dbr
* @param array $conditions
- * @access private
+ * @private
*/
function pageData( &$dbr, $conditions ) {
$fields = array(
* some source.
*
* @param object $data
- * @access private
+ * @private
*/
- function loadPageData( $data ) {
- $this->mTitle->mArticleID = $data->page_id;
- $this->mTitle->loadRestrictions( $data->page_restrictions );
- $this->mTitle->mRestrictionsLoaded = true;
+ function loadPageData( $data = 'fromdb' ) {
+ if ( $data === 'fromdb' ) {
+ $dbr =& $this->getDB();
+ $data = $this->pageDataFromId( $dbr, $this->getId() );
+ }
+
+ $lc =& LinkCache::singleton();
+ if ( $data ) {
+ $lc->addGoodLinkObj( $data->page_id, $this->mTitle );
- $this->mCounter = $data->page_counter;
- $this->mTouched = wfTimestamp( TS_MW, $data->page_touched );
- $this->mIsRedirect = $data->page_is_redirect;
- $this->mLatest = $data->page_latest;
+ $this->mTitle->mArticleID = $data->page_id;
+ $this->mTitle->loadRestrictions( $data->page_restrictions );
+ $this->mTitle->mRestrictionsLoaded = true;
+
+ $this->mCounter = $data->page_counter;
+ $this->mTouched = wfTimestamp( TS_MW, $data->page_touched );
+ $this->mIsRedirect = $data->page_is_redirect;
+ $this->mLatest = $data->page_latest;
+ } else {
+ if ( is_object( $this->mTitle ) ) {
+ $lc->addBadLinkObj( $this->mTitle );
+ }
+ $this->mTitle->mArticleID = 0;
+ }
$this->mDataLoaded = true;
}
}
$dbr =& $this->getDB();
- $fname = 'Article::fetchContent';
# Pre-fill content with error message so that if something
# fails we'll have something telling us what we intended.
if( $oldid ) {
$revision = Revision::newFromId( $oldid );
if( is_null( $revision ) ) {
- wfDebug( "$fname failed to retrieve specified revision, id $oldid\n" );
+ wfDebug( __METHOD__." failed to retrieve specified revision, id $oldid\n" );
return false;
}
$data = $this->pageDataFromId( $dbr, $revision->getPage() );
if( !$data ) {
- wfDebug( "$fname failed to get page data linked to revision id $oldid\n" );
+ wfDebug( __METHOD__." failed to get page data linked to revision id $oldid\n" );
return false;
}
$this->mTitle = Title::makeTitle( $data->page_namespace, $data->page_title );
if( !$this->mDataLoaded ) {
$data = $this->pageDataFromTitle( $dbr, $this->mTitle );
if( !$data ) {
- wfDebug( "$fname failed to find page data for title " . $this->mTitle->getPrefixedText() . "\n" );
+ wfDebug( __METHOD__." failed to find page data for title " . $this->mTitle->getPrefixedText() . "\n" );
return false;
}
$this->loadPageData( $data );
}
$revision = Revision::newFromId( $this->mLatest );
if( is_null( $revision ) ) {
- wfDebug( "$fname failed to retrieve current page, rev_id $data->page_latest\n" );
+ wfDebug( __METHOD__." failed to retrieve current page, rev_id {$data->page_latest}\n" );
return false;
}
}
- $this->mContent = $revision->getText();
+ // FIXME: Horrible, horrible! This content-loading interface just plain sucks.
+ // We should instead work with the Revision object when we need it...
+ $this->mContent = $revision->userCan( Revision::DELETED_TEXT ) ? $revision->getRawText() : "";
+ //$this->mContent = $revision->getText();
$this->mUser = $revision->getUser();
$this->mUserText = $revision->getUserText();
/**
* Read/write accessor to select FOR UPDATE
*
- * @param mixed $x
+ * @param $x Mixed: FIXME
*/
function forUpdate( $x = NULL ) {
return wfSetVar( $this->mForUpdate, $x );
/**
* Get options for all SELECT statements
*
- * @param array $options an optional options array which'll be appended to
+ * @param $options Array: an optional options array which'll be appended to
* the default
- * @return array Options
+ * @return Array: options
*/
function getSelectOptions( $options = '' ) {
if ( $this->mForUpdate ) {
function getCount() {
if ( -1 == $this->mCounter ) {
$id = $this->getID();
- $dbr =& wfGetDB( DB_SLAVE );
- $this->mCounter = $dbr->selectField( 'page', 'page_counter', array( 'page_id' => $id ),
- 'Article::getCount', $this->getSelectOptions() );
+ if ( $id == 0 ) {
+ $this->mCounter = 0;
+ } else {
+ $dbr =& wfGetDB( DB_SLAVE );
+ $this->mCounter = $dbr->selectField( 'page', 'page_counter', array( 'page_id' => $id ),
+ 'Article::getCount', $this->getSelectOptions() );
+ }
}
return $this->mCounter;
}
* Determine whether a page would be suitable for being counted as an
* article in the site_stats table based on the title & its content
*
- * @param string $text Text to analyze
+ * @param $text String: text to analyze
* @return bool
*/
function isCountable( $text ) {
- global $wgUseCommaCount;
+ global $wgUseCommaCount, $wgContentNamespaces;
$token = $wgUseCommaCount ? ',' : '[[';
return
- $this->mTitle->getNamespace() == NS_MAIN
+ array_search( $this->mTitle->getNamespace(), $wgContentNamespaces ) !== false
&& ! $this->isRedirect( $text )
&& in_string( $token, $text );
}
/**
* Tests if the article text represents a redirect
*
- * @param string $text
+ * @param $text String: FIXME
* @return bool
*/
function isRedirect( $text = false ) {
/**
* Loads everything except the text
* This isn't necessary for all uses, so it's only done if needed.
- * @access private
+ * @private
*/
function loadLastEdit() {
if ( -1 != $this->mUser )
}
function getTimestamp() {
- $this->loadLastEdit();
+ // Check if the field has been filled by ParserCache::get()
+ if ( !$this->mTimestamp ) {
+ $this->loadLastEdit();
+ }
return wfTimestamp(TS_MW, $this->mTimestamp);
}
return $this->mRevIdFetched;
}
+ /**
+ * @todo Document, fixme $offset never used.
+ * @param $limit Integer: default 0.
+ * @param $offset Integer: default 0.
+ */
function getContributors($limit = 0, $offset = 0) {
- $fname = 'Article::getContributors';
-
# XXX: this is expensive; cache this info somewhere.
$title = $this->mTitle;
if ($limit > 0) { $sql .= ' LIMIT '.$limit; }
$sql .= ' '. $this->getSelectOptions();
- $res = $dbr->query($sql, $fname);
+ $res = $dbr->query($sql, __METHOD__);
while ( $line = $dbr->fetchObject( $res ) ) {
$contribs[] = array($line->rev_user, $line->rev_user_text, $line->user_real_name);
* the given title.
*/
function view() {
- global $wgUser, $wgOut, $wgRequest, $wgOnlySysopsCanPatrol, $wgContLang;
+ global $wgUser, $wgOut, $wgRequest, $wgContLang;
global $wgEnableParserCache, $wgStylePath, $wgUseRCPatrol, $wgParser;
- global $wgUseTrackbacks;
+ global $wgUseTrackbacks, $wgNamespaceRobotPolicies;
$sk = $wgUser->getSkin();
- $fname = 'Article::view';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
+
$parserCache =& ParserCache::singleton();
+ $ns = $this->mTitle->getNamespace(); # shortcut
+
# Get variables from query string
$oldid = $this->getOldID();
# getOldID may want us to redirect somewhere else
if ( $this->mRedirectUrl ) {
$wgOut->redirect( $this->mRedirectUrl );
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return;
}
$rdfrom = $wgRequest->getVal( 'rdfrom' );
$wgOut->setArticleFlag( true );
- $wgOut->setRobotpolicy( 'index,follow' );
+ if ( isset( $wgNamespaceRobotPolicies[$ns] ) ) {
+ $policy = $wgNamespaceRobotPolicies[$ns];
+ } else {
+ $policy = 'index,follow';
+ }
+ $wgOut->setRobotpolicy( $policy );
+
# If we got diff and oldid in the query, we want to see a
# diff page instead of the article.
if ( !is_null( $diff ) ) {
- require_once( 'DifferenceEngine.php' );
$wgOut->setPageTitle( $this->mTitle->getPrefixedText() );
$de = new DifferenceEngine( $this->mTitle, $oldid, $diff, $rcid );
// DifferenceEngine directly fetched the revision:
$this->mRevIdFetched = $de->mNewid;
$de->showDiffPage();
-
- if( $diff == 0 ) {
+
+ // Needed to get the page's current revision
+ $this->loadPageData();
+ if( $diff == 0 || $diff == $this->mLatest ) {
# Run view updates for current revision only
$this->viewUpdates();
}
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return;
}
-
+
if ( empty( $oldid ) && $this->checkTouched() ) {
$wgOut->setETag($parserCache->getETag($this, $wgUser));
if( $wgOut->checkLastModified( $this->mTouched ) ){
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return;
} else if ( $this->tryFileCache() ) {
# tell wgOut that output is taken care of
$wgOut->disable();
$this->viewUpdates();
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return;
}
}
+
# Should the parser cache be used?
$pcache = $wgEnableParserCache &&
intval( $wgUser->getOption( 'stubthreshold' ) ) == 0 &&
$outputDone = false;
if ( $pcache ) {
if ( $wgOut->tryParserCache( $this, $wgUser ) ) {
+ wfRunHooks( 'ArticleViewHeader', array( &$this ) );
$outputDone = true;
}
}
# We're looking at an old revision
if ( !empty( $oldid ) ) {
- $this->setOldSubtitle( isset($this->mOldId) ? $this->mOldId : $oldid );
- $wgOut->setRobotpolicy( 'noindex,follow' );
+ $wgOut->setRobotpolicy( 'noindex,nofollow' );
+ if( is_null( $this->mRevision ) ) {
+ // FIXME: This would be a nice place to load the 'no such page' text.
+ } else {
+ $this->setOldSubtitle( isset($this->mOldId) ? $this->mOldId : $oldid );
+ if( $this->mRevision->isDeleted( Revision::DELETED_TEXT ) ) {
+ if( !$this->mRevision->userCan( Revision::DELETED_TEXT ) ) {
+ $wgOut->addWikiText( wfMsg( 'rev-deleted-text-permission' ) );
+ $wgOut->setPageTitle( $this->mTitle->getPrefixedText() );
+ return;
+ } else {
+ $wgOut->addWikiText( wfMsg( 'rev-deleted-text-view' ) );
+ // and we are allowed to see...
+ }
+ }
+ }
+
}
}
if( !$outputDone ) {
# wrap user css and user js in pre and don't parse
# XXX: use $this->mTitle->usCssJsSubpage() when php is fixed/ a workaround is found
if (
- $this->mTitle->getNamespace() == NS_USER &&
+ $ns == NS_USER &&
preg_match('/\\/[\\w]+\\.(css|js)$/', $this->mTitle->getDBkey())
) {
$wgOut->addWikiText( wfMsg('clearyourcache'));
# Display redirect
$imageDir = $wgContLang->isRTL() ? 'rtl' : 'ltr';
$imageUrl = $wgStylePath.'/common/images/redirect' . $imageDir . '.png';
- if( !$wasRedirected ) {
+ # Don't overwrite the subtitle if this was an old revision
+ if( !$wasRedirected && $this->isCurrent() ) {
$wgOut->setSubtitle( wfMsgHtml( 'redirectpagesub' ) );
}
$targetUrl = $rt->escapeLocalURL();
+ # fixme unused $titleText :
$titleText = htmlspecialchars( $rt->getPrefixedText() );
$link = $sk->makeLinkObj( $rt );
$wgOut->addPrimaryWikiText( $text, $this );
} else {
# Display content, don't attempt to save to parser cache
-
# Don't show section-edit links on old revisions... this way lies madness.
if( !$this->isCurrent() ) {
- $oldEditSectionSetting = $wgOut->mParserOptions->setEditSection( false );
+ $oldEditSectionSetting = $wgOut->parserOptions()->setEditSection( false );
}
# Display content and don't save to parser cache
$wgOut->addPrimaryWikiText( $text, $this, false );
if( !$this->isCurrent() ) {
- $wgOut->mParserOptions->setEditSection( $oldEditSectionSetting );
+ $wgOut->parserOptions()->setEditSection( $oldEditSectionSetting );
}
}
}
$wgOut->setPageTitle( $this->mTitle->getPrefixedText() );
}
+ # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
+ if( $ns == NS_USER_TALK &&
+ User::isIP( $this->mTitle->getText() ) ) {
+ $wgOut->addWikiText( wfMsg('anontalkpagetext') );
+ }
+
# If we have been passed an &rcid= parameter, we want to give the user a
# chance to mark this new article as patrolled.
- if ( $wgUseRCPatrol
- && !is_null($rcid)
- && $rcid != 0
- && $wgUser->isLoggedIn()
- && ( $wgUser->isAllowed('patrol') || !$wgOnlySysopsCanPatrol ) )
- {
+ if ( $wgUseRCPatrol && !is_null( $rcid ) && $rcid != 0 && $wgUser->isAllowed( 'patrol' ) ) {
$wgOut->addHTML(
"<div class='patrollink'>" .
wfMsg ( 'markaspatrolledlink',
$this->addTrackbacks();
$this->viewUpdates();
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
}
function addTrackbacks() {
$tbtext = "";
while ($o = $dbr->fetchObject($tbs)) {
$rmvtxt = "";
- if ($wgUser->isSysop()) {
+ if ($wgUser->isAllowed( 'trackback' )) {
$delurl = $this->mTitle->getFullURL("action=deletetrackback&tbid="
. $o->tb_id . "&token=" . $wgUser->editToken());
$rmvtxt = wfMsg('trackbackremove', $delurl);
}
if ((!$wgUser->isAllowed('delete'))) {
- $wgOut->sysopRequired();
+ $wgOut->permissionRequired( 'delete' );
return;
}
* @param Database $dbw
* @param string $restrictions
* @return int The newly created page_id key
- * @access private
+ * @private
*/
function insertOn( &$dbw, $restrictions = '' ) {
- $fname = 'Article::insertOn';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
$page_id = $dbw->nextSequenceValue( 'page_page_id_seq' );
$dbw->insert( 'page', array(
'page_touched' => $dbw->timestamp(),
'page_latest' => 0, # Fill this in shortly...
'page_len' => 0, # Fill this in shortly...
- ), $fname );
+ ), __METHOD__ );
$newid = $dbw->insertId();
$this->mTitle->resetArticleId( $newid );
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return $newid;
}
* Giving 0 indicates the new page flag should
* be set on.
* @return bool true on success, false on failure
- * @access private
+ * @private
*/
function updateRevisionOn( &$dbw, $revision, $lastRevision = null ) {
- $fname = 'Article::updateToRevision';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
$conditions = array( 'page_id' => $this->getId() );
if( !is_null( $lastRevision ) ) {
'page_len' => strlen( $text ),
),
$conditions,
- $fname );
+ __METHOD__ );
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return ( $dbw->affectedRows() != 0 );
}
* @param Revision $revision
*/
function updateIfNewerOn( &$dbw, $revision ) {
- $fname = 'Article::updateIfNewerOn';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
$row = $dbw->selectRow(
array( 'revision', 'page' ),
array(
'page_id' => $this->getId(),
'page_latest=rev_id' ),
- $fname );
+ __METHOD__ );
if( $row ) {
if( wfTimestamp(TS_MW, $row->rev_timestamp) >= $revision->getTimestamp() ) {
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return false;
}
$prev = $row->rev_id;
}
$ret = $this->updateRevisionOn( $dbw, $revision, $prev );
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return $ret;
}
- /**
- * Insert a new article into the database
- * @access private
- */
- function insertNewArticle( $text, $summary, $isminor, $watchthis, $suppressRC=false, $comment=false ) {
- global $wgUser;
-
- $fname = 'Article::insertNewArticle';
- wfProfileIn( $fname );
-
- if( !wfRunHooks( 'ArticleSave', array( &$this, &$wgUser, &$text,
- &$summary, &$isminor, &$watchthis, NULL ) ) ) {
- wfDebug( "$fname: ArticleSave hook aborted save!\n" );
- wfProfileOut( $fname );
- return false;
- }
-
- $this->mGoodAdjustment = (int)$this->isCountable( $text );
- $this->mTotalAdjustment = 1;
-
- $ns = $this->mTitle->getNamespace();
- $ttl = $this->mTitle->getDBkey();
-
- # If this is a comment, add the summary as headline
- if($comment && $summary!="") {
- $text="== {$summary} ==\n\n".$text;
- }
- $text = $this->preSaveTransform( $text );
-
- /* Silently ignore minoredit if not allowed */
- $isminor = $isminor && $wgUser->isAllowed('minoredit');
- $now = wfTimestampNow();
-
- $dbw =& wfGetDB( DB_MASTER );
-
- # Add the page record; stake our claim on this title!
- $newid = $this->insertOn( $dbw );
-
- # Save the revision text...
- $revision = new Revision( array(
- 'page' => $newid,
- 'comment' => $summary,
- 'minor_edit' => $isminor,
- 'text' => $text
- ) );
- $revisionId = $revision->insertOn( $dbw );
-
- $this->mTitle->resetArticleID( $newid );
-
- # Update the page record with revision data
- $this->updateRevisionOn( $dbw, $revision, 0 );
-
- Article::onArticleCreate( $this->mTitle );
- if(!$suppressRC) {
- require_once( 'RecentChange.php' );
- RecentChange::notifyNew( $now, $this->mTitle, $isminor, $wgUser, $summary, 'default',
- '', strlen( $text ), $revisionId );
- }
-
- if ($watchthis) {
- if(!$this->mTitle->userIsWatching()) $this->doWatch();
- } else {
- if ( $this->mTitle->userIsWatching() ) {
- $this->doUnwatch();
- }
- }
-
- # The talk page isn't in the regular link tables, so we need to update manually:
- $talkns = $ns ^ 1; # talk -> normal; normal -> talk
- $dbw->update( 'page',
- array( 'page_touched' => $dbw->timestamp($now) ),
- array( 'page_namespace' => $talkns,
- 'page_title' => $ttl ),
- $fname );
-
- # standard deferred updates
- $this->editUpdates( $text, $summary, $isminor, $now, $revisionId );
-
- $oldid = 0; # new article
- $this->showArticle( $text, wfMsg( 'newarticle' ), false, $isminor, $now, $summary, $oldid );
-
- wfRunHooks( 'ArticleInsertComplete', array( &$this, &$wgUser, $text,
- $summary, $isminor,
- $watchthis, NULL ) );
- wfRunHooks( 'ArticleSaveComplete', array( &$this, &$wgUser, $text,
- $summary, $isminor,
- $watchthis, NULL ) );
- wfProfileOut( $fname );
- }
-
- function getTextOfLastEditWithSectionReplacedOrAdded($section, $text, $summary = '', $edittime = NULL) {
- $this->replaceSection( $section, $text, $summary, $edittime );
- }
-
/**
* @return string Complete article text, or null if error
*/
function replaceSection($section, $text, $summary = '', $edittime = NULL) {
- $fname = 'Article::replaceSection';
- wfProfileIn( $fname );
-
- if ($section != '') {
+ wfProfileIn( __METHOD__ );
+
+ if( $section == '' ) {
+ // Whole-page edit; let the text through unmolested.
+ } else {
if( is_null( $edittime ) ) {
$rev = Revision::newFromTitle( $this->mTitle );
} else {
if($summary) $subject="== {$summary} ==\n\n";
$text=$oldtext."\n\n".$subject.$text;
} else {
+ global $wgParser;
+ $text = $wgParser->replaceSection( $oldtext, $section, $text );
+ }
+ }
- # strip NOWIKI etc. to avoid confusion (true-parameter causes HTML
- # comments to be stripped as well)
- $striparray=array();
- $parser=new Parser();
- $parser->mOutputType=OT_WIKI;
- $parser->mOptions = new ParserOptions();
- $oldtext=$parser->strip($oldtext, $striparray, true);
-
- # now that we can be sure that no pseudo-sections are in the source,
- # split it up
- # Unfortunately we can't simply do a preg_replace because that might
- # replace the wrong section, so we have to use the section counter instead
- $secs=preg_split('/(^=+.+?=+|^<h[1-6].*?>.*?<\/h[1-6].*?>)(?!\S)/mi',
- $oldtext,-1,PREG_SPLIT_DELIM_CAPTURE);
- $secs[$section*2]=$text."\n\n"; // replace with edited
-
- # section 0 is top (intro) section
- if($section!=0) {
-
- # headline of old section - we need to go through this section
- # to determine if there are any subsections that now need to
- # be erased, as the mother section has been replaced with
- # the text of all subsections.
- $headline=$secs[$section*2-1];
- preg_match( '/^(=+).+?=+|^<h([1-6]).*?>.*?<\/h[1-6].*?>(?!\S)/mi',$headline,$matches);
- $hlevel=$matches[1];
-
- # determine headline level for wikimarkup headings
- if(strpos($hlevel,'=')!==false) {
- $hlevel=strlen($hlevel);
- }
+ wfProfileOut( __METHOD__ );
+ return $text;
+ }
- $secs[$section*2-1]=''; // erase old headline
- $count=$section+1;
- $break=false;
- while(!empty($secs[$count*2-1]) && !$break) {
-
- $subheadline=$secs[$count*2-1];
- preg_match(
- '/^(=+).+?=+|^<h([1-6]).*?>.*?<\/h[1-6].*?>(?!\S)/mi',$subheadline,$matches);
- $subhlevel=$matches[1];
- if(strpos($subhlevel,'=')!==false) {
- $subhlevel=strlen($subhlevel);
- }
- if($subhlevel > $hlevel) {
- // erase old subsections
- $secs[$count*2-1]='';
- $secs[$count*2]='';
- }
- if($subhlevel <= $hlevel) {
- $break=true;
- }
- $count++;
+ /**
+ * @deprecated use Article::doEdit()
+ */
+ function insertNewArticle( $text, $summary, $isminor, $watchthis, $suppressRC=false, $comment=false ) {
+ $flags = EDIT_NEW | EDIT_DEFER_UPDATES |
+ ( $isminor ? EDIT_MINOR : 0 ) |
+ ( $suppressRC ? EDIT_SUPPRESS_RC : 0 );
- }
+ # If this is a comment, add the summary as headline
+ if ( $comment && $summary != "" ) {
+ $text = "== {$summary} ==\n\n".$text;
+ }
+
+ $this->doEdit( $text, $summary, $flags );
+
+ $dbw =& wfGetDB( DB_MASTER );
+ if ($watchthis) {
+ if (!$this->mTitle->userIsWatching()) {
+ $dbw->begin();
+ $this->doWatch();
+ $dbw->commit();
+ }
+ } else {
+ if ( $this->mTitle->userIsWatching() ) {
+ $dbw->begin();
+ $this->doUnwatch();
+ $dbw->commit();
+ }
+ }
+ $this->doRedirect( $this->isRedirect( $text ) );
+ }
+ /**
+ * @deprecated use Article::doEdit()
+ */
+ function updateArticle( $text, $summary, $minor, $watchthis, $forceBot = false, $sectionanchor = '' ) {
+ $flags = EDIT_UPDATE | EDIT_DEFER_UPDATES |
+ ( $minor ? EDIT_MINOR : 0 ) |
+ ( $forceBot ? EDIT_FORCE_BOT : 0 );
+
+ $good = $this->doEdit( $text, $summary, $flags );
+ if ( $good ) {
+ $dbw =& wfGetDB( DB_MASTER );
+ if ($watchthis) {
+ if (!$this->mTitle->userIsWatching()) {
+ $dbw->begin();
+ $this->doWatch();
+ $dbw->commit();
+ }
+ } else {
+ if ( $this->mTitle->userIsWatching() ) {
+ $dbw->begin();
+ $this->doUnwatch();
+ $dbw->commit();
}
- $text=join('',$secs);
- # reinsert the stuff that we stripped out earlier
- $text=$parser->unstrip($text,$striparray);
- $text=$parser->unstripNoWiki($text,$striparray);
}
+ $this->doRedirect( $this->isRedirect( $text ), $sectionanchor );
}
- wfProfileOut( $fname );
- return $text;
+ return $good;
}
/**
- * Change an existing article. Puts the previous version back into the old table, updates RC
- * and all necessary caches, mostly via the deferred update array.
+ * Article::doEdit()
*
- * It is possible to call this function from a command-line script, but note that you should
- * first set $wgUser, and clean up $wgDeferredUpdates after each edit.
+ * Change an existing article or create a new article. Updates RC and all necessary caches,
+ * optionally via the deferred update array.
+ *
+ * $wgUser must be set before calling this function.
+ *
+ * @param string $text New text
+ * @param string $summary Edit summary
+ * @param integer $flags bitfield:
+ * EDIT_NEW
+ * Article is known or assumed to be non-existent, create a new one
+ * EDIT_UPDATE
+ * Article is known or assumed to be pre-existing, update it
+ * EDIT_MINOR
+ * Mark this edit minor, if the user is allowed to do so
+ * EDIT_SUPPRESS_RC
+ * Do not log the change in recentchanges
+ * EDIT_FORCE_BOT
+ * Mark the edit a "bot" edit regardless of user rights
+ * EDIT_DEFER_UPDATES
+ * Defer some of the updates until the end of index.php
+ *
+ * If neither EDIT_NEW nor EDIT_UPDATE is specified, the status of the article will be detected.
+ * If EDIT_UPDATE is specified and the article doesn't exist, the function will return false. If
+ * EDIT_NEW is specified and the article does exist, a duplicate key error will cause an exception
+ * to be thrown from the Database. These two conditions are also possible with auto-detection due
+ * to MediaWiki's performance-optimised locking strategy.
+ *
+ * @return bool success
*/
- function updateArticle( $text, $summary, $minor, $watchthis, $forceBot = false, $sectionanchor = '' ) {
- global $wgUser, $wgDBtransactions, $wgUseSquid;
- global $wgPostCommitUpdateList, $wgUseFileCache;
+ function doEdit( $text, $summary, $flags = 0 ) {
+ global $wgUser, $wgDBtransactions;
- $fname = 'Article::updateArticle';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
$good = true;
+ if ( !($flags & EDIT_NEW) && !($flags & EDIT_UPDATE) ) {
+ $aid = $this->mTitle->getArticleID( GAID_FOR_UPDATE );
+ if ( $aid ) {
+ $flags |= EDIT_UPDATE;
+ } else {
+ $flags |= EDIT_NEW;
+ }
+ }
+
if( !wfRunHooks( 'ArticleSave', array( &$this, &$wgUser, &$text,
- &$summary, &$minor,
- &$watchthis, &$sectionanchor ) ) ) {
- wfDebug( "$fname: ArticleSave hook aborted save!\n" );
- wfProfileOut( $fname );
+ &$summary, $flags & EDIT_MINOR,
+ null, null, &$flags ) ) )
+ {
+ wfDebug( __METHOD__ . ": ArticleSave hook aborted save!\n" );
+ wfProfileOut( __METHOD__ );
return false;
}
- $isminor = $minor && $wgUser->isAllowed('minoredit');
- $redir = (int)$this->isRedirect( $text );
+ # Silently ignore EDIT_MINOR if not allowed
+ $isminor = ( $flags & EDIT_MINOR ) && $wgUser->isAllowed('minoredit');
+ $bot = $wgUser->isAllowed( 'bot' ) || ( $flags & EDIT_FORCE_BOT );
$text = $this->preSaveTransform( $text );
+
$dbw =& wfGetDB( DB_MASTER );
$now = wfTimestampNow();
+
+ if ( $flags & EDIT_UPDATE ) {
+ # Update article, but only if changed.
- # Update article, but only if changed.
+ # Make sure the revision is either completely inserted or not inserted at all
+ if( !$wgDBtransactions ) {
+ $userAbort = ignore_user_abort( true );
+ }
- # It's important that we either rollback or complete, otherwise an attacker could
- # overwrite cur entries by sending precisely timed user aborts. Random bored users
- # could conceivably have the same effect, especially if cur is locked for long periods.
- if( !$wgDBtransactions ) {
- $userAbort = ignore_user_abort( true );
- }
+ $oldtext = $this->getContent();
+ $oldsize = strlen( $oldtext );
+ $newsize = strlen( $text );
+ $lastRevision = 0;
+ $revisionId = 0;
+
+ if ( 0 != strcmp( $text, $oldtext ) ) {
+ $this->mGoodAdjustment = (int)$this->isCountable( $text )
+ - (int)$this->isCountable( $oldtext );
+ $this->mTotalAdjustment = 0;
+
+ $lastRevision = $dbw->selectField(
+ 'page', 'page_latest', array( 'page_id' => $this->getId() ) );
+
+ if ( !$lastRevision ) {
+ # Article gone missing
+ wfDebug( __METHOD__.": EDIT_UPDATE specified but article doesn't exist\n" );
+ wfProfileOut( __METHOD__ );
+ return false;
+ }
+
+ $revision = new Revision( array(
+ 'page' => $this->getId(),
+ 'comment' => $summary,
+ 'minor_edit' => $isminor,
+ 'text' => $text
+ ) );
+
+ $dbw->begin();
+ $revisionId = $revision->insertOn( $dbw );
+
+ # Update page
+ $ok = $this->updateRevisionOn( $dbw, $revision, $lastRevision );
+
+ if( !$ok ) {
+ /* Belated edit conflict! Run away!! */
+ $good = false;
+ $dbw->rollback();
+ } else {
+ # Update recentchanges
+ if( !( $flags & EDIT_SUPPRESS_RC ) ) {
+ $rcid = RecentChange::notifyEdit( $now, $this->mTitle, $isminor, $wgUser, $summary,
+ $lastRevision, $this->getTimestamp(), $bot, '', $oldsize, $newsize,
+ $revisionId );
+
+ # Mark as patrolled if the user can do so and has it set in their options
+ if( $wgUser->isAllowed( 'patrol' ) && $wgUser->getOption( 'autopatrol' ) ) {
+ RecentChange::markPatrolled( $rcid );
+ }
+ }
+ $dbw->commit();
+ }
+ } else {
+ // Keep the same revision ID, but do some updates on it
+ $revisionId = $this->getRevIdFetched();
+ // Update page_touched, this is usually implicit in the page update
+ // Other cache updates are done in onArticleEdit()
+ $this->mTitle->invalidateCache();
+ }
- $oldtext = $this->getContent();
- $oldsize = strlen( $oldtext );
- $newsize = strlen( $text );
- $lastRevision = 0;
- $revisionId = 0;
+ if( !$wgDBtransactions ) {
+ ignore_user_abort( $userAbort );
+ }
- if ( 0 != strcmp( $text, $oldtext ) ) {
- $this->mGoodAdjustment = (int)$this->isCountable( $text )
- - (int)$this->isCountable( $oldtext );
- $this->mTotalAdjustment = 0;
- $now = wfTimestampNow();
+ if ( $good ) {
+ # Invalidate cache of this article and all pages using this article
+ # as a template. Partly deferred.
+ Article::onArticleEdit( $this->mTitle );
+
+ # Update links tables, site stats, etc.
+ $changed = ( strcmp( $oldtext, $text ) != 0 );
+ $this->editUpdates( $text, $summary, $isminor, $now, $revisionId, $changed );
+ }
+ } else {
+ # Create new article
+
+ # Set statistics members
+ # We work out if it's countable after PST to avoid counter drift
+ # when articles are created with {{subst:}}
+ $this->mGoodAdjustment = (int)$this->isCountable( $text );
+ $this->mTotalAdjustment = 1;
+
+ $dbw->begin();
- $lastRevision = $dbw->selectField(
- 'page', 'page_latest', array( 'page_id' => $this->getId() ) );
+ # Add the page record; stake our claim on this title!
+ # This will fail with a database query exception if the article already exists
+ $newid = $this->insertOn( $dbw );
+ # Save the revision text...
$revision = new Revision( array(
- 'page' => $this->getId(),
+ 'page' => $newid,
'comment' => $summary,
'minor_edit' => $isminor,
'text' => $text
) );
-
- $dbw->immediateCommit();
- $dbw->begin();
$revisionId = $revision->insertOn( $dbw );
- # Update page
- $ok = $this->updateRevisionOn( $dbw, $revision, $lastRevision );
+ $this->mTitle->resetArticleID( $newid );
- if( !$ok ) {
- /* Belated edit conflict! Run away!! */
- $good = false;
- $dbw->rollback();
- } else {
- # Update recentchanges and purge cache and whatnot
- require_once( 'RecentChange.php' );
- $bot = (int)($wgUser->isBot() || $forceBot);
- RecentChange::notifyEdit( $now, $this->mTitle, $isminor, $wgUser, $summary,
- $lastRevision, $this->getTimestamp(), $bot, '', $oldsize, $newsize,
- $revisionId );
- $dbw->commit();
+ # Update the page record with revision data
+ $this->updateRevisionOn( $dbw, $revision, 0 );
- // Update caches outside the main transaction
- Article::onArticleEdit( $this->mTitle );
- }
- } else {
- // Keep the same revision ID, but do some updates on it
- $revisionId = $this->getRevIdFetched();
- }
-
- if( !$wgDBtransactions ) {
- ignore_user_abort( $userAbort );
- }
-
- if ( $good ) {
- if ($watchthis) {
- if (!$this->mTitle->userIsWatching()) {
- $dbw->immediateCommit();
- $dbw->begin();
- $this->doWatch();
- $dbw->commit();
- }
- } else {
- if ( $this->mTitle->userIsWatching() ) {
- $dbw->immediateCommit();
- $dbw->begin();
- $this->doUnwatch();
- $dbw->commit();
+ if( !( $flags & EDIT_SUPPRESS_RC ) ) {
+ $rcid = RecentChange::notifyNew( $now, $this->mTitle, $isminor, $wgUser, $summary, $bot,
+ '', strlen( $text ), $revisionId );
+ # Mark as patrolled if the user can and has the option set
+ if( $wgUser->isAllowed( 'patrol' ) && $wgUser->getOption( 'autopatrol' ) ) {
+ RecentChange::markPatrolled( $rcid );
}
}
- # standard deferred updates
- $this->editUpdates( $text, $summary, $minor, $now, $revisionId );
+ $dbw->commit();
+ # Update links, etc.
+ $this->editUpdates( $text, $summary, $isminor, $now, $revisionId, true );
- $urls = array();
- # Invalidate caches of all articles using this article as a template
+ # Clear caches
+ Article::onArticleCreate( $this->mTitle );
- # Template namespace
- # Purge all articles linking here
- $titles = $this->mTitle->getTemplateLinksTo();
- Title::touchArray( $titles );
- if ( $wgUseSquid ) {
- foreach ( $titles as $title ) {
- $urls[] = $title->getInternalURL();
- }
- }
-
- # Squid updates
- if ( $wgUseSquid ) {
- $urls = array_merge( $urls, $this->mTitle->getSquidURLs() );
- $u = new SquidUpdate( $urls );
- array_push( $wgPostCommitUpdateList, $u );
- }
-
- # File cache
- if ( $wgUseFileCache ) {
- $cm = new CacheManager($this->mTitle);
- @unlink($cm->fileCacheName());
- }
+ wfRunHooks( 'ArticleInsertComplete', array( &$this, &$wgUser, $text,
+ $summary, $flags & EDIT_MINOR,
+ null, null, &$flags ) );
+ }
- $this->showArticle( $text, wfMsg( 'updated' ), $sectionanchor, $isminor, $now, $summary, $lastRevision );
+ if ( $good && !( $flags & EDIT_DEFER_UPDATES ) ) {
+ wfDoUpdates();
}
+
wfRunHooks( 'ArticleSaveComplete',
array( &$this, &$wgUser, $text,
- $summary, $minor,
- $watchthis, $sectionanchor ) );
- wfProfileOut( $fname );
+ $summary, $flags & EDIT_MINOR,
+ null, null, &$flags ) );
+
+ wfProfileOut( __METHOD__ );
return $good;
}
/**
- * After we've either updated or inserted the article, update
- * the link tables and redirect to the new page.
+ * @deprecated wrapper for doRedirect
*/
function showArticle( $text, $subtitle , $sectionanchor = '', $me2, $now, $summary, $oldid ) {
- global $wgOut;
-
- $fname = 'Article::showArticle';
- wfProfileIn( $fname );
-
- # Output the redirect
- if( $this->isRedirect( $text ) )
- $r = 'redirect=no';
- else
- $r = '';
- $wgOut->redirect( $this->mTitle->getFullURL( $r ).$sectionanchor );
-
- wfProfileOut( $fname );
+ $this->doRedirect( $this->isRedirect( $text ), $sectionanchor );
}
+ /**
+ * Output a redirect back to the article.
+ * This is typically used after an edit.
+ *
+ * @param boolean $noRedir Add redirect=no
+ * @param string $sectionAnchor section to redirect to, including "#"
+ */
+ function doRedirect( $noRedir = false, $sectionAnchor = '' ) {
+ global $wgOut;
+ if ( $noRedir ) {
+ $query = 'redirect=no';
+ } else {
+ $query = '';
+ }
+ $wgOut->redirect( $this->mTitle->getFullURL( $query ) . $sectionAnchor );
+ }
+
/**
* Mark this particular edit as patrolled
*/
function markpatrolled() {
- global $wgOut, $wgRequest, $wgOnlySysopsCanPatrol, $wgUseRCPatrol, $wgUser;
- $wgOut->setRobotpolicy( 'noindex,follow' );
+ global $wgOut, $wgRequest, $wgUseRCPatrol, $wgUser;
+ $wgOut->setRobotpolicy( 'noindex,nofollow' );
# Check RC patrol config. option
if( !$wgUseRCPatrol ) {
}
# Check permissions
- if( $wgUser->isLoggedIn() ) {
- if( !$wgUser->isAllowed( 'patrol' ) ) {
- $wgOut->permissionRequired( 'patrol' );
- return;
- }
- } else {
- $wgOut->loginToUse();
+ if( !$wgUser->isAllowed( 'patrol' ) ) {
+ $wgOut->permissionRequired( 'patrol' );
return;
}
$rcid = $wgRequest->getVal( 'rcid' );
- if ( !is_null ( $rcid ) )
- {
- if( wfRunHooks( 'MarkPatrolled', array( &$rcid, &$wgUser, $wgOnlySysopsCanPatrol ) ) ) {
- require_once( 'RecentChange.php' );
+ if ( !is_null ( $rcid ) ) {
+ if( wfRunHooks( 'MarkPatrolled', array( &$rcid, &$wgUser, false ) ) ) {
RecentChange::markPatrolled( $rcid );
- wfRunHooks( 'MarkPatrolledComplete', array( &$rcid, &$wgUser, $wgOnlySysopsCanPatrol ) );
+ wfRunHooks( 'MarkPatrolledComplete', array( &$rcid, &$wgUser, false ) );
$wgOut->setPagetitle( wfMsg( 'markedaspatrolled' ) );
$wgOut->addWikiText( wfMsg( 'markedaspatrolledtext' ) );
}
$rcTitle = Title::makeTitle( NS_SPECIAL, 'Recentchanges' );
$wgOut->returnToMain( false, $rcTitle->getPrefixedText() );
}
- else
- {
- $wgOut->errorpage( 'markedaspatrollederror', 'markedaspatrollederrortext' );
+ else {
+ $wgOut->showErrorPage( 'markedaspatrollederror', 'markedaspatrollederrortext' );
}
}
global $wgUser, $wgOut;
if ( $wgUser->isAnon() ) {
- $wgOut->errorpage( 'watchnologin', 'watchnologintext' );
+ $wgOut->showErrorPage( 'watchnologin', 'watchnologintext' );
return;
}
if ( wfReadOnly() ) {
if( $this->doWatch() ) {
$wgOut->setPagetitle( wfMsg( 'addedwatch' ) );
- $wgOut->setRobotpolicy( 'noindex,follow' );
+ $wgOut->setRobotpolicy( 'noindex,nofollow' );
- $link = $this->mTitle->getPrefixedText();
+ $link = wfEscapeWikiText( $this->mTitle->getPrefixedText() );
$text = wfMsg( 'addedwatchtext', $link );
$wgOut->addWikiText( $text );
}
if (wfRunHooks('WatchArticle', array(&$wgUser, &$this))) {
$wgUser->addWatch( $this->mTitle );
- $wgUser->saveSettings();
return wfRunHooks('WatchArticleComplete', array(&$wgUser, &$this));
}
global $wgUser, $wgOut;
if ( $wgUser->isAnon() ) {
- $wgOut->errorpage( 'watchnologin', 'watchnologintext' );
+ $wgOut->showErrorPage( 'watchnologin', 'watchnologintext' );
return;
}
if ( wfReadOnly() ) {
if( $this->doUnwatch() ) {
$wgOut->setPagetitle( wfMsg( 'removedwatch' ) );
- $wgOut->setRobotpolicy( 'noindex,follow' );
+ $wgOut->setRobotpolicy( 'noindex,nofollow' );
- $link = $this->mTitle->getPrefixedText();
+ $link = wfEscapeWikiText( $this->mTitle->getPrefixedText() );
$text = wfMsg( 'removedwatchtext', $link );
$wgOut->addWikiText( $text );
}
if (wfRunHooks('UnwatchArticle', array(&$wgUser, &$this))) {
$wgUser->removeWatch( $this->mTitle );
- $wgUser->saveSettings();
return wfRunHooks('UnwatchArticleComplete', array(&$wgUser, &$this));
}
* action=protect handler
*/
function protect() {
- require_once 'ProtectionForm.php';
$form = new ProtectionForm( $this );
$form->show();
}
* @return bool true on success
*/
function updateRestrictions( $limit = array(), $reason = '' ) {
- global $wgUser;
-
- if ( !$wgUser->isAllowed( 'protect' ) ) {
- return false;
- }
-
- if( wfReadOnly() ) {
- return false;
- }
-
+ global $wgUser, $wgRestrictionTypes, $wgContLang;
+
$id = $this->mTitle->getArticleID();
- if ( 0 == $id ) {
+ if( !$wgUser->isAllowed( 'protect' ) || wfReadOnly() || $id == 0 ) {
return false;
}
- $flat = Article::flattenRestrictions( $limit );
- $protecting = ($flat != '');
-
- if( wfRunHooks( 'ArticleProtect', array( &$this, &$wgUser,
- $limit, $reason ) ) ) {
-
- $dbw =& wfGetDB( DB_MASTER );
- $dbw->update( 'page',
- array( /* SET */
- 'page_touched' => $dbw->timestamp(),
- 'page_restrictions' => $flat
- ), array( /* WHERE */
- 'page_id' => $id
- ), 'Article::protect'
- );
+ # FIXME: Same limitations as described in ProtectionForm.php (line 37);
+ # we expect a single selection, but the schema allows otherwise.
+ $current = array();
+ foreach( $wgRestrictionTypes as $action )
+ $current[$action] = implode( '', $this->mTitle->getRestrictions( $action ) );
- wfRunHooks( 'ArticleProtectComplete', array( &$this, &$wgUser,
- $limit, $reason ) );
+ $current = Article::flattenRestrictions( $current );
+ $updated = Article::flattenRestrictions( $limit );
+
+ $changed = ( $current != $updated );
+ $protect = ( $updated != '' );
+
+ # If nothing's changed, do nothing
+ if( $changed ) {
+ if( wfRunHooks( 'ArticleProtect', array( &$this, &$wgUser, $limit, $reason ) ) ) {
- $log = new LogPage( 'protect' );
- if( $protecting ) {
- $log->addEntry( 'protect', $this->mTitle, trim( $reason . " [$flat]" ) );
- } else {
- $log->addEntry( 'unprotect', $this->mTitle, $reason );
- }
- }
+ $dbw =& wfGetDB( DB_MASTER );
+
+ # Prepare a null revision to be added to the history
+ $comment = $wgContLang->ucfirst( wfMsgForContent( $protect ? 'protectedarticle' : 'unprotectedarticle', $this->mTitle->getPrefixedText() ) );
+ if( $reason )
+ $comment .= ": $reason";
+ if( $protect )
+ $comment .= " [$updated]";
+ $nullRevision = Revision::newNullRevision( $dbw, $id, $comment, true );
+ $nullRevId = $nullRevision->insertOn( $dbw );
+
+ # Update page record
+ $dbw->update( 'page',
+ array( /* SET */
+ 'page_touched' => $dbw->timestamp(),
+ 'page_restrictions' => $updated,
+ 'page_latest' => $nullRevId
+ ), array( /* WHERE */
+ 'page_id' => $id
+ ), 'Article::protect'
+ );
+ wfRunHooks( 'ArticleProtectComplete', array( &$this, &$wgUser, $limit, $reason ) );
+
+ # Update the protection log
+ $log = new LogPage( 'protect' );
+ if( $protect ) {
+ $log->addEntry( 'protect', $this->mTitle, trim( $reason . " [$updated]" ) );
+ } else {
+ $log->addEntry( 'unprotect', $this->mTitle, $reason );
+ }
+
+ } # End hook
+ } # End "changed" check
+
return true;
}
* suitable for insertion into the page_restrictions field.
* @param array $limit
* @return string
- * @access private
+ * @private
*/
function flattenRestrictions( $limit ) {
if( !is_array( $limit ) ) {
- wfDebugDieBacktrace( 'Article::flattenRestrictions given non-array restriction set' );
+ throw new MWException( 'Article::flattenRestrictions given non-array restriction set' );
}
$bits = array();
+ ksort( $limit );
foreach( $limit as $action => $restrictions ) {
if( $restrictions != '' ) {
$bits[] = "$action=$restrictions";
*/
function delete() {
global $wgUser, $wgOut, $wgRequest;
- $fname = 'Article::delete';
$confirm = $wgRequest->wasPosted() &&
$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) );
$reason = $wgRequest->getText( 'wpReason' );
# Check permissions
if( $wgUser->isAllowed( 'delete' ) ) {
- if( $wgUser->isBlocked() ) {
+ if( $wgUser->isBlocked( !$confirm ) ) {
$wgOut->blockedPage();
return;
}
# Better double-check that it hasn't been deleted yet!
$dbw =& wfGetDB( DB_MASTER );
$conds = $this->mTitle->pageCond();
- $latest = $dbw->selectField( 'page', 'page_latest', $conds, $fname );
+ $latest = $dbw->selectField( 'page', 'page_latest', $conds, __METHOD__ );
if ( $latest === false ) {
- $wgOut->fatalError( wfMsg( 'cannotdelete' ) );
+ $wgOut->showFatalError( wfMsg( 'cannotdelete' ) );
return;
}
if( count( $authors ) > 1 && !$confirm ) {
$skin=$wgUser->getSkin();
- $wgOut->addHTML('<b>'.wfMsg('historywarning'));
- $wgOut->addHTML( $skin->historyLink() .'</b>');
+ $wgOut->addHTML( '<strong>' . wfMsg( 'historywarning' ) . ' ' . $skin->historyLink() . '</strong>' );
}
# If a single user is responsible for all revisions, find out who they are
}
/**
- * Get the last N authors
+ * Get the last N authors
* @param int $num Number of revisions to get
* @param string $revLatest The latest rev_id, selected from the master (optional)
* @return array Array of authors, duplicates not removed
*/
function getLastNAuthors( $num, $revLatest = 0 ) {
- $fname = 'Article::getLastNAuthors';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
// First try the slave
// If that doesn't have the latest revision, try the master
'page_namespace' => $this->mTitle->getNamespace(),
'page_title' => $this->mTitle->getDBkey(),
'rev_page = page_id'
- ), $fname, $this->getSelectOptions( array(
+ ), __METHOD__, $this->getSelectOptions( array(
'ORDER BY' => 'rev_timestamp DESC',
'LIMIT' => $num
) )
);
if ( !$res ) {
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return array();
}
$row = $db->fetchObject( $res );
while ( $row = $db->fetchObject( $res ) ) {
$authors[] = $row->rev_user_text;
}
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return $authors;
}
*/
function doDelete( $reason ) {
global $wgOut, $wgUser;
- $fname = 'Article::doDelete';
- wfDebug( $fname."\n" );
+ wfDebug( __METHOD__."\n" );
if (wfRunHooks('ArticleDelete', array(&$this, &$wgUser, &$reason))) {
if ( $this->doDeleteArticle( $reason ) ) {
- $deleted = $this->mTitle->getPrefixedText();
+ $deleted = wfEscapeWikiText( $this->mTitle->getPrefixedText() );
$wgOut->setPagetitle( wfMsg( 'actioncomplete' ) );
$wgOut->setRobotpolicy( 'noindex,nofollow' );
$wgOut->returnToMain( false );
wfRunHooks('ArticleDeleteComplete', array(&$this, &$wgUser, $reason));
} else {
- $wgOut->fatalError( wfMsg( 'cannotdelete' ) );
+ $wgOut->showFatalError( wfMsg( 'cannotdelete' ) );
}
}
}
global $wgUseSquid, $wgDeferredUpdateList;
global $wgPostCommitUpdateList, $wgUseTrackbacks;
- $fname = 'Article::doDeleteArticle';
- wfDebug( $fname."\n" );
+ wfDebug( __METHOD__."\n" );
$dbw =& wfGetDB( DB_MASTER );
$ns = $this->mTitle->getNamespace();
$u = new SiteStatsUpdate( 0, 1, -(int)$this->isCountable( $this->getContent() ), -1 );
array_push( $wgDeferredUpdateList, $u );
- $linksTo = $this->mTitle->getLinksTo();
-
- # Squid purging
- if ( $wgUseSquid ) {
- $urls = array(
- $this->mTitle->getInternalURL(),
- $this->mTitle->getInternalURL( 'history' )
- );
-
- $u = SquidUpdate::newFromTitles( $linksTo, $urls );
- array_push( $wgPostCommitUpdateList, $u );
-
- }
-
- # Client and file cache invalidation
- Title::touchArray( $linksTo );
-
-
// For now, shunt the revision data into the archive table.
// Text is *not* removed from the text table; bulk storage
// is left intact to avoid breaking block-compression or
), array(
'page_id' => $id,
'page_id = rev_page'
- ), $fname
+ ), __METHOD__
);
# Now that it's safely backed up, delete it
- $dbw->delete( 'revision', array( 'rev_page' => $id ), $fname );
- $dbw->delete( 'page', array( 'page_id' => $id ), $fname);
+ $dbw->delete( 'page', array( 'page_id' => $id ), __METHOD__);
- if ($wgUseTrackbacks)
- $dbw->delete( 'trackbacks', array( 'tb_page' => $id ), $fname );
+ # If using cascading deletes, we can skip some explicit deletes
+ if ( !$dbw->cascadingDeletes() ) {
- # Clean up recentchanges entries...
- $dbw->delete( 'recentchanges', array( 'rc_namespace' => $ns, 'rc_title' => $t ), $fname );
+ $dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
- # Finally, clean up the link tables
- $t = $this->mTitle->getPrefixedDBkey();
+ if ($wgUseTrackbacks)
+ $dbw->delete( 'trackbacks', array( 'tb_page' => $id ), __METHOD__ );
- Article::onArticleDelete( $this->mTitle );
+ # Delete outgoing links
+ $dbw->delete( 'pagelinks', array( 'pl_from' => $id ) );
+ $dbw->delete( 'imagelinks', array( 'il_from' => $id ) );
+ $dbw->delete( 'categorylinks', array( 'cl_from' => $id ) );
+ $dbw->delete( 'templatelinks', array( 'tl_from' => $id ) );
+ $dbw->delete( 'externallinks', array( 'el_from' => $id ) );
+ $dbw->delete( 'langlinks', array( 'll_from' => $id ) );
+ }
+
+ # If using cleanup triggers, we can skip some manual deletes
+ if ( !$dbw->cleanupTriggers() ) {
- # Delete outgoing links
- $dbw->delete( 'pagelinks', array( 'pl_from' => $id ) );
- $dbw->delete( 'imagelinks', array( 'il_from' => $id ) );
- $dbw->delete( 'categorylinks', array( 'cl_from' => $id ) );
- $dbw->delete( 'templatelinks', array( 'tl_from' => $id ) );
- $dbw->delete( 'externallinks', array( 'el_from' => $id ) );
+ # Clean up recentchanges entries...
+ $dbw->delete( 'recentchanges', array( 'rc_namespace' => $ns, 'rc_title' => $t ), __METHOD__ );
+ }
+
+ # Clear caches
+ Article::onArticleDelete( $this->mTitle );
# Log the deletion
$log = new LogPage( 'delete' );
*/
function rollback() {
global $wgUser, $wgOut, $wgRequest, $wgUseRCPatrol;
- $fname = 'Article::rollback';
if( $wgUser->isAllowed( 'rollback' ) ) {
if( $wgUser->isBlocked() ) {
$tt = $this->mTitle->getDBKey();
$n = $this->mTitle->getNamespace();
- # Get the last editor, lock table exclusively
- $dbw->begin();
+ # Get the last editor
$current = Revision::newFromTitle( $this->mTitle );
if( is_null( $current ) ) {
# Something wrong... no page?
- $dbw->rollback();
$wgOut->addHTML( wfMsg( 'notanarticle' ) );
return;
}
array(
'rev_page' => $current->getPage(),
"rev_user <> {$user} OR rev_user_text <> {$user_text}"
- ), $fname,
+ ), __METHOD__,
array(
'USE INDEX' => 'page_timestamp',
'ORDER BY' => 'rev_timestamp DESC' )
);
if( $s === false ) {
# Something wrong
- $dbw->rollback();
$wgOut->setPageTitle(wfMsg('rollbackfailed'));
$wgOut->addHTML( wfMsg( 'cantrollback' ) );
return;
'rc_cur_id' => $current->getPage(),
'rc_user_text' => $current->getUserText(),
"rc_timestamp > '{$s->rev_timestamp}'",
- ), $fname
+ ), __METHOD__
);
}
$wgOut->addHTML( '<h2>' . htmlspecialchars( $newComment ) . "</h2>\n<hr />\n" );
$this->updateArticle( $target->getText(), $newComment, 1, $this->mTitle->userIsWatching(), $bot );
- Article::onArticleEdit( $this->mTitle );
- $dbw->commit();
$wgOut->returnToMain( false );
}
/**
* Do standard deferred updates after page view
- * @access private
+ * @private
*/
function viewUpdates() {
global $wgDeferredUpdateList;
/**
* Do standard deferred updates after page edit.
+ * Update links tables, site stats, search index and message cache.
* Every 1000th edit, prune the recent changes table.
- * @access private
- * @param string $text
- */
- function editUpdates( $text, $summary, $minoredit, $timestamp_of_pagechange, $newid) {
+ *
+ * @private
+ * @param $text New text of the article
+ * @param $summary Edit summary
+ * @param $minoredit Minor edit
+ * @param $timestamp_of_pagechange Timestamp associated with the page change
+ * @param $newid rev_id value of the new revision
+ * @param $changed Whether or not the content actually changed
+ */
+ function editUpdates( $text, $summary, $minoredit, $timestamp_of_pagechange, $newid, $changed = true ) {
global $wgDeferredUpdateList, $wgMessageCache, $wgUser, $wgParser;
- $fname = 'Article::editUpdates';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
# Parse the text
$options = new ParserOptions;
$shortTitle = $this->mTitle->getDBkey();
if ( 0 == $id ) {
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return;
}
array_push( $wgDeferredUpdateList, $u );
# If this is another user's talk page, update newtalk
-
- if ($this->mTitle->getNamespace() == NS_USER_TALK && $shortTitle != $wgUser->getName()) {
+ # Don't do this if $changed = false otherwise some idiot can null-edit a
+ # load of user talk pages and piss people off
+ if( $this->mTitle->getNamespace() == NS_USER_TALK && $shortTitle != $wgUser->getTitleKey() && $changed ) {
if (wfRunHooks('ArticleEditUpdateNewTalk', array(&$this)) ) {
$other = User::newFromName( $shortTitle );
if( is_null( $other ) && User::isIP( $shortTitle ) ) {
$wgMessageCache->replace( $shortTitle, $text );
}
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
+ }
+
+ /**
+ * Perform article updates on a special page creation.
+ *
+ * @param Revision $rev
+ *
+ * @fixme This is a shitty interface function. Kill it and replace the
+ * other shitty functions like editUpdates and such so it's not needed
+ * anymore.
+ */
+ function createUpdates( $rev ) {
+ $this->mGoodAdjustment = $this->isCountable( $rev->getText() );
+ $this->mTotalAdjustment = 1;
+ $this->editUpdates( $rev->getText(), $rev->getComment(),
+ $rev->isMinor(), wfTimestamp(), $rev->getId(), true );
}
/**
* Generate the navigation links when browsing through an article revisions
* It shows the information as:
- * Revision as of <date>; view current revision
- * <- Previous version | Next Version ->
+ * Revision as of \<date\>; view current revision
+ * \<- Previous version | Next Version -\>
*
- * @access private
+ * @private
* @param string $oldid Revision ID of this article revision
*/
function setOldSubtitle( $oldid=0 ) {
global $wgLang, $wgOut, $wgUser;
+ if ( !wfRunHooks( 'DisplayOldSubtitle', array(&$this, &$oldid) ) ) {
+ return;
+ }
+
+ $revision = Revision::newFromId( $oldid );
+
$current = ( $oldid == $this->mLatest );
$td = $wgLang->timeanddate( $this->mTimestamp, true );
$sk = $wgUser->getSkin();
$prevlink = $prev
? $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'previousrevision' ), 'direction=prev&oldid='.$oldid )
: wfMsg( 'previousrevision' );
+ $prevdiff = $prev
+ ? $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'diff' ), 'diff=prev&oldid='.$oldid )
+ : wfMsg( 'diff' );
$nextlink = $current
? wfMsg( 'nextrevision' )
: $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'nextrevision' ), 'direction=next&oldid='.$oldid );
- $r = wfMsg( 'revisionasofwithlink', $td, $lnk, $prevlink, $nextlink );
+ $nextdiff = $current
+ ? wfMsg( 'diff' )
+ : $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'diff' ), 'diff=next&oldid='.$oldid );
+
+ $userlinks = $sk->userLink( $revision->getUser(), $revision->getUserText() )
+ . $sk->userToolLinks( $revision->getUser(), $revision->getUserText() );
+
+ $r = wfMsg( 'old-revision-navigation', $td, $lnk, $prevlink, $nextlink, $userlinks, $prevdiff, $nextdiff );
$wgOut->setSubtitle( $r );
}
function tryFileCache() {
static $called = false;
if( $called ) {
- wfDebug( " tryFileCache() -- called twice!?\n" );
+ wfDebug( "Article::tryFileCache(): called twice!?\n" );
return;
}
$called = true;
$touched = $this->mTouched;
$cache = new CacheManager( $this->mTitle );
if($cache->isFileCacheGood( $touched )) {
- wfDebug( " tryFileCache() - about to load\n" );
+ wfDebug( "Article::tryFileCache(): about to load file\n" );
$cache->loadFromFileCache();
return true;
} else {
- wfDebug( " tryFileCache() - starting buffer\n" );
+ wfDebug( "Article::tryFileCache(): starting buffer\n" );
ob_start( array(&$cache, 'saveToFileCache' ) );
}
} else {
- wfDebug( " tryFileCache() - not cacheable\n" );
+ wfDebug( "Article::tryFileCache(): not cacheable\n" );
}
}
*
*/
function checkTouched() {
- $fname = 'Article::checkTouched';
if( !$this->mDataLoaded ) {
- $dbr =& $this->getDB();
- $data = $this->pageDataFromId( $dbr, $this->getId() );
- if( $data ) {
- $this->loadPageData( $data );
- }
+ $this->loadPageData();
}
return !$this->mIsRedirect;
}
function getTouched() {
# Ensure that page data has been loaded
if( !$this->mDataLoaded ) {
- $dbr =& $this->getDB();
- $data = $this->pageDataFromId( $dbr, $this->getId() );
- if( $data ) {
- $this->loadPageData( $data );
- }
+ $this->loadPageData();
}
return $this->mTouched;
}
+ /**
+ * Get the page_latest field
+ */
+ function getLatest() {
+ if ( !$this->mDataLoaded ) {
+ $this->loadPageData();
+ }
+ return $this->mLatest;
+ }
+
/**
* Edit an article without doing all that other stuff
* The article must already exist; link tables etc
* @param bool $minor whereas it's a minor modification
*/
function quickEdit( $text, $comment = '', $minor = 0 ) {
- $fname = 'Article::quickEdit';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
$dbw =& wfGetDB( DB_MASTER );
$dbw->begin();
'comment' => $comment,
'minor_edit' => $minor ? 1 : 0,
) );
+ # fixme : $revisionId never used
$revisionId = $revision->insertOn( $dbw );
$this->updateRevisionOn( $dbw, $revision );
$dbw->commit();
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
}
/**
*/
function incViewCount( $id ) {
$id = intval( $id );
- global $wgHitcounterUpdateFreq;
+ global $wgHitcounterUpdateFreq, $wgDBtype;
$dbw =& wfGetDB( DB_MASTER );
$pageTable = $dbw->tableName( 'page' );
wfProfileIn( 'Article::incViewCount-collect' );
$old_user_abort = ignore_user_abort( true );
- $dbw->query("LOCK TABLES $hitcounterTable WRITE");
- $dbw->query("CREATE TEMPORARY TABLE $acchitsTable TYPE=HEAP ".
+ if ($wgDBtype == 'mysql')
+ $dbw->query("LOCK TABLES $hitcounterTable WRITE");
+ $tabletype = $wgDBtype == 'mysql' ? "ENGINE=HEAP " : '';
+ $dbw->query("CREATE TEMPORARY TABLE $acchitsTable $tabletype".
"SELECT hc_id,COUNT(*) AS hc_n FROM $hitcounterTable ".
'GROUP BY hc_id');
$dbw->query("DELETE FROM $hitcounterTable");
- $dbw->query('UNLOCK TABLES');
+ if ($wgDBtype == 'mysql')
+ $dbw->query('UNLOCK TABLES');
$dbw->query("UPDATE $pageTable,$acchitsTable SET page_counter=page_counter + hc_n ".
'WHERE page_id = hc_id');
$dbw->query("DROP TABLE $acchitsTable");
* @param $title_obj a title object
*/
- function onArticleCreate($title_obj) {
- global $wgUseSquid, $wgPostCommitUpdateList;
-
- $title_obj->touchLinks();
- $titles = $title_obj->getLinksTo();
-
- # Purge squid
- if ( $wgUseSquid ) {
- $urls = $title_obj->getSquidURLs();
- foreach ( $titles as $linkTitle ) {
- $urls[] = $linkTitle->getInternalURL();
- }
- $u = new SquidUpdate( $urls );
- array_push( $wgPostCommitUpdateList, $u );
+ static function onArticleCreate($title) {
+ # The talk page isn't in the regular link tables, so we need to update manually:
+ if ( $title->isTalkPage() ) {
+ $other = $title->getSubjectPage();
+ } else {
+ $other = $title->getTalkPage();
}
+ $other->invalidateCache();
+ $other->purgeSquid();
+
+ $title->touchLinks();
+ $title->purgeSquid();
}
- function onArticleDelete( $title ) {
- global $wgMessageCache;
+ static function onArticleDelete( $title ) {
+ global $wgUseFileCache, $wgMessageCache;
$title->touchLinks();
+ $title->purgeSquid();
+
+ # File cache
+ if ( $wgUseFileCache ) {
+ $cm = new CacheManager( $title );
+ @unlink( $cm->fileCacheName() );
+ }
if( $title->getNamespace() == NS_MEDIAWIKI) {
$wgMessageCache->replace( $title->getDBkey(), false );
/**
* Purge caches on page update etc
*/
- function onArticleEdit( $title ) {
- global $wgUseSquid, $wgPostCommitUpdateList, $wgUseFileCache;
+ static function onArticleEdit( $title ) {
+ global $wgDeferredUpdateList, $wgUseFileCache;
$urls = array();
- // Template namespace? Purge all articles linking here.
- // FIXME: When a templatelinks table arrives, use it for all includes.
- if ( $title->getNamespace() == NS_TEMPLATE) {
- $titles = $title->getLinksTo();
- Title::touchArray( $titles );
- if ( $wgUseSquid ) {
- foreach ( $titles as $link ) {
- $urls[] = $link->getInternalURL();
- }
- }
- }
+ // Invalidate caches of articles which include this page
+ $update = new HTMLCacheUpdate( $title, 'templatelinks' );
+ $wgDeferredUpdateList[] = $update;
- # Squid updates
- if ( $wgUseSquid ) {
- $urls = array_merge( $urls, $title->getSquidURLs() );
- $u = new SquidUpdate( $urls );
- array_push( $wgPostCommitUpdateList, $u );
- }
+ # Purge squid for this page only
+ $title->purgeSquid();
- # File cache
+ # Clear file cache
if ( $wgUseFileCache ) {
$cm = new CacheManager( $title );
@unlink( $cm->fileCacheName() );
* Info about this page
* Called for ?action=info when $wgAllowPageInfo is on.
*
- * @access public
+ * @public
*/
function info() {
global $wgLang, $wgOut, $wgAllowPageInfo, $wgUser;
- $fname = 'Article::info';
if ( !$wgAllowPageInfo ) {
- $wgOut->errorpage( 'nosuchaction', 'nosuchactiontext' );
+ $wgOut->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
return;
}
'watchlist',
'COUNT(*)',
$wl_clause,
- $fname,
+ __METHOD__,
$this->getSelectOptions() );
$pageInfo = $this->pageCountInfo( $page );
*
* @param Title $title
* @return array
- * @access private
+ * @private
*/
function pageCountInfo( $title ) {
$id = $title->getArticleId();
$dbr =& wfGetDB( DB_SLAVE );
$rev_clause = array( 'rev_page' => $id );
- $fname = 'Article::pageCountInfo';
$edits = $dbr->selectField(
'revision',
'COUNT(rev_page)',
$rev_clause,
- $fname,
+ __METHOD__,
$this->getSelectOptions() );
$authors = $dbr->selectField(
'revision',
'COUNT(DISTINCT rev_user_text)',
$rev_clause,
- $fname,
+ __METHOD__,
$this->getSelectOptions() );
return array( 'edits' => $edits, 'authors' => $authors );