WikiPage::prepareTextForEdit() was removed
[lhc/web/wiklou.git] / includes / WatchedItemQueryService.php
index 8497224..cd78b49 100644 (file)
@@ -50,10 +50,24 @@ class WatchedItemQueryService {
         */
        private $loadBalancer;
 
+       /** @var WatchedItemQueryServiceExtension[]|null */
+       private $extensions = null;
+
        public function __construct( LoadBalancer $loadBalancer ) {
                $this->loadBalancer = $loadBalancer;
        }
 
+       /**
+        * @return WatchedItemQueryServiceExtension[]
+        */
+       private function getExtensions() {
+               if ( $this->extensions === null ) {
+                       $this->extensions = [];
+                       Hooks::run( 'WatchedItemQueryServiceExtensions', [ &$this->extensions, $this ] );
+               }
+               return $this->extensions;
+       }
+
        /**
         * @return IDatabase
         * @throws MWException
@@ -84,9 +98,6 @@ class WatchedItemQueryService {
         *                                 timestamp to start enumerating from
         *        'end'                 => string (format accepted by wfTimestamp) requires 'dir' option,
         *                                 timestamp to end enumerating
-        *        'startFrom'           => [ string $rcTimestamp, int $rcId ] requires 'dir' option,
-        *                                 return items starting from the RecentChange specified by this,
-        *                                 $rcTimestamp should be in the format accepted by wfTimestamp
         *        'watchlistOwner'      => User user whose watchlist items should be listed if different
         *                                 than the one specified with $user param,
         *                                 requires 'watchlistOwnerToken' option
@@ -97,6 +108,7 @@ class WatchedItemQueryService {
         *                                 generator ('rc_cur_id' or 'rc_this_oldid') if true, or all
         *                                 id fields ('rc_cur_id', 'rc_this_oldid', 'rc_last_oldid')
         *                                 if false (default)
+        * @param array|null &$startFrom Continuation value: [ string $rcTimestamp, int $rcId ]
         * @return array of pairs ( WatchedItem $watchedItem, string[] $recentChangeInfo ),
         *         where $recentChangeInfo contains the following keys:
         *         - 'rc_id',
@@ -107,7 +119,9 @@ class WatchedItemQueryService {
         *         - 'rc_deleted',
         *         Additional keys could be added by specifying the 'includeFields' option
         */
-       public function getWatchedItemsWithRecentChangeInfo( User $user, array $options = [] ) {
+       public function getWatchedItemsWithRecentChangeInfo(
+               User $user, array $options = [], &$startFrom = null
+       ) {
                $options += [
                        'includeFields' => [],
                        'namespaceIds' => [],
@@ -128,15 +142,19 @@ class WatchedItemQueryService {
                        'must be DIR_OLDER or DIR_NEWER'
                );
                Assert::parameter(
-                       !isset( $options['start'] ) && !isset( $options['end'] ) && !isset( $options['startFrom'] )
+                       !isset( $options['start'] ) && !isset( $options['end'] ) && $startFrom === null
                                || isset( $options['dir'] ),
                        '$options[\'dir\']',
-                       'must be provided when providing any of options: start, end, startFrom'
+                       'must be provided when providing the "start" or "end" options or the $startFrom parameter'
                );
                Assert::parameter(
-                       !isset( $options['startFrom'] )
-                               || ( is_array( $options['startFrom'] ) && count( $options['startFrom'] ) === 2 ),
+                       !isset( $options['startFrom'] ),
                        '$options[\'startFrom\']',
+                       'must not be provided, use $startFrom instead'
+               );
+               Assert::parameter(
+                       !isset( $startFrom ) || ( is_array( $startFrom ) && count( $startFrom ) === 2 ),
+                       '$startFrom',
                        'must be a two-element array'
                );
                if ( array_key_exists( 'watchlistOwner', $options ) ) {
@@ -164,6 +182,21 @@ class WatchedItemQueryService {
                $dbOptions = $this->getWatchedItemsWithRCInfoQueryDbOptions( $options );
                $joinConds = $this->getWatchedItemsWithRCInfoQueryJoinConds( $options );
 
+               if ( $startFrom !== null ) {
+                       $conds[] = $this->getStartFromConds( $db, $options, $startFrom );
+               }
+
+               foreach ( $this->getExtensions() as $extension ) {
+                       $extension->modifyWatchedItemsWithRCInfoQuery(
+                               $user, $options, $db,
+                               $tables,
+                               $fields,
+                               $conds,
+                               $dbOptions,
+                               $joinConds
+                       );
+               }
+
                $res = $db->select(
                        $tables,
                        $fields,
@@ -173,8 +206,15 @@ class WatchedItemQueryService {
                        $joinConds
                );
 
+               $limit = isset( $dbOptions['LIMIT'] ) ? $dbOptions['LIMIT'] : INF;
                $items = [];
+               $startFrom = null;
                foreach ( $res as $row ) {
+                       if ( --$limit <= 0 ) {
+                               $startFrom = [ $row->rc_timestamp, $row->rc_id ];
+                               break;
+                       }
+
                        $items[] = [
                                new WatchedItem(
                                        $user,
@@ -185,6 +225,10 @@ class WatchedItemQueryService {
                        ];
                }
 
+               foreach ( $this->getExtensions() as $extension ) {
+                       $extension->modifyWatchedItemsWithRCInfo( $user, $options, $db, $items, $res, $startFrom );
+               }
+
                return $items;
        }
 
@@ -368,10 +412,6 @@ class WatchedItemQueryService {
                        $conds[] = $deletedPageLogCond;
                }
 
-               if ( array_key_exists( 'startFrom', $options ) ) {
-                       $conds[] = $this->getStartFromConds( $db, $options );
-               }
-
                return $conds;
        }
 
@@ -382,10 +422,7 @@ class WatchedItemQueryService {
                        $ownersToken = $watchlistOwner->getOption( 'watchlisttoken' );
                        $token = $options['watchlistOwnerToken'];
                        if ( $ownersToken == '' || !hash_equals( $ownersToken, $token ) ) {
-                               throw new UsageException(
-                                       'Incorrect watchlist token provided -- please set a correct token in Special:Preferences',
-                                       'bad_wltoken'
-                               );
+                               throw ApiUsageException::newWithMessage( null, 'apierror-bad-watchlist-token', 'bad_wltoken' );
                        }
                        return $watchlistOwner->getId();
                }
@@ -442,11 +479,13 @@ class WatchedItemQueryService {
 
                if ( isset( $options['start'] ) ) {
                        $after = $options['dir'] === self::DIR_OLDER ? '<=' : '>=';
-                       $conds[] = 'rc_timestamp ' . $after . ' ' . $db->addQuotes( $options['start'] );
+                       $conds[] = 'rc_timestamp ' . $after . ' ' .
+                               $db->addQuotes( $db->timestamp( $options['start'] ) );
                }
                if ( isset( $options['end'] ) ) {
                        $before = $options['dir'] === self::DIR_OLDER ? '>=' : '<=';
-                       $conds[] = 'rc_timestamp ' . $before . ' ' . $db->addQuotes( $options['end'] );
+                       $conds[] = 'rc_timestamp ' . $before . ' ' .
+                               $db->addQuotes( $db->timestamp( $options['end'] ) );
                }
 
                return $conds;
@@ -497,9 +536,9 @@ class WatchedItemQueryService {
                return '';
        }
 
-       private function getStartFromConds( IDatabase $db, array $options ) {
+       private function getStartFromConds( IDatabase $db, array $options, array $startFrom ) {
                $op = $options['dir'] === self::DIR_OLDER ? '<' : '>';
-               list( $rcTimestamp, $rcId ) = $options['startFrom'];
+               list( $rcTimestamp, $rcId ) = $startFrom;
                $rcTimestamp = $db->addQuotes( $db->timestamp( $rcTimestamp ) );
                $rcId = (int)$rcId;
                return $db->makeList(
@@ -581,7 +620,7 @@ class WatchedItemQueryService {
                }
 
                if ( array_key_exists( 'limit', $options ) ) {
-                       $dbOptions['LIMIT'] = (int)$options['limit'];
+                       $dbOptions['LIMIT'] = (int)$options['limit'] + 1;
                }
 
                return $dbOptions;