$table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($baseurl->out()); if (!isset($hiddenfields['lastaccess'])) { $table->sortable(true, 'lastaccess', SORT_DESC); } else { $table->sortable(true, 'firstname', SORT_ASC); } $table->no_sorting('roles'); $table->no_sorting('groups'); $table->no_sorting('groupings'); $table->no_sorting('select'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'participants'); $table->set_attribute('class', 'generaltable generalbox'); $table->set_control_variables(array(TABLE_VAR_SORT => 'ssort', TABLE_VAR_HIDE => 'shide', TABLE_VAR_SHOW => 'sshow', TABLE_VAR_IFIRST => 'sifirst', TABLE_VAR_ILAST => 'silast', TABLE_VAR_PAGE => 'spage')); $table->setup(); list($esql, $params) = get_enrolled_sql($context, null, $currentgroup, true); $joins = array("FROM {user} u"); $wheres = array(); $userfields = array('username', 'email', 'city', 'country', 'lang', 'timezone', 'maildisplay'); $mainuserfields = user_picture::fields('u', $userfields); $extrasql = get_extra_user_fields_sql($context, 'u', '', $userfields); if ($isfrontpage) { $select = "SELECT {$mainuserfields}, u.lastaccess{$extrasql}"; $joins[] = "JOIN ({$esql}) e ON e.id = u.id"; // Everybody on the frontpage usually. if ($accesssince) { $wheres[] = get_user_lastaccess_sql($accesssince); } } else {
/** * Real raster that prints graphs and data * */ function print_dashboard() { global $CFG, $EXTRADBCONNECT, $COURSE, $DB, $OUTPUT; /* $text = '<link type="text/css" rel="stylesheet" href="'.$CFG->wwwroot.'/blocks/dashboard/js/dhtmlxCalendar/codebase/dhtmlxcalendar.css" />'; $text .= '<link type="text/css" rel="stylesheet" href="'.$CFG->wwwroot.'/blocks/dashboard/js/dhtmlxCalendar/codebase/skins/dhtmlxcalendar_dhx_web.css" />'; */ $text = ''; if (!isset($this->config)) { $this->config = new StdClass(); } $this->config->limit = 20; $coursepage = ''; if ($COURSE->format == 'page') { include_once $CFG->dirroot . '/course/format/page/lib.php'; $pageid = optional_param('page', 0, PARAM_INT); // flexipage page number if (!$pageid) { $flexpage = course_page::get_current_page($COURSE->id); } else { $flexpage = new StdClass(); $flexpage->id = $pageid; } $coursepage = "&page=" . $flexpage->id; } $rpage = optional_param('rpage' . $this->instance->id, 0, PARAM_INT); // result page if ($rpage < 0) { $rpage = 0; } // unlogged people cannot see their status if ((!isloggedin() || isguestuser()) && @$this->config->guestsallowed) { $text = get_string('guestsnotallowed', 'block_dashboard'); $loginstr = get_string('login'); $text .= "<a href=\"{$wwwroot}/login/index.php\">{$loginstr}</a>"; return $text; } if (!isset($this->config) || empty($this->config->query)) { $noquerystr = get_string('noquerystored', 'block_dashboard'); $text = $noquerystr; return $text; } if (!isset($CFG->block_dashboard_big_result_threshold)) { $CFG->block_dashboard_big_result_threshold = 500; } // connecting if ($this->config->target == 'moodle') { // already connected } else { $error = ''; if (!isset($EXTRADBCONNECT)) { $EXTRADBCONNECT = extra_db_connect(true, $error); } if ($error) { $text = $error; return $text; } } // prepare all params from config $this->prepare_config(); $graphdata = array(); $ticks = array(); $filterquerystring = ''; if (!empty($this->config->filters)) { try { $filterquerystring = $this->prepare_filters(); } catch (Exception $e) { if (debugging()) { echo $e->error; } return get_string('invalidorobsoletefilterquery', 'block_dashboard'); } } else { $this->filteredsql = str_replace('<%%FILTERS%%>', '', $this->sql); } $this->sql = str_replace('<%%FILTERS%%>', '', $this->sql); // needed to prepare for filter range prefetch if (!empty($this->params)) { $filterquerystring = $filterquerystring ? $filterquerystring . '&' . $this->prepare_params() : $this->prepare_params(); } else { $this->sql = str_replace('<%%PARAMS%%>', '', $this->sql); // needed to prepare for filter range prefetch $this->filteredsql = str_replace('<%%PARAMS%%>', '', $this->filteredsql); // needed to prepare for filter range prefetch } $sort = optional_param('tsort' . $this->instance->id, @$this->config->defaultsort, PARAM_TEXT); if (!empty($sort)) { // do not sort if already sorted in explained query if (!preg_match('/ORDER\\s+BY/si', $this->sql)) { $this->filteredsql .= " ORDER BY {$sort}"; } } $this->filteredsql = $this->protect($this->filteredsql); // ######### GETTING RESULTS $countres = $this->count_records($error); // if too many results, we force paging mode if (empty($this->config->pagesize) && $countres > $CFG->block_dashboard_big_result_threshold && !empty($this->config->bigresult)) { $text .= '<span class="error">' . get_string('toomanyrecordsusepaging', 'block_dashboard') . '</span><br/>'; $this->config->pagesize = $CFG->block_dashboard_big_result_threshold; $rpage = 0; } // getting real results including page and offset if (!empty($this->config->pagesize)) { $offset = $rpage * $this->config->pagesize; } else { $offset = ''; } try { $results = $this->fetch_dashboard_data($this->filteredsql, @$this->config->pagesize, $offset); } catch (Exception $e) { return get_string('invalidorobsoletequery', 'block_dashboard', $this->config->query); } if ($results) { $table = new flexible_table('mod-dashboard' . $this->instance->id); $instancecontrolvars = array(TABLE_VAR_PAGE => 'rpage' . $this->instance->id, TABLE_VAR_SORT => 'tsort' . $this->instance->id, TABLE_VAR_HIDE => 'thide' . $this->instance->id, TABLE_VAR_SHOW => 'tshow' . $this->instance->id); $table->set_control_variables($instancecontrolvars); // use full not to collide with flexipage paging $tablecolumns = array(); $tableheaders = array(); foreach ($this->output as $field => $label) { $tablecolumns[] = $field; $tableheaders[] = $label; } $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $filterquerystringadd = isset($filterquerystring) ? "&{$filterquerystring}" : ''; if (@$this->config->inblocklayout) { $table->define_baseurl($CFG->wwwroot . '/course/view.php?id=' . $COURSE->id . $coursepage . $filterquerystringadd); } else { $table->define_baseurl($CFG->wwwroot . '/blocks/dashboard/view.php?id=' . $COURSE->id . '&blockid=' . $this->instance->id . $coursepage . $filterquerystringadd); } if (!empty($this->config->sortable)) { $table->sortable(true, $this->config->xaxisfield, SORT_DESC); } //sorted by xaxisfield by default $table->collapsible(true); $table->initialbars(true); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'dashboard' . $this->instance->id); $table->set_attribute('class', 'dashboard'); $table->set_attribute('width', '100%'); foreach ($this->output as $field => $label) { $table->column_class($field, $field); } $table->setup(); /* $where = $table->get_sql_where(); $sortsql = $table->get_sql_sort(); */ if (!empty($this->config->pagesize)) { $table->pagesize($this->config->pagesize, $countres); // no paginating at start } $graphseries = array(); $treedata = array(); $treekeys = array(); $lastvalue = array(); $hcols = array(); $splitnumsonsort = @$this->config->splitsumsonsort; foreach ($results as $result) { // prepare for subsums if (!empty($splitnumsonsort)) { $orderkeyed = strtoupper($result->{$splitnumsonsort}); if (!isset($oldorderkeyed)) { $oldorderkeyed = $orderkeyed; } // first time } // pre-aggregates sums if (!empty($this->config->shownumsums)) { foreach (array_keys($this->numsumsf) as $numsum) { if (empty($numsum)) { continue; } if (!isset($result->{$numsum})) { continue; } // make subaggregates (only for linear tables and when sorting criteria is the split column) // post aggregate after table output if (!isset($aggr)) { $aggr = new StdClass(); } $aggr->{$numsum} = 0 + (double) @$aggr->{$numsum} + (double) $result->{$numsum}; if (!empty($splitnumsonsort) && @$this->config->tabletype == 'linear' && preg_match("/\\b{$splitnumsonsort}\\b/", $sort)) { $this->subaggr[$orderkeyed]->{$numsum} = 0 + (double) @$this->subaggr[$orderkeyed]->{$numsum} + (double) $result->{$numsum}; } } } if (!empty($splitnumsonsort) && @$this->config->tabletype == 'linear' && preg_match("/\\b{$splitnumsonsort}\\b/", $sort)) { if ($orderkeyed != $oldorderkeyed) { // when range changes $k = 0; $tabledata = null; foreach (array_keys($this->output) as $field) { if (in_array($field, array_keys($this->numsumsf))) { if (is_null($tabledata)) { $tabledata = array(); for ($j = 0; $j < $k; $j++) { $tabledata[$j] = ''; } } $tabledata[$k] = '<b>Tot: ' . @$this->subaggr[$oldorderkeyed]->{$field} . '</b>'; } $k++; } if (!is_null($tabledata)) { $table->add_data($tabledata); } $oldorderkeyed = $orderkeyed; } } // Print data in results if (!empty($this->config->showdata)) { if (empty($this->config->tabletype) || $this->config->tabletype == 'linear') { $tabledata = array(); foreach (array_keys($this->output) as $field) { if (empty($field)) { continue; } // did we ask for cumulative results ? $cumulativeix = null; if (preg_match('/S\\((.+?)\\)/', $field, $matches)) { $field = $matches[1]; $cumulativeix = $this->instance->id . '_' . $field; } if (!empty($this->outputf[$field])) { $datum = dashboard_format_data($this->outputf[$field], $result->{$field}, $cumulativeix); } else { $datum = dashboard_format_data(null, @$result->{$field}, $cumulativeix); } // process coloring if required if (!empty($this->config->colorfield) && $this->config->colorfield == $field) { $datum = dashboard_colour_code($this, $datum, $this->colourcoding); } if (!empty($this->config->cleandisplay)) { if (!array_key_exists($field, $lastvalue) || $lastvalue[$field] != $datum) { $lastvalue[$field] = $datum; $tabledata[] = $datum; } else { $tabledata[] = ''; // if same as above, add blanck } } else { $tabledata[] = $datum; } } $table->add_data($tabledata); } else { if ($this->config->tabletype == 'tabular') { // this is a tabular table /* in a tabular table, data can be placed : * - in first columns in order of vertical keys * the results are grabbed sequentially and spread into the matrix */ $keystack = array(); $matrix = array(); foreach (array_keys($this->vertkeys->formats) as $vkey) { if (empty($vkey)) { continue; } $vkeyvalue = $result->{$vkey}; $matrix[] = "['" . addslashes($vkeyvalue) . "']"; } $hkey = $this->config->horizkey; $hkeyvalue = !empty($hkey) ? $result->{$hkey} : ''; $matrix[] = "['" . addslashes($hkeyvalue) . "']"; $matrixst = "\$m" . implode($matrix); if (!in_array($hkeyvalue, $hcols)) { $hcols[] = $hkeyvalue; } // now put the cell value in it $outvalues = array(); foreach (array_keys($this->output) as $field) { // did we ask for cumulative results ? $cumulativeix = null; if (preg_match('/S\\((.+?)\\)/', $field, $matches)) { $field = $matches[1]; $cumulativeix = $this->instance->id . '_' . $field; } if (!empty($this->outputf[$field])) { $datum = dashboard_format_data($this->outputf[$field], $result->{$field}, $cumulativeix); } else { $datum = dashboard_format_data(null, @$result->{$field}, $cumulativeix); } if (!empty($this->config->colorfield) && $this->config->colorfield == $field) { $datum = dashboard_colour_code($this, $datum, $this->colourcoding); } $outvalues[] = str_replace("\"", "\\\"", $datum); } $matrixst .= ' = "' . implode(' ', $outvalues) . '"'; // make the matrix in memory eval($matrixst . ";"); } else { $debug = optional_param('debug', false, PARAM_BOOL); // treeview $resultarr = array_values((array) $result); $resultid = $resultarr[0]; if (!empty($parentserie)) { if (!empty($result->{$parentserie})) { // non root node, attache to his parent if we found it if (array_key_exists($result->{$parentserie}, $treekeys)) { if (!empty($debug)) { echo 'binding to ' . $result->{$parentserie} . '. '; } $treekeys[$result->{$parentserie}]->childs[$resultid] = $result; if (!array_key_exists($resultid, $treekeys)) { $treekeys[$resultid] = $result; } } else { // in case nodes do not come in correct order, do not connect but register only if (!empty($debug)) { echo 'waiting for ' . $result->{$parentserie} . '. '; } $waitingnodes[$resultid] = $result; if (!array_key_exists($resultid, $treekeys)) { $treekeys[$resultid] = $result; } } } else { // root node if (!empty($debug)) { echo 'root as ' . $resultid . '. '; } if (!array_key_exists($resultid, $treekeys)) { $treekeys[$resultid] = $result; } $treedata[$resultid] =& $treekeys[$resultid]; } } else { if (!array_key_exists($resultid, $treekeys)) { $treekeys[$resultid] = $result; } } } } } // Prepare data for graphs if (!empty($this->config->showgraph)) { if (!empty($this->config->xaxisfield) && $this->config->graphtype != 'googlemap' && $this->config->graphtype != 'timeline') { $xaxisfield = $this->config->xaxisfield; if ($this->config->graphtype != 'pie') { // TODO : check if $this->config->xaxisfield exists really (misconfiguration) $ticks[] = addslashes($result->{$xaxisfield}); $ys = 0; foreach (array_keys($this->yseriesf) as $yserie) { if (!isset($result->{$yserie})) { continue; } // did we ask for cumulative results ? $cumulativeix = null; if (preg_match('/S\\((.+?)\\)/', $yserie, $matches)) { $yserie = $matches[1]; $cumulativeix = $this->instance->id . '_' . $yserie; } if ($this->config->graphtype != 'timegraph') { if (!empty($this->yseriesf[$yserie])) { $graphseries[$yserie][] = dashboard_format_data($this->yseriesf[$yserie], $result->{$yserie}, $cumulativeix); } else { $graphseries[$yserie][] = dashboard_format_data(null, $result->{$yserie}, $cumulativeix); } } else { if (!empty($this->yseriesf[$yserie])) { $timeelm = array($result->{$xaxisfield}, dashboard_format_data($this->yseriesf[$yserie], $result->{$yserie}, $cumulativeix)); $graphseries[$ys][] = $timeelm; } else { $timeelm = array($result->{$xaxisfield}, dashboard_format_data(null, $result->{$yserie}, $cumulativeix)); $graphseries[$ys][] = $timeelm; } } $ys++; } } elseif ($this->config->graphtype == 'pie') { foreach ($yseries as $yserie) { if (empty($result->{$xaxisfield})) { $result->{$xaxisfield} = 'N.C.'; } if (!empty($this->yseriesf[$field])) { $graphseries[$yserie][] = array($result->{$xaxisfield}, dashboard_format_data($this->yseriesf[$field], $result->{$yserie}, false)); } else { $graphseries[$yserie][] = array($result->{$xaxisfield}, $result->{$yserie}); } } } } else { $data[] = $result; } } $graphdata = array_values($graphseries); } //************ post aggregating last subtotal *************// if (!empty($this->config->shownumsums) && $results) { if (!empty($splitnumsonsort) && @$this->config->tabletype == 'linear' && preg_match("/\\b{$splitnumsonsort}\\b/", $sort)) { $k = 0; $tabledata = null; foreach (array_keys($this->output) as $field) { if (in_array($field, array_keys($this->numsumsf))) { if (is_null($tabledata)) { $tabledata = array(); for ($j = 0; $j < $k; $j++) { $tabledata[$j] = ''; } } $tabledata[$k] = '<b>Tot: ' . @$this->subaggr[$orderkeyed]->{$field} . '</b>'; } $k++; } $oldorderkeyed = $orderkeyed; if (!is_null($tabledata)) { $table->add_data($tabledata); } } } //************ Starting outputing data ************************// // if treeview, need to post process waiting nodes if (@$this->config->tabletype == 'treeview') { if (!empty($waitingnodes)) { foreach ($waitingnodes as $wnid => $wn) { if (array_key_exists($wn->{$parentserie}, $treekeys)) { if (!empty($debug)) { echo ' postbinding to ' . $wn->{$parentserie} . '. '; } $treekeys[$wn->{$parentserie}]->childs[$wnid] = $wn; unset($waitingnodes[$wnid]); // free some stuff } } } } if (@$this->config->inblocklayout) { $url = $CFG->wwwroot . '/course/view.php?id=' . $COURSE->id . $coursepage . '&tsort' . $this->instance->id . '=' . $sort; } else { $url = $CFG->wwwroot . '/blocks/dashboard/view.php?id=' . $COURSE->id . '&blocksid=' . $this->instance->id . $coursepage . '&tsort' . $this->instance->id . '=' . $sort; } $text .= dashboard_render_filters_and_params_form($this, $sort); if ($this->config->showdata) { $allexportstr = get_string('exportall', 'block_dashboard'); $tableexportstr = get_string('exportdataastable', 'block_dashboard'); $filteredexportstr = get_string('exportfiltered', 'block_dashboard'); $filterquerystring = !empty($filterquerystring) ? '&' . $filterquerystring : ''; if (empty($this->config->tabletype) || @$this->config->tabletype == 'linear') { ob_start(); $table->print_html(); $text .= ob_get_clean(); $text .= "<div style=\"text-align:right\">"; $text .= "<a href=\"{$CFG->wwwroot}/blocks/dashboard/export/export_csv.php?id={$COURSE->id}&instance={$this->instance->id}&tsort{$this->instance->id}={$sort}&alldata=1\">{$allexportstr}</a>"; if ($filterquerystring) { $text .= " - <a href=\"{$CFG->wwwroot}/blocks/dashboard/export/export_csv.php?id={$COURSE->id}&instance={$this->instance->id}&tsort{$this->instance->id}={$sort}{$filterquerystring}\">{$filteredexportstr}</a>"; } $text .= "</div>"; } elseif (@$this->config->tabletype == 'tabular') { // forget table and use $m matrix for making display $text .= print_cross_table($this, $m, $hcols, $this->config->horizkey, $this->vertkeys, $this->config->horizlabel, true); $text .= "<div style=\"text-align:right\"><a href=\"{$CFG->wwwroot}/blocks/dashboard/export/export_csv.php?id={$COURSE->id}&instance={$this->instance->id}&tsort{$this->instance->id}={$sort}&alldata=1\">{$allexportstr}</a></div>"; $text .= "<div style=\"text-align:right\"><a href=\"{$CFG->wwwroot}/blocks/dashboard/export/export_csv_tabular.php?id={$COURSE->id}&instance={$this->instance->id}&tsort{$this->instance->id}={$sort}{$filterquerystring}\">{$tableexportstr}</a></div>"; } else { $text .= dashboard_print_tree_view($this, $treedata, $this->treeoutput, $this->output, $this->outputf, $this->colourcoding, true); $text .= "<div style=\"text-align:right\"><a href=\"{$CFG->wwwroot}/blocks/dashboard/export/export_csv.php?id={$COURSE->id}&instance={$this->instance->id}&tsort{$this->instance->id}={$sort}&alldata=1\">{$allexportstr}</a></div>"; } } else { $text .= ''; } } else { // no data, but render filters anyway $text .= dashboard_render_filters_and_params_form($this, $sort); } // showing graph if ($this->config->showgraph && !empty($this->config->graphtype)) { $text .= $OUTPUT->box_start('dashboard-graph-box'); $graphdesc = $this->dashboard_graph_properties(); if ($this->config->graphtype != 'googlemap' && $this->config->graphtype != 'timeline') { $data = $graphdata; $text .= jqplot_print_graph('dashboard' . $this->instance->id, $graphdesc, $data, $this->config->graphwidth, $this->config->graphheight, '', true, $ticks); } elseif ($this->config->graphtype == 'googlemap') { $text .= dashboard_render_googlemaps_data($this, $data, $graphdesc); } else { // timeline graph if (empty($this->config->timelineeventstart) || empty($this->config->timelineeventend)) { $text .= $OUTPUT->notification("Missing mappings (start or titles)", 'notifyproblem'); } else { $text .= timeline_print_graph($this, 'dashboard' . $this->instance->id, $this->config->graphwidth, $this->config->graphheight, $data, true); } } $text .= $OUTPUT->box_end(); } // showing bottom summators if ($this->config->numsums) { $text .= dashboard_render_numsums($this, $aggr); } // showing query if (@$this->config->showquery) { $text .= '<div class="dashboard-query-box" style="padding:1px;border:1px solid #808080;margin:2px;font-size:0.75em;font-family:monospace">'; $text .= '<pre>' . $this->filteredsql . '</pre>'; $text .= '</div>'; } // showing SQL benches if (@$this->config->showbenches) { $text .= '<div class="dashboard-benches-box" style="padding:1px;border:1px solid #808080;margin:2px;font-size:0.75em;font-family:monospace">'; $text .= '<table width="100%">'; foreach ($this->benches as $bench) { $value = $bench->end - $bench->start; $text .= "<tr><td>{$bench->name}</td><td>{$value} sec.</td></tr>"; } $text .= '</table>'; $text .= '</div>'; } return $text; }