Count the number of attempts in need of a regrade.
@param object $quiz the quiz settings.
@param \core\dml\sql_join $groupstudentsjoins (joins, wheres, params) If this is given, only data relating
to these users is cleared.
513273
protected function count_question_attempts_needing_regrade($quiz, \core\dml\sql_join $groupstudentsjoins) {
        global $DB;

        $userjoin = '';
        $usertest = '';
        $params = array();
        if ($this->hasgroupstudents) {
            $userjoin = "JOIN {user} u ON u.id = quiza.userid
                    {$groupstudentsjoins->joins}";
            $usertest = "{$groupstudentsjoins->wheres} AND u.id = quiza.userid AND ";
            $params = $groupstudentsjoins->params;
        }

        $params['cquiz'] = $quiz->id;
        $sql = "SELECT COUNT(DISTINCT quiza.id)
                  FROM {quiz_attempts} quiza
                  JOIN {quiz_overview_regrades} qqr ON quiza.uniqueid = qqr.questionusageid
                $userjoin
                 WHERE
                      $usertest
                      quiza.quiz = :cquiz AND
                      quiza.preview = 0 AND
                      qqr.regraded = 0";
        return $DB->count_records_sql($sql, $params);
    }
142473
private function applyJoins(ClassMetadata $metadata, array $joins, string $alias): void
    {
        foreach ($joins as $field => $join) {
            $joinedAlias = $this->createJoin($alias, $field, $join['type']);

            if (isset($join['joins']) || isset($join['conditions'])) {
                $targetClassName = $metadata->getAssociationMapping($field)['targetEntity'];
                $targetMetadata = $this->entityManager->getClassMetadata($targetClassName);
                $type = $this->types->getFilterGroupCondition($targetClassName);
                $this->applyJoinsAndFilters($targetMetadata, $joinedAlias, $type, $join['joins'] ?? [], $join['conditions'] ?? []);
            }
        }
    }
14671
public function count_teams($activitygroup = 0) {

        $count = 0;

        $participants = $this->list_participants($activitygroup, true);

        // If a team submission grouping id is provided all good as all returned groups
        // are the submission teams, but if no team submission grouping was specified
        // $groups will contain all participants groups.
        if ($this->get_instance()->teamsubmissiongroupingid) {

            // We restrict the users to the selected group ones.
            $groups = groups_get_all_groups($this->get_course()->id,
                                            array_keys($participants),
                                            $this->get_instance()->teamsubmissiongroupingid,
                                            'DISTINCT g.id, g.name');

            $count = count($groups);

            // When a specific group is selected we don't count the default group users.
            if ($activitygroup == 0) {
                if (empty($this->get_instance()->preventsubmissionnotingroup)) {
                    // See if there are any users in the default group.
                    $defaultusers = $this->get_submission_group_members(0, true);
                    if (count($defaultusers) > 0) {
                        $count += 1;
                    }
                }
            } else if ($activitygroup != 0 && empty($groups)) {
                // Set count to 1 if $groups returns empty.
                // It means the group is not part of $this->get_instance()->teamsubmissiongroupingid.
                $count = 1;
            }
        } else {
            // It is faster to loop around participants if no grouping was specified.
            $groups = array();
            foreach ($participants as $participant) {
                if ($group = $this->get_submission_group($participant->id)) {
                    $groups[$group->id] = true;
                } else if (empty($this->get_instance()->preventsubmissionnotingroup)) {
                    $groups[0] = true;
                }
            }

            $count = count($groups);
        }

        return $count;
    }
532473
private function applyGroups(ClassMetadata $metadata, InputObjectType $type, array $filter, string $alias): void
    {
        $typeFields = $type->getField('groups')->type->getWrappedType(true)->getField('conditions')->type->getWrappedType(true);
        foreach ($filter['groups'] ?? [] as $group) {
            $this->applyJoinsAndFilters($metadata, $alias, $typeFields, $group['joins'] ?? [], $group['conditions'] ?? []);
            $this->applyCollectedDqlConditions($group);
        }
    }
288099
public static function get_users_in_context(userlist $userlist) {
        $context = $userlist->get_context();

        if (!$context instanceof \context_module) {
            return;
        }

        $params = [
            'cmid'    => $context->instanceid,
            'modname' => 'quiz',
        ];

        // Users who attempted the quiz.
        $sql = "SELECT qa.userid
                  FROM {course_modules} cm
                  JOIN {modules} m ON m.id = cm.module AND m.name = :modname
                  JOIN {quiz} q ON q.id = cm.instance
                  JOIN {quiz_attempts} qa ON qa.quiz = q.id
                 WHERE cm.id = :cmid AND qa.preview = 0";
        $userlist->add_from_sql('userid', $sql, $params);

        // Users with quiz overrides.
        $sql = "SELECT qo.userid
                  FROM {course_modules} cm
                  JOIN {modules} m ON m.id = cm.module AND m.name = :modname
                  JOIN {quiz} q ON q.id = cm.instance
                  JOIN {quiz_overrides} qo ON qo.quiz = q.id
                 WHERE cm.id = :cmid";
        $userlist->add_from_sql('userid', $sql, $params);

        // Question usages in context.
        // This includes where a user is the manual marker on a question attempt.
        $sql = "SELECT qa.uniqueid
                  FROM {course_modules} cm
                  JOIN {modules} m ON m.id = cm.module AND m.name = :modname
                  JOIN {quiz} q ON q.id = cm.instance
                  JOIN {quiz_attempts} qa ON qa.quiz = q.id
                 WHERE cm.id = :cmid AND qa.preview = 0";
        \core_question\privacy\provider::get_users_in_context_from_sql($userlist, 'qn', $sql, $params);
    }
966469
private function setManyToManyJoin($table, $alias, $condition = null)
    {
        if (!in_array($alias, $this->tables)) {
            if ($condition) {
                $this->queryBuilder->join($table, $alias, 'WITH', $condition);
            } else {
                $this->queryBuilder->join($table, $alias);
            }
            $this->tables[] = $alias;
        }
    }
331595
public function innerJoin($join, $alias)
    {
        if (!in_array($alias, $this->joins)) {
            $this->queryBuilder->innerJoin($join, $alias);
            array_push($this->joins, $alias);
        }

        return $this;
    }
557814
protected function doJoins($source, $joins, &$dest, $from, $contextAlias, $buildImpactIndex=true)
    {
        // expand sequences before doing any joins...
        $this->expandSequence($joins,$source);

        foreach ($joins as $predicate=>$ruleset) {
            if ($predicate=='followSequence') {
                continue;
            }

            if (isset($source[$predicate]))
            {
                // todo: perhaps we can get better performance by detecting whether or not
                // the uri to join on is already in the impact index, and if so not attempting
                // to join on it. However, we need to think about different combinations of
                // nested joins in different points of the view spec and see if this would
                // complicate things. Needs a unit test or two.
                $joinUris = [];
                if (isset($source[$predicate][VALUE_URI]))
                {
                    // single value for join
                    $joinUris[] = array(_ID_RESOURCE=>$source[$predicate][VALUE_URI],_ID_CONTEXT=>$contextAlias);
                }
                else
                {
                    // multiple values for join
                    $joinsPushed = 0;
                    foreach ($source[$predicate] as $v)
                    {
                        if (isset($ruleset['maxJoins']) && !$joinsPushed<$ruleset['maxJoins'])
                        {
                            break; // maxJoins reached
                        }
                        $joinUris[] = array(_ID_RESOURCE=>$v[VALUE_URI],_ID_CONTEXT=>$contextAlias);
                        $joinsPushed++;
                    }
                }

                $recursiveJoins = [];
                $collection = (
                isset($ruleset['from'])
                    ? $this->config->getCollectionForCBD($this->storeName, $ruleset['from'])
                    : $this->config->getCollectionForCBD($this->storeName, $from)
                );

                $cursor = $collection->find(array('_id'=>array('$in'=>$joinUris)), array(
                    'maxTimeMS' => $this->getConfigInstance()->getMongoCursorTimeout()
                ));

                $this->addIdToImpactIndex($joinUris, $dest, $buildImpactIndex);
                foreach($cursor as $linkMatch) {
                    // if there is a condition, check it...
                    if (isset($ruleset['condition']))
                    {
                        $ruleset['condition']['._id'] = $linkMatch['_id'];
                    }
                    if (!(isset($ruleset['condition']) && $collection->count($ruleset['condition'])==0))
                    {
                        // make sure any sequences are expanded before extracting properties
                        if (isset($ruleset['joins'])) $this->expandSequence($ruleset['joins'],$linkMatch);
                        if (isset($ruleset['filter']))
                        {
                            foreach($ruleset['filter'] as $filterPredicate => $filter)
                            {
                                foreach($filter as $filterType => $filterMatch)
                                {
                                    if (isset($linkMatch[$filterPredicate]))
                                    {
                                        foreach($linkMatch[$filterPredicate] as $linkMatchType => $linkMatchValues)
                                        {
                                            if (is_array($linkMatchValues) == false)
                                            {
                                                $linkMatchValues = array($linkMatchType => $linkMatchValues);
                                            }
                                            foreach($linkMatchValues as $linkMatchType => $linkMatchValue)
                                            {
                                                if ($this->matchesFilter($linkMatchType, $linkMatchValue, $filterType, $filterMatch))
                                                {
                                                    $dest[_GRAPHS][] = $this->extractProperties($linkMatch,$ruleset,$from);
                                                }
                                            }

                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            $dest[_GRAPHS][] = $this->extractProperties($linkMatch,$ruleset,$from);
                        }

                        if (isset($ruleset['joins']))
                        {
                            // recursive joins must be done after this cursor has completed, otherwise things get messy
                            $recursiveJoins[] = array('data'=>$linkMatch, 'ruleset'=>$ruleset['joins']);
                        }
                    }
                }
                if (count($recursiveJoins)>0)
                {
                    foreach ($recursiveJoins as $r)
                    {
                        $this->doJoins($r['data'],$r['ruleset'],$dest,$from,$contextAlias,$buildImpactIndex);
                    }
                }
            }
        }
        return;
    }
716921
public static function processCampaignWinnersBatch($campaign, $branches, $activities, $places, $isVisitsGoal, &$context) {
    if (empty($context['sandbox'])) {
      $context['sandbox']['progress'] = 0;

      $context['sandbox']['campaign'] = $campaign;
      $context['sandbox']['activities'] = $activities;
      $context['sandbox']['branches'] = array_keys($branches);
      $context['sandbox']['places'] = $places;

      $context['sandbox']['max'] = count($branches);
    }

    $branchId = $context['sandbox']['branches'][$context['sandbox']['progress']];
    $campaign = $context['sandbox']['campaign'];
    $activities = $context['sandbox']['activities'];
    $places = $context['sandbox']['places'];

    // Get all member campaigns for this branch.
    $memberCampaignsInfo = self::getInfoByBranch($campaign, $branchId, $activities);

    $alreadyWinners = [];

    $activityWinners = [];
    // Assign places.
    foreach ($places as $place) {
      // Calculate winners per activity.
      foreach ($memberCampaignsInfo as $category => $data) {
        if (empty($data)) {
          break;
        }

        $memberCampaignItem = self::getRandomWinner($data, $alreadyWinners);

        // Create Winner entities.
        if (!empty($memberCampaignItem)) {
          $activityWinners[] = [
            'member_campaign' => $memberCampaignItem['member_campaign'],
            'activity' => $category,
            'place' => $place,
          ];
        }
      }
    }

    // Calculate winners by Visits goal.
    $goalWinners = [];
    if ($isVisitsGoal) {
      /** @var \Drupal\openy_campaign\CampaignMenuService $campaignMenuService */
      $campaignMenuService = \Drupal::service('openy_campaign.campaign_menu_handler');
      $goalWinnersIds = $campaignMenuService->getVisitsGoalWinners($campaign, $branchId, $alreadyWinners);
      // Create Winner entity. If winner defined by Visits goal without activity - set Activity = 0.
      foreach ($places as $place) {
        $goalWinnerId = array_shift($goalWinnersIds);
        $goalWinners[] = [
          'member_campaign' => $goalWinnerId,
          'activity' => 0,
          'place' => $place,
        ];
      }
    }

    $winners = array_merge($goalWinners, $activityWinners);

    foreach ($winners as $item) {
      $winner = Winner::create($item);
      $winner->save();

      $context['results'][] = $item['member_campaign'];
    }

    $context['sandbox']['progress']++;

    if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
    }
  }
825852
public static function findJoinByAlias(QueryBuilder $qb, $rootAlias, $joinAlias)
    {
        $dqlParts = $qb->getDQLParts();

        if (!isset($dqlParts['join'][$rootAlias])) {
            return null;
        }
        /** @var \Doctrine\ORM\Query\Expr\Join $join */
        foreach ($dqlParts['join'][$rootAlias] as $join) {
            if ($joinAlias === $join->getAlias()) {
                return $join;
            }
        }

        return null;
    }
601619
public static function add_group_members($members) {
        global $CFG, $DB;
        require_once("$CFG->dirroot/group/lib.php");

        $params = self::validate_parameters(self::add_group_members_parameters(), array('members'=>$members));

        $transaction = $DB->start_delegated_transaction();
        foreach ($params['members'] as $member) {
            // validate params
            $groupid = $member['groupid'];
            $userid = $member['userid'];

            $group = groups_get_group($groupid, '*', MUST_EXIST);
            $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0, 'mnethostid'=>$CFG->mnet_localhost_id), '*', MUST_EXIST);

            // now security checks
            $context = context_course::instance($group->courseid, IGNORE_MISSING);
            try {
                self::validate_context($context);
            } catch (Exception $e) {
                $exceptionparam = new stdClass();
                $exceptionparam->message = $e->getMessage();
                $exceptionparam->courseid = $group->courseid;
                throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
            }
            require_capability('moodle/course:managegroups', $context);

            // now make sure user is enrolled in course - this is mandatory requirement,
            // unfortunately this is slow
            if (!is_enrolled($context, $userid)) {
                throw new invalid_parameter_exception('Only enrolled users may be members of groups');
            }

            groups_add_member($group, $user);
        }

        $transaction->allow_commit();
    }
782271
function updateCountSuccess(that) {
    if(that.expected !== undefined) {
        var countSuccess = that.count === that.expected
        that.countBlock.state.set("success", countSuccess)
        if(that.groupEnded) that.countBlock.results.state.set("late", true)

        if(countSuccess) {
            that.mainGroup.title.testTotalPasses++
            that.title.passed++
            if(that.groupEnded) {
                that.mainGroup.title.testTotalFailures--
                that.groupEndCountSubtracted = true // marks that failures were subtracted after the test finished (so successes can be later subtracted correctly if need be)
            }
        } else if(that.groupEndCountSubtracted || that.count - 1 === that.expected) {
            that.title.passed--
            that.mainGroup.title.testTotalPasses--
            if(that.groupEnded) {
                that.mainGroup.title.testTotalFailures++
            }
        }
    }
}
481557
protected function performJoin($table, $foreign, $other, $deletedAt = false, $type = 'left')
    {
        $joins = [];
        foreach ((array) $this->getBaseQueryBuilder()->joins as $key => $join) {
            $joins[] = $join->table;
        }

        if (! in_array($table, $joins)) {
            $this->getBaseQueryBuilder()->join($table, $foreign, '=', $other, $type);
        }

        if ($deletedAt !== false) {
            $this->getBaseQueryBuilder()->whereNull($deletedAt);
        }
    }
1158807
protected function filterExistingJoins(
        QueryBuilder $queryBuilder,
        array $joinParts,
        string $alias,
        string $join,
        string $joinType
    ): QueryBuilder {
        $existingJoin = array_filter(
            $joinParts,
            function (Join $joinObj) use ($alias, $join, $joinType) {
                return $joinObj->getJoinType() == $joinType
                    && $joinObj->getAlias() == $alias
                    && $joinObj->getJoin() == $join;
            }
        );

        if ([] != $existingJoin) {
            return $queryBuilder;
        }

        return $this->makeJoin($queryBuilder, $join, $alias, $joinType);
    }
572326
public static function group_member_removed($event) {
        if (!empty(self::$resetinprogress)) {
            // We will take care of that once the course reset ends.
            return;
        }
        quiz_update_open_attempts(array('userid' => $event->relateduserid, 'groupid' => $event->objectid));
    }
34634
public function countSkillGroups(Criteria $criteria = null, $distinct = false, ConnectionInterface $con = null)
    {
        $partial = $this->collSkillGroupsPartial && !$this->isNew();
        if (null === $this->collSkillGroups || null !== $criteria || $partial) {
            if ($this->isNew() && null === $this->collSkillGroups) {
                return 0;
            }

            if ($partial && !$criteria) {
                return count($this->getSkillGroups());
            }

            $query = ChildSkillGroupQuery::create(null, $criteria);
            if ($distinct) {
                $query->distinct();
            }

            return $query
                ->filterByGroup($this)
                ->count($con);
        }

        return count($this->collSkillGroups);
    }
463569
public static function group_deleted($event) {
        if (!empty(self::$resetinprogress)) {
            // We will take care of that once the course reset ends.
            return;
        }
        lesson_process_group_deleted_in_course($event->courseid, $event->objectid);
    }