AutorÃa | Ultima modificación | Ver Log |
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Configurable Reports
* A Moodle block for creating Configurable Reports
* @package blocks
* @author: Juan leyva <http://www.twitter.com/jleyvadelgado>
* @date: 2009
*/
require_once($CFG->dirroot.'/lib/evalmath/evalmath.class.php');
class report_base {
public $id = 0;
public $components = array();
public $finalreport;
public $totalrecords = 0;
public $currentuser = 0;
public $currentcourse = 0;
public $starttime = 0;
public $endtime = 0;
public $sql = '';
public $filterform = null;
public function reports_base($report) {
global $DB, $CFG, $USER, $remotedb;
if (is_numeric($report)) {
$this->config = $DB->get_record('block_configurable_reports', array('id' => $report));
} else {
$this->config = $report;
}
$this->currentuser = $USER;
$this->currentcourseid = $this->config->courseid;
$this->init();
// Use a custom $DB (and not current system's $DB)
// TODO: major security issue.
$remotedbhost = get_config('block_configurable_reports', 'dbhost');
$remotedbname = get_config('block_configurable_reports', 'dbname');
$remotedbuser = get_config('block_configurable_reports', 'dbuser');
$remotedbpass = get_config('block_configurable_reports', 'dbpass');
if (!empty($remotedbhost) && !empty($remotedbname) && !empty($remotedbuser) && !empty($remotedbpass) && $this->config->remote) {
$dbclass = get_class($DB);
$remotedb = new $dbclass();
$remotedb->connect($remotedbhost, $remotedbuser, $remotedbpass, $remotedbname, $CFG->prefix);
} else {
$remotedb = $DB;
}
}
public function __construct($report) {
$this->reports_base($report);
}
public function check_permissions($userid, $context) {
global $DB, $CFG, $USER;
if (has_capability('block/configurable_reports:manageownreports', $context, $userid) && $this->config->ownerid == $userid) {
return true;
}
if (has_capability('block/configurable_reports:managereports', $context, $userid)) {
return true;
}
if (empty($this->config->visible)) {
return false;
}
$components = cr_unserialize($this->config->components);
$permissions = (isset($components['permissions'])) ? $components['permissions'] : [];
if (empty($permissions['elements'])) {
return has_capability('block/configurable_reports:viewreports', $context);
} else {
$i = 1;
$cond = array();
foreach ($permissions['elements'] as $p) {
require_once($CFG->dirroot.'/blocks/configurable_reports/plugin.class.php');
require_once($CFG->dirroot.'/blocks/configurable_reports/components/permissions/'.$p['pluginname'].'/plugin.class.php');
$classname = 'plugin_'.$p['pluginname'];
$class = new $classname($this->config);
$cond[$i] = $class->execute($userid, $context, $p['formdata']);
$i++;
}
if (count($cond) == 1) {
return $cond[1];
} else {
$m = new EvalMath;
$orig = $dest = array();
if (isset($permissions['config']) && isset($permissions['config']->conditionexpr)) {
$logic = trim($permissions['config']->conditionexpr);
// Security
// No more than: conditions * 10 chars.
$logic = substr($logic, 0, count($permissions['elements']) * 10);
$logic = str_replace(array('and', 'or'), array('&&', '||'), strtolower($logic));
// More Security Only allowed chars.
$logic = preg_replace('/[^&c\d\s|()]/i', '', $logic);
$logic = str_replace(array('&&', '||'), array('*', '+'), $logic);
for ($j = $i - 1; $j > 0; $j--) {
$orig[] = 'c'.$j;
$dest[] = ($cond[$j]) ? 1 : 0;
}
return $m->evaluate(str_replace($orig, $dest, $logic));
} else {
return false;
}
}
}
}
public function add_filter_elements(&$mform) {
global $DB, $CFG;
$components = cr_unserialize($this->config->components);
$filters = (isset($components['filters']['elements'])) ? $components['filters']['elements'] : array();
require_once($CFG->dirroot.'/blocks/configurable_reports/plugin.class.php');
foreach ($filters as $f) {
require_once($CFG->dirroot.'/blocks/configurable_reports/components/filters/'.$f['pluginname'].'/plugin.class.php');
$classname = 'plugin_'.$f['pluginname'];
$class = new $classname($this->config);
$finalelements = $class->print_filter($mform, $f['formdata']);
}
}
public function check_filters_request() {
global $DB, $CFG;
$components = cr_unserialize($this->config->components);
$filters = (isset($components['filters']['elements'])) ? $components['filters']['elements'] : array();
if (!empty($filters)) {
$formdata = new stdclass;
$request = array_merge($_POST, $_GET);
if ($request) {
foreach ($request as $key => $val) {
if (strpos($key, 'filter_') !== false) {
$key = clean_param($key, PARAM_CLEANHTML);
if (is_array($val)) {
$val = clean_param_array($val, PARAM_CLEANHTML);
} else {
$val = clean_param($val, PARAM_CLEANHTML);
}
$formdata->{$key} = $val;
}
}
}
require_once('filter_form.php');
$filterform = new report_edit_form(null, $this);
$filterform->set_data($formdata);
if ($filterform->is_cancelled()) {
$params = ['id' => $this->config->id, 'courseid' => $this->config->courseid];
redirect(new \moodle_url('/blocks/configurable_reports/viewreport.php', $params));
die;
}
$this->filterform = $filterform;
}
}
public function print_filters() {
if (!is_null($this->filterform)) {
$this->filterform->display();
}
}
public function print_graphs($return = false) {
$output = '';
$graphs = $this->get_graphs($this->finalreport->table->data);
if ($graphs) {
foreach ($graphs as $g) {
$output .= '<div class="centerpara">';
$output .= ' <img src="'.$g.'" alt="'.$this->config->name.'"><br />';
$output .= '</div>';
}
}
if ($return) {
return $output;
}
echo $output;
return true;
}
public function print_export_options($return = false) {
global $CFG;
$wwwpath = $CFG->wwwroot;
$request = array_merge($_POST, $_GET);
if ($request) {
$id = clean_param($request['id'], PARAM_INT);
$wwwpath = 'viewreport.php?id='.$id;
unset($request['id']);
foreach ($request as $key => $val) {
$key = clean_param($key, PARAM_CLEANHTML);
if (is_array($val)) {
foreach ($val as $k => $v) {
$k = clean_param($k, PARAM_CLEANHTML);
$v = clean_param($v, PARAM_CLEANHTML);
$wwwpath .= "&{$key}[$k]=".$v;
}
} else {
$val = clean_param($val, PARAM_CLEANHTML);
$wwwpath .= "&$key=".$val;
}
}
}
$output = '';
$export = explode(',', $this->config->export);
if (!empty($this->config->export)) {
$output .= '<br /><div class="centerpara">';
$output .= get_string('downloadreport', 'block_configurable_reports').': ';
foreach ($export as $e) {
if ($e) {
$output .= '<a href="'.$wwwpath.'&download=1&format='.$e.'"><img src="'.$CFG->wwwroot.'/blocks/configurable_reports/export/'.$e.'/pix.gif" alt="'.$e.'"> '.(strtoupper($e)).'</a> ';
}
}
$output .= '</div>';
}
if ($return) {
return $output;
}
echo $output;
return true;
}
public function evaluate_conditions($data, $logic) {
global $DB, $CFG;
require_once($CFG->dirroot.'/blocks/configurable_reports/reports/evalwise.class.php');
$logic = trim(strtolower($logic));
$logic = substr($logic, 0, count($data) * 10);
$logic = str_replace(array('or', 'and', 'not'), array('+', '*', '-'), $logic);
$logic = preg_replace('/[^\*c\d\s\+\-()]/i', '', $logic);
$orig = $dest = array();
for ($j = count($data); $j > 0; $j--) {
$orig[] = 'c'.$j;
$dest[] = $j;
}
$logic = str_replace($orig, $dest, $logic);
$m = new \EvalWise();
$m->set_data($data);
$result = $m->evaluate($logic);
return $result;
}
public function get_graphs($finalreport) {
global $DB, $CFG;
$components = cr_unserialize($this->config->components);
$graphs = (isset($components['plot']['elements'])) ? $components['plot']['elements'] : array();
$reportgraphs = array();
if (!empty($graphs)) {
$series = array();
foreach ($graphs as $g) {
require_once($CFG->dirroot.'/blocks/configurable_reports/components/plot/'.$g['pluginname'].'/plugin.class.php');
$classname = 'plugin_'.$g['pluginname'];
$class = new $classname($this->config);
$reportgraphs[] = $class->execute($g['id'], $g['formdata'], $finalreport);
}
}
return $reportgraphs;
}
public function get_calcs($finaltable, $tablehead) {
global $DB, $CFG;
$components = cr_unserialize($this->config->components);
$calcs = (isset($components['calcs']['elements'])) ? $components['calcs']['elements'] : array();
// Calcs doesn't work with multi-rows so far.
$columnscalcs = array();
$finalcalcs = array();
if (!empty($calcs)) {
foreach ($calcs as $calc) {
$columnscalcs[$calc['formdata']->column] = array();
}
$columnstostore = array_keys($columnscalcs);
foreach ($finaltable as $r) {
foreach ($columnstostore as $c) {
if (isset($r[$c])) {
$columnscalcs[$c][] = $r[$c];
}
}
}
foreach ($calcs as $calc) {
require_once($CFG->dirroot.'/blocks/configurable_reports/components/calcs/'.$calc['pluginname'].'/plugin.class.php');
$classname = 'plugin_'.$calc['pluginname'];
$class = new $classname($this->config);
$result = $class->execute($columnscalcs[$calc['formdata']->column]);
$finalcalcs[$calc['formdata']->column] = $result;
}
for ($i = 0; $i < count($tablehead); $i++) {
if (!isset($finalcalcs[$i])) {
$finalcalcs[$i] = '';
}
}
ksort($finalcalcs);
}
return $finalcalcs;
}
public function elements_by_conditions($conditions) {
global $DB, $CFG;
if (empty($conditions['elements'])) {
$finalelements = $this->get_all_elements();
return $finalelements;
}
$finalelements = array();
$i = 1;
foreach ($conditions['elements'] as $c) {
require_once($CFG->dirroot.'/blocks/configurable_reports/components/conditions/'.$c['pluginname'].'/plugin.class.php');
$classname = 'plugin_'.$c['pluginname'];
$class = new $classname($this->config);
$elements[$i] = $class->execute($c['formdata'], $this->currentuser, $this->currentcourseid);
$i++;
}
if (count($conditions['elements']) == 1) {
$finalelements = $elements[1];
} else {
$logic = $conditions['config']->conditionexpr;
$finalelements = $this->evaluate_conditions($elements, $logic);
if ($finalelements === false) {
return false;
}
}
return $finalelements;
}
/**
* Returns a report object
*/
public function create_report() {
global $DB, $CFG;
// Conditions.
$components = cr_unserialize($this->config->components);
$conditions = (isset($components['conditions']['elements'])) ? $components['conditions']['elements'] : array();
$filters = (isset($components['filters']['elements'])) ? $components['filters']['elements'] : array();
$columns = (isset($components['columns']['elements'])) ? $components['columns']['elements'] : array();
$ordering = (isset($components['ordering']['elements'])) ? $components['ordering']['elements'] : array();
$finalelements = array();
if (!empty($conditions)) {
$finalelements = $this->elements_by_conditions($components['conditions']);
} else {
// All elements.
$finalelements = $this->get_all_elements();
}
// Filters.
if (!empty($filters)) {
foreach ($filters as $f) {
require_once($CFG->dirroot.'/blocks/configurable_reports/components/filters/'.$f['pluginname'].'/plugin.class.php');
$classname = 'plugin_'.$f['pluginname'];
$class = new $classname($this->config);
$finalelements = $class->execute($finalelements, $f['formdata']);
}
}
// Ordering.
$sqlorder = '';
$orderingdata = array();
if (!empty($ordering)) {
foreach ($ordering as $o) {
require_once($CFG->dirroot.'/blocks/configurable_reports/components/ordering/'.$o['pluginname'].'/plugin.class.php');
$classname = 'plugin_'.$o['pluginname'];
$classorder = new $classname($this->config);
$orderingdata = $o['formdata'];
if ($classorder->sql) {
$sqlorder = $classorder->execute($orderingdata);
}
}
}
// COLUMNS - FIELDS.
$rows = $this->get_rows($finalelements, $sqlorder);
if (!$sqlorder && isset($classorder)) {
$rows = $classorder->execute($rows, $orderingdata);
}
$reporttable = array();
$tablehead = array();
$tablealign = array();
$tablesize = array();
$tablewrap = array();
$firstrow = true;
$pluginscache = array();
if ($rows) {
foreach ($rows as $r) {
$tempcols = array();
foreach ($columns as $c) {
if (empty($c)) {
continue;
}
require_once($CFG->dirroot.'/blocks/configurable_reports/components/columns/'.$c['pluginname'].'/plugin.class.php');
$classname = 'plugin_'.$c['pluginname'];
if (!isset($pluginscache[$classname])) {
$class = new $classname($this->config, $c);
$pluginscache[$classname] = $class;
} else {
$class = $pluginscache[$classname];
}
$tempcols[] = $class->execute($c['formdata'], $r, $this->currentuser, $this->currentcourseid, $this->starttime, $this->endtime);
if ($firstrow) {
$tablehead[] = $class->summary($c['formdata']);
list($align, $size, $wrap) = $class->colformat($c['formdata']);
$tablealign[] = $align;
$tablesize[] = $size;
$tablewrap[] = $wrap;
}
}
$firstrow = false;
$reporttable[] = $tempcols;
}
}
// EXPAND ROWS.
$finaltable = array();
$newcols = array();
foreach ($reporttable as $row) {
$col = array();
$multiple = false;
$nrows = 0;
$mrowsi = array();
foreach ($row as $key => $cell) {
if (!is_array($cell)) {
$col[] = $cell;
} else {
$multiple = true;
$nrows = count($cell);
$mrowsi[] = $key;
}
}
if ($multiple) {
$newrows = array();
for ($i = 0; $i < $nrows; $i++) {
$newrows[$i] = $row;
foreach ($mrowsi as $index) {
$newrows[$i][$index] = $row[$index][$i];
}
}
foreach ($newrows as $r) {
$finaltable[] = $r;
}
} else {
$finaltable[] = $col;
}
}
// CALCS.
$finalcalcs = $this->get_calcs($finaltable, $tablehead);
// Make the table, head, columns, etc...
$table = new \stdClass;
$table->id = 'reporttable';
$table->data = $finaltable;
$table->head = $tablehead;
$table->size = $tablesize;
$table->align = $tablealign;
$table->wrap = $tablewrap;
$table->width = (isset($components['columns']['config'])) ? $components['columns']['config']->tablewidth : '';
$table->summary = $this->config->summary;
$table->tablealign = (isset($components['columns']['config'])) ? $components['columns']['config']->tablealign : 'center';
$table->cellpadding = (isset($components['columns']['config'])) ? $components['columns']['config']->cellpadding : '5';
$table->cellspacing = (isset($components['columns']['config'])) ? $components['columns']['config']->cellspacing : '1';
$table->class = (isset($components['columns']['config'])) ? $components['columns']['config']->class : 'generaltable';
$calcs = new \html_table();
$calcs->data = array($finalcalcs);
$calcs->head = $tablehead;
$calcs->size = $tablesize;
$calcs->align = $tablealign;
$calcs->wrap = $tablewrap;
$calcs->summary = $this->config->summary;
$calcs->attributes['class'] = (isset($components['columns']['config'])) ? $components['columns']['config']->class : 'generaltable';
if (!$this->finalreport) {
$this->finalreport = new \stdClass;
}
$this->finalreport->table = $table;
$this->finalreport->calcs = $calcs;
return true;
}
public function add_jsordering(\moodle_page $moodle_page) {
switch (get_config('block_configurable_reports', 'reporttableui')) {
case 'datatables':
cr_add_jsdatatables('#reporttable', $moodle_page);
break;
case 'jquery':
cr_add_jsordering('#reporttable', $moodle_page);
echo html_writer::tag('style',
'#page-blocks-configurable_reports-viewreport .generaltable {
overflow: auto;
width: 100%;
display: block;}');
break;
case 'html':
echo html_writer::tag('style',
'#page-blocks-configurable_reports-viewreport .generaltable {
overflow: auto;
width: 100%;
display: block;}');
break;
default:
break;
}
}
public function print_template($config, \moodle_page $moodle_page) {
global $DB, $CFG, $OUTPUT;
$pagecontents = array();
$pagecontents['header'] = (isset($config->header) && $config->header) ? $config->header : '';
$pagecontents['footer'] = (isset($config->footer) && $config->footer) ? $config->footer : '';
$recordtpl = (isset($config->record) && $config->record) ? $config->record : '';;
$calculations = '';
if (!empty($this->finalreport->calcs->data[0])) {
$calculations = html_writer::table($this->finalreport->calcs);
}
$pagination = '';
if ($this->config->pagination) {
$page = optional_param('page', 0, PARAM_INT);
$postfiltervars = '';
$request = array_merge($_POST, $_GET);
if ($request) {
foreach ($request as $key => $val) {
if (strpos($key, 'filter_') !== false) {
$key = clean_param($key, PARAM_CLEANHTML);
if (is_array($val)) {
foreach ($val as $k => $v) {
$k = clean_param($k, PARAM_CLEANHTML);
$v = clean_param($v, PARAM_CLEANHTML);
$postfiltervars .= "&{$key}[$k]=".$v;
}
} else {
$val = clean_param($val, PARAM_CLEANHTML);
$postfiltervars .= "&$key=".$val;
}
}
}
}
$this->totalrecords = count($this->finalreport->table->data);
$pagingbar = new \paging_bar($this->totalrecords, $page, $this->config->pagination, "viewreport.php?id=".$this->config->id."&courseid=".$this->config->courseid."$postfiltervars&");
$pagingbar->pagevar = 'page';
$pagination = $OUTPUT->render($pagingbar);
}
$search = [
'##reportname##',
'##reportsummary##',
'##graphs##',
'##exportoptions##',
'##calculationstable##',
'##pagination##'
];
$replace = [
format_string($this->config->name),
format_text($this->config->summary),
$this->print_graphs(true),
$this->print_export_options(true),
$calculations,
$pagination
];
foreach ($pagecontents as $key => $p) {
if ($p) {
$pagecontents[$key] = str_ireplace($search, $replace, $p);
}
}
if ($this->config->jsordering) {
$this->add_jsordering($moodle_page);
}
$this->print_filters();
echo "<div id=\"printablediv\">\n";
// Print the header.
if (is_array($pagecontents['header'])) {
echo format_text($pagecontents['header']['text'], $pagecontents['header']['format']);
} else {
echo format_text($pagecontents['header'], FORMAT_HTML);
}
$a = new \stdClass();
$a->totalrecords = $this->totalrecords;
echo \html_writer::tag('div', get_string('totalrecords', 'block_configurable_reports', $a), array('id' => 'totalrecords'));
if ($recordtpl) {
if ($this->config->pagination) {
$page = optional_param('page', 0, PARAM_INT);
$this->totalrecords = count($this->finalreport->table->data);
$this->finalreport->table->data = array_slice($this->finalreport->table->data, $page * $this->config->pagination, $this->config->pagination);
}
foreach ($this->finalreport->table->data as $r) {
if (is_array($recordtpl)) {
$recordtext = $recordtpl['text'];
} else {
$recordtext = $recordtpl;
}
foreach ($this->finalreport->table->head as $key => $c) {
$recordtext = str_ireplace("[[$c]]", $r[$key], $recordtext);
}
echo format_text($recordtext, FORMAT_HTML);
}
}
// Print the footer.
if (is_array($pagecontents['footer'])) {
echo format_text($pagecontents['footer']['text'], $pagecontents['footer']['format']);
} else {
echo format_text($pagecontents['footer'], FORMAT_HTML);
}
echo "</div>\n";
echo '<div class="centerpara"><br />';
echo $OUTPUT->pix_icon('print', get_string('printreport', 'block_configurable_reports'), 'block_configurable_reports');
echo " <a href=\"javascript: printDiv('printablediv')\">".get_string('printreport', 'block_configurable_reports')."</a>";
echo "</div>\n";
}
public function print_report_page(\moodle_page $moodlepage) {
global $DB, $CFG, $OUTPUT, $USER;
cr_print_js_function();
$components = cr_unserialize($this->config->components);
$template = (isset($components['template']['config']) && $components['template']['config']->enabled && $components['template']['config']->record) ? $components['template']['config'] : false;
if ($template) {
$this->print_template($template, $moodlepage);
return true;
}
// Debug.
$debug = optional_param('debug', false, PARAM_BOOL);
if ($debug or !empty($this->config->debug)) {
echo \html_writer::empty_tag('hr');
echo \html_writer::tag('div', $this->sql, ['id' => 'debug', 'style' => 'direction:ltr;text-align:left;']);
echo \html_writer::empty_tag('hr');
}
echo '<div class="centerpara">';
echo format_text($this->config->summary);
echo '</div>';
$this->print_filters();
if ($this->finalreport->table && !empty($this->finalreport->table->data[0])) {
echo "<div id=\"printablediv\">\n";
$this->print_graphs();
if ($this->config->jsordering) {
$this->add_jsordering($moodlepage);
}
$this->totalrecords = count($this->finalreport->table->data);
if ($this->config->pagination) {
$page = optional_param('page', 0, PARAM_INT);
$this->totalrecords = count($this->finalreport->table->data);
$this->finalreport->table->data = array_slice($this->finalreport->table->data, $page * $this->config->pagination, $this->config->pagination);
}
cr_print_table($this->finalreport->table);
if ($this->config->pagination) {
$postfiltervars = '';
$request = array_merge($_POST, $_GET);
if ($request) {
foreach ($request as $key => $val) {
if (strpos($key, 'filter_') !== false) {
$key = clean_param($key, PARAM_CLEANHTML);
if (is_array($val)) {
foreach ($val as $k => $v) {
$k = clean_param($k, PARAM_CLEANHTML);
$v = clean_param($v, PARAM_CLEANHTML);
$postfiltervars .= "&{$key}[$k]=".$v;
}
} else {
$val = clean_param($val, PARAM_CLEANHTML);
$postfiltervars .= "&$key=".$val;
}
}
}
}
$pagingbar = new paging_bar($this->totalrecords, $page, $this->config->pagination, "viewreport.php?id=".$this->config->id."&courseid=".$this->config->courseid."$postfiltervars&");
$pagingbar->pagevar = 'page';
echo $OUTPUT->render($pagingbar);
}
// Report statistics.
$a = new \stdClass();
$a->totalrecords = $this->totalrecords;
echo \html_writer::tag('div', get_string('totalrecords', 'block_configurable_reports', $a), ['id' => 'totalrecords']);
echo \html_writer::tag('div', get_string('lastexecutiontime', 'block_configurable_reports', $this->config->lastexecutiontime / 1000), array('id' => 'lastexecutiontime'));
if (!empty($this->finalreport->calcs->data[0])) {
echo '<br /><br /><br /><div class="centerpara"><b>'.get_string('columncalculations', 'block_configurable_reports').'</b></div><br />';
echo html_writer::table($this->finalreport->calcs);
}
echo "</div>";
$this->print_export_options();
} else {
echo '<div class="centerpara">'.get_string('norecordsfound', 'block_configurable_reports').'</div>';
}
echo '<div class="centerpara"><br />';
echo $OUTPUT->pix_icon('print', get_string('printreport', 'block_configurable_reports'), 'block_configurable_reports');
echo " <a href=\"javascript: printDiv('printablediv')\">".get_string('printreport', 'block_configurable_reports')."</a>";
echo "</div>\n";
}
public function utf8_strrev($str) {
preg_match_all('/./us', $str, $ar);
return join('', array_reverse($ar[0]));
}
}