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]));}}