*/
const VERSION = 10;
- /**
- * Maximum items in $mWatchedItems
- */
- const MAX_WATCHED_ITEMS_CACHE = 100;
-
/**
* Exclude user options that are set to their default value.
* @since 1.25
*/
const GETOPTIONS_EXCLUDE_DEFAULTS = 1;
+ /**
+ * @since 1.27
+ */
+ const CHECK_USER_RIGHTS = true;
+
+ /**
+ * @since 1.27
+ */
+ const IGNORE_USER_RIGHTS = false;
+
/**
* Array of Strings List of member variables which are saved to the
* shared cache (memcached). Any operation which changes the
*/
protected static $mAllRights = false;
+ /**
+ * An in-process cache for user data lookup
+ * @var HashBagOStuff
+ */
+ protected static $inProcessCache;
+
/** Cache variables */
// @{
public $mId;
/** @var Block */
private $mBlockedFromCreateAccount = false;
- /** @var array */
- private $mWatchedItems = [];
-
/** @var integer User::READ_* constant bitfield used to load data */
protected $queryFlagsUsed = self::READ_NORMAL;
*/
public static function purge( $wikiId, $userId ) {
$cache = ObjectCache::getMainWANInstance();
- $cache->delete( $cache->makeGlobalKey( 'user', 'id', $wikiId, $userId ) );
+ $processCache = self::getInProcessCache();
+ $key = $cache->makeGlobalKey( 'user', 'id', $wikiId, $userId );
+ $cache->delete( $key );
+ $processCache->delete( $key );
}
/**
return $cache->makeGlobalKey( 'user', 'id', wfWikiID(), $this->mId );
}
+ /**
+ * @since 1.27
+ * @return HashBagOStuff
+ */
+ protected static function getInProcessCache() {
+ if ( !self::$inProcessCache ) {
+ self::$inProcessCache = new HashBagOStuff( ['maxKeys' => 10] );
+ }
+ return self::$inProcessCache;
+ }
+
/**
* Load user data from shared cache, given mId has already been set.
*
}
$cache = ObjectCache::getMainWANInstance();
- $data = $cache->get( $this->getCacheKey( $cache ) );
- if ( !is_array( $data ) || $data['mVersion'] < self::VERSION ) {
- // Object is expired
- return false;
+ $processCache = self::getInProcessCache();
+ $key = $this->getCacheKey( $cache );
+ $data = $processCache->get( $key );
+ if ( !is_array( $data ) ) {
+ $data = $cache->get( $key );
+ if ( !is_array( $data ) || $data['mVersion'] < self::VERSION ) {
+ // Object is expired
+ return false;
+ }
+ $processCache->set( $key, $data );
}
-
wfDebug( "User: got user {$this->mId} from cache\n" );
// Restore from cache
$opts = Database::getCacheSetOptions( wfGetDB( DB_SLAVE ) );
$cache = ObjectCache::getMainWANInstance();
+ $processCache = self::getInProcessCache();
$key = $this->getCacheKey( $cache );
$cache->set( $key, $data, $cache::TTL_HOUR, $opts );
+ $processCache->set( $key, $data );
}
/** @name newFrom*() static factory methods */
|| strlen( $name ) > $wgMaxNameChars
|| $name != $wgContLang->ucfirst( $name )
) {
- wfDebugLog( 'username', __METHOD__ .
- ": '$name' invalid due to empty, IP, slash, length, or lowercase" );
return false;
}
if ( is_null( $parsed )
|| $parsed->getNamespace()
|| strcmp( $name, $parsed->getPrefixedText() ) ) {
- wfDebugLog( 'username', __METHOD__ .
- ": '$name' invalid due to ambiguous prefixes" );
return false;
}
'\x{e000}-\x{f8ff}' . # private use
']/u';
if ( preg_match( $unicodeBlacklist, $name ) ) {
- wfDebugLog( 'username', __METHOD__ .
- ": '$name' invalid due to blacklisted characters" );
return false;
}
// Get the "last viewed rev" timestamp from the oldest message notification
$timestamp = $dbr->selectField( 'user_newtalk',
'MIN(user_last_timestamp)',
- $this->isAnon() ? [ 'user_ip' => $this->getName() ] : [ 'user_id' => $this->getID() ],
+ $this->isAnon() ? [ 'user_ip' => $this->getName() ] : [ 'user_id' => $this->getId() ],
__METHOD__ );
$rev = $timestamp ? Revision::loadFromTimestamp( $dbr, $utp, $timestamp ) : null;
return [ [ 'wiki' => wfWikiID(), 'link' => $utp->getLocalURL(), 'rev' => $rev ] ];
}
$cache = ObjectCache::getMainWANInstance();
+ $processCache = self::getInProcessCache();
$key = $this->getCacheKey( $cache );
if ( $mode === 'refresh' ) {
$cache->delete( $key, 1 );
+ $processCache->delete( $key );
} else {
- wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle( function() use ( $cache, $key ) {
- $cache->delete( $key );
- } );
+ wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle(
+ function() use ( $cache, $processCache, $key ) {
+ $cache->delete( $key );
+ $processCache->delete( $key );
+ }
+ );
}
}
if ( $this->getId() ) {
$dbw->insert( 'user_groups',
[
- 'ug_user' => $this->getID(),
+ 'ug_user' => $this->getId(),
'ug_group' => $group,
],
__METHOD__,
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'user_groups',
[
- 'ug_user' => $this->getID(),
+ 'ug_user' => $this->getId(),
'ug_group' => $group,
], __METHOD__
);
// Remember that the user was in this group
$dbw->insert( 'user_former_groups',
[
- 'ufg_user' => $this->getID(),
+ 'ufg_user' => $this->getId(),
'ufg_group' => $group,
],
__METHOD__,
* @return bool
*/
public function isLoggedIn() {
- return $this->getID() != 0;
+ return $this->getId() != 0;
}
/**
}
}
- /**
- * Get a WatchedItem for this user and $title.
- *
- * @since 1.22 $checkRights parameter added
- * @param Title $title
- * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
- * Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
- * @return WatchedItem
- */
- public function getWatchedItem( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
- $key = $checkRights . ':' . $title->getNamespace() . ':' . $title->getDBkey();
-
- if ( isset( $this->mWatchedItems[$key] ) ) {
- return $this->mWatchedItems[$key];
- }
-
- if ( count( $this->mWatchedItems ) >= self::MAX_WATCHED_ITEMS_CACHE ) {
- $this->mWatchedItems = [];
- }
-
- $this->mWatchedItems[$key] = WatchedItem::fromUserTitle( $this, $title, $checkRights );
- return $this->mWatchedItems[$key];
- }
-
/**
* Check the watched status of an article.
* @since 1.22 $checkRights parameter added
* @param Title $title Title of the article to look at
- * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
- * Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
+ * @param bool $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
+ * Pass User::CHECK_USER_RIGHTS or User::IGNORE_USER_RIGHTS.
* @return bool
*/
- public function isWatched( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
- return $this->getWatchedItem( $title, $checkRights )->isWatched();
+ public function isWatched( $title, $checkRights = self::CHECK_USER_RIGHTS ) {
+ if ( $title->isWatchable() && ( !$checkRights || $this->isAllowed( 'viewmywatchlist' ) ) ) {
+ return WatchedItemStore::getDefaultInstance()->isWatched( $this, $title );
+ }
+ return false;
}
/**
* Watch an article.
* @since 1.22 $checkRights parameter added
* @param Title $title Title of the article to look at
- * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
- * Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
- */
- public function addWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
- $this->getWatchedItem( $title, $checkRights )->addWatch();
+ * @param bool $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
+ * Pass User::CHECK_USER_RIGHTS or User::IGNORE_USER_RIGHTS.
+ */
+ public function addWatch( $title, $checkRights = self::CHECK_USER_RIGHTS ) {
+ if ( !$checkRights || $this->isAllowed( 'editmywatchlist' ) ) {
+ WatchedItemStore::getDefaultInstance()->addWatchBatch( [
+ [ $this, $title->getSubjectPage() ],
+ [ $this, $title->getTalkPage() ],
+ ]
+ );
+ }
$this->invalidateCache();
}
* Stop watching an article.
* @since 1.22 $checkRights parameter added
* @param Title $title Title of the article to look at
- * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
- * Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
+ * @param bool $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
+ * Pass User::CHECK_USER_RIGHTS or User::IGNORE_USER_RIGHTS.
*/
- public function removeWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
- $this->getWatchedItem( $title, $checkRights )->removeWatch();
+ public function removeWatch( $title, $checkRights = self::CHECK_USER_RIGHTS ) {
+ if ( !$checkRights || $this->isAllowed( 'editmywatchlist' ) ) {
+ WatchedItemStore::getDefaultInstance()->removeWatch( $this, $title->getSubjectPage() );
+ WatchedItemStore::getDefaultInstance()->removeWatch( $this, $title->getTalkPage() );
+ }
$this->invalidateCache();
}
$force = 'force';
}
- $this->getWatchedItem( $title )->resetNotificationTimestamp(
- $force, $oldid
- );
+ WatchedItemStore::getDefaultInstance()
+ ->resetNotificationTimestamp( $this, $title, $force, $oldid );
}
/**
} else {
$this->clearInstanceCache( 'defaults' );
$delay = $session->delaySave();
+ $session->unpersist(); // Clear cookies (T127436)
$session->setLoggedOutTimestamp( time() );
$session->setUser( new User );
$session->set( 'wsUserID', 0 ); // Other code expects this
if ( $this->isLoggedIn() && $this->isBlocked() ) {
return $this->spreadBlock();
}
+
return false;
}