*/
class WatchedItemStore {
+ const SORT_DESC = 'DESC';
+ const SORT_ASC = 'ASC';
+
/**
* @var LoadBalancer
*/
* @param User $user
* @param array $options Allowed keys:
* 'forWrite' => bool defaults to false
+ * 'sort' => string optional sorting by namespace ID and title
+ * one of the self::SORT_* constants
*
* @return WatchedItem[]
*/
public function getWatchedItemsForUser( User $user, array $options = [] ) {
$options += [ 'forWrite' => false ];
+ $dbOptions = [];
+ if ( array_key_exists( 'sort', $options ) ) {
+ Assert::parameter(
+ ( in_array( $options['sort'], [ self::SORT_ASC, self::SORT_DESC ] ) ),
+ '$options[\'sort\']',
+ 'must be SORT_ASC or SORT_DESC'
+ );
+ $dbOptions['ORDER BY'] = [
+ "wl_namespace {$options['sort']}",
+ "wl_title {$options['sort']}"
+ ];
+ }
$db = $this->getConnection( $options['forWrite'] ? DB_MASTER : DB_SLAVE );
+
$res = $db->select(
'watchlist',
[ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
[ 'wl_user' => $user->getId() ],
- __METHOD__
+ __METHOD__,
+ $dbOptions
);
$this->reuseConnection( $db );
[],
// Automatically append redirect=no to each link, since most of them are
// redirect pages themselves.
- [ 'redirect' => 'no' ],
+ $title->isRedirect() ? [ 'redirect' => 'no' ] : [],
( $forceKnown ? [ 'known', 'noclasses' ] : [] )
) . '</li>';
}
*/
protected function getWatchlistInfo() {
$titles = [];
- $dbr = wfGetDB( DB_SLAVE );
- $res = $dbr->select(
- [ 'watchlist' ],
- [ 'wl_namespace', 'wl_title' ],
- [ 'wl_user' => $this->getUser()->getId() ],
- __METHOD__,
- [ 'ORDER BY' => [ 'wl_namespace', 'wl_title' ] ]
- );
+ $watchedItems = WatchedItemStore::getDefaultInstance()
+ ->getWatchedItemsForUser( $this->getUser(), [ 'sort' => WatchedItemStore::SORT_ASC ] );
$lb = new LinkBatch();
- foreach ( $res as $row ) {
- $lb->add( $row->wl_namespace, $row->wl_title );
- if ( !MWNamespace::isTalk( $row->wl_namespace ) ) {
- $titles[$row->wl_namespace][$row->wl_title] = 1;
+ foreach ( $watchedItems as $watchedItem ) {
+ $namespace = $watchedItem->getLinkTarget()->getNamespace();
+ $dbKey = $watchedItem->getLinkTarget()->getDBkey();
+ $lb->add( $namespace, $dbKey );
+ if ( !MWNamespace::isTalk( $namespace ) ) {
+ $titles[$namespace][$dbKey] = 1;
}
}
}
if ( isset( $watchedItemStore ) ) {
- $rcTitleValue = new TitleValue( $obj->rc_namespace, $obj->rc_title );
+ $rcTitleValue = new TitleValue( (int)$obj->rc_namespace, $obj->rc_title );
$rc->numberofWatchingusers = $watchedItemStore->countWatchers( $rcTitleValue );
} else {
$rc->numberofWatchingusers = 0;
$startPos = 0;
}
+ if ( $this->getFileLength() === 0 ) {
+ $this->error( 'zip-wrong-format', "The file is empty." );
+ }
+
$block = $this->getBlock( $startPos );
$sigPos = strrpos( $block, "PK\x05\x06" );
if ( $sigPos === false ) {
->with(
'watchlist',
[ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
- [ 'wl_user' => 1 ]
+ [ 'wl_user' => 1 ],
+ $this->isType( 'string' ),
+ [ 'ORDER BY' => [ 'wl_namespace ASC', 'wl_title ASC' ] ]
)
->will( $this->returnValue( [] ) );
$watchedItems = $store->getWatchedItemsForUser(
$user,
- [ 'forWrite' => $forWrite ]
+ [ 'forWrite' => $forWrite, 'sort' => WatchedItemStore::SORT_ASC ]
);
$this->assertEquals( [], $watchedItems );
}
+ public function testGetWatchedItemsForUser_badSortOptionThrowsException() {
+ $store = new WatchedItemStore(
+ $this->getMockLoadBalancer( $this->getMockDb() ),
+ $this->getMockCache()
+ );
+
+ $this->setExpectedException( 'InvalidArgumentException' );
+ $store->getWatchedItemsForUser(
+ $this->getMockNonAnonUserWithId( 1 ),
+ [ 'sort' => 'foo' ]
+ );
+ }
+
public function testIsWatchedItem_existingItem() {
$mockDb = $this->getMockDb();
$mockDb->expects( $this->once() )
--- /dev/null
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @group Database
+ *
+ * @covers SpecialEditWatchlist
+ */
+class SpecialEditWatchlistTest extends SpecialPageTestBase {
+
+ /**
+ * Returns a new instance of the special page under test.
+ *
+ * @return SpecialPage
+ */
+ protected function newSpecialPage() {
+ return new SpecialEditWatchlist();
+ }
+
+ public function testNotLoggedIn_throwsException() {
+ $this->setExpectedException( 'UserNotLoggedIn' );
+ $this->executeSpecialPage();
+ }
+
+ public function testRootPage_displaysExplanationMessage() {
+ $user = new TestUser( __METHOD__ );
+ list( $html, ) = $this->executeSpecialPage( '', null, 'qqx', $user->getUser() );
+ $this->assertContains( '(watchlistedit-normal-explain)', $html );
+ }
+
+ public function testClearPage_hasClearButtonForm() {
+ $user = new TestUser( __METHOD__ );
+ list( $html, ) = $this->executeSpecialPage( 'clear', null, 'qqx', $user->getUser() );
+ $this->assertRegExp(
+ '/<form action=".*?Special:EditWatchlist\/clear" method="post" class="visualClear">/',
+ $html
+ );
+ }
+
+ public function testEditRawPage_hasTitlesBox() {
+ $user = new TestUser( __METHOD__ );
+ list( $html, ) = $this->executeSpecialPage( 'raw', null, 'qqx', $user->getUser() );
+ $this->assertContains(
+ '<textarea id="mw-input-wpTitles"',
+ $html
+ );
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @group Database
+ *
+ * @covers SpecialWatchlist
+ */
+class SpecialWatchlistTest extends SpecialPageTestBase {
+
+ /**
+ * Returns a new instance of the special page under test.
+ *
+ * @return SpecialPage
+ */
+ protected function newSpecialPage() {
+ return new SpecialWatchlist();
+ }
+
+ public function testNotLoggedIn_throwsException() {
+ $this->setExpectedException( 'UserNotLoggedIn' );
+ $this->executeSpecialPage();
+ }
+
+ public function testUserWithNoWatchedItems_displaysNoWatchlistMessage() {
+ $user = new TestUser( __METHOD__ );
+ list( $html, ) = $this->executeSpecialPage( '', null, 'qqx', $user->getUser() );
+ $this->assertContains( '(nowatchlist)', $html );
+ }
+
+}