use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
use MediaWiki\Linker\LinkTarget;
+use MediaWiki\Revision\RevisionLookup;
use MediaWiki\User\UserIdentity;
use Wikimedia\Assert\Assert;
use Wikimedia\Rdbms\IDatabase;
private $deferredUpdatesAddCallableUpdateCallback;
/**
- * @var callable|null
+ * @var int
*/
- private $revisionGetTimestampFromIdCallback;
+ private $updateRowsPerQuery;
/**
- * @var int
+ * @var NamespaceInfo
*/
- private $updateRowsPerQuery;
+ private $nsInfo;
+
+ /**
+ * @var RevisionLookup
+ */
+ private $revisionLookup;
/**
* @var StatsdDataFactoryInterface
* @param HashBagOStuff $cache
* @param ReadOnlyMode $readOnlyMode
* @param int $updateRowsPerQuery
+ * @param NamespaceInfo $nsInfo
+ * @param RevisionLookup $revisionLookup
*/
public function __construct(
ILBFactory $lbFactory,
BagOStuff $stash,
HashBagOStuff $cache,
ReadOnlyMode $readOnlyMode,
- $updateRowsPerQuery
+ $updateRowsPerQuery,
+ NamespaceInfo $nsInfo,
+ RevisionLookup $revisionLookup
) {
$this->lbFactory = $lbFactory;
$this->loadBalancer = $lbFactory->getMainLB();
$this->stats = new NullStatsdDataFactory();
$this->deferredUpdatesAddCallableUpdateCallback =
[ DeferredUpdates::class, 'addCallableUpdate' ];
- $this->revisionGetTimestampFromIdCallback =
- [ Revision::class, 'getTimestampFromId' ];
$this->updateRowsPerQuery = $updateRowsPerQuery;
+ $this->nsInfo = $nsInfo;
+ $this->revisionLookup = $revisionLookup;
$this->latestUpdateCache = new HashBagOStuff( [ 'maxKeys' => 3 ] );
}
} );
}
- /**
- * Overrides the Revision::getTimestampFromId callback
- * This is intended for use while testing and will fail if MW_PHPUNIT_TEST is not defined.
- *
- * @param callable $callback
- * @see Revision::getTimestampFromId for callback signiture
- *
- * @return ScopedCallback to reset the overridden value
- * @throws MWException
- */
- public function overrideRevisionGetTimestampFromIdCallback( callable $callback ) {
- if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
- throw new MWException(
- 'Cannot override Revision::getTimestampFromId callback in operation.'
- );
- }
- $previousValue = $this->revisionGetTimestampFromIdCallback;
- $this->revisionGetTimestampFromIdCallback = $callback;
- return new ScopedCallback( function () use ( $previousValue ) {
- $this->revisionGetTimestampFromIdCallback = $previousValue;
- } );
- }
-
private function getCacheKey( UserIdentity $user, LinkTarget $target ) {
return $this->cache->makeKey(
(string)$target->getNamespace(),
* @since 1.27
* @param UserIdentity $user
* @param LinkTarget $target
- * @return bool
+ * @return WatchedItem|false
*/
public function getWatchedItem( UserIdentity $user, LinkTarget $target ) {
if ( !$user->isRegistered() ) {
* @since 1.27
* @param UserIdentity $user
* @param LinkTarget $target
- * @return WatchedItem|bool
+ * @return WatchedItem|false
*/
public function loadWatchedItem( UserIdentity $user, LinkTarget $target ) {
// Only registered user can have a watchlist
/**
* @since 1.27
* @param UserIdentity $user
- * @param Title $title
+ * @param LinkTarget $title
* @param string $force
* @param int $oldid
* @return bool
*/
public function resetNotificationTimestamp(
- UserIdentity $user, Title $title, $force = '', $oldid = 0
+ UserIdentity $user, LinkTarget $title, $force = '', $oldid = 0
) {
$time = time();
return false;
}
- // Hook expects User, not UserIdentity
+ // Hook expects User and Title, not UserIdentity and LinkTarget
$userObj = User::newFromId( $user->getId() );
+ $titleObj = Title::castFromLinkTarget( $title );
if ( !Hooks::run( 'BeforeResetNotificationTimestamp',
- [ &$userObj, &$title, $force, &$oldid ] )
+ [ &$userObj, &$titleObj, $force, &$oldid ] )
) {
return false;
}
if ( !$userObj->equals( $user ) ) {
$user = $userObj;
}
+ if ( !$titleObj->equals( $title ) ) {
+ $title = $titleObj;
+ }
$item = null;
if ( $force != 'force' ) {
}
// Get the timestamp (TS_MW) of this revision to track the latest one seen
- $seenTime = call_user_func(
- $this->revisionGetTimestampFromIdCallback,
- $title,
- $oldid ?: $title->getLatestRevID()
- );
+ $id = $oldid;
+ $seenTime = null;
+ if ( !$id ) {
+ $latestRev = $this->revisionLookup->getRevisionByTitle( $title );
+ if ( $latestRev ) {
+ $id = $latestRev->getId();
+ // Save a DB query
+ $seenTime = $latestRev->getTimestamp();
+ }
+ }
+ if ( $seenTime === null ) {
+ $seenTime = $this->revisionLookup->getTimestampFromId( $id );
+ }
// Mark the item as read immediately in lightweight storage
$this->stash->merge(
return "{$target->getNamespace()}:{$target->getDBkey()}";
}
+ /**
+ * @param UserIdentity $user
+ * @param LinkTarget $title
+ * @param WatchedItem $item
+ * @param bool $force
+ * @param int|bool $oldid The ID of the last revision that the user viewed
+ * @return bool|string|null
+ */
private function getNotificationTimestamp(
- UserIdentity $user, Title $title, $item, $force, $oldid
+ UserIdentity $user, LinkTarget $title, $item, $force, $oldid
) {
if ( !$oldid ) {
// No oldid given, assuming latest revision; clear the timestamp.
return null;
}
- if ( !$title->getNextRevisionID( $oldid ) ) {
+ $oldRev = $this->revisionLookup->getRevisionById( $oldid );
+ $nextRev = $this->revisionLookup->getNextRevision( $oldRev );
+ if ( !$nextRev ) {
// Oldid given and is the latest revision for this title; clear the timestamp.
return null;
}
// Oldid given and isn't the latest; update the timestamp.
// This will result in no further notification emails being sent!
- // Calls Revision::getTimestampFromId in normal operation
- $notificationTimestamp = call_user_func(
- $this->revisionGetTimestampFromIdCallback,
- $title,
- $oldid
- );
+ $notificationTimestamp = $this->revisionLookup->getTimestampFromId( $oldid );
+ // @FIXME: this should use getTimestamp() for consistency with updates on new edits
+ // $notificationTimestamp = $nextRev->getTimestamp(); // first unseen revision timestamp
// We need to go one second to the future because of various strict comparisons
// throughout the codebase
* @param LinkTarget $newTarget
*/
public function duplicateAllAssociatedEntries( LinkTarget $oldTarget, LinkTarget $newTarget ) {
- $oldTarget = Title::newFromLinkTarget( $oldTarget );
- $newTarget = Title::newFromLinkTarget( $newTarget );
-
- $this->duplicateEntry( $oldTarget->getSubjectPage(), $newTarget->getSubjectPage() );
- $this->duplicateEntry( $oldTarget->getTalkPage(), $newTarget->getTalkPage() );
+ // Duplicate first the subject page, then the talk page
+ $this->duplicateEntry(
+ $this->nsInfo->getSubjectPage( $oldTarget ),
+ $this->nsInfo->getSubjectPage( $newTarget )
+ );
+ $this->duplicateEntry(
+ $this->nsInfo->getTalkPage( $oldTarget ),
+ $this->nsInfo->getTalkPage( $newTarget )
+ );
}
/**
/**
* @param UserIdentity $user
- * @param Title[] $titles
+ * @param LinkTarget[] $titles
*/
private function uncacheTitlesForUser( UserIdentity $user, array $titles ) {
foreach ( $titles as $title ) {