Add method to determine unread articles per category
authorJoshua Rüsweg <josh@bastelstu.be>
Wed, 29 Aug 2018 14:47:18 +0000 (16:47 +0200)
committerJoshua Rüsweg <josh@bastelstu.be>
Wed, 29 Aug 2018 14:47:18 +0000 (16:47 +0200)
See #2648

wcfsetup/install/files/lib/data/article/ArticleAction.class.php
wcfsetup/install/files/lib/data/article/ViewableArticle.class.php

index 4a86e8ac6883a82bf969919aec7477311251e83c..ee7eb976f8035060037d6be02571b28534587591 100644 (file)
@@ -140,6 +140,7 @@ class ArticleAction extends AbstractDatabaseObjectAction {
                if (ARTICLE_ENABLE_VISIT_TRACKING) {
                        UserStorageHandler::getInstance()->resetAll('unreadArticles');
                        UserStorageHandler::getInstance()->resetAll('unreadWatchedArticles');
+                       UserStorageHandler::getInstance()->resetAll('unreadArticlesByCategory');
                }
                
                if ($article->publicationStatus == Article::PUBLISHED) {
@@ -257,6 +258,7 @@ class ArticleAction extends AbstractDatabaseObjectAction {
                if (ARTICLE_ENABLE_VISIT_TRACKING) {
                        UserStorageHandler::getInstance()->resetAll('unreadArticles');
                        UserStorageHandler::getInstance()->resetAll('unreadWatchedArticles');
+                       UserStorageHandler::getInstance()->resetAll('unreadArticlesByCategory');
                }
                
                $publicationStatus = (isset($this->parameters['data']['publicationStatus'])) ? $this->parameters['data']['publicationStatus'] : null;
@@ -400,6 +402,7 @@ class ArticleAction extends AbstractDatabaseObjectAction {
                if (ARTICLE_ENABLE_VISIT_TRACKING) {
                        UserStorageHandler::getInstance()->resetAll('unreadArticles');
                        UserStorageHandler::getInstance()->resetAll('unreadWatchedArticles');
+                       UserStorageHandler::getInstance()->resetAll('unreadArticlesByCategory');
                }
                
                return ['objectIDs' => $this->objectIDs];
@@ -428,6 +431,7 @@ class ArticleAction extends AbstractDatabaseObjectAction {
                if (ARTICLE_ENABLE_VISIT_TRACKING) {
                        UserStorageHandler::getInstance()->resetAll('unreadArticles');
                        UserStorageHandler::getInstance()->resetAll('unreadWatchedArticles');
+                       UserStorageHandler::getInstance()->resetAll('unreadArticlesByCategory');
                }
                
                return ['objectIDs' => $this->objectIDs];
@@ -529,6 +533,7 @@ class ArticleAction extends AbstractDatabaseObjectAction {
                if (WCF::getUser()->userID) {
                        UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadArticles');
                        UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadWatchedArticles');
+                       UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadArticlesByCategory');
                }
        }
        
@@ -542,6 +547,7 @@ class ArticleAction extends AbstractDatabaseObjectAction {
                if (WCF::getUser()->userID) {
                        UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadArticles');
                        UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadWatchedArticles');
+                       UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadArticlesByCategory');
                }
        }
        
@@ -650,6 +656,7 @@ class ArticleAction extends AbstractDatabaseObjectAction {
                if (ARTICLE_ENABLE_VISIT_TRACKING) {
                        UserStorageHandler::getInstance()->resetAll('unreadArticles');
                        UserStorageHandler::getInstance()->resetAll('unreadWatchedArticles');
+                       UserStorageHandler::getInstance()->resetAll('unreadArticlesByCategory');
                }
                
                $this->unmarkItems();
index dd231f5ec8325577faf664e94b7efc9598879b80..7b74c1cc27264e5199aac2ff6b65d44623b75a81 100644 (file)
@@ -55,9 +55,17 @@ class ViewableArticle extends DatabaseObjectDecorator {
        /**
         * number of unread articles in watched categories
         * @var integer
+        * @since 3.2
         */
        protected static $unreadWatchedArticles;
        
+       /**
+        * number of unread articles ordered by categories
+        * @var integer
+        * @since 3.2
+        */
+       protected static $unreadArticlesByCategory;
+       
        /**
         * list of assigned labels
         * @var Label[]
@@ -244,10 +252,97 @@ class ViewableArticle extends DatabaseObjectDecorator {
                return self::$unreadArticles;
        }
        
+       /**
+        * Returns the number of unread articles for a specific category.
+        *
+        * @param       integer         $articleCategoryID
+        * @return      integer
+        * @since       3.2
+        */
+       public static function getUnreadArticlesForCategory($articleCategoryID) {
+               if (self::$unreadArticlesByCategory === null) {
+                       self::$unreadArticlesByCategory = [];
+                       
+                       if (WCF::getUser()->userID) {
+                               $unreadArticlesByCategory = UserStorageHandler::getInstance()->getField('unreadArticlesByCategory');
+                               
+                               // cache does not exist or is outdated
+                               if ($unreadArticlesByCategory === null) {
+                                       self::$unreadArticlesByCategory[$articleCategoryID] = self::fetchUnreadArticlesForCategory($articleCategoryID);
+                                       
+                                       // update storage unreadEntries
+                                       UserStorageHandler::getInstance()->update(WCF::getUser()->userID, 'unreadArticlesByCategory', serialize(self::$unreadArticlesByCategory));
+                               }
+                               else {
+                                       $unreadArticlesByCategory = unserialize($unreadArticlesByCategory);
+                                       
+                                       if (isset($unreadArticlesByCategory[$articleCategoryID])) {
+                                               self::$unreadArticlesByCategory = $unreadArticlesByCategory;
+                                       }
+                                       else {
+                                               self::$unreadArticlesByCategory[$articleCategoryID] = self::fetchUnreadArticlesForCategory($articleCategoryID);
+                                               
+                                               // update storage unreadEntries
+                                               UserStorageHandler::getInstance()->update(WCF::getUser()->userID, 'unreadArticlesByCategory', serialize(self::$unreadArticlesByCategory));
+                                       }
+                               }
+                       }
+               }
+               
+               return self::$unreadArticlesByCategory[$articleCategoryID];
+       }
+       
+       /**
+        * Returns the unread article count for a specific category. 
+        * 
+        * @param       integer         $articleCategoryID
+        * @return      integer
+        * @since       3.2
+        */
+       private static function fetchUnreadArticlesForCategory($articleCategoryID) {
+               $accessibleCategoryIDs = ArticleCategory::getAccessibleCategoryIDs();
+               
+               if (!in_array($articleCategoryID, $accessibleCategoryIDs)) {
+                       // the category is not accessible
+                       return 0;
+               }
+               
+               $category = ArticleCategory::getCategory($articleCategoryID);
+               
+               if ($category === null) {
+                       throw new \InvalidArgumentException('The given article category id "'.$articleCategoryID.'" is not valid.');
+               }
+               
+               $categoryIDs = array_intersect(array_merge(array_map(function ($category) {
+                       /** @var ArticleCategory $category */
+                       return $category->categoryID;
+               }, $category->getChildCategories()), [$articleCategoryID]), $accessibleCategoryIDs);
+               
+               $conditionBuilder = new PreparedStatementConditionBuilder();
+               $conditionBuilder->add('article.categoryID IN (?)', [$categoryIDs]);
+               $conditionBuilder->add('article.time > ?', [VisitTracker::getInstance()->getVisitTime('com.woltlab.wcf.article')]);
+               $conditionBuilder->add('article.isDeleted = ?', [0]);
+               $conditionBuilder->add('article.publicationStatus = ?', [Article::PUBLISHED]);
+               $conditionBuilder->add('(article.time > tracked_visit.visitTime OR tracked_visit.visitTime IS NULL)');
+               
+               $sql = "SELECT          COUNT(*)
+                       FROM            wcf".WCF_N."_article article
+                       LEFT JOIN       wcf".WCF_N."_tracked_visit tracked_visit
+                       ON              (tracked_visit.objectTypeID = ".VisitTracker::getInstance()->getObjectTypeID('com.woltlab.wcf.article')."
+                                       AND tracked_visit.objectID = article.articleID
+                                       AND tracked_visit.userID = ".WCF::getUser()->userID.")
+                                       ".$conditionBuilder;
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute($conditionBuilder->getParameters());
+               
+               return $statement->fetchSingleColumn();
+       }
+       
        /**
         * Returns the number of unread articles in watched categories.
         *
         * @return      integer
+        * @since       3.2
         */
        public static function getWatchedUnreadArticles() {
                if (self::$unreadWatchedArticles === null) {