Remove un-needed cast for array key in WatchedItemStore
[lhc/web/wiklou.git] / includes / WatchedItemStore.php
index ff3ae21..9e21f14 100644 (file)
@@ -225,6 +225,29 @@ class WatchedItemStore {
                $this->loadBalancer->reuseConnection( $connection );
        }
 
+       /**
+        * Count the number of individual items that are watched by the user.
+        * If a subject and corresponding talk page are watched this will return 2.
+        *
+        * @param User $user
+        *
+        * @return int
+        */
+       public function countWatchedItems( User $user ) {
+               $dbr = $this->getConnection( DB_SLAVE );
+               $return = (int)$dbr->selectField(
+                       'watchlist',
+                       'COUNT(*)',
+                       [
+                               'wl_user' => $user->getId()
+                       ],
+                       __METHOD__
+               );
+               $this->reuseConnection( $dbr );
+
+               return $return;
+       }
+
        /**
         * @param LinkTarget $target
         *
@@ -316,6 +339,100 @@ class WatchedItemStore {
                return $watchCounts;
        }
 
+       /**
+        * Number of watchers of each page who have visited recent edits to that page
+        *
+        * @param array $targetsWithVisitThresholds array of pairs (LinkTarget $target, mixed $threshold),
+        *        $threshold is:
+        *        - a timestamp of the recent edit if $target exists (format accepted by wfTimestamp)
+        *        - null if $target doesn't exist
+        * @param int|null $minimumWatchers
+        * @return array multi-dimensional like $return[$namespaceId][$titleString] = $watchers,
+        *         where $watchers is an int:
+        *         - if the page exists, number of users watching who have visited the page recently
+        *         - if the page doesn't exist, number of users that have the page on their watchlist
+        *         - 0 means there are no visiting watchers or their number is below the minimumWatchers
+        *         option (if passed).
+        */
+       public function countVisitingWatchersMultiple(
+               array $targetsWithVisitThresholds,
+               $minimumWatchers = null
+       ) {
+               $dbr = $this->getConnection( DB_SLAVE );
+
+               $conds = $this->getVisitingWatchersCondition( $dbr, $targetsWithVisitThresholds );
+
+               $dbOptions = [ 'GROUP BY' => [ 'wl_namespace', 'wl_title' ] ];
+               if ( $minimumWatchers !== null ) {
+                       $dbOptions['HAVING'] = 'COUNT(*) >= ' . (int)$minimumWatchers;
+               }
+               $res = $dbr->select(
+                       'watchlist',
+                       [ 'wl_namespace', 'wl_title', 'watchers' => 'COUNT(*)' ],
+                       $conds,
+                       __METHOD__,
+                       $dbOptions
+               );
+
+               $this->reuseConnection( $dbr );
+
+               $watcherCounts = [];
+               foreach ( $targetsWithVisitThresholds as list( $target ) ) {
+                       /* @var LinkTarget $target */
+                       $watcherCounts[$target->getNamespace()][$target->getDBkey()] = 0;
+               }
+
+               foreach ( $res as $row ) {
+                       $watcherCounts[$row->wl_namespace][$row->wl_title] = (int)$row->watchers;
+               }
+
+               return $watcherCounts;
+       }
+
+       /**
+        * Generates condition for the query used in a batch count visiting watchers.
+        *
+        * @param IDatabase $db
+        * @param array $targetsWithVisitThresholds array of pairs (LinkTarget, last visit threshold)
+        * @return string
+        */
+       private function getVisitingWatchersCondition(
+               IDatabase $db,
+               array $targetsWithVisitThresholds
+       ) {
+               $missingTargets = [];
+               $namespaceConds = [];
+               foreach ( $targetsWithVisitThresholds as list( $target, $threshold ) ) {
+                       if ( $threshold === null ) {
+                               $missingTargets[] = $target;
+                               continue;
+                       }
+                       /* @var LinkTarget $target */
+                       $namespaceConds[$target->getNamespace()][] = $db->makeList( [
+                               'wl_title = ' . $db->addQuotes( $target->getDBkey() ),
+                               $db->makeList( [
+                                       'wl_notificationtimestamp >= ' . $db->addQuotes( $db->timestamp( $threshold ) ),
+                                       'wl_notificationtimestamp IS NULL'
+                               ], LIST_OR )
+                       ], LIST_AND );
+               }
+
+               $conds = [];
+               foreach ( $namespaceConds as $namespace => $pageConds ) {
+                       $conds[] = $db->makeList( [
+                               'wl_namespace = ' . $namespace,
+                               '(' . $db->makeList( $pageConds, LIST_OR ) . ')'
+                       ], LIST_AND );
+               }
+
+               if ( $missingTargets ) {
+                       $lb = new LinkBatch( $missingTargets );
+                       $conds[] = $lb->constructSet( 'wl', $db );
+               }
+
+               return $db->makeList( $conds, LIST_OR );
+       }
+
        /**
         * Get an item (may be cached)
         *
@@ -373,6 +490,38 @@ class WatchedItemStore {
                return $item;
        }
 
+       /**
+        * @param User $user
+        * @param array $options Allowed keys:
+        *        'forWrite' => bool defaults to false
+        *
+        * @return WatchedItem[]
+        */
+       public function getWatchedItemsForUser( User $user, array $options = [] ) {
+               $options += [ 'forWrite' => false ];
+
+               $db = $this->getConnection( $options['forWrite'] ? DB_MASTER : DB_SLAVE );
+               $res = $db->select(
+                       'watchlist',
+                       [ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
+                       [ 'wl_user' => $user->getId() ],
+                       __METHOD__
+               );
+               $this->reuseConnection( $db );
+
+               $watchedItems = [];
+               foreach ( $res as $row ) {
+                       // todo these could all be cached at some point?
+                       $watchedItems[] = new WatchedItem(
+                               $user,
+                               new TitleValue( (int)$row->wl_namespace, $row->wl_title ),
+                               $row->wl_notificationtimestamp
+                       );
+               }
+
+               return $watchedItems;
+       }
+
        /**
         * Must be called separately for Subject & Talk namespaces
         *
@@ -385,6 +534,61 @@ class WatchedItemStore {
                return (bool)$this->getWatchedItem( $user, $target );
        }
 
+       /**
+        * @param User $user
+        * @param LinkTarget[] $targets
+        *
+        * @return array multi-dimensional like $return[$namespaceId][$titleString] = $timestamp,
+        *         where $timestamp is:
+        *         - string|null value of wl_notificationtimestamp,
+        *         - false if $target is not watched by $user.
+        */
+       public function getNotificationTimestampsBatch( User $user, array $targets ) {
+               $timestamps = [];
+               foreach ( $targets as $target ) {
+                       $timestamps[$target->getNamespace()][$target->getDBkey()] = false;
+               }
+
+               if ( $user->isAnon() ) {
+                       return $timestamps;
+               }
+
+               $targetsToLoad = [];
+               foreach ( $targets as $target ) {
+                       $cachedItem = $this->getCached( $user, $target );
+                       if ( $cachedItem ) {
+                               $timestamps[$target->getNamespace()][$target->getDBkey()] =
+                                       $cachedItem->getNotificationTimestamp();
+                       } else {
+                               $targetsToLoad[] = $target;
+                       }
+               }
+
+               if ( !$targetsToLoad ) {
+                       return $timestamps;
+               }
+
+               $dbr = $this->getConnection( DB_SLAVE );
+
+               $lb = new LinkBatch( $targetsToLoad );
+               $res = $dbr->select(
+                       'watchlist',
+                       [ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
+                       [
+                               $lb->constructSet( 'wl', $dbr ),
+                               'wl_user' => $user->getId(),
+                       ],
+                       __METHOD__
+               );
+               $this->reuseConnection( $dbr );
+
+               foreach ( $res as $row ) {
+                       $timestamps[$row->wl_namespace][$row->wl_title] = $row->wl_notificationtimestamp;
+               }
+
+               return $timestamps;
+       }
+
        /**
         * Must be called separately for Subject & Talk namespaces
         *