$i = 0;
foreach ($trophyList as $trophy) {
- $userTrophyIDs = $this->getRevocableUserTrophyIDs($trophy);
+ $userTrophyIDs = $this->getRevocableUserTrophyIDs($trophy, $maxRevokes - $i);
$i += count($userTrophyIDs);
* @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());