Refine documentation
authorJoshua Rüsweg <josh@bastelstu.be>
Tue, 7 Aug 2018 18:14:46 +0000 (20:14 +0200)
committerJoshua Rüsweg <josh@bastelstu.be>
Tue, 7 Aug 2018 18:14:46 +0000 (20:14 +0200)
See #2665

wcfsetup/install/files/lib/acp/form/TrophyAddForm.class.php
wcfsetup/install/files/lib/data/trophy/Trophy.class.php
wcfsetup/install/files/lib/system/trophy/condition/TrophyConditionHandler.class.php

index bef34411825d0b32dff19323f1ae703824e82a1e..9831ee2ad93cbdb965133020ccd82336be8037b9 100644 (file)
@@ -120,7 +120,7 @@ class TrophyAddForm extends AbstractAcpForm {
        public $awardAutomatically = 0;
        
        /**
-        * `1` if the trophy is automatically revoked, if the conditions are not longer fulfilled
+        * `1` if the trophy should be automatically revoked once the conditions are no longer met.
         * @var int
         */
        public $revokeAutomatically = 0;
index 5bcde024c4088024cf462f0bb2a3c2d5ffc220d9..278f7f8f2fa147ba98ce47a22d51044b21a7a3a6 100644 (file)
@@ -32,7 +32,7 @@ use wcf\util\StringUtil;
  * @property-read      string          $badgeColor                     the icon badge color
  * @property-read      integer         $isDisabled                     `1` if the trophy is disabled
  * @property-read      integer         $awardAutomatically             `1` if the trophy is awarded automatically
- * @property-read      integer         $revokeAutomatically            `1` if the trophy is automatically revoked, if the conditions are not longer fulfilled
+ * @property-read      integer         $revokeAutomatically            `1` if the trophy should be automatically revoked once the conditions are no longer met.
  * @property-read      integer         $trophyUseHtml                  `1` if the trophy use a html description
  * @property-read      integer         $showOrder                      position of the trophy in relation to the other trophies at the same location
  */
index 4f060da0d06aa0acf232e0d312416663cccc890a..d8fbe3d7e0a27ed8fc834cfb0e615316da447913 100644 (file)
@@ -99,7 +99,7 @@ class TrophyConditionHandler extends SingletonFactory {
                
                $i = 0;
                foreach ($trophyList as $trophy) {
-                       $userTrophyIDs = $this->getRevocableUserTrophyIDs($trophy);
+                       $userTrophyIDs = $this->getRevocableUserTrophyIDs($trophy, $maxRevokes - $i);
                        
                        $i += count($userTrophyIDs);
                        
@@ -137,27 +137,50 @@ class TrophyConditionHandler extends SingletonFactory {
         * @param       Trophy          $trophy
         * @return      integer[]
         */
-       private function getRevocableUserTrophyIDs(Trophy $trophy) {
+       private function getRevocableUserTrophyIDs(Trophy $trophy, $maxTrophyIDs) {
+               // Unfortunately, the condition system does not support negated conditions. 
+               // Therefore, we need to build our own SQL query. To get to the conditions
+               // that must be fulfilled for earning a specific trophy, we first create
+               // a pseudo DBOList element to pass them to the condition handler. Then we
+               // extract the condition builder from the object.  
                $pseudoUserList = new UserList();
-               $pseudoUserList->sqlConditionJoins .= " LEFT JOIN wcf".WCF_N."_user_option_value user_option_value ON (user_option_value.userID = user_table.userID)";
                
+               // Assign the condition to the pseudo DBOList object 
                $conditions = $trophy->getConditions();
                foreach ($conditions as $condition) {
                        $condition->getObjectType()->getProcessor()->addUserCondition($condition, $pseudoUserList);
                }
                
+               // Now we create our own query to find out which users no longer meet the conditions. 
+               // For this we use a UserList object again and transfer basic data from the pseudo object. 
                $userList = new UserList();
-               $userList->sqlConditionJoins = $pseudoUserList->sqlConditionJoins;
                $userList->sqlOrderBy = $pseudoUserList->sqlOrderBy;
+               $userList->sqlLimit = $maxTrophyIDs;
+               
+               // Now we copy the sql joins from the pseudo object to the new one if a condition
+               // has joined a table. 
                $userList->sqlJoins = $pseudoUserList->sqlJoins;
+               
+               // We joining the user_trophy table to receive the userTrophyID, which should be deleted.
                $userList->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_trophy user_trophy ON (user_table.userID = user_trophy.userID)";
+               
+               // We do not need the complete user object, but only the userTrophyID. 
+               // So that the UserList object can also assign the users (which is used
+               // as an array index), we also get the userID. 
                $userList->useQualifiedShorthand = false;
                $userList->sqlSelects = "user_trophy.userTrophyID, user_table.userID";
+               
+               // Now we transfer the old conditions to our new object. To avoid having two WHERE keywords,
+               // we deactivate it in the pseudo-object.
                $pseudoUserList->getConditionBuilder()->enableWhereKeyword(false);
                $userList->getConditionBuilder()->add('NOT('. $pseudoUserList->getConditionBuilder() .')', $pseudoUserList->getConditionBuilder()->getParameters());
+               
+               // In order not to get all users who do not fulfill the conditions (in case of
+               // doubt there can be many), we filter for users who have received the trophy. 
                $userList->getConditionBuilder()->add('user_table.userID IN (SELECT userID FROM wcf'.WCF_N.'_user_trophy WHERE trophyID IN (?))', [$trophy->trophyID]);
                $userList->readObjects();
                
+               // We now return an array of userTrophyIDs instead of user objects to remove them directly via DBOAction. 
                return array_map(function($object) {
                        return $object->userTrophyID; 
                }, $userList->getObjects());