Apply PSR-12 code style (#3886)
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / trophy / condition / TrophyConditionHandler.class.php
index 007df17ed1f031fe774d44bb7564e2f3cddbd019..947298cf1eb577e6de828a5f5dc94e1539a11239 100644 (file)
@@ -1,5 +1,7 @@
 <?php
+
 namespace wcf\system\trophy\condition;
+
 use wcf\data\object\type\ObjectType;
 use wcf\data\object\type\ObjectTypeCache;
 use wcf\data\trophy\Trophy;
@@ -9,195 +11,217 @@ use wcf\data\user\UserList;
 use wcf\system\SingletonFactory;
 
 /**
- * Handles trophy conditions. 
+ * Handles trophy conditions.
  *
- * @author     Joshua Ruesweg
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    WoltLabSuite\Core\System\Trophy\Condition
- * @since      3.1
+ * @author  Joshua Ruesweg
+ * @copyright   2001-2019 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Trophy\Condition
+ * @since   3.1
  */
-class TrophyConditionHandler extends SingletonFactory {
-       /**
-        * definition name for trophy conditions
-        * @var string
-        */
-       const CONDITION_DEFINITION_NAME = 'com.woltlab.wcf.condition.trophy';
-       
-       /**
-        * list of grouped trophy condition object types
-        * @var ObjectType[][]
-        */
-       protected $groupedObjectTypes = [];
-       
-       /**
-        * @inheritDoc
-        */
-       protected function init() {
-               $objectTypes = ObjectTypeCache::getInstance()->getObjectTypes(self::CONDITION_DEFINITION_NAME);
-               
-               foreach ($objectTypes as $objectType) {
-                       if (!$objectType->conditiongroup) continue;
-                       
-                       if (!isset($this->groupedObjectTypes[$objectType->conditiongroup])) {
-                               $this->groupedObjectTypes[$objectType->conditiongroup] = [];
-                       }
-                       
-                       $this->groupedObjectTypes[$objectType->conditiongroup][$objectType->objectTypeID] = $objectType;
-               }
-       }
-       
-       /**
-        * Returns the list of grouped trophy condition object types.
-        *
-        * @return      ObjectType[][]
-        */
-       public function getGroupedObjectTypes() {
-               return $this->groupedObjectTypes;
-       }
-       
-       /**
-        * Assign trophies based on rules. 
-        * 
-        * @param       int             $maxAssigns
-        */
-       public function assignTrophies($maxAssigns = 500) {
-               $trophyList = new TrophyList();
-               $trophyList->getConditionBuilder()->add('awardAutomatically = ?', [1]);
-               $trophyList->getConditionBuilder()->add('isDisabled = ?', [0]);
-               $trophyList->readObjects();
-               
-               $i = 0;
-               foreach ($trophyList as $trophy) {
-                       $userIDs = $this->getUserIDs($trophy);
-                       
-                       foreach ($userIDs as $userID) {
-                               (new UserTrophyAction([], 'create', [
-                                       'data' => [
-                                               'trophyID' => $trophy->trophyID,
-                                               'userID' => $userID,
-                                               'time' => TIME_NOW
-                                       ]
-                               ]))->executeAction();
-                               
-                               if (++$i >= $maxAssigns) return;
-                       }
-               }
-       }
-       
-       /**
-        * Revoke user trophies which are not longer fulfills the conditions. 
-        * 
-        * @param       int             $maxRevokes
-        * @since       5.2
-        */
-       public function revokeTrophies($maxRevokes = 500) {
-               $trophyList = new TrophyList();
-               $trophyList->getConditionBuilder()->add('awardAutomatically = ?', [1]);
-               $trophyList->getConditionBuilder()->add('revokeAutomatically = ?', [1]);
-               $trophyList->getConditionBuilder()->add('isDisabled = ?', [0]);
-               $trophyList->readObjects();
-               
-               $i = 0;
-               foreach ($trophyList as $trophy) {
-                       $userTrophyIDs = $this->getRevocableUserTrophyIDs($trophy, $maxRevokes - $i);
-                       
-                       $i += count($userTrophyIDs);
-                       
-                       (new UserTrophyAction($userTrophyIDs, 'delete'))->executeAction();
-                       
-                       if ($i >= $maxRevokes) return;
-               }
-       }
-       
-       /**
-        * Returns the users who fulfill all conditions of the given trophy.
-        *
-        * @param       Trophy          $trophy
-        * @return      int[]
-        * @since       5.2
-        */
-       private function getUserIDs(Trophy $trophy) {
-               $userList = new UserList();
-               $userList->sqlConditionJoins .= " LEFT JOIN wcf".WCF_N."_user_option_value user_option_value ON (user_option_value.userID = user_table.userID)";
-               
-               $conditions = $trophy->getConditions();
-               foreach ($conditions as $condition) {
-                       $condition->getObjectType()->getProcessor()->addUserCondition($condition, $userList);
-               }
-               
-               // prevent multiple awards from a trophy for a user 
-               $userList->getConditionBuilder()->add('user_table.userID NOT IN (SELECT userID FROM wcf'.WCF_N.'_user_trophy WHERE trophyID IN (?))', [$trophy->trophyID]);
-               $userList->readObjectIDs();
-               
-               return $userList->getObjectIDs();
-       }
-       
-       /**
-        * Returns the userTrophyIDs of the users, which no longer fulfills the trophy conditions. 
-        * 
-        * @param       Trophy          $trophy
-        * @param       int         $maxTrophyIDs               maximum number of trophies that are processed
-        * @return      int[]
-        * @since       5.2
-        */
-       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();
-               
-               $conditions = $trophy->getConditions();
-               
-               // Check if there are conditions for the award of the trophy for the given trophy.
-               // If there are no conditions, we simply return an empty list and do not remove any trophy. 
-               // A trophy without conditions that is awarded automatically cannot be created by default. 
-               if (empty($conditions)) {
-                       return [];
-               }
-               
-               // Assign the condition to the pseudo DBOList object 
-               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->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]);
-               
-               // Prevents us from getting faulty UserTrophyIDs.
-               $userList->getConditionBuilder()->add('user_trophy.trophyID = ?', [$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());
-       }
+class TrophyConditionHandler extends SingletonFactory
+{
+    /**
+     * definition name for trophy conditions
+     * @var string
+     */
+    const CONDITION_DEFINITION_NAME = 'com.woltlab.wcf.condition.trophy';
+
+    /**
+     * list of grouped trophy condition object types
+     * @var ObjectType[][]
+     */
+    protected $groupedObjectTypes = [];
+
+    /**
+     * @inheritDoc
+     */
+    protected function init()
+    {
+        $objectTypes = ObjectTypeCache::getInstance()->getObjectTypes(self::CONDITION_DEFINITION_NAME);
+
+        foreach ($objectTypes as $objectType) {
+            if (!$objectType->conditiongroup) {
+                continue;
+            }
+
+            if (!isset($this->groupedObjectTypes[$objectType->conditiongroup])) {
+                $this->groupedObjectTypes[$objectType->conditiongroup] = [];
+            }
+
+            $this->groupedObjectTypes[$objectType->conditiongroup][$objectType->objectTypeID] = $objectType;
+        }
+    }
+
+    /**
+     * Returns the list of grouped trophy condition object types.
+     *
+     * @return  ObjectType[][]
+     */
+    public function getGroupedObjectTypes()
+    {
+        return $this->groupedObjectTypes;
+    }
+
+    /**
+     * Assign trophies based on rules.
+     *
+     * @param int $maxAssigns
+     */
+    public function assignTrophies($maxAssigns = 500)
+    {
+        $trophyList = new TrophyList();
+        $trophyList->getConditionBuilder()->add('awardAutomatically = ?', [1]);
+        $trophyList->getConditionBuilder()->add('isDisabled = ?', [0]);
+        $trophyList->readObjects();
+
+        $i = 0;
+        foreach ($trophyList as $trophy) {
+            $userIDs = $this->getUserIDs($trophy);
+
+            foreach ($userIDs as $userID) {
+                (new UserTrophyAction([], 'create', [
+                    'data' => [
+                        'trophyID' => $trophy->trophyID,
+                        'userID' => $userID,
+                        'time' => TIME_NOW,
+                    ],
+                ]))->executeAction();
+
+                if (++$i >= $maxAssigns) {
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Revoke user trophies which are not longer fulfills the conditions.
+     *
+     * @param int $maxRevokes
+     * @since       5.2
+     */
+    public function revokeTrophies($maxRevokes = 500)
+    {
+        $trophyList = new TrophyList();
+        $trophyList->getConditionBuilder()->add('awardAutomatically = ?', [1]);
+        $trophyList->getConditionBuilder()->add('revokeAutomatically = ?', [1]);
+        $trophyList->getConditionBuilder()->add('isDisabled = ?', [0]);
+        $trophyList->readObjects();
+
+        $i = 0;
+        foreach ($trophyList as $trophy) {
+            $userTrophyIDs = $this->getRevocableUserTrophyIDs($trophy, $maxRevokes - $i);
+
+            $i += \count($userTrophyIDs);
+
+            (new UserTrophyAction($userTrophyIDs, 'delete'))->executeAction();
+
+            if ($i >= $maxRevokes) {
+                return;
+            }
+        }
+    }
+
+    /**
+     * Returns the users who fulfill all conditions of the given trophy.
+     *
+     * @param Trophy $trophy
+     * @return  int[]
+     * @since       5.2
+     */
+    private function getUserIDs(Trophy $trophy)
+    {
+        $userList = new UserList();
+        $userList->sqlConditionJoins .= " LEFT JOIN wcf" . WCF_N . "_user_option_value user_option_value ON (user_option_value.userID = user_table.userID)";
+
+        $conditions = $trophy->getConditions();
+        foreach ($conditions as $condition) {
+            $condition->getObjectType()->getProcessor()->addUserCondition($condition, $userList);
+        }
+
+        // prevent multiple awards from a trophy for a user
+        $userList->getConditionBuilder()->add(
+            'user_table.userID NOT IN (SELECT userID FROM wcf' . WCF_N . '_user_trophy WHERE trophyID IN (?))',
+            [$trophy->trophyID]
+        );
+        $userList->readObjectIDs();
+
+        return $userList->getObjectIDs();
+    }
+
+    /**
+     * Returns the userTrophyIDs of the users, which no longer fulfills the trophy conditions.
+     *
+     * @param Trophy $trophy
+     * @param int $maxTrophyIDs maximum number of trophies that are processed
+     * @return      int[]
+     * @since       5.2
+     */
+    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();
+
+        $conditions = $trophy->getConditions();
+
+        // Check if there are conditions for the award of the trophy for the given trophy.
+        // If there are no conditions, we simply return an empty list and do not remove any trophy.
+        // A trophy without conditions that is awarded automatically cannot be created by default.
+        if (empty($conditions)) {
+            return [];
+        }
+
+        // Assign the condition to the pseudo DBOList object
+        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->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]
+        );
+
+        // Prevents us from getting faulty UserTrophyIDs.
+        $userList->getConditionBuilder()->add('user_trophy.trophyID = ?', [$trophy->trophyID]);
+        $userList->readObjects();
+
+        // We now return an array of userTrophyIDs instead of user objects to remove them directly via DBOAction.
+        return \array_map(static function ($object) {
+            return $object->userTrophyID;
+        }, $userList->getObjects());
+    }
 }