mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 16:32:18 +02:00
MDL-40084 mod_data: Refactor exporting data
Functions data_export_csv, data_export_ods, data_get_exportdata have been deprecated.
This commit is contained in:
parent
ab09cf2b84
commit
bdf02ec088
78
mod/data/classes/local/csv_exporter.php
Normal file
78
mod/data/classes/local/csv_exporter.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?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/>.
|
||||
|
||||
namespace mod_data\local;
|
||||
|
||||
use coding_exception;
|
||||
use csv_export_writer;
|
||||
|
||||
/**
|
||||
* CSV exporter for mod_data.
|
||||
*
|
||||
* @package mod_data
|
||||
* @copyright 2023 ISB Bayern
|
||||
* @author Philipp Memmel
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class csv_exporter extends exporter {
|
||||
|
||||
/** @var string[] Possible delimiter names. Only used internally to check if a valid delimiter name
|
||||
* has been specified.
|
||||
*/
|
||||
private const POSSIBLE_DELIMITER_NAMES = ['comma', 'tab', 'semicolon', 'colon', 'cfg'];
|
||||
|
||||
/**
|
||||
* @var string name of the delimiter to use for the csv export. Possible values:
|
||||
* 'comma', 'tab', 'semicolon', 'colon' or 'cfg'.
|
||||
*/
|
||||
private string $delimitername = 'comma';
|
||||
|
||||
/**
|
||||
* Returns the csv data exported by the csv_export_writer for further handling.
|
||||
*
|
||||
* @see \mod_data\local\exporter::get_data_file_content()
|
||||
*/
|
||||
public function get_data_file_content(): string {
|
||||
return csv_export_writer::print_array($this->exportdata, $this->delimitername, '"', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file extension of this exporter.
|
||||
*
|
||||
* @see \mod_data\local\exporter::get_export_data_file_extension()
|
||||
*/
|
||||
public function get_export_data_file_extension(): string {
|
||||
return 'csv';
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the delimiter name which should be used in this csv_exporter object.
|
||||
*
|
||||
* Calling this setter is optional, the delimiter name defaults to 'comma'.
|
||||
*
|
||||
* @param string $delimitername one of 'comma', 'tab', 'semicolon', 'colon' or 'cfg'
|
||||
* @return void
|
||||
* @throws coding_exception if a wrong delimiter name has been specified
|
||||
*/
|
||||
public function set_delimiter_name(string $delimitername): void {
|
||||
if (!in_array($delimitername, self::POSSIBLE_DELIMITER_NAMES)) {
|
||||
throw new coding_exception('Wrong delimiter type',
|
||||
'Please choose on of the following delimiters: '
|
||||
. '\"comma\", \"tab\", \"semicolon\", \"colon\", \"cfg\"');
|
||||
}
|
||||
$this->delimitername = $delimitername;
|
||||
}
|
||||
}
|
149
mod/data/classes/local/exporter.php
Normal file
149
mod/data/classes/local/exporter.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?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/>.
|
||||
|
||||
namespace mod_data\local;
|
||||
|
||||
use file_serving_exception;
|
||||
use zip_archive;
|
||||
|
||||
/**
|
||||
* Exporter class for exporting data.
|
||||
*
|
||||
* @package mod_data
|
||||
* @copyright 2023 ISB Bayern
|
||||
* @author Philipp Memmel
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class exporter {
|
||||
|
||||
/** @var int Tracks the currently edited row of the export data file. */
|
||||
private int $currentrow;
|
||||
|
||||
/**
|
||||
* @var array The data structure containing the data for exporting. It's a 2-dimensional array of
|
||||
* rows and columns.
|
||||
*/
|
||||
protected array $exportdata;
|
||||
|
||||
/** @var string Name of the export file name without extension. */
|
||||
protected string $exportfilename;
|
||||
|
||||
/**
|
||||
* Creates an exporter object.
|
||||
*
|
||||
* This object can be used to export data to different formats.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->currentrow = 0;
|
||||
$this->exportdata = [];
|
||||
$this->exportfilename = 'Exportfile';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a row (array of strings) to the export data.
|
||||
*
|
||||
* @param array $row the row to add, $row has to be a plain array of strings
|
||||
* @return void
|
||||
*/
|
||||
public function add_row(array $row): void {
|
||||
$this->exportdata[] = $row;
|
||||
$this->currentrow++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a data string (so the content for a "cell") to the current row.
|
||||
*
|
||||
* @param string $cellcontent the content to add to the current row
|
||||
* @return void
|
||||
*/
|
||||
public function add_to_current_row(string $cellcontent): void {
|
||||
$this->exportdata[$this->currentrow][] = $cellcontent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal the exporter to finish the current row and jump to the next row.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function next_row(): void {
|
||||
$this->currentrow++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the export file.
|
||||
*
|
||||
* Only use the basename without path and without extension here.
|
||||
*
|
||||
* @param string $exportfilename name of the file without path and extension
|
||||
* @return void
|
||||
*/
|
||||
public function set_export_file_name(string $exportfilename): void {
|
||||
$this->exportfilename = $exportfilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* The exporter will prepare a data file from the rows and columns being added.
|
||||
* Overwrite this method to generate the data file as string.
|
||||
*
|
||||
* @return string the data file as a string
|
||||
*/
|
||||
abstract protected function get_data_file_content(): string;
|
||||
|
||||
/**
|
||||
* Overwrite the method to return the file extension your data file will have, for example
|
||||
* <code>return 'csv';</code> for a csv file exporter.
|
||||
*
|
||||
* @return string the file extension of the data file your exporter is using
|
||||
*/
|
||||
abstract protected function get_export_data_file_extension(): string;
|
||||
|
||||
/**
|
||||
* Returns the count of currently stored records (rows excluding header row).
|
||||
*
|
||||
* @return int the count of records/rows
|
||||
*/
|
||||
public function get_records_count(): int {
|
||||
// The attribute $this->exportdata also contains a header. If only one row is present, this
|
||||
// usually is the header, so record count should be 0.
|
||||
if (count($this->exportdata) <= 1) {
|
||||
return 0;
|
||||
}
|
||||
return count($this->exportdata) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the generated export file.
|
||||
*
|
||||
* Care: By default this function finishes the current PHP request and directly serves the file to the user as download.
|
||||
*
|
||||
* @param bool $sendtouser true if the file should be sent directly to the user, if false the file content will be returned
|
||||
* as string
|
||||
* @return string|null file content as string if $sendtouser is true
|
||||
*/
|
||||
public function send_file(bool $sendtouser = true): null|string {
|
||||
if (empty($this->filenamesinzip)) {
|
||||
if ($sendtouser) {
|
||||
send_file($this->get_data_file_content(),
|
||||
$this->exportfilename . '.' . $this->get_export_data_file_extension(),
|
||||
null, 0, true, true);
|
||||
return null;
|
||||
} else {
|
||||
return $this->get_data_file_content();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
137
mod/data/classes/local/exporter_utils.php
Normal file
137
mod/data/classes/local/exporter_utils.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?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/>.
|
||||
|
||||
namespace mod_data\local;
|
||||
|
||||
use coding_exception;
|
||||
use context;
|
||||
use context_system;
|
||||
use dml_exception;
|
||||
use moodle_exception;
|
||||
|
||||
/**
|
||||
* Utility class for exporting data from a mod_data instance.
|
||||
*
|
||||
* @package mod_data
|
||||
* @copyright 2023 ISB Bayern
|
||||
* @author Philipp Memmel
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class exporter_utils {
|
||||
|
||||
/**
|
||||
* Exports the data of the mod_data instance to an exporter object which then can export it to a file format.
|
||||
*
|
||||
* @param int $dataid
|
||||
* @param array $fields
|
||||
* @param array $selectedfields
|
||||
* @param exporter $exporter the exporter object used
|
||||
* @param int $currentgroup group ID of the current group. This is used for
|
||||
* exporting data while maintaining group divisions.
|
||||
* @param context|null $context the context in which the operation is performed (for capability checks)
|
||||
* @param bool $userdetails whether to include the details of the record author
|
||||
* @param bool $time whether to include time created/modified
|
||||
* @param bool $approval whether to include approval status
|
||||
* @param bool $tags whether to include tags
|
||||
* @return void
|
||||
* @throws coding_exception
|
||||
* @throws dml_exception
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
public static function data_exportdata(int $dataid, array $fields, array $selectedfields, exporter $exporter,
|
||||
int $currentgroup = 0, context $context = null, bool $userdetails = false, bool $time = false, bool $approval = false,
|
||||
bool $tags = false): void {
|
||||
global $DB;
|
||||
|
||||
if (is_null($context)) {
|
||||
$context = context_system::instance();
|
||||
}
|
||||
// Exporting user data needs special permission.
|
||||
$userdetails = $userdetails && has_capability('mod/data:exportuserinfo', $context);
|
||||
|
||||
// Populate the header in first row of export.
|
||||
$header = [];
|
||||
foreach ($fields as $key => $field) {
|
||||
if (!in_array($field->field->id, $selectedfields)) {
|
||||
// Ignore values we aren't exporting.
|
||||
unset($fields[$key]);
|
||||
} else {
|
||||
$header[] = $field->field->name;
|
||||
}
|
||||
}
|
||||
if ($tags) {
|
||||
$header[] = get_string('tags', 'data');
|
||||
}
|
||||
if ($userdetails) {
|
||||
$header[] = get_string('user');
|
||||
$header[] = get_string('username');
|
||||
$header[] = get_string('email');
|
||||
}
|
||||
if ($time) {
|
||||
$header[] = get_string('timeadded', 'data');
|
||||
$header[] = get_string('timemodified', 'data');
|
||||
}
|
||||
if ($approval) {
|
||||
$header[] = get_string('approved', 'data');
|
||||
}
|
||||
$exporter->add_row($header);
|
||||
|
||||
$datarecords = $DB->get_records('data_records', array('dataid' => $dataid));
|
||||
ksort($datarecords);
|
||||
$line = 1;
|
||||
foreach ($datarecords as $record) {
|
||||
// Get content indexed by fieldid.
|
||||
if ($currentgroup) {
|
||||
$select = 'SELECT c.fieldid, c.content, c.content1, c.content2, c.content3, c.content4 FROM {data_content} c, '
|
||||
. '{data_records} r WHERE c.recordid = ? AND r.id = c.recordid AND r.groupid = ?';
|
||||
$where = array($record->id, $currentgroup);
|
||||
} else {
|
||||
$select = 'SELECT fieldid, content, content1, content2, content3, content4 FROM {data_content} WHERE recordid = ?';
|
||||
$where = array($record->id);
|
||||
}
|
||||
|
||||
if ($content = $DB->get_records_sql($select, $where)) {
|
||||
foreach ($fields as $field) {
|
||||
$contents = '';
|
||||
if (isset($content[$field->field->id])) {
|
||||
$contents = $field->export_text_value($content[$field->field->id]);
|
||||
}
|
||||
// Just be double sure.
|
||||
$contents = !empty($contents) ? $contents : '';
|
||||
$exporter->add_to_current_row($contents);
|
||||
}
|
||||
if ($tags) {
|
||||
$itemtags = \core_tag_tag::get_item_tags_array('mod_data', 'data_records', $record->id);
|
||||
$exporter->add_to_current_row(implode(', ', $itemtags));
|
||||
}
|
||||
if ($userdetails) { // Add user details to the export data.
|
||||
$userdata = get_complete_user_data('id', $record->userid);
|
||||
$exporter->add_to_current_row(fullname($userdata));
|
||||
$exporter->add_to_current_row($userdata->username);
|
||||
$exporter->add_to_current_row($userdata->email);
|
||||
}
|
||||
if ($time) { // Add time added / modified.
|
||||
$exporter->add_to_current_row(userdate($record->timecreated));
|
||||
$exporter->add_to_current_row(userdate($record->timemodified));
|
||||
}
|
||||
if ($approval) { // Add approval status.
|
||||
$exporter->add_to_current_row((int) $record->approved);
|
||||
}
|
||||
}
|
||||
$exporter->next_row();
|
||||
}
|
||||
}
|
||||
}
|
65
mod/data/classes/local/ods_exporter.php
Normal file
65
mod/data/classes/local/ods_exporter.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?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/>.
|
||||
|
||||
namespace mod_data\local;
|
||||
|
||||
use MoodleODSWorkbook;
|
||||
use MoodleODSWriter;
|
||||
|
||||
/**
|
||||
* ODS exporter for mod_data.
|
||||
*
|
||||
* @package mod_data
|
||||
* @copyright 2023 ISB Bayern
|
||||
* @author Philipp Memmel
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class ods_exporter extends exporter {
|
||||
|
||||
/**
|
||||
* Returns the file extension of this exporter.
|
||||
*
|
||||
* @see \mod_data\local\exporter::get_export_data_file_extension()
|
||||
*/
|
||||
public function get_export_data_file_extension(): string {
|
||||
return 'ods';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ods data exported by the ODS library for further handling.
|
||||
*
|
||||
* @see \mod_data\local\exporter::get_data_file_content()
|
||||
*/
|
||||
public function get_data_file_content(): string {
|
||||
global $CFG;
|
||||
require_once("$CFG->libdir/odslib.class.php");
|
||||
$filearg = '-';
|
||||
$workbook = new MoodleODSWorkbook($filearg);
|
||||
$worksheet = [];
|
||||
$worksheet[0] = $workbook->add_worksheet('');
|
||||
$rowno = 0;
|
||||
foreach ($this->exportdata as $row) {
|
||||
$colno = 0;
|
||||
foreach ($row as $col) {
|
||||
$worksheet[0]->write($rowno, $colno, $col);
|
||||
$colno++;
|
||||
}
|
||||
$rowno++;
|
||||
}
|
||||
$writer = new MoodleODSWriter($worksheet);
|
||||
return $writer->get_file_content();
|
||||
}
|
||||
}
|
@ -100,3 +100,170 @@ function data_export_xls($export, $dataname, $count) {
|
||||
$workbook->close();
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Moodle 4.3, exporting is now being done by \mod_data\local\csv_exporter
|
||||
* @global object
|
||||
* @param array $export
|
||||
* @param string $delimiter_name
|
||||
* @param object $database
|
||||
* @param int $count
|
||||
* @param bool $return
|
||||
* @return string|void
|
||||
*/
|
||||
function data_export_csv($export, $delimiter_name, $database, $count, $return=false) {
|
||||
global $CFG;
|
||||
|
||||
debugging('Function data_export_csv has been deprecated. Exporting is now being done by '
|
||||
. '\mod_data\local\csv_exporter.', DEBUG_DEVELOPER);
|
||||
require_once($CFG->libdir . '/csvlib.class.php');
|
||||
|
||||
$filename = $database . '-' . $count . '-record';
|
||||
if ($count > 1) {
|
||||
$filename .= 's';
|
||||
}
|
||||
if ($return) {
|
||||
return csv_export_writer::print_array($export, $delimiter_name, '"', true);
|
||||
} else {
|
||||
csv_export_writer::download_array($filename, $export, $delimiter_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Moodle 4.3, exporting is now being done by \mod_data\local\ods_exporter
|
||||
* @global object
|
||||
* @param array $export
|
||||
* @param string $dataname
|
||||
* @param int $count
|
||||
* @param string
|
||||
*/
|
||||
function data_export_ods($export, $dataname, $count) {
|
||||
global $CFG;
|
||||
|
||||
debugging('Function data_export_ods has been deprecated. Exporting is now being done by '
|
||||
. '\mod_data\local\ods_exporter.', DEBUG_DEVELOPER);
|
||||
require_once("$CFG->libdir/odslib.class.php");
|
||||
$filename = clean_filename("{$dataname}-{$count}_record");
|
||||
if ($count > 1) {
|
||||
$filename .= 's';
|
||||
}
|
||||
$filename .= clean_filename('-' . gmdate("Ymd_Hi"));
|
||||
$filename .= '.ods';
|
||||
$filearg = '-';
|
||||
$workbook = new MoodleODSWorkbook($filearg);
|
||||
$workbook->send($filename);
|
||||
$worksheet = array();
|
||||
$worksheet[0] = $workbook->add_worksheet('');
|
||||
$rowno = 0;
|
||||
foreach ($export as $row) {
|
||||
$colno = 0;
|
||||
foreach($row as $col) {
|
||||
$worksheet[0]->write($rowno, $colno, $col);
|
||||
$colno++;
|
||||
}
|
||||
$rowno++;
|
||||
}
|
||||
$workbook->close();
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Moodle 4.3, use \mod_data\local\exporter_utils::data_exportdata with a \mod_data\local\exporter object
|
||||
* @global object
|
||||
* @param int $dataid
|
||||
* @param array $fields
|
||||
* @param array $selectedfields
|
||||
* @param int $currentgroup group ID of the current group. This is used for
|
||||
* exporting data while maintaining group divisions.
|
||||
* @param object $context the context in which the operation is performed (for capability checks)
|
||||
* @param bool $userdetails whether to include the details of the record author
|
||||
* @param bool $time whether to include time created/modified
|
||||
* @param bool $approval whether to include approval status
|
||||
* @param bool $tags whether to include tags
|
||||
* @return array
|
||||
*/
|
||||
function data_get_exportdata($dataid, $fields, $selectedfields, $currentgroup=0, $context=null,
|
||||
$userdetails=false, $time=false, $approval=false, $tags = false) {
|
||||
global $DB;
|
||||
|
||||
debugging('Function data_get_exportdata has been deprecated. Use '
|
||||
. '\mod_data\local\exporter_utils::data_exportdata with a \mod_data\local\exporter object instead',
|
||||
DEBUG_DEVELOPER);
|
||||
|
||||
if (is_null($context)) {
|
||||
$context = context_system::instance();
|
||||
}
|
||||
// exporting user data needs special permission
|
||||
$userdetails = $userdetails && has_capability('mod/data:exportuserinfo', $context);
|
||||
|
||||
$exportdata = array();
|
||||
|
||||
// populate the header in first row of export
|
||||
foreach($fields as $key => $field) {
|
||||
if (!in_array($field->field->id, $selectedfields)) {
|
||||
// ignore values we aren't exporting
|
||||
unset($fields[$key]);
|
||||
} else {
|
||||
$exportdata[0][] = $field->field->name;
|
||||
}
|
||||
}
|
||||
if ($tags) {
|
||||
$exportdata[0][] = get_string('tags', 'data');
|
||||
}
|
||||
if ($userdetails) {
|
||||
$exportdata[0][] = get_string('user');
|
||||
$exportdata[0][] = get_string('username');
|
||||
$exportdata[0][] = get_string('email');
|
||||
}
|
||||
if ($time) {
|
||||
$exportdata[0][] = get_string('timeadded', 'data');
|
||||
$exportdata[0][] = get_string('timemodified', 'data');
|
||||
}
|
||||
if ($approval) {
|
||||
$exportdata[0][] = get_string('approved', 'data');
|
||||
}
|
||||
|
||||
$datarecords = $DB->get_records('data_records', array('dataid'=>$dataid));
|
||||
ksort($datarecords);
|
||||
$line = 1;
|
||||
foreach($datarecords as $record) {
|
||||
// get content indexed by fieldid
|
||||
if ($currentgroup) {
|
||||
$select = 'SELECT c.fieldid, c.content, c.content1, c.content2, c.content3, c.content4 FROM {data_content} c, {data_records} r WHERE c.recordid = ? AND r.id = c.recordid AND r.groupid = ?';
|
||||
$where = array($record->id, $currentgroup);
|
||||
} else {
|
||||
$select = 'SELECT fieldid, content, content1, content2, content3, content4 FROM {data_content} WHERE recordid = ?';
|
||||
$where = array($record->id);
|
||||
}
|
||||
|
||||
if( $content = $DB->get_records_sql($select, $where) ) {
|
||||
foreach($fields as $field) {
|
||||
$contents = '';
|
||||
if(isset($content[$field->field->id])) {
|
||||
$contents = $field->export_text_value($content[$field->field->id]);
|
||||
}
|
||||
$exportdata[$line][] = $contents;
|
||||
}
|
||||
if ($tags) {
|
||||
$itemtags = \core_tag_tag::get_item_tags_array('mod_data', 'data_records', $record->id);
|
||||
$exportdata[$line][] = implode(', ', $itemtags);
|
||||
}
|
||||
if ($userdetails) { // Add user details to the export data
|
||||
$userdata = get_complete_user_data('id', $record->userid);
|
||||
$exportdata[$line][] = fullname($userdata);
|
||||
$exportdata[$line][] = $userdata->username;
|
||||
$exportdata[$line][] = $userdata->email;
|
||||
}
|
||||
if ($time) { // Add time added / modified
|
||||
$exportdata[$line][] = userdate($record->timecreated);
|
||||
$exportdata[$line][] = userdate($record->timemodified);
|
||||
}
|
||||
if ($approval) { // Add approval status
|
||||
$exportdata[$line][] = (int) $record->approved;
|
||||
}
|
||||
}
|
||||
$line++;
|
||||
}
|
||||
$line--;
|
||||
return $exportdata;
|
||||
}
|
||||
|
@ -95,20 +95,30 @@ if ($mform->is_cancelled()) {
|
||||
|
||||
$currentgroup = groups_get_activity_group($cm);
|
||||
|
||||
$exportdata = data_get_exportdata($data->id, $fields, $selectedfields, $currentgroup, $context,
|
||||
$exportuser, $exporttime, $exportapproval, $tags);
|
||||
$count = count($exportdata);
|
||||
$exporter = null;
|
||||
switch ($formdata['exporttype']) {
|
||||
case 'csv':
|
||||
data_export_csv($exportdata, $formdata['delimiter_name'], $data->name, $count);
|
||||
$exporter = new \mod_data\local\csv_exporter();
|
||||
$exporter->set_delimiter_name($formdata['delimiter_name']);
|
||||
break;
|
||||
case 'ods':
|
||||
data_export_ods($exportdata, $data->name, $count);
|
||||
$exporter = new \mod_data\local\ods_exporter();
|
||||
break;
|
||||
default:
|
||||
throw new coding_exception('Invalid export format has been specified. '
|
||||
. 'Only "csv" and "ods" are currently supported.');
|
||||
}
|
||||
|
||||
\mod_data\local\exporter_utils::data_exportdata($data->id, $fields, $selectedfields, $exporter, $currentgroup, $context,
|
||||
$exportuser, $exporttime, $exportapproval, $tags);
|
||||
$count = $exporter->get_records_count();
|
||||
$filename = clean_filename("{$data->name}-{$count}_record");
|
||||
if ($count > 1) {
|
||||
$filename .= 's';
|
||||
}
|
||||
$filename .= clean_filename('-' . gmdate("Ymd_Hi"));
|
||||
$exporter->set_export_file_name($filename);
|
||||
$exporter->send_file();
|
||||
}
|
||||
|
||||
// Build header to match the rest of the UI.
|
||||
|
154
mod/data/lib.php
154
mod/data/lib.php
@ -3111,160 +3111,6 @@ function data_import_csv($cm, $data, &$csvdata, $encoding, $fielddelimiter) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @global object
|
||||
* @param array $export
|
||||
* @param string $delimiter_name
|
||||
* @param object $database
|
||||
* @param int $count
|
||||
* @param bool $return
|
||||
* @return string|void
|
||||
*/
|
||||
function data_export_csv($export, $delimiter_name, $database, $count, $return=false) {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/csvlib.class.php');
|
||||
|
||||
$filename = $database . '-' . $count . '-record';
|
||||
if ($count > 1) {
|
||||
$filename .= 's';
|
||||
}
|
||||
if ($return) {
|
||||
return csv_export_writer::print_array($export, $delimiter_name, '"', true);
|
||||
} else {
|
||||
csv_export_writer::download_array($filename, $export, $delimiter_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @global object
|
||||
* @param array $export
|
||||
* @param string $dataname
|
||||
* @param int $count
|
||||
* @param string
|
||||
*/
|
||||
function data_export_ods($export, $dataname, $count) {
|
||||
global $CFG;
|
||||
require_once("$CFG->libdir/odslib.class.php");
|
||||
$filename = clean_filename("{$dataname}-{$count}_record");
|
||||
if ($count > 1) {
|
||||
$filename .= 's';
|
||||
}
|
||||
$filename .= clean_filename('-' . gmdate("Ymd_Hi"));
|
||||
$filename .= '.ods';
|
||||
$filearg = '-';
|
||||
$workbook = new MoodleODSWorkbook($filearg);
|
||||
$workbook->send($filename);
|
||||
$worksheet = array();
|
||||
$worksheet[0] = $workbook->add_worksheet('');
|
||||
$rowno = 0;
|
||||
foreach ($export as $row) {
|
||||
$colno = 0;
|
||||
foreach($row as $col) {
|
||||
$worksheet[0]->write($rowno, $colno, $col);
|
||||
$colno++;
|
||||
}
|
||||
$rowno++;
|
||||
}
|
||||
$workbook->close();
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @global object
|
||||
* @param int $dataid
|
||||
* @param array $fields
|
||||
* @param array $selectedfields
|
||||
* @param int $currentgroup group ID of the current group. This is used for
|
||||
* exporting data while maintaining group divisions.
|
||||
* @param object $context the context in which the operation is performed (for capability checks)
|
||||
* @param bool $userdetails whether to include the details of the record author
|
||||
* @param bool $time whether to include time created/modified
|
||||
* @param bool $approval whether to include approval status
|
||||
* @param bool $tags whether to include tags
|
||||
* @return array
|
||||
*/
|
||||
function data_get_exportdata($dataid, $fields, $selectedfields, $currentgroup=0, $context=null,
|
||||
$userdetails=false, $time=false, $approval=false, $tags = false) {
|
||||
global $DB;
|
||||
|
||||
if (is_null($context)) {
|
||||
$context = context_system::instance();
|
||||
}
|
||||
// exporting user data needs special permission
|
||||
$userdetails = $userdetails && has_capability('mod/data:exportuserinfo', $context);
|
||||
|
||||
$exportdata = array();
|
||||
|
||||
// populate the header in first row of export
|
||||
foreach($fields as $key => $field) {
|
||||
if (!in_array($field->field->id, $selectedfields)) {
|
||||
// ignore values we aren't exporting
|
||||
unset($fields[$key]);
|
||||
} else {
|
||||
$exportdata[0][] = $field->field->name;
|
||||
}
|
||||
}
|
||||
if ($tags) {
|
||||
$exportdata[0][] = get_string('tags', 'data');
|
||||
}
|
||||
if ($userdetails) {
|
||||
$exportdata[0][] = get_string('user');
|
||||
$exportdata[0][] = get_string('username');
|
||||
$exportdata[0][] = get_string('email');
|
||||
}
|
||||
if ($time) {
|
||||
$exportdata[0][] = get_string('timeadded', 'data');
|
||||
$exportdata[0][] = get_string('timemodified', 'data');
|
||||
}
|
||||
if ($approval) {
|
||||
$exportdata[0][] = get_string('approved', 'data');
|
||||
}
|
||||
|
||||
$datarecords = $DB->get_records('data_records', array('dataid'=>$dataid));
|
||||
ksort($datarecords);
|
||||
$line = 1;
|
||||
foreach($datarecords as $record) {
|
||||
// get content indexed by fieldid
|
||||
if ($currentgroup) {
|
||||
$select = 'SELECT c.fieldid, c.content, c.content1, c.content2, c.content3, c.content4 FROM {data_content} c, {data_records} r WHERE c.recordid = ? AND r.id = c.recordid AND r.groupid = ?';
|
||||
$where = array($record->id, $currentgroup);
|
||||
} else {
|
||||
$select = 'SELECT fieldid, content, content1, content2, content3, content4 FROM {data_content} WHERE recordid = ?';
|
||||
$where = array($record->id);
|
||||
}
|
||||
|
||||
if( $content = $DB->get_records_sql($select, $where) ) {
|
||||
foreach($fields as $field) {
|
||||
$contents = '';
|
||||
if(isset($content[$field->field->id])) {
|
||||
$contents = $field->export_text_value($content[$field->field->id]);
|
||||
}
|
||||
$exportdata[$line][] = $contents;
|
||||
}
|
||||
if ($tags) {
|
||||
$itemtags = \core_tag_tag::get_item_tags_array('mod_data', 'data_records', $record->id);
|
||||
$exportdata[$line][] = implode(', ', $itemtags);
|
||||
}
|
||||
if ($userdetails) { // Add user details to the export data
|
||||
$userdata = get_complete_user_data('id', $record->userid);
|
||||
$exportdata[$line][] = fullname($userdata);
|
||||
$exportdata[$line][] = $userdata->username;
|
||||
$exportdata[$line][] = $userdata->email;
|
||||
}
|
||||
if ($time) { // Add time added / modified
|
||||
$exportdata[$line][] = userdate($record->timecreated);
|
||||
$exportdata[$line][] = userdate($record->timemodified);
|
||||
}
|
||||
if ($approval) { // Add approval status
|
||||
$exportdata[$line][] = (int) $record->approved;
|
||||
}
|
||||
}
|
||||
$line++;
|
||||
}
|
||||
$line--;
|
||||
return $exportdata;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// File API //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
114
mod/data/tests/export_test.php
Normal file
114
mod/data/tests/export_test.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?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/>.
|
||||
|
||||
namespace mod_data;
|
||||
|
||||
use coding_exception;
|
||||
use context_module;
|
||||
use dml_exception;
|
||||
use mod_data\local\csv_exporter;
|
||||
use mod_data\local\exporter_utils;
|
||||
use mod_data\local\mod_data_csv_importer;
|
||||
|
||||
/**
|
||||
* Unit tests for import.php.
|
||||
*
|
||||
* @package mod_data
|
||||
* @category test
|
||||
* @copyright 2019 Tobias Reischmann
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class export_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Get the test data.
|
||||
*
|
||||
* In this instance we are setting up database records to be used in the unit tests.
|
||||
*
|
||||
* @return array of test instances
|
||||
* @throws coding_exception
|
||||
*/
|
||||
protected function get_test_data(): array {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
|
||||
$this->setUser($teacher);
|
||||
$student = $this->getDataGenerator()->create_and_enrol($course, 'student', ['username' => 'student']);
|
||||
|
||||
$data = $generator->create_instance(['course' => $course->id]);
|
||||
$cm = get_coursemodule_from_instance('data', $data->id);
|
||||
|
||||
// Add fields.
|
||||
$fieldrecord = new \stdClass();
|
||||
$fieldrecord->name = 'numberfield'; // Identifier of the records for testing.
|
||||
$fieldrecord->type = 'number';
|
||||
$numberfield = $generator->create_field($fieldrecord, $data);
|
||||
|
||||
$fieldrecord->name = 'textfield';
|
||||
$fieldrecord->type = 'text';
|
||||
$textfield = $generator->create_field($fieldrecord, $data);
|
||||
|
||||
$contents[$numberfield->field->id] = '3';
|
||||
$contents[$textfield->field->id] = 'a simple text';
|
||||
$generator->create_entry($data, $contents);
|
||||
|
||||
return [
|
||||
'teacher' => $teacher,
|
||||
'student' => $student,
|
||||
'data' => $data,
|
||||
'cm' => $cm,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the exporting of the content of a mod_data instance.
|
||||
*
|
||||
* @covers \mod_data\local\exporter
|
||||
* @covers \mod_data\local\exporter_utils::data_exportdata
|
||||
*/
|
||||
public function test_export(): void {
|
||||
global $DB;
|
||||
[
|
||||
'data' => $data,
|
||||
'cm' => $cm,
|
||||
] = $this->get_test_data();
|
||||
|
||||
$exporter = new csv_exporter();
|
||||
$exporter->set_export_file_name('testexportfile');
|
||||
$fieldrecords = $DB->get_records('data_fields', ['dataid' => $data->id], 'id');
|
||||
|
||||
$fields = [];
|
||||
foreach ($fieldrecords as $fieldrecord) {
|
||||
$fields[] = data_get_field($fieldrecord, $data);
|
||||
}
|
||||
|
||||
// We select all fields.
|
||||
$selectedfields = array_map(fn($field) => $field->field->id, $fields);
|
||||
$currentgroup = groups_get_activity_group($cm);
|
||||
$context = context_module::instance($cm->id);
|
||||
$exportuser = false;
|
||||
$exporttime = false;
|
||||
$exportapproval = false;
|
||||
$tags = false;
|
||||
|
||||
exporter_utils::data_exportdata($data->id, $fields, $selectedfields, $exporter, $currentgroup, $context,
|
||||
$exportuser, $exporttime, $exportapproval, $tags);
|
||||
$this->assertEquals(file_get_contents(__DIR__ . '/fixtures/test_data_export.csv'),
|
||||
$exporter->send_file(false));
|
||||
}
|
||||
}
|
2
mod/data/tests/fixtures/test_data_export.csv
vendored
Normal file
2
mod/data/tests/fixtures/test_data_export.csv
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
numberfield,textfield
|
||||
3,"a simple text"
|
|
@ -3,6 +3,10 @@ information provided here is intended especially for developers.
|
||||
|
||||
== 4.3 ==
|
||||
* Function data_export_xls() has been deprecated and moved to deprecatedlib, because xls support has already been dropped.
|
||||
* Functions data_export_csv(), data_export_ods() and data_get_exportdata() have been deprecated due to a bigger
|
||||
refactoring of the way data is being exported. This is now being done by new exporter classes
|
||||
\mod_data\local\csv_exporter and \mod_data\local\ods_exporter (inheriting from exporter base class
|
||||
\mod_data\local\exporter) as well as \mod_data\local\exporter_utils::data_exportdata().
|
||||
|
||||
== 4.2 ==
|
||||
* The field base class now has a method validate(). Overwrite it in the field type to provide validation of field type's
|
||||
|
Loading…
x
Reference in New Issue
Block a user