jonof / moodle-block_completion_progress

A time management tool for students using activity completion
https://moodle.org/plugins/block_completion_progress
GNU General Public License v3.0
17 stars 65 forks source link

Paging incorrect when course has multiple enrol records per user #104

Closed Trynes closed 7 months ago

Trynes commented 7 months ago

Problem: Too many paging links and incorrect participant count in courses that have multiple enrol records returned per user. (Crosslisted courses in our case sometimes return 3 records per user, tripling the count).

Cause: The function query_db() in /classes/table/overview.php that uses the parent::query_db() function from /moodle/lib/tablelib.php and relies on an sql of 'SELECT COUNT(1)' for returning how many rows to return.

Solution: In my case, I used the existing plugin function for query_db(), removing the if (array_keys($sortcols)[0] === 'progress') from the top of the function, and putting in around other appropriate parts. (As shown below) I didn't re-arrange anything so as to keep the changes to a minimum.

public function query_db($pagesize, $useinitialsbar=true) {
    global $DB;

    $sortcols = $this->get_sort_columns();
    // Kludge to sort by the runtime-computed percentage column.
    if ($useinitialsbar && !$this->is_downloading()) {
        $this->initialbars(true);
    }
    list($wsql, $wparams) = $this->get_sql_where();
    if ($wsql) {
        $this->sql->where .= ' AND '.$wsql;
        $this->sql->params = array_merge($this->sql->params, $wparams);
    }
    if (($sort = $this->get_sql_sort())) {
        $sort = "ORDER BY $sort";
    }
    $sql = "SELECT {$this->sql->fields}
            FROM {$this->sql->from}
            WHERE {$this->sql->where}
            {$sort}";
    $rawdata = $DB->get_recordset_sql($sql, $this->sql->params);

    // Compute the percentage for each record and sort.
    $data = [];
    $percents = [];
    foreach ($rawdata as $key => $row) {
        $this->progress->for_user($row);
        $percents[$key] = $this->progress->get_percentage() ?? -1;
        $data[$key] = $row;
    }
    if (array_keys($sortcols)[0] === 'progress') { 
        $sortfunc = $sortcols['progress'] === SORT_ASC ? 'asort' : 'arsort';
        $sortfunc($percents);
    }
    $rawdata->close();

    if (!$this->is_downloading()) {
        $pagestart = $this->currpage * $pagesize;
        $percents = array_slice($percents, $pagestart, $pagesize, true);
        $this->pagesize($pagesize, count($data));
    }
    if (array_keys($sortcols)[0] === 'progress') { 
        $this->rawdata = [];
        foreach (array_keys($percents) as $key) {
            $this->rawdata[] = $data[$key];
        }
    } else if (!$this->is_downloading()) {
        $this->rawdata = $DB->get_records_sql($sql, $this->sql->params, $this->get_page_start(), $this->get_page_size());
    } else {
        $this->rawdata = $DB->get_records_sql($sql, $this->sql->params);
    }
    return;
}