Proyectos de Subversion Moodle

Rev

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 .= "&amp;{$key}[$k]=".$v;
                    }
                } else {
                    $val = clean_param($val, PARAM_CLEANHTML);
                    $wwwpath .= "&amp;$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.'&amp;download=1&amp;format='.$e.'"><img src="'.$CFG->wwwroot.'/blocks/configurable_reports/export/'.$e.'/pix.gif" alt="'.$e.'">&nbsp;'.(strtoupper($e)).'</a>&nbsp;';
                }
            }
            $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 .= "&amp;{$key}[$k]=".$v;
                            }
                        } else {
                            $val = clean_param($val, PARAM_CLEANHTML);
                            $postfiltervars .= "&amp;$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&amp;");
            $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 "&nbsp;<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 .= "&amp;{$key}[$k]=".$v;
                                }
                            } else {
                                $val = clean_param($val, PARAM_CLEANHTML);
                                $postfiltervars .= "&amp;$key=".$val;
                            }
                        }
                    }
                }

                $pagingbar = new paging_bar($this->totalrecords, $page, $this->config->pagination, "viewreport.php?id=".$this->config->id."&courseid=".$this->config->courseid."$postfiltervars&amp;");
                $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 "&nbsp;<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]));
    }
}