Add UserProfileCache
authorMatthias Schmidt <gravatronics@live.com>
Sun, 24 May 2015 11:05:58 +0000 (13:05 +0200)
committerMatthias Schmidt <gravatronics@live.com>
Sun, 24 May 2015 11:05:58 +0000 (13:05 +0200)
27 files changed:
CHANGELOG.md
wcfsetup/install/files/lib/data/TLegacyUserPropertyAccess.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/comment/CommentAction.class.php
wcfsetup/install/files/lib/data/comment/StructuredComment.class.php
wcfsetup/install/files/lib/data/comment/StructuredCommentList.class.php
wcfsetup/install/files/lib/data/comment/ViewableComment.class.php
wcfsetup/install/files/lib/data/comment/ViewableCommentList.class.php
wcfsetup/install/files/lib/data/comment/response/StructuredCommentResponse.class.php
wcfsetup/install/files/lib/data/comment/response/StructuredCommentResponseList.class.php
wcfsetup/install/files/lib/data/comment/response/ViewableCommentResponse.class.php
wcfsetup/install/files/lib/data/comment/response/ViewableCommentResponseList.class.php
wcfsetup/install/files/lib/data/like/ViewableLike.class.php
wcfsetup/install/files/lib/data/like/ViewableLikeList.class.php
wcfsetup/install/files/lib/data/moderation/queue/ViewableModerationQueue.class.php
wcfsetup/install/files/lib/data/moderation/queue/ViewableModerationQueueList.class.php
wcfsetup/install/files/lib/data/user/UserProfile.class.php
wcfsetup/install/files/lib/data/user/UserProfileCache.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/user/activity/event/ViewableUserActivityEvent.class.php
wcfsetup/install/files/lib/data/user/activity/event/ViewableUserActivityEventList.class.php
wcfsetup/install/files/lib/system/dashboard/box/MostActiveMembersDashboardBox.class.php
wcfsetup/install/files/lib/system/dashboard/box/MostLikedMembersDashboardBox.class.php
wcfsetup/install/files/lib/system/dashboard/box/NewestMembersDashboardBox.class.php
wcfsetup/install/files/lib/system/dashboard/box/TodaysBirthdaysDashboardBox.class.php
wcfsetup/install/files/lib/system/dashboard/box/TodaysFollowingBirthdaysDashboardBox.class.php
wcfsetup/install/files/lib/system/message/embedded/object/QuoteMessageEmbeddedObjectHandler.class.php
wcfsetup/install/files/lib/system/user/activity/event/ProfileCommentResponseUserActivityEvent.class.php
wcfsetup/install/files/lib/system/user/activity/event/ProfileCommentUserActivityEvent.class.php

index 064cb5d3cee3c4344bf50bfdf44f7e9f3bf36d9e..39be1748cf03a0035a3f1618ef3e415e158ec305 100644 (file)
@@ -4,6 +4,7 @@
 
 ### 2.2.0 Alpha 1 (XXXX-YY-ZZ)
 
+* `wcf\data\user\UserProfileCache` for caching user profiles during runtime.
 * instruction file name for most PIPs has default value provided by `wcf\system\package\plugin\IPackageInstallationPlugin::getDefaultFilename()`.
 * `options` support for cronjobs.
 * `name` attribute for cronjob PIP (`cronjobName` for cronjob objects).
diff --git a/wcfsetup/install/files/lib/data/TLegacyUserPropertyAccess.class.php b/wcfsetup/install/files/lib/data/TLegacyUserPropertyAccess.class.php
new file mode 100644 (file)
index 0000000..399b65b
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+namespace wcf\data;
+
+/**
+ * Provides legacy access to the properties of the related user profile object.
+ *
+ * @author     Matthias Schmidt
+ * @copyright  2001-2015 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.user
+ * @category   Community Framework
+ * @deprecated
+ */
+trait TLegacyUserPropertyAccess {
+       /**
+        * @see \wcf\data\IStorableObject::__get()
+        */
+       public function __get($name) {
+               $value = parent::__get($name);
+               if ($value !== null) {
+                       return $value;
+               }
+               else if (!($this instanceof DatabaseObjectDecorator) && array_key_exists($name, $this->data)) {
+                       return null;
+               }
+               else if ($this instanceof DatabaseObjectDecorator && array_key_exists($name, $this->object->data)) {
+                       return null;
+               }
+               
+               // in case any code should rely on directly accessing user properties,
+               // refer them to the user profile object
+               return $this->getUserProfile()->$name;
+       }
+}
index 58f6b011a750b092c80c7b9c21fc6b7066351622..9be651011f72c6882819427e3ccfdd57b7924160 100644 (file)
@@ -630,12 +630,6 @@ class CommentAction extends AbstractDatabaseObjectAction {
                $comment->setIsDeletable($this->commentProcessor->canDeleteComment($comment->getDecoratedObject()));
                $comment->setIsEditable($this->commentProcessor->canEditComment($comment->getDecoratedObject()));
                
-               // set user profile
-               if ($comment->userID) {
-                       $userProfile = UserProfile::getUserProfile($comment->userID);
-                       $comment->setUserProfile($userProfile);
-               }
-               
                WCF::getTPL()->assign(array(
                        'commentList' => array($comment),
                        'commentManager' => $this->commentProcessor
@@ -654,12 +648,6 @@ class CommentAction extends AbstractDatabaseObjectAction {
                $response->setIsDeletable($this->commentProcessor->canDeleteResponse($response->getDecoratedObject()));
                $response->setIsEditable($this->commentProcessor->canEditResponse($response->getDecoratedObject()));
                
-               // set user profile
-               if ($response->userID) {
-                       $userProfile = UserProfile::getUserProfile($response->userID);
-                       $response->setUserProfile($userProfile);
-               }
-               
                // render response
                WCF::getTPL()->assign(array(
                        'responseList' => array($response),
index 18de999aa031b785012574b43c19de2435cf31b9..1aca1fd78921501e8db48bcaf62af0f9098a74c1 100644 (file)
@@ -3,6 +3,7 @@ namespace wcf\data\comment;
 use wcf\data\comment\response\StructuredCommentResponse;
 use wcf\data\user\User;
 use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\data\DatabaseObjectDecorator;
 
 /**
@@ -103,7 +104,14 @@ class StructuredComment extends DatabaseObjectDecorator implements \Countable, \
         */
        public function getUserProfile() {
                if ($this->userProfile === null) {
-                       $this->userProfile = new UserProfile(new User(null, $this->data));
+                       if ($this->userID) {
+                               $this->userProfile = UserProfileCache::getInstance()->getUserProfile($this->userID);
+                       }
+                       else {
+                               $this->userProfile = new UserProfile(new User(null, array(
+                                       'username' => $this->username
+                               )));
+                       }
                }
                
                return $this->userProfile;
index fe33bc3180b0d9a60cee13fc7620dab0962c3316..a78d9f6beb15fb9a38ec54bb3b832543d7fd6e21 100644 (file)
@@ -2,7 +2,7 @@
 namespace wcf\data\comment;
 use wcf\data\comment\response\CommentResponseList;
 use wcf\data\comment\response\StructuredCommentResponse;
-use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\system\comment\manager\ICommentManager;
 use wcf\system\like\LikeHandler;
 
@@ -125,22 +125,9 @@ class StructuredCommentList extends CommentList {
                        }
                }
                
-               // fetch user data and avatars
+               // cache user ids
                if (!empty($userIDs)) {
-                       $userIDs = array_unique($userIDs);
-                       
-                       $users = UserProfile::getUserProfiles($userIDs);
-                       foreach ($this->objects as $comment) {
-                               if ($comment->userID && isset($users[$comment->userID])) {
-                                       $comment->setUserProfile($users[$comment->userID]);
-                               }
-                               
-                               foreach ($comment as $response) {
-                                       if ($response->userID && isset($users[$response->userID])) {
-                                               $response->setUserProfile($users[$response->userID]);
-                                       }
-                               }
-                       }
+                       UserProfileCache::getInstance()->cacheUserIDs(array_unique($userIDs));
                }
        }
        
index 2036c37b718ea46c3f9192bb945c09030226e498..f505207ce8a299dc52e9839f6c14e4ef44ea02e0 100644 (file)
@@ -2,7 +2,9 @@
 namespace wcf\data\comment;
 use wcf\data\user\User;
 use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\data\DatabaseObjectDecorator;
+use wcf\data\TLegacyUserPropertyAccess;
 
 /**
  * Represents a viewable comment.
@@ -15,6 +17,8 @@ use wcf\data\DatabaseObjectDecorator;
  * @category   Community Framework
  */
 class ViewableComment extends DatabaseObjectDecorator {
+       use TLegacyUserPropertyAccess;
+       
        /**
         * @see \wcf\data\DatabaseObjectDecorator::$baseClass
         */
@@ -33,7 +37,14 @@ class ViewableComment extends DatabaseObjectDecorator {
         */
        public function getUserProfile() {
                if ($this->userProfile === null) {
-                       $this->userProfile = new UserProfile(new User(null, $this->getDecoratedObject()->data));
+                       if ($this->userID) {
+                               $this->userProfile = UserProfileCache::getInstance()->getUserProfile($this->userID);
+                       }
+                       else {
+                               $this->userProfile = new UserProfile(new User(null, array(
+                                       'username' => $this->username
+                               )));
+                       }
                }
                
                return $this->userProfile;
index af5c942d7a621cfa505af9ff251af45ce7d831d9..89b8db4c54bb890951e1470fea38c395b838936b 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\data\comment;
+use wcf\data\user\UserProfileCache;
 
 /**
  * Represents a list of decorated comment objects.
@@ -17,16 +18,20 @@ class ViewableCommentList extends CommentList {
         */
        public $decoratorClassName = 'wcf\data\comment\ViewableComment';
        
-       /**
-        * Creates a new ViewableCommentList object.
-        */
-       public function __construct() {
-               parent::__construct();
+       public function readObjects() {
+               parent::readObjects();
                
-               // get avatars
-               if (!empty($this->sqlSelects)) $this->sqlSelects .= ',';
-               $this->sqlSelects .= "user_avatar.*, user_table.*";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user user_table ON (user_table.userID = comment.userID)";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_avatar user_avatar ON (user_avatar.avatarID = user_table.avatarID)";
+               if (!empty($this->objects)) {
+                       $userIDs = array();
+                       foreach ($this->objects as $comment) {
+                               if ($comment->userID) {
+                                       $userIDs[] = $comment->userID;
+                               }
+                       }
+                       
+                       if (!empty($userIDs)) {
+                               UserProfileCache::getInstance()->cacheUserIDs($userIDs);
+                       }
+               }
        }
 }
index 8ac2e58ae9f193448dcd1b24ad93267269365ed0..9ead82e6fb3eaf63bb475ca73b698eeb5382655d 100644 (file)
@@ -2,6 +2,7 @@
 namespace wcf\data\comment\response;
 use wcf\data\user\User;
 use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\data\DatabaseObjectDecorator;
 
 /**
@@ -54,7 +55,14 @@ class StructuredCommentResponse extends DatabaseObjectDecorator {
         */
        public function getUserProfile() {
                if ($this->userProfile === null) {
-                       $this->userProfile = new UserProfile(new User(null, $this->data));
+                       if ($this->userID) {
+                               $this->userProfile = UserProfileCache::getInstance()->getUserProfile($this->userID);
+                       }
+                       else {
+                               $this->userProfile = new UserProfile(new User(null, array(
+                                       'username' => $this->username
+                               )));
+                       }
                }
                
                return $this->userProfile;
@@ -75,9 +83,10 @@ class StructuredCommentResponse extends DatabaseObjectDecorator {
                // prepare structured response
                $response = new StructuredCommentResponse($response);
                
-               // add user profile
-               $userProfile = UserProfile::getUserProfile($response->userID);
-               $response->setUserProfile($userProfile);
+               // cache user profile
+               if ($response->userID) {
+                       UserProfileCache::getInstance()->cacheUserID($response->userID);
+               }
                
                return $response;
        }
index a8139a2ec62a2684b0d9c5648df50709309d8549..67e02014bdb13eede4bcb8f9ff6103b550a1455f 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 namespace wcf\data\comment\response;
 use wcf\data\comment\Comment;
-use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\system\comment\manager\ICommentManager;
 use wcf\system\like\LikeHandler;
 
@@ -76,16 +76,9 @@ class StructuredCommentResponseList extends CommentResponseList {
                        $response->setIsEditable($this->commentManager->canEditResponse($response->getDecoratedObject()));
                }
                
-               // fetch user data and avatars
+               // cache user ids
                if (!empty($userIDs)) {
-                       $userIDs = array_unique($userIDs);
-                       
-                       $users = UserProfile::getUserProfiles($userIDs);
-                       foreach ($this->objects as $response) {
-                               if (isset($users[$response->userID])) {
-                                       $response->setUserProfile($users[$response->userID]);
-                               }
-                       }
+                       UserProfileCache::getInstance()->cacheUserIDs(array_unique($userIDs));
                }
        }
        
index a90ae1c9532923c3b5f6a4a1efffbf74378a0a4b..63c88d99cc7f4858ad6d03e29533cc3135138a41 100644 (file)
@@ -2,7 +2,9 @@
 namespace wcf\data\comment\response;
 use wcf\data\user\User;
 use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\data\DatabaseObjectDecorator;
+use wcf\data\TLegacyUserPropertyAccess;
 
 /**
  * Represents a viewable comment response.
@@ -15,6 +17,8 @@ use wcf\data\DatabaseObjectDecorator;
  * @category   Community Framework
  */
 class ViewableCommentResponse extends DatabaseObjectDecorator {
+       use TLegacyUserPropertyAccess;
+       
        /**
         * @see \wcf\data\DatabaseObjectDecorator::$baseClass
         */
@@ -33,7 +37,14 @@ class ViewableCommentResponse extends DatabaseObjectDecorator {
         */
        public function getUserProfile() {
                if ($this->userProfile === null) {
-                       $this->userProfile = new UserProfile(new User(null, $this->getDecoratedObject()->data));
+                       if ($this->userID) {
+                               $this->userProfile = UserProfileCache::getInstance()->getUserProfile($this->userID);
+                       }
+                       else {
+                               $this->userProfile = new UserProfile(new User(null, array(
+                                       'username' => $this->username
+                               )));
+                       }
                }
                
                return $this->userProfile;
index e39253be811ea4c4d797fd1ed5fe19d57f6bbab8..97b9f8454886a4fbf7713ce4c9945d72862700f1 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\data\comment\response;
+use wcf\data\user\UserProfileCache;
 
 /**
  * Represents a list of decorated comment response objects.
@@ -16,17 +17,21 @@ class ViewableCommentResponseList extends CommentResponseList {
         * @see \wcf\data\DatabaseObjectList::$decoratorClassName
         */
        public $decoratorClassName = 'wcf\data\comment\response\ViewableCommentResponse';
-
-       /**
-        * Creates a new ViewableCommentResponseList object.
-        */
-       public function __construct() {
-               parent::__construct();
        
-               // get avatars
-               if (!empty($this->sqlSelects)) $this->sqlSelects .= ',';
-               $this->sqlSelects .= "user_avatar.*, user_table.*";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user user_table ON (user_table.userID = comment_response.userID)";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_avatar user_avatar ON (user_avatar.avatarID = user_table.avatarID)";
+       public function readObjects() {
+               parent::readObjects();
+               
+               if (!empty($this->objects)) {
+                       $userIDs = array();
+                       foreach ($this->objects as $response) {
+                               if ($response->userID) {
+                                       $userIDs[] = $response->userID;
+                               }
+                       }
+                       
+                       if (!empty($userIDs)) {
+                               UserProfileCache::getInstance()->cacheUserIDs($userIDs);
+                       }
+               }
        }
 }
index 1400e8b1e887c22a373f0c23b743c5d7fc5a325c..4c860373d0a7ae097cfd9cedbef7577752534b4c 100644 (file)
@@ -2,6 +2,7 @@
 namespace wcf\data\like;
 use wcf\data\object\type\ObjectTypeCache;
 use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\data\DatabaseObjectDecorator;
 
 /**
@@ -75,6 +76,10 @@ class ViewableLike extends DatabaseObjectDecorator {
         * @return      \wcf\data\user\UserProfile
         */
        public function getUserProfile() {
+               if ($this->userProfile === null) {
+                       $this->userProfile = UserProfileCache::getInstance()->getUserProfile($this->userID);
+               }
+               
                return $this->userProfile;
        }
        
index 9199d3178f79e7b66693c786db76fe717dc940ad..21e15489e96dcc542ef7d5efe93e4ad4f1deeb8b 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 namespace wcf\data\like;
 use wcf\data\object\type\ObjectTypeCache;
-use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\system\like\IViewableLikeProvider;
 
 /**
@@ -59,12 +59,7 @@ class ViewableLikeList extends LikeList {
                
                // set user profiles
                if (!empty($userIDs)) {
-                       $userIDs = array_unique($userIDs);
-                       
-                       $users = UserProfile::getUserProfiles($userIDs);
-                       foreach ($this->objects as $like) {
-                               $like->setUserProfile($users[$like->userID]);
-                       }
+                       UserProfileCache::getInstance()->cacheUserIDs(array_unique($userIDs));
                }
                
                // parse like
index 3b1566cba9180eda6c098a0ac23c5919f8014e13..a98ea6445391fb3cc0af4fb25dbea83cd6b30db0 100644 (file)
@@ -3,6 +3,7 @@ namespace wcf\data\moderation\queue;
 use wcf\data\object\type\ObjectTypeCache;
 use wcf\data\user\User;
 use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\data\DatabaseObjectDecorator;
 use wcf\data\IUserContent;
 use wcf\system\moderation\queue\ModerationQueueManager;
@@ -97,7 +98,7 @@ class ViewableModerationQueue extends DatabaseObjectDecorator {
        public function getUserProfile() {
                if ($this->affectedObject !== null && $this->userProfile === null) {
                        if ($this->affectedObject->getUserID()) {
-                               $this->userProfile = UserProfile::getUserProfile($this->affectedObject->getUserID());
+                               $this->userProfile = UserProfileCache::getInstance()->getUserProfile($this->affectedObject->getUserID());
                        }
                        else {
                                $this->userProfile = new UserProfile(new User(null, array()));
index 1ddd7061afe09d23539ad197015f270ee5d10f73..7c6d6556a14dc373de5ba0819b14684d137e89b1 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 namespace wcf\data\moderation\queue;
-use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\system\moderation\queue\ModerationQueueManager;
 use wcf\system\WCF;
 
@@ -93,12 +93,7 @@ class ViewableModerationQueueList extends ModerationQueueList {
                                        $userIDs[] = $object->getAffectedObject()->getUserID();
                                }
                                
-                               $userProfiles = UserProfile::getUserProfiles($userIDs);
-                               foreach ($this->objects as $object) {
-                                       if (isset($userProfiles[$object->getAffectedObject()->getUserID()])) {
-                                               $object->setUserProfile($userProfiles[$object->getAffectedObject()->getUserID()]);
-                                       }
-                               }
+                               UserProfileCache::getInstance()->cacheUserIDs(array_unique($userIDs));
                        }
                }
        }
index ec2078e1cbb164a4de0ffbb1d6acc985da891464..aa2129da4e6bd1f06a4d383c8039d7433b0a02a9 100644 (file)
@@ -342,11 +342,10 @@ class UserProfile extends DatabaseObjectDecorator implements IBreadcrumbProvider
         * 
         * @param       integer                         $userID
         * @return      \wcf\data\user\UserProfile
+        * @deprecated  use UserProfileCache::getUserProfile()
         */
        public static function getUserProfile($userID) {
-               $users = self::getUserProfiles(array($userID));
-               
-               return (isset($users[$userID]) ? $users[$userID] : null);
+               return UserProfileCache::getInstance()->getUserProfile($userID);
        }
        
        /**
@@ -354,26 +353,15 @@ class UserProfile extends DatabaseObjectDecorator implements IBreadcrumbProvider
         * 
         * @param       array                           $userIDs
         * @return      array<\wcf\data\user\UserProfile>
+        * @deprecated  use UserProfileCache::getUserProfiles()
         */
        public static function getUserProfiles(array $userIDs) {
-               $users = array();
-               
-               // check cache
-               foreach ($userIDs as $index => $userID) {
-                       if (isset(self::$userProfiles[$userID])) {
-                               $users[$userID] = self::$userProfiles[$userID];
-                               unset($userIDs[$index]);
-                       }
-               }
+               $users = UserProfileCache::getInstance()->getUserProfiles($userIDs);
                
-               if (!empty($userIDs)) {
-                       $userList = new UserProfileList();
-                       $userList->setObjectIDs($userIDs);
-                       $userList->readObjects();
-                       
-                       foreach ($userList as $user) {
-                               $users[$user->userID] = $user;
-                               self::$userProfiles[$user->userID] = $user;
+               // this method does not return null for non-existing user profiles
+               foreach ($users as $userID => $user) {
+                       if ($user === null) {
+                               unset($users[$userID]);
                        }
                }
                
@@ -385,6 +373,7 @@ class UserProfile extends DatabaseObjectDecorator implements IBreadcrumbProvider
         * 
         * @param       string                          $username
         * @return      \wcf\data\user\UserProfile
+        * @todo        move to UserProfileCache?
         */
        public static function getUserProfileByUsername($username) {
                $users = self::getUserProfilesByUsername(array($username));
@@ -397,6 +386,7 @@ class UserProfile extends DatabaseObjectDecorator implements IBreadcrumbProvider
         * 
         * @param       array<string>                   $usernames
         * @return      array<\wcf\data\user\UserProfile>
+        * @todo        move to UserProfileCache?
         */
        public static function getUserProfilesByUsername(array $usernames) {
                $users = array();
@@ -411,8 +401,9 @@ class UserProfile extends DatabaseObjectDecorator implements IBreadcrumbProvider
                unset($username);
                
                // check cache
+               $userProfiles = UserProfileCache::getInstance()->getCachedUserProfiles();
                foreach ($usernames as $index => $username) {
-                       foreach (self::$userProfiles as $user) {
+                       foreach ($userProfiles as $user) {
                                if (mb_strtolower($user->username) === $username) {
                                        $users[$username] = $user;
                                        unset($usernames[$index]);
diff --git a/wcfsetup/install/files/lib/data/user/UserProfileCache.class.php b/wcfsetup/install/files/lib/data/user/UserProfileCache.class.php
new file mode 100644 (file)
index 0000000..3067768
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+namespace wcf\data\user;
+use wcf\system\SingletonFactory;
+
+/**
+ * Caches user profile objects during runtime.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2015 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.user
+ * @category   Community Framework
+ */
+class UserProfileCache extends SingletonFactory {
+       /**
+        * cached user ids whose profiles will be loaded during the next request
+        * @var array<integer>
+        */
+       protected $userIDs = array();
+       
+       /**
+        * locally cached user profiles
+        * @var array<\wcf\data\user\UserProfile>
+        */
+       protected $userProfiles = array();
+       
+       /**
+        * Caches the given user id.
+        * 
+        * @param       integer         $userID
+        */
+       public function cacheUserID($userID) {
+               $this->userIDs[] = $userID;
+       }
+       
+       /**
+        * Caches the given user ids.
+        * 
+        * @param       array<integer>          $userID
+        */
+       public function cacheUserIDs(array $userIDs) {
+               $this->userIDs = array_merge($this->userIDs, $userIDs);
+       }
+       
+       /**
+        * Returns all currently cached user profile objects.
+        * 
+        * @return      array<\wcf\data\user\UserProfile>
+        */
+       public function getCachedUserProfiles() {
+               return $this->userProfiles;
+       }
+       
+       /**
+        * Returns the user profile of the user with the given user id. If no such
+        * user profile exists, null is returned.
+        * 
+        * @param       integer         $userID
+        * @return      \wcf\data\user\UserProfile
+        */
+       public function getUserProfile($userID) {
+               if (array_key_exists($userID, $this->userProfiles)) {
+                       return $this->userProfiles[$userID];
+               }
+               
+               return $this->getUserProfiles(array($userID))[$userID];
+       }
+       
+       /**
+        * Returns the user profiles of the users with the given user ids. For ids
+        * without a user profile, null is returned.
+        * 
+        * @param       array<integer>          $userIDs
+        * @return      array<\wcf\data\user\UserProfile>
+        */
+       public function getUserProfiles(array $userIDs) {
+               $userProfiles = array();
+               foreach ($userIDs as $key => $userID) {
+                       if (array_key_exists($userID, $this->userProfiles)) {
+                               $userProfiles[$userID] = $this->userProfiles[$userID];
+                               
+                               unset($userIDs[$key]);
+                       }
+               }
+               
+               if (empty($userIDs)) {
+                       return $userProfiles;
+               }
+               
+               $this->userIDs = array_unique(array_merge($this->userIDs, $userIDs));
+               
+               $userProfileList = new UserProfileList();
+               $userProfileList->setObjectIDs($this->userIDs);
+               $userProfileList->readObjects();
+               $readUserProfiles = $userProfileList->getObjects();
+               
+               foreach ($this->userIDs as $userID) {
+                       if (!isset($readUserProfiles[$userID])) {
+                               $this->userProfiles[$userID] = null;
+                       }
+                       else {
+                               $this->userProfiles[$userID] = $readUserProfiles[$userID];
+                       }
+               }
+               
+               $this->userIDs = array();
+               
+               foreach ($userIDs as $userID) {
+                       $userProfiles[$userID] = $this->userProfiles[$userID];
+               }
+               
+               return $userProfiles;
+       }
+}
index a7e41ff778b6271c02c307db628f9b0e369ceee3..19e6736ba0b50faf7ae6882616f4d4f923499d5e 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace wcf\data\user\activity\event;
 use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\data\DatabaseObjectDecorator;
 use wcf\system\user\activity\event\UserActivityEventHandler;
 
@@ -97,6 +98,10 @@ class ViewableUserActivityEvent extends DatabaseObjectDecorator {
         * @return      \wcf\data\user\UserProfile
         */
        public function getUserProfile() {
+               if ($this->userProfile === null) {
+                       $this->userProfile = UserProfileCache::getInstance()->getUserProfile($this->userID);
+               }
+               
                return $this->userProfile;
        }
        
index 1455c716f7333ab0f6480434ac10d23243f72630..afdb5f3b38d665d8295cdcba8c7a15b2d80cf209 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 namespace wcf\data\user\activity\event;
-use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 use wcf\system\language\LanguageFactory;
 use wcf\system\user\activity\event\UserActivityEventHandler;
 use wcf\system\WCF;
@@ -71,12 +71,7 @@ class ViewableUserActivityEventList extends UserActivityEventList {
                
                // set user profiles
                if (!empty($userIDs)) {
-                       $userIDs = array_unique($userIDs);
-                       
-                       $users = UserProfile::getUserProfiles($userIDs);
-                       foreach ($this->objects as $event) {
-                               $event->setUserProfile($users[$event->userID]);
-                       }
+                       UserProfileCache::getInstance()->cacheUserIDs(array_unique($userIDs));
                }
                
                // parse events
index 568125ad51f6489dc86dfb900d32def0537f4be7..50895a1af33dd43f675ff48e7fd0eddb6bc28491 100644 (file)
@@ -1,7 +1,8 @@
 <?php
 namespace wcf\system\dashboard\box;
 use wcf\data\dashboard\box\DashboardBox;
-use wcf\data\user\UserProfileList;
+use wcf\data\user\UserProfileCache;
+use wcf\data\DatabaseObject;
 use wcf\page\IPage;
 use wcf\system\cache\builder\MostActiveMembersCacheBuilder;
 use wcf\system\request\LinkHandler;
@@ -19,10 +20,10 @@ use wcf\system\WCF;
  */
 class MostActiveMembersDashboardBox extends AbstractSidebarDashboardBox {
        /**
-        * user profile list
-        * @var \wcf\data\user\UserProfileList
+        * ids of the most active members
+        * @var array<integer>
         */
-       public $userProfileList = null;
+       public $mostActiveMemberIDs = array();
        
        /**
         * @see \wcf\system\dashboard\box\AbstractDashboardBoxContent::init()
@@ -31,13 +32,9 @@ class MostActiveMembersDashboardBox extends AbstractSidebarDashboardBox {
                parent::init($box, $page);
                
                // get ids
-               $mostActiveMemberIDs = MostActiveMembersCacheBuilder::getInstance()->getData();
-               if (!empty($mostActiveMemberIDs)) {
-                       // get profile data
-                       $this->userProfileList = new UserProfileList();
-                       $this->userProfileList->sqlOrderBy = 'user_table.activityPoints DESC';
-                       $this->userProfileList->setObjectIDs($mostActiveMemberIDs);
-                       $this->userProfileList->readObjects();
+               $this->mostActiveMemberIDs = MostActiveMembersCacheBuilder::getInstance()->getData();
+               if (!empty($this->mostActiveMemberIDs)) {
+                       UserProfileCache::getInstance()->cacheUserIDs($this->mostActiveMemberIDs);
                }
                
                $this->fetched();
@@ -47,13 +44,17 @@ class MostActiveMembersDashboardBox extends AbstractSidebarDashboardBox {
         * @see \wcf\system\dashboard\box\AbstractContentDashboardBox::render()
         */
        protected function render() {
-               if ($this->userProfileList == null) return '';
+               if (empty($this->mostActiveMemberIDs)) return '';
                
                if (MODULE_MEMBERS_LIST) {
                        $this->titleLink = LinkHandler::getInstance()->getLink('MembersList', array(), 'sortField=activityPoints&sortOrder=DESC');
                }
+               
+               $mostActiveMembers = UserProfileCache::getInstance()->getUserProfiles($this->mostActiveMemberIDs);
+               DatabaseObject::sort($mostActiveMembers, 'activityPoints', 'DESC');
+               
                WCF::getTPL()->assign(array(
-                       'mostActiveMembers' => $this->userProfileList
+                       'mostActiveMembers' => $mostActiveMembers
                ));
                return WCF::getTPL()->fetch('dashboardBoxMostActiveMembers');
        }
index 2c1e1f3a72281ea10f057b5ac1b89d0289450edd..fa80d6ad91708e26ca9951f30ee309cb7395be0a 100644 (file)
@@ -1,7 +1,8 @@
 <?php
 namespace wcf\system\dashboard\box;
 use wcf\data\dashboard\box\DashboardBox;
-use wcf\data\user\UserProfileList;
+use wcf\data\user\UserProfileCache;
+use wcf\data\DatabaseObject;
 use wcf\page\IPage;
 use wcf\system\cache\builder\MostLikedMembersCacheBuilder;
 use wcf\system\request\LinkHandler;
@@ -19,10 +20,10 @@ use wcf\system\WCF;
  */
 class MostLikedMembersDashboardBox extends AbstractSidebarDashboardBox {
        /**
-        * user profile list
-        * @var \wcf\data\user\UserProfileList
+        * ids of the most liked members
+        * @var array<integer>
         */
-       public $userProfileList = null;
+       public $mostLikedMemberIDs = array();
        
        /**
         * @see \wcf\system\dashboard\box\IDashboardBox::init()
@@ -31,29 +32,30 @@ class MostLikedMembersDashboardBox extends AbstractSidebarDashboardBox {
                parent::init($box, $page);
                
                // get ids
-               $mostLikedMemberIDs = MostLikedMembersCacheBuilder::getInstance()->getData();
-               if (!empty($mostLikedMemberIDs)) {
-                       // get profile data
-                       $this->userProfileList = new UserProfileList();
-                       $this->userProfileList->sqlOrderBy = 'user_table.likesReceived DESC';
-                       $this->userProfileList->setObjectIDs($mostLikedMemberIDs);
-                       $this->userProfileList->readObjects();
-               }
+               $this->mostLikedMemberIDs = MostLikedMembersCacheBuilder::getInstance()->getData();
                
                $this->fetched();
+               
+               if (!empty($this->mostLikedMemberIDs)) {
+                       UserProfileCache::getInstance()->cacheUserIDs($this->mostLikedMemberIDs);
+               }
        }
        
        /**
         * @see \wcf\system\dashboard\box\AbstractContentDashboardBox::render()
         */
        protected function render() {
-               if ($this->userProfileList == null) return '';
+               if (empty($this->mostLikedMemberIDs)) return '';
                
                if (MODULE_MEMBERS_LIST) {
                        $this->titleLink = LinkHandler::getInstance()->getLink('MembersList', array(), 'sortField=likesReceived&sortOrder=DESC');
                }
+               
+               $mostLikedMembers = UserProfileCache::getInstance()->getUserProfiles($this->mostLikedMemberIDs);
+               DatabaseObject::sort($mostLikedMembers, 'likesReceived', 'DESC');
+               
                WCF::getTPL()->assign(array(
-                       'mostLikedMembers' => $this->userProfileList
+                       'mostLikedMembers' => $mostLikedMembers
                ));
                return WCF::getTPL()->fetch('dashboardBoxMostLikedMembers');
        }
index 4fe5e00ee380f00242306f729d12b186dae63d73..2d807c3525b6da2f3149bb91968448c5d71487a5 100644 (file)
@@ -1,7 +1,8 @@
 <?php
 namespace wcf\system\dashboard\box;
 use wcf\data\dashboard\box\DashboardBox;
-use wcf\data\user\UserProfileList;
+use wcf\data\user\UserProfileCache;
+use wcf\data\DatabaseObject;
 use wcf\page\IPage;
 use wcf\system\cache\builder\NewestMembersCacheBuilder;
 use wcf\system\request\LinkHandler;
@@ -19,10 +20,10 @@ use wcf\system\WCF;
  */
 class NewestMembersDashboardBox extends AbstractSidebarDashboardBox {
        /**
-        * user profile list
-        * @var \wcf\data\user\UserProfileList
+        * ids of the newest members
+        * @var array<integer>
         */
-       public $userProfileList = null;
+       public $newestMemberIDs = array();
        
        /**
         * @see \wcf\system\dashboard\box\IDashboardBox::init()
@@ -31,13 +32,9 @@ class NewestMembersDashboardBox extends AbstractSidebarDashboardBox {
                parent::init($box, $page);
                
                // get ids
-               $newestMemberIDs = NewestMembersCacheBuilder::getInstance()->getData();
-               if (!empty($newestMemberIDs)) {
-                       // get profile data
-                       $this->userProfileList = new UserProfileList();
-                       $this->userProfileList->sqlOrderBy = 'user_table.registrationDate DESC';
-                       $this->userProfileList->setObjectIDs($newestMemberIDs);
-                       $this->userProfileList->readObjects();
+               $this->newestMemberIDs = NewestMembersCacheBuilder::getInstance()->getData();
+               if (!empty($this->newestMemberIDs)) {
+                       UserProfileCache::getInstance()->cacheUserIDs($this->newestMemberIDs);
                }
                
                $this->fetched();
@@ -47,13 +44,17 @@ class NewestMembersDashboardBox extends AbstractSidebarDashboardBox {
         * @see \wcf\system\dashboard\box\AbstractContentDashboardBox::render()
         */
        protected function render() {
-               if ($this->userProfileList == null) return '';
+               if (empty($this->newestMemberIDs)) return '';
                
                if (MODULE_MEMBERS_LIST) {
                        $this->titleLink = LinkHandler::getInstance()->getLink('MembersList', array(), 'sortField=registrationDate&sortOrder=DESC');
                }
+               
+               $newestMembers = UserProfileCache::getInstance()->getUserProfiles($this->newestMemberIDs);
+               DatabaseObject::sort($newestMembers, 'registrationDate', 'DESC');
+               
                WCF::getTPL()->assign(array(
-                       'newestMembers' => $this->userProfileList
+                       'newestMembers' => $newestMembers
                ));
                return WCF::getTPL()->fetch('dashboardBoxNewestMembers');
        }
index fa1ae27e2aa7a171597c3a0f0a7e28389ea3cdae..3b6976e5b6982384bd788b6803446c85cd8a15a7 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 namespace wcf\system\dashboard\box;
 use wcf\data\dashboard\box\DashboardBox;
-use wcf\data\user\UserProfileList;
+use wcf\data\user\UserProfileCache;
 use wcf\page\IPage;
 use wcf\system\cache\builder\UserOptionCacheBuilder;
 use wcf\system\user\UserBirthdayCache;
@@ -43,15 +43,14 @@ class TodaysBirthdaysDashboardBox extends AbstractSidebarDashboardBox {
                        if (isset($userOptions['birthday'])) {
                                $birthdayUserOption = $userOptions['birthday'];
                                
-                               $userProfileList = new UserProfileList();
-                               $userProfileList->setObjectIDs($userIDs);
-                               $userProfileList->readObjects();
+                               $userProfiles = UserProfileCache::getInstance()->getUserProfiles($userIDs);
+                               
                                $i = 0;
-                               foreach ($userProfileList as $userProfile) {
+                               foreach ($userProfiles as $userProfile) {
                                        if ($i == 10) break;
                                        
                                        $birthdayUserOption->setUser($userProfile->getDecoratedObject());
-                                               
+                                       
                                        if (!$userProfile->isProtected() && $birthdayUserOption->isVisible() && substr($userProfile->birthday, 5) == $currentDay) {
                                                $this->userProfiles[] = $userProfile;
                                                $i++;
index 8e249afac7ffea4c4f2149f4693e6aba0e085365..8f3640f1bd1432f90f7b82b25de90b86d7c22333 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 namespace wcf\system\dashboard\box;
 use wcf\data\dashboard\box\DashboardBox;
-use wcf\data\user\UserProfileList;
+use wcf\data\user\UserProfileCache;
 use wcf\page\IPage;
 use wcf\system\user\UserBirthdayCache;
 use wcf\system\WCF;
@@ -39,11 +39,10 @@ class TodaysFollowingBirthdaysDashboardBox extends AbstractSidebarDashboardBox {
                $userIDs = array_intersect($userIDs, WCF::getUserProfileHandler()->getFollowingUsers());
                
                if (!empty($userIDs)) {
-                       $userProfileList = new UserProfileList();
-                       $userProfileList->setObjectIDs($userIDs);
-                       $userProfileList->readObjects();
+                       $userProfiles = UserProfileCache::getInstance()->getUserProfiles($userIDs);
+                       
                        $i = 0;
-                       foreach ($userProfileList as $userProfile) {
+                       foreach ($userProfiles as $userProfile) {
                                if ($i == 10) break;
                                
                                if (!$userProfile->isProtected() && substr($userProfile->birthday, 5) == $currentDay) {
index f65135fcefe2881d1cd00c23a969945c35c9aef4..ce7d2d7ff24d34f3cf47280f8a13d49a2b699e40 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 namespace wcf\system\message\embedded\object;
 use wcf\data\user\UserList;
-use wcf\data\user\UserProfile;
+use wcf\data\user\UserProfileCache;
 
 /**
  * IMessageEmbeddedObjectHandler implementation for quotes.
@@ -33,6 +33,6 @@ class QuoteMessageEmbeddedObjectHandler extends AbstractMessageEmbeddedObjectHan
         * @see \wcf\system\message\embedded\object\IMessageEmbeddedObjectHandler::loadObjects()
         */
        public function loadObjects(array $objectIDs) {
-               return UserProfile::getUserProfiles($objectIDs);
+               return UserProfileCache::getInstance()->getUserProfiles($objectIDs);
        }
 }
index a9a58be2234b0d04f7f50130a01f781fc7162a84..b3687c7ede9959aa7ccf5a183880e2c8a74ef97c 100644 (file)
@@ -2,7 +2,7 @@
 namespace wcf\system\user\activity\event;
 use wcf\data\comment\response\CommentResponseList;
 use wcf\data\comment\CommentList;
-use wcf\data\user\UserProfileList;
+use wcf\data\user\UserProfileCache;
 use wcf\system\user\activity\event\IUserActivityEvent;
 use wcf\system\SingletonFactory;
 use wcf\system\WCF;
@@ -56,10 +56,7 @@ class ProfileCommentResponseUserActivityEvent extends SingletonFactory implement
                        $userIDs[] = $comment->userID;
                }
                if (!empty($userIDs)) {
-                       $userList = new UserProfileList();
-                       $userList->setObjectIDs($userIDs);
-                       $userList->readObjects();
-                       $users = $userList->getObjects();
+                       $users = UserProfileCache::getInstance()->getUserProfiles($userIDs);
                }
                
                // set message
index 068e439a2b2987f95fd72720212270ccd1706011..47f4663076c19ae9a7d076b461a8ca00cc310209 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 namespace wcf\system\user\activity\event;
 use wcf\data\comment\CommentList;
-use wcf\data\user\UserProfileList;
+use wcf\data\user\UserProfileCache;
 use wcf\system\user\activity\event\IUserActivityEvent;
 use wcf\system\SingletonFactory;
 use wcf\system\WCF;
@@ -42,10 +42,7 @@ class ProfileCommentUserActivityEvent extends SingletonFactory implements IUserA
                        $userIDs[] = $comment->objectID;
                }
                if (!empty($userIDs)) {
-                       $userList = new UserProfileList();
-                       $userList->setObjectIDs($userIDs);
-                       $userList->readObjects();
-                       $users = $userList->getObjects();
+                       $users = UserProfileCache::getInstance()->getUserProfiles($userIDs);
                }
                
                // set message