MOODLE Mostrar Tabla de Datos HTML con flexible_table

Vamos a partir de la base en la que no sé nada sobre la API de Moodle. Buscando información, he encontrado que NO HAY CASI NADA DE INFORMACIÓN / DOCUMENTACIÓN / EJEMPLOS.

Por lo que voy a compartir una mini guía personal y algunos recursos que he utilizado para poder mostrar una tabla dinámica que incluye paginación, ordenación y exportación de datos.

Para ello vamos a crear nuestra propia clase partiendo de la clase table_sql la cual extiende la clase flexible_table.

// Esta clase se encuentra en 
// lib\tablelib.php
class table_sql extends flexible_table{
}


// Crearemos nuestra propia clase en nuestra carpeta
// personal o en la misma carpeta lib
class table_sql_pers extends table_sql {
}

La idea de crear otra clase a partir de la table_sql es añadir un nuevo parámetro al método set_sql y personalizar así nuestra MySql Query sin tener que modificar la clase original.

En el mismo archivo he creado la clase para la gestión de alumnos creando una query personalizada dividiendo las partes de SELECT FROM WHERE y GROUP BY en variables para poder añadir los datos que necesitemos:

<?php

require "$CFG->libdir/tablelib.php";

/**
 * Clase de gestión personalizada de Alumnos
 * Métodos:
 * 		LIstado
 * 		Importación
 */

class GestionAlumnos{

	/**
	 * Variable FIELDS para SELECT
	 *
	 * @var string
	 */
	private $selectAlumnosFields = "
		{user}.`id`,
		DATE_FORMAT(
			FROM_UNIXTIME({user}.`timecreated`),
			'%d/%m/%Y %H:%i:%s'
		) AS `timecreated`,
		DATE_FORMAT(
			FROM_UNIXTIME({user}.`timemodified`),
			'%d/%m/%Y %H:%i:%s'
		) AS `timemodified`,
		{user}.`username` AS `username`
	";

	/**
	 * Variable FROM con las tablas y JOINS
	 *
	 * @var string
	 */
	private $selectAlumnosFrom = "
	(
		(
			(
				(
					(
						(
							(
								(
									(
										{role_assignments}
										LEFT JOIN {user} ON(
											(
												{user}.`id` = {role_assignments}.`userid`
											)
										)
									)
									LEFT JOIN {context} ON(
										(
											{role_assignments}.`contextid` = {context}.`id`
										)
									)
								)
							)
							JOIN {user_info_data} ON(
								(
									{user}.`id` = {user_info_data}.`userid`
								)
							)
						)
						JOIN {user_enrolments} ON(
							(
								{user_enrolments}.`userid` = {user}.`id`
							)
						)
					)
					JOIN {enrol} ON(
						(
							{enrol}.`id` = {user_enrolments}.`enrolid`
						)
					)
				)
				JOIN {course} ON(
					(
						{course}.`id` = {enrol}.`courseid`
					)
				)
			)
		)
	)
	";

	/**
	 * Variable WHERE
	 *
	 * @var string
	 */
	private $selectAlumnosWhere = "
		(
			NOT(
				(
					{user}.`firstname` LIKE '%\\_%'
				)
			)
		)
		AND (
			{user_info_data}.`fieldid` = 1
		)
		AND (
			{role_assignments}.`roleid` = 5
		)
	";

	/**
	 * Variable GROUP BY
	 *
	 * @var string
	 */
	private $selectAlumnosGroupBy = "
		{user}.`id`,
		{user}.`timecreated`,
		{user}.`timemodified`,
		{user}.`username`
	";

	/**
	 * Variable con las columnas que vamos a mostrar de la query original
	 *
	 * @var array
	 */
	protected $columns = array(
		'id',
		'username',
		'timecreated',
		'timemodified'
	);

	/**
	 * Cabeceras para el listado de la tabla HTML
	 *
	 * @var array
	 */
	protected $headers = array(
		'ID',
		'Usuario',
		'F. Crea.',
		'F. Modif.'
	);

	protected $database;
	protected $baseUrl;

	/**
	 * Constructor al que pasamos el recurso de BBDD
	 * y la URL para mostrar los links de paginación,
	 * ordenación en la tabla de datos
	 *
	 * @param [type] $DB
	 * @param [type] $baseUrl
	 */
	public function __construct($DB, $baseUrl)
	{
		$this->database = $DB;
		$this->baseUrl = $baseUrl;
	}

	/**
	 * Setea las columnas para mostrar solamente las que necesitamos
	 *
	 * @param array $columns
	 * @return void
	 */
	public function setColumns($columns = array()){
		$this->columns = $columns;
	}

	/**
	 * Undocumented function
	 *
	 * @param array $headers
	 * @return void
	 */
	public function setHeaders($headers = array()){
		$this->headers = $headers;
	}

	/**
	 * Crea la tabla para mostrar el listado de alumnos
	 * Devuelve el recurso $table que se podrá utilizar 
	 * para renderizar la tabla con el método out()
	 * Ejemplo: $table->out(15, true); 
	 * 
	 * Lo hacemos así para poder verificar cuando se hace un renderizado en HTML
	 * o una exportación ya que a la hora de exportar no debemos mostrar más que
	 * los datos. En la página donde llamamos esta clase y sus métodos debemos
	 * utilizar la siguiente condición antes de mostrar los headers / footers o
	 * cualquier tipo de $OUTPUT:
	 * if (!$table->is_downloading()) {
	 * 		echo $OUTPUT->header();
	 * 		echo $OUTPUT->footer();
	 * }
	 *
	 * @return $table
	 */
	public function getListAlumnosHTML(){

		$table = new table_sql_alumnos('listado-alumnos');

		$download = optional_param('download', '', PARAM_ALPHA);
		$table->is_downloading($download, 'Listado de Alumnos', 'Listado');

		$table->define_columns($this->columns);

		$table->define_headers($this->headers);

		$table->set_sql(
			$this->selectAlumnosFields,
			$this->selectAlumnosFrom,
			$this->selectAlumnosWhere,
			array(),
			$this->selectAlumnosGroupBy
		);

		$table->define_baseurl($this->baseUrl);

		return $table;
	}
}


/**
 * Extendemos la clase para modificar el método set_sql y añadir un nuevo parámetro $groupBy
 */
class table_sql_alumnos extends table_sql {

	/**
     * Set the sql to query the db. Query will be :
     *      SELECT $fields FROM $from WHERE $where
     * Of course you can use sub-queries, JOINS etc. by putting them in the
     * appropriate clause of the query.
     */

	/**
	 * MODIFICADO del original para añadir el parámetro GROUP BY
	 */
    function set_sql($fields, $from, $where, array $params = array(), $groupBy) {
        $this->sql = new stdClass();
        $this->sql->fields = $fields;
        $this->sql->from = $from;
        $this->sql->where = $where;
        $this->sql->params = $params;
        $this->sql->groupBy = $groupBy;
    }

    /**
     * Query the db. Store results in the table object for use by build_table.
     *
     * @param int $pagesize size of page for paginated displayed table.
     * @param bool $useinitialsbar do you want to use the initials bar. Bar
     * will only be used if there is a fullname column defined for the table.
     */
    function query_db($pagesize, $useinitialsbar=true) {
        global $DB;
        if (!$this->is_downloading()) {
            if ($this->countsql === NULL) {
                $this->countsql = 'SELECT COUNT(1) FROM '.$this->sql->from.' WHERE '.$this->sql->where;
                $this->countparams = $this->sql->params;
            }
            $grandtotal = $DB->count_records_sql($this->countsql, $this->countparams);
            if ($useinitialsbar && !$this->is_downloading()) {
                $this->initialbars($grandtotal > $pagesize);
            }

            list($wsql, $wparams) = $this->get_sql_where();
            if ($wsql) {
                $this->countsql .= ' AND '.$wsql;
                $this->countparams = array_merge($this->countparams, $wparams);

                $this->sql->where .= ' AND '.$wsql;
                $this->sql->params = array_merge($this->sql->params, $wparams);

                $total  = $DB->count_records_sql($this->countsql, $this->countparams);
            } else {
                $total = $grandtotal;
            }

            $this->pagesize($pagesize, $total);
        }

        // Fetch the attempts
        $sort = $this->get_sql_sort();
        if ($sort) {
            $sort = "ORDER BY $sort";
		}
		
		/**
		 * MODIFICADO del original para añadir GROUP BY
		 */
        $sql = "SELECT
                {$this->sql->fields}
                FROM {$this->sql->from}
                WHERE {$this->sql->where}
				GROUP BY {$this->sql->groupBy}
				{$sort}";

        if (!$this->is_downloading()) {
            $this->rawdata = $DB->get_records_sql($sql, $this->sql->params, $this->get_page_start(), $this->get_page_size());
        } else {
            $this->rawdata = $DB->get_records_sql($sql, $this->sql->params);
        }
    }
}

Este bloque es el que utilizaremos para renderizar nuestro HTML:

<?php

/**
 * Contiene la clase para la gestión de Alumnos
 */
require_once('./lib/GestionAlumnos.php');

$title = "Gestión de Alumnos";

$download = optional_param('download', '', PARAM_ALPHA);
$baseUrl = $CFG->wwwroot."/gestion_alumnos.php";
$gestAlumnos = new GestionAlumnos($DB,$baseUrl);
$table = $gestAlumnos->getListAlumnosHTML();

// Si no se está exportando, mostramos el HTML
if (!$table->is_downloading()) {

    $PAGE->set_title($title);
    $PAGE->set_heading($title);
    $PAGE->set_cacheable(false);
    $PAGE->navbar->ignore_active();
    $PAGE->set_url('/gestion_alumnos.php');

    $PAGE->navbar->add($title, new moodle_url(substr($PAGE->url, 0, strpos($PAGE->url, '?'))));
    $PAGE->set_pagelayout('frametop');

    echo $OUTPUT->header();
    echo '<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">';

?>

<style>
    #tabs{
        min-height: 1150px;height:100%;margin-top:10px
    }
</style>

<h2><?= $title ?></h2>

<div id="tabs">
    <ul>
        <li><a href="#listado">Listado Alumnos</a></li>
	</ul>
	<div id="listado">
		<?php
			$table->out(15, true); 
		?>
    </div>
</div>

<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function() {
    $("#tabs").tabs();
});
</script>

<?php
    echo $OUTPUT->footer();
}else{
    $table->out(15, true); 
}

?>

RECURSOS

  • Moodle Docs: https://docs.moodle.org/dev/lib/tablelib.php
  • Moodle Forums (Entrar como Invitado): https://moodle.org/mod/forum/discuss.php?d=335786