Merge branch 'next' into reactions
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / like / LikeHandler.class.php
index 027da64336b0ec5a02dec3efcceb84b48cbd652e..db68d31be248451aa8e94ab3af3af2ed4f198f22 100644 (file)
@@ -2,20 +2,12 @@
 namespace wcf\system\like;
 use wcf\data\like\object\ILikeObject;
 use wcf\data\like\object\LikeObject;
-use wcf\data\like\object\LikeObjectEditor;
-use wcf\data\like\object\LikeObjectList;
 use wcf\data\like\Like;
-use wcf\data\like\LikeEditor;
-use wcf\data\like\LikeList;
 use wcf\data\object\type\ObjectType;
-use wcf\data\object\type\ObjectTypeCache;
+use wcf\data\reaction\type\ReactionType;
+use wcf\data\reaction\type\ReactionTypeCache;
 use wcf\data\user\User;
-use wcf\data\user\UserEditor;
-use wcf\system\database\util\PreparedStatementConditionBuilder;
-use wcf\system\database\DatabaseException;
-use wcf\system\user\activity\event\UserActivityEventHandler;
-use wcf\system\user\activity\point\UserActivityPointHandler;
-use wcf\system\user\notification\UserNotificationHandler;
+use wcf\system\reaction\ReactionHandler;
 use wcf\system\SingletonFactory;
 use wcf\system\WCF;
 
@@ -31,9 +23,10 @@ use wcf\system\WCF;
  * $likeObjects = LikeHandler::getInstance()->getLikeObjects($objectType);
  * 
  * @author     Marcel Werk
- * @copyright  2001-2017 WoltLab GmbH
+ * @copyright  2001-2018 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Like
+ * @deprecated  The LikeHandler is deprecated since 3.2 in favor of the \wcf\system\reaction\ReactionHandler
  */
 class LikeHandler extends SingletonFactory {
        /**
@@ -52,8 +45,7 @@ class LikeHandler extends SingletonFactory {
         * Creates a new LikeHandler instance.
         */
        protected function init() {
-               // load cache
-               $this->cache = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.like.likeableObject');
+               // does nothing
        }
        
        /**
@@ -63,11 +55,7 @@ class LikeHandler extends SingletonFactory {
         * @return      ObjectType
         */
        public function getObjectType($objectName) {
-               if (isset($this->cache[$objectName])) {
-                       return $this->cache[$objectName];
-               }
-               
-               return null;
+               return ReactionHandler::getInstance()->getObjectType($objectName);
        }
        
        /**
@@ -78,11 +66,7 @@ class LikeHandler extends SingletonFactory {
         * @return      LikeObject|null
         */
        public function getLikeObject(ObjectType $objectType, $objectID) {
-               if (isset($this->likeObjectCache[$objectType->objectTypeID][$objectID])) {
-                       return $this->likeObjectCache[$objectType->objectTypeID][$objectID];
-               }
-               
-               return null;
+               return ReactionHandler::getInstance()->getLikeObject($objectType, $objectID);
        }
        
        /**
@@ -92,11 +76,7 @@ class LikeHandler extends SingletonFactory {
         * @return      LikeObject[]
         */
        public function getLikeObjects(ObjectType $objectType) {
-               if (isset($this->likeObjectCache[$objectType->objectTypeID])) {
-                       return $this->likeObjectCache[$objectType->objectTypeID];
-               }
-               
-               return [];
+               return ReactionHandler::getInstance()->getLikeObjects($objectType);
        }
        
        /**
@@ -108,43 +88,7 @@ class LikeHandler extends SingletonFactory {
         * @return      integer
         */
        public function loadLikeObjects(ObjectType $objectType, array $objectIDs) {
-               if (empty($objectIDs)) {
-                       return 0;
-               }
-               
-               $i = 0;
-               
-               $conditions = new PreparedStatementConditionBuilder();
-               $conditions->add("like_object.objectTypeID = ?", [$objectType->objectTypeID]);
-               $conditions->add("like_object.objectID IN (?)", [$objectIDs]);
-               $parameters = $conditions->getParameters();
-               
-               if (WCF::getUser()->userID) {
-                       $sql = "SELECT          like_object.*,
-                                               CASE WHEN like_table.userID IS NOT NULL THEN like_table.likeValue ELSE 0 END AS liked
-                               FROM            wcf".WCF_N."_like_object like_object
-                               LEFT JOIN       wcf".WCF_N."_like like_table
-                               ON              (like_table.objectTypeID = like_object.objectTypeID
-                                               AND like_table.objectID = like_object.objectID
-                                               AND like_table.userID = ?)
-                               ".$conditions;
-                       
-                       array_unshift($parameters, WCF::getUser()->userID);
-               }
-               else {
-                       $sql = "SELECT          like_object.*, 0 AS liked
-                               FROM            wcf".WCF_N."_like_object like_object
-                               ".$conditions;
-               }
-               
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute($parameters);
-               while ($row = $statement->fetchArray()) {
-                       $this->likeObjectCache[$objectType->objectTypeID][$row['objectID']] = new LikeObject(null, $row);
-                       $i++;
-               }
-               
-               return $i;
+               return ReactionHandler::getInstance()->loadLikeObjects($objectType, $objectIDs);
        }
        
        /**
@@ -157,174 +101,40 @@ class LikeHandler extends SingletonFactory {
         * @return      array
         */
        public function like(ILikeObject $likeable, User $user, $likeValue, $time = TIME_NOW) {
-               // verify if object is already liked by user
-               $like = Like::getLike($likeable->getObjectType()->objectTypeID, $likeable->getObjectID(), $user->userID);
-               
-               // get like object
-               $likeObject = LikeObject::getLikeObject($likeable->getObjectType()->objectTypeID, $likeable->getObjectID());
-               
-               // if vote is identically just revert the vote
-               if ($like->likeID && ($like->likeValue == $likeValue)) {
-                       return $this->revertLike($like, $likeable, $likeObject, $user);
+               if ($likeValue == 1) {
+                       $reactionTypeID = ReactionHandler::getInstance()->getLegacyReactionTypeID(ReactionType::REACTION_TYPE_POSITIVE);
+               }
+               else {
+                       $reactionTypeID = ReactionHandler::getInstance()->getLegacyReactionTypeID(ReactionType::REACTION_TYPE_NEGATIVE);
                }
                
-               // like data
-               /** @noinspection PhpUnusedLocalVariableInspection */
-               $cumulativeLikes = 0;
-               /** @noinspection PhpUnusedLocalVariableInspection */
-               $newValue = $oldValue = null;
-               $users = [];
+               if ($reactionTypeID === null) {
+                       return [
+                               'data' => [],
+                               'like' => 0,
+                               'newValue' => 0,
+                               'oldValue' => 0,
+                               'users' => []
+                       ];
+               }
                
-               try {
-                       WCF::getDB()->beginTransaction();
-                       
-                       // update existing object
-                       if ($likeObject->likeObjectID) {
-                               $likes = $likeObject->likes;
-                               $dislikes = $likeObject->dislikes;
-                               $cumulativeLikes = $likeObject->cumulativeLikes;
-                               
-                               // previous (dis-)like already exists
-                               if ($like->likeID) {
-                                       $oldValue = $like->likeValue;
-                                       
-                                       // revert like and replace it with a dislike
-                                       if ($like->likeValue == Like::LIKE) {
-                                               $likes--;
-                                               $dislikes++;
-                                               $cumulativeLikes -= 2;
-                                               $newValue = Like::DISLIKE;
-                                       }
-                                       else {
-                                               // revert dislike and replace it with a like
-                                               $likes++;
-                                               $dislikes--;
-                                               $cumulativeLikes += 2;
-                                               $newValue = Like::LIKE;
-                                       }
-                               }
-                               else {
-                                       if ($likeValue == Like::LIKE) {
-                                               $likes++;
-                                               $cumulativeLikes++;
-                                               $newValue = Like::LIKE;
-                                       }
-                                       else {
-                                               $dislikes++;
-                                               $cumulativeLikes--;
-                                               $newValue = Like::DISLIKE;
-                                       }
-                               }
-                               
-                               // build update date
-                               $updateData = [
-                                       'likes' => $likes,
-                                       'dislikes' => $dislikes,
-                                       'cumulativeLikes' => $cumulativeLikes
-                               ];
-                               
-                               if ($likeValue == 1) {
-                                       $users = unserialize($likeObject->cachedUsers);
-                                       if (count($users) < 3) {
-                                               $users[$user->userID] = ['userID' => $user->userID, 'username' => $user->username];
-                                               $updateData['cachedUsers'] = serialize($users);
-                                       }
-                               }
-                               else if ($likeValue == -1) {
-                                       $users = unserialize($likeObject->cachedUsers);
-                                       if (isset($users[$user->userID])) {
-                                               unset($users[$user->userID]);
-                                               $updateData['cachedUsers'] = serialize($users);
-                                       }
-                               }
-                               
-                               // update data
-                               $likeObjectEditor = new LikeObjectEditor($likeObject);
-                               $likeObjectEditor->update($updateData);
-                       }
-                       else {
-                               $cumulativeLikes = $likeValue;
-                               $newValue = $likeValue;
-                               $users = [];
-                               if ($likeValue == 1) $users = [$user->userID => ['userID' => $user->userID, 'username' => $user->username]];
-                               
-                               // create cache
-                               $likeObject = LikeObjectEditor::create([
-                                       'objectTypeID' => $likeable->getObjectType()->objectTypeID,
-                                       'objectID' => $likeable->getObjectID(),
-                                       'objectUserID' => $likeable->getUserID() ?: null,
-                                       'likes' => ($likeValue == Like::LIKE) ? 1 : 0,
-                                       'dislikes' => ($likeValue == Like::DISLIKE) ? 1 : 0,
-                                       'cumulativeLikes' => $cumulativeLikes,
-                                       'cachedUsers' => serialize($users)
-                               ]);
-                       }
-                       
-                       // update owner's like counter
-                       if ($likeable->getUserID()) {
-                               if ($like->likeID) {
-                                       $userEditor = new UserEditor(new User($likeable->getUserID()));
-                                       $userEditor->updateCounters([
-                                               'likesReceived' => $like->likeValue == Like::LIKE ? -1 : 1
-                                       ]);
-                               }
-                               else if ($likeValue == Like::LIKE) {
-                                       $userEditor = new UserEditor(new User($likeable->getUserID()));
-                                       $userEditor->updateCounters([
-                                               'likesReceived' => 1
-                                       ]);
-                               }
-                       }
-                       
-                       if (!$like->likeID) {
-                               // save like
-                               $like = LikeEditor::create([
-                                       'objectID' => $likeable->getObjectID(),
-                                       'objectTypeID' => $likeable->getObjectType()->objectTypeID,
-                                       'objectUserID' => $likeable->getUserID() ?: null,
-                                       'userID' => $user->userID,
-                                       'time' => $time,
-                                       'likeValue' => $likeValue
-                               ]);
-                               
-                               if ($likeValue == Like::LIKE && $likeable->getUserID()) {
-                                       UserActivityPointHandler::getInstance()->fireEvent('com.woltlab.wcf.like.activityPointEvent.receivedLikes', $like->likeID, $likeable->getUserID());
-                                       $likeable->sendNotification($like);
-                               }
-                       }
-                       else {
-                               $likeEditor = new LikeEditor($like);
-                               $likeEditor->update([
-                                       'time' => $time,
-                                       'likeValue' => $likeValue
-                               ]);
-                               
-                               if ($likeable->getUserID()) {
-                                       if ($likeValue == Like::DISLIKE) {
-                                               UserActivityPointHandler::getInstance()->removeEvents('com.woltlab.wcf.like.activityPointEvent.receivedLikes', [$likeable->getUserID() => 1]);
-                                       }
-                                       else {
-                                               UserActivityPointHandler::getInstance()->fireEvent('com.woltlab.wcf.like.activityPointEvent.receivedLikes', $like->likeID, $likeable->getUserID());
-                                               $likeable->sendNotification($like);
-                                       }
-                               }
-                       }
-                       
-                       // update object's like counter
-                       $likeable->updateLikeCounter($cumulativeLikes);
-                       
-                       WCF::getDB()->commitTransaction();
+               $reactData = ReactionHandler::getInstance()->react($likeable, $user, $reactionTypeID, $time);
+               if ($reactData['reactionTypeID'] === null) {
+                       $newValue = 0; 
                }
-               catch (DatabaseException $e) {
-                       WCF::getDB()->rollBackTransaction();
+               else if (ReactionTypeCache::getInstance()->getReactionTypeByID($reactData['reactionTypeID'])->type == ReactionType::REACTION_TYPE_NEGATIVE) {
+                       $newValue = -1;
+               }
+               else {
+                       $newValue = 1;
                }
                
                return [
-                       'data' => $this->loadLikeStatus($likeObject, $user),
-                       'like' => $like,
+                       'data' => $this->loadLikeStatus($reactData['likeObject'], $user),
+                       'like' => $reactData['likeObject'],
                        'newValue' => $newValue,
-                       'oldValue' => $oldValue,
-                       'users' => $users
+                       'oldValue' => 0, // this value is currently a dummy value, maybe determine a real value
+                       'users' => []
                ];
        }
        
@@ -338,82 +148,14 @@ class LikeHandler extends SingletonFactory {
         * @return      array
         */
        public function revertLike(Like $like, ILikeObject $likeable, LikeObject $likeObject, User $user) {
-               $usersArray = [];
-               
-               try {
-                       WCF::getDB()->beginTransaction();
-                       
-                       // delete like
-                       $editor = new LikeEditor($like);
-                       $editor->delete();
-                       
-                       // update like object cache
-                       $likes = $likeObject->likes;
-                       $dislikes = $likeObject->dislikes;
-                       $cumulativeLikes = $likeObject->cumulativeLikes;
-                       
-                       if ($like->likeValue == Like::LIKE) {
-                               $likes--;
-                               $cumulativeLikes--;
-                       }
-                       else {
-                               $dislikes--;
-                               $cumulativeLikes++;
-                       }
-                       
-                       // build update data
-                       $updateData = [
-                               'likes' => $likes,
-                               'dislikes' => $dislikes,
-                               'cumulativeLikes' => $cumulativeLikes
-                       ];
-                       
-                       $users = $likeObject->getUsers();
-                       foreach ($users as $user2) {
-                               $usersArray[$user2->userID] = ['userID' => $user2->userID, 'username' => $user2->username];
-                       }
-                       
-                       if (isset($usersArray[$user->userID])) {
-                               unset($usersArray[$user->userID]);
-                               $updateData['cachedUsers'] = serialize($usersArray);
-                       }
-                       
-                       $likeObjectEditor = new LikeObjectEditor($likeObject);
-                       if (!$updateData['likes'] && !$updateData['dislikes']) {
-                               // remove object instead
-                               $likeObjectEditor->delete();
-                       }
-                       else {
-                               // update data
-                               $likeObjectEditor->update($updateData);
-                       }
-                       
-                       // update owner's like counter and activity points
-                       if ($likeable->getUserID()) {
-                               if ($like->likeValue == Like::LIKE) {
-                                       $userEditor = new UserEditor(new User($likeable->getUserID()));
-                                       $userEditor->updateCounters([
-                                               'likesReceived' => -1
-                                       ]);
-                                       
-                                       UserActivityPointHandler::getInstance()->removeEvents('com.woltlab.wcf.like.activityPointEvent.receivedLikes', [$likeable->getUserID() => 1]);
-                               }
-                       }
-                       
-                       // update object's like counter
-                       $likeable->updateLikeCounter($cumulativeLikes);
-                       
-                       WCF::getDB()->commitTransaction();
-               }
-               catch (DatabaseException $e) {
-                       WCF::getDB()->rollBackTransaction();
-               }
+               $reactData = ReactionHandler::getInstance()->revertReact($like, $likeable, $likeObject, $user);
                
                return [
-                       'data' => $this->loadLikeStatus($likeObject, $user),
-                       'newValue' => null,
-                       'oldValue' => $like->likeValue,
-                       'users' => $usersArray
+                       'data' => $this->loadLikeStatus($reactData['likeObject'], $user),
+                       'like' => null,
+                       'newValue' => 0,
+                       'oldValue' => 0, // this value is currently a dummy value, maybe determine a real value
+                       'users' => []
                ];
        }
        
@@ -425,69 +167,7 @@ class LikeHandler extends SingletonFactory {
         * @param       string[]        $notificationObjectTypes
         */
        public function removeLikes($objectType, array $objectIDs, array $notificationObjectTypes = []) {
-               $objectTypeObj = $this->getObjectType($objectType);
-               
-               // get like objects
-               $likeObjectList = new LikeObjectList();
-               $likeObjectList->getConditionBuilder()->add('like_object.objectTypeID = ?', [$objectTypeObj->objectTypeID]);
-               $likeObjectList->getConditionBuilder()->add('like_object.objectID IN (?)', [$objectIDs]);
-               $likeObjectList->readObjects();
-               $likeObjects = $likeObjectList->getObjects();
-               $likeObjectIDs = $likeObjectList->getObjectIDs();
-               
-               // reduce count of received users
-               $users = [];
-               foreach ($likeObjects as $likeObject) {
-                       if ($likeObject->likes) {
-                               if (!isset($users[$likeObject->objectUserID])) $users[$likeObject->objectUserID] = 0;
-                               $users[$likeObject->objectUserID] += $likeObject->likes;
-                       }
-               }
-               foreach ($users as $userID => $receivedLikes) {
-                       $userEditor = new UserEditor(new User(null, ['userID' => $userID]));
-                       $userEditor->updateCounters([
-                               'likesReceived' => $receivedLikes * -1
-                       ]);
-               }
-               
-               // get like ids
-               $likeList = new LikeList();
-               $likeList->getConditionBuilder()->add('like_table.objectTypeID = ?', [$objectTypeObj->objectTypeID]);
-               $likeList->getConditionBuilder()->add('like_table.objectID IN (?)', [$objectIDs]);
-               $likeList->readObjects();
-               
-               if (count($likeList)) {
-                       $likeData = [];
-                       foreach ($likeList as $like) {
-                               $likeData[$like->likeID] = $like->userID;
-                       }
-                       
-                       // delete like notifications
-                       if (!empty($notificationObjectTypes)) {
-                               foreach ($notificationObjectTypes as $notificationObjectType) {
-                                       UserNotificationHandler::getInstance()->removeNotifications($notificationObjectType, $likeList->getObjectIDs());
-                               }
-                       }
-                       else if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType.'.notification')) {
-                               UserNotificationHandler::getInstance()->removeNotifications($objectType.'.notification', $likeList->getObjectIDs());
-                       }
-                       
-                       // revoke activity points
-                       UserActivityPointHandler::getInstance()->removeEvents('com.woltlab.wcf.like.activityPointEvent.receivedLikes', $likeData);
-                       
-                       // delete likes
-                       LikeEditor::deleteAll(array_keys($likeData));
-               }
-               
-               // delete like objects
-               if (!empty($likeObjectIDs)) {
-                       LikeObjectEditor::deleteAll($likeObjectIDs);
-               }
-               
-               // delete activity events
-               if (UserActivityEventHandler::getInstance()->getObjectTypeID($objectTypeObj->objectType.'.recentActivityEvent')) {
-                       UserActivityEventHandler::getInstance()->removeEvents($objectTypeObj->objectType.'.recentActivityEvent', $objectIDs);
-               }
+               ReactionHandler::getInstance()->removeReacts($objectType, $objectIDs, $notificationObjectTypes);
        }
        
        /**