MDL-55971 dataformat: method to write exports to file storage.
[moodle.git] / lib / classes / dataformat.php
CommitLineData
8844cb82
PH
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Class containing utility methods for dataformats
19 *
20 * @package core
c1c57e81 21 * @copyright 2020 Paul Holden <paulh@moodle.com>
8844cb82 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8844cb82
PH
23 */
24
25namespace core;
26
27use coding_exception;
28use core_php_time_limit;
1ffb6b09 29use stored_file;
8844cb82
PH
30
31/**
32 * Dataformat utility class
33 *
34 * @package core
c1c57e81 35 * @copyright 2020 Paul Holden <paulh@moodle.com>
8844cb82 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8844cb82
PH
37 */
38class dataformat {
39
40 /**
c1c57e81 41 * Return an instance of a dataformat writer from given dataformat type
8844cb82
PH
42 *
43 * @param string $dataformat
44 * @return dataformat\base
45 * @throws coding_exception
46 */
47 protected static function get_format_instance(string $dataformat): \core\dataformat\base {
48 $classname = 'dataformat_' . $dataformat . '\writer';
49 if (!class_exists($classname)) {
50 throw new coding_exception('Invalid dataformat', $dataformat);
51 }
52
53 return new $classname();
54 }
55
56 /**
57 * Sends a formatted data file to the browser
58 *
59 * @param string $filename
60 * @param string $dataformat
61 * @param array $columns
62 * @param Iterable $iterator
63 * @param callable|null $callback
64 * @throws coding_exception
65 */
66 public static function download_data(string $filename, string $dataformat, array $columns, Iterable $iterator,
67 callable $callback = null): void {
68
69 if (ob_get_length()) {
70 throw new coding_exception('Output can not be buffered before calling download_data()');
71 }
72
73 $format = self::get_format_instance($dataformat);
74
75 // The data format export could take a while to generate.
76 core_php_time_limit::raise();
77
78 // Close the session so that the users other tabs in the same session are not blocked.
79 \core\session\manager::write_close();
80
81 // If this file was requested from a form, then mark download as complete (before sending headers).
82 \core_form\util::form_download_complete();
83
84 $format->set_filename($filename);
85 $format->send_http_headers();
86
87 $format->start_output();
88 $format->start_sheet($columns);
89
90 $rownum = 0;
91 foreach ($iterator as $row) {
92 if (is_callable($callback)) {
93 $row = $callback($row);
94 }
95 if ($row === null) {
96 continue;
97 }
98 $format->write_record($row, $rownum++);
99 }
100
101 $format->close_sheet($columns);
102 $format->close_output();
103 }
104
105 /**
106 * Writes a formatted data file with specified filename
107 *
108 * @param string $filename
109 * @param string $dataformat
110 * @param array $columns
111 * @param Iterable $iterator
112 * @param callable|null $callback
113 * @return string Complete path to the file on disk
114 */
115 public static function write_data(string $filename, string $dataformat, array $columns, Iterable $iterator,
116 callable $callback = null): string {
117
118 $format = self::get_format_instance($dataformat);
119
120 // The data format export could take a while to generate.
121 core_php_time_limit::raise();
122
123 // Close the session so that the users other tabs in the same session are not blocked.
124 \core\session\manager::write_close();
125
126 $filepath = make_request_directory() . '/' . $filename . $format->get_extension();
127 $format->set_filepath($filepath);
128
129 $format->start_output_to_file();
130 $format->start_sheet($columns);
131
132 $rownum = 0;
133 foreach ($iterator as $row) {
134 if (is_callable($callback)) {
135 $row = $callback($row);
136 }
137 if ($row === null) {
138 continue;
139 }
140 $format->write_record($row, $rownum++);
141 }
142
143 $format->close_sheet($columns);
144 $format->close_output_to_file();
145
146 return $filepath;
147 }
1ffb6b09
PH
148
149 /**
150 * Writes a formatted data file to file storage
151 *
152 * @param array $filerecord File record for storage, 'filename' extension should be omitted as it's added by the dataformat
153 * @param string $dataformat
154 * @param array $columns
155 * @param Iterable $iterator Iterable set of records to write
156 * @param callable|null $callback Optional callback method to apply to each record prior to writing
157 * @return stored_file
158 */
159 public static function write_data_to_filearea(array $filerecord, string $dataformat, array $columns, Iterable $iterator,
160 callable $callback = null): stored_file {
161
162 $filepath = self::write_data($filerecord['filename'], $dataformat, $columns, $iterator, $callback);
163
164 // Update filename of returned file record.
165 $filerecord['filename'] = basename($filepath);
166
167 return get_file_storage()->create_file_from_pathname($filerecord, $filepath);
168 }
8844cb82 169}