Merge "Move WatchedItem::duplicateEntries to WatchedItemStore"
This commit is contained in:
commit
f26ac509db
4 changed files with 185 additions and 55 deletions
|
|
@ -1402,6 +1402,7 @@ $wgAutoloadLocalClasses = [
|
|||
'WantedTemplatesPage' => __DIR__ . '/includes/specials/SpecialWantedtemplates.php',
|
||||
'WatchAction' => __DIR__ . '/includes/actions/WatchAction.php',
|
||||
'WatchedItem' => __DIR__ . '/includes/WatchedItem.php',
|
||||
'WatchedItemStore' => __DIR__ . '/includes/WatchedItemStore.php',
|
||||
'WatchlistCleanup' => __DIR__ . '/maintenance/cleanupWatchlist.php',
|
||||
'WebInstaller' => __DIR__ . '/includes/installer/WebInstaller.php',
|
||||
'WebInstallerComplete' => __DIR__ . '/includes/installer/WebInstallerComplete.php',
|
||||
|
|
|
|||
|
|
@ -379,63 +379,15 @@ class WatchedItem {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if the given title already is watched by the user, and if so
|
||||
* add watches on a new title. To be used for page renames and such.
|
||||
* @deprecated since 1.27. See WatchedItemStore::duplicateEntry
|
||||
*
|
||||
* @param Title $ot Page title to duplicate entries from, if present
|
||||
* @param Title $nt Page title to add watches on
|
||||
* @param Title $oldTitle
|
||||
* @param Title $newTitle
|
||||
*/
|
||||
public static function duplicateEntries( $ot, $nt ) {
|
||||
WatchedItem::doDuplicateEntries( $ot->getSubjectPage(), $nt->getSubjectPage() );
|
||||
WatchedItem::doDuplicateEntries( $ot->getTalkPage(), $nt->getTalkPage() );
|
||||
public static function duplicateEntries( Title $oldTitle, Title $newTitle ) {
|
||||
$store = WatchedItemStore::getDefaultInstance();
|
||||
$store->duplicateEntry( $oldTitle->getSubjectPage(), $newTitle->getSubjectPage() );
|
||||
$store->duplicateEntry( $oldTitle->getTalkPage(), $newTitle->getTalkPage() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle duplicate entries. Backend for duplicateEntries().
|
||||
*
|
||||
* @param Title $ot
|
||||
* @param Title $nt
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function doDuplicateEntries( $ot, $nt ) {
|
||||
$oldnamespace = $ot->getNamespace();
|
||||
$newnamespace = $nt->getNamespace();
|
||||
$oldtitle = $ot->getDBkey();
|
||||
$newtitle = $nt->getDBkey();
|
||||
|
||||
$dbw = wfGetDB( DB_MASTER );
|
||||
$res = $dbw->select( 'watchlist',
|
||||
[ 'wl_user', 'wl_notificationtimestamp' ],
|
||||
[ 'wl_namespace' => $oldnamespace, 'wl_title' => $oldtitle ],
|
||||
__METHOD__, 'FOR UPDATE'
|
||||
);
|
||||
# Construct array to replace into the watchlist
|
||||
$values = [];
|
||||
foreach ( $res as $s ) {
|
||||
$values[] = [
|
||||
'wl_user' => $s->wl_user,
|
||||
'wl_namespace' => $newnamespace,
|
||||
'wl_title' => $newtitle,
|
||||
'wl_notificationtimestamp' => $s->wl_notificationtimestamp,
|
||||
];
|
||||
}
|
||||
|
||||
if ( empty( $values ) ) {
|
||||
// Nothing to do
|
||||
return true;
|
||||
}
|
||||
|
||||
# Perform replace
|
||||
# Note that multi-row replace is very efficient for MySQL but may be inefficient for
|
||||
# some other DBMSes, mostly due to poor simulation by us
|
||||
$dbw->replace(
|
||||
'watchlist',
|
||||
[ [ 'wl_user', 'wl_namespace', 'wl_title' ] ],
|
||||
$values,
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
86
includes/WatchedItemStore.php
Normal file
86
includes/WatchedItemStore.php
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Storage layer class for WatchedItems.
|
||||
* Database interaction
|
||||
*
|
||||
* @author Addshore
|
||||
*
|
||||
* @since 1.27
|
||||
*/
|
||||
class WatchedItemStore {
|
||||
|
||||
/**
|
||||
* @var LoadBalancer
|
||||
*/
|
||||
private $loadBalancer;
|
||||
|
||||
public function __construct( LoadBalancer $loadBalancer ) {
|
||||
$this->loadBalancer = $loadBalancer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public static function getDefaultInstance() {
|
||||
static $instance;
|
||||
if ( !$instance ) {
|
||||
$instance = new self( wfGetLB() );
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given title already is watched by the user, and if so
|
||||
* add a watch for the new title.
|
||||
*
|
||||
* To be used for page renames and such.
|
||||
* This must be called separately for Subject and Talk pages
|
||||
*
|
||||
* @param LinkTarget $oldTarget
|
||||
* @param LinkTarget $newTarget
|
||||
*/
|
||||
public function duplicateEntry( LinkTarget $oldTarget, LinkTarget $newTarget ) {
|
||||
$dbw = $this->loadBalancer->getConnection( DB_MASTER, [ 'watchlist' ] );
|
||||
|
||||
$result = $dbw->select(
|
||||
'watchlist',
|
||||
[ 'wl_user', 'wl_notificationtimestamp' ],
|
||||
[
|
||||
'wl_namespace' => $oldTarget->getNamespace(),
|
||||
'wl_title' => $oldTarget->getDBkey(),
|
||||
],
|
||||
__METHOD__,
|
||||
[ 'FOR UPDATE' ]
|
||||
);
|
||||
|
||||
$newNamespace = $newTarget->getNamespace();
|
||||
$newDBkey = $newTarget->getDBkey();
|
||||
|
||||
# Construct array to replace into the watchlist
|
||||
$values = [];
|
||||
foreach ( $result as $row ) {
|
||||
$values[] = [
|
||||
'wl_user' => $row->wl_user,
|
||||
'wl_namespace' => $newNamespace,
|
||||
'wl_title' => $newDBkey,
|
||||
'wl_notificationtimestamp' => $row->wl_notificationtimestamp,
|
||||
];
|
||||
}
|
||||
|
||||
if ( !empty( $values ) ) {
|
||||
# Perform replace
|
||||
# Note that multi-row replace is very efficient for MySQL but may be inefficient for
|
||||
# some other DBMSes, mostly due to poor simulation by us
|
||||
$dbw->replace(
|
||||
'watchlist',
|
||||
[ [ 'wl_user', 'wl_namespace', 'wl_title' ] ],
|
||||
$values,
|
||||
__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->loadBalancer->reuseConnection( $dbw );
|
||||
}
|
||||
|
||||
}
|
||||
91
tests/phpunit/includes/WatchedItemStoreTest.php
Normal file
91
tests/phpunit/includes/WatchedItemStoreTest.php
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @author Addshore
|
||||
*
|
||||
* @covers WatchedItemStore
|
||||
*/
|
||||
class WatchedItemStoreTest extends PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* @return PHPUnit_Framework_MockObject_MockObject|IDatabase
|
||||
*/
|
||||
private function getMockDb() {
|
||||
return $this->getMock( 'IDatabase' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PHPUnit_Framework_MockObject_MockObject|LoadBalancer
|
||||
*/
|
||||
private function getMockLoadBalancer( $mockDb ) {
|
||||
$mock = $this->getMockBuilder( 'LoadBalancer' )
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mock->expects( $this->any() )
|
||||
->method( 'getConnection' )
|
||||
->will( $this->returnValue( $mockDb ) );
|
||||
return $mock;
|
||||
}
|
||||
|
||||
private function getFakeRow( $userId, $timestamp ) {
|
||||
$fakeRow = new stdClass();
|
||||
$fakeRow->wl_user = $userId;
|
||||
$fakeRow->wl_notificationtimestamp = $timestamp;
|
||||
return $fakeRow;
|
||||
}
|
||||
|
||||
public function testDuplicateEntry_nothingToDuplicate() {
|
||||
$mockDb = $this->getMockDb();
|
||||
$mockDb->expects( $this->exactly( 1 ) )
|
||||
->method( 'select' )
|
||||
->will( $this->returnValue( new FakeResultWrapper( [] ) ) );
|
||||
|
||||
$store = new WatchedItemStore( $this->getMockLoadBalancer( $mockDb ) );
|
||||
|
||||
$store->duplicateEntry(
|
||||
Title::newFromText( 'Old_Title' ),
|
||||
Title::newFromText( 'New_Title' )
|
||||
);
|
||||
}
|
||||
|
||||
public function testDuplicateEntry_somethingToDuplicate() {
|
||||
$fakeRows = [
|
||||
$this->getFakeRow( 1, '20151212010101' ),
|
||||
$this->getFakeRow( 2, null ),
|
||||
];
|
||||
|
||||
$mockDb = $this->getMockDb();
|
||||
$mockDb->expects( $this->at( 0 ) )
|
||||
->method( 'select' )
|
||||
->will( $this->returnValue( new FakeResultWrapper( $fakeRows ) ) );
|
||||
$mockDb->expects( $this->at( 1 ) )
|
||||
->method( 'replace' )
|
||||
->with(
|
||||
'watchlist',
|
||||
[ [ 'wl_user', 'wl_namespace', 'wl_title' ] ],
|
||||
[
|
||||
[
|
||||
'wl_user' => 1,
|
||||
'wl_namespace' => 0,
|
||||
'wl_title' => 'New_Title',
|
||||
'wl_notificationtimestamp' => '20151212010101',
|
||||
],
|
||||
[
|
||||
'wl_user' => 2,
|
||||
'wl_namespace' => 0,
|
||||
'wl_title' => 'New_Title',
|
||||
'wl_notificationtimestamp' => null,
|
||||
],
|
||||
],
|
||||
$this->isType( 'string' )
|
||||
);
|
||||
|
||||
$store = new WatchedItemStore( $this->getMockLoadBalancer( $mockDb ) );
|
||||
|
||||
$store->duplicateEntry(
|
||||
Title::newFromText( 'Old_Title' ),
|
||||
Title::newFromText( 'New_Title' )
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue