1 |
efrain |
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 |
* Extend this class when creating new layouts.
|
|
|
19 |
*
|
|
|
20 |
* @package block_dash
|
|
|
21 |
* @copyright 2019 bdecent gmbh <https://bdecent.de>
|
|
|
22 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
23 |
*/
|
|
|
24 |
|
|
|
25 |
namespace block_dash\local\layout;
|
|
|
26 |
|
|
|
27 |
use block_dash\local\data_grid\data\data_collection_interface;
|
|
|
28 |
use block_dash\local\data_grid\data\field;
|
|
|
29 |
use block_dash\local\data_grid\data\strategy\data_strategy_interface;
|
|
|
30 |
use block_dash\local\data_grid\data\strategy\standard_strategy;
|
|
|
31 |
use block_dash\local\data_grid\field\attribute\context_attribute;
|
|
|
32 |
use block_dash\local\data_grid\field\attribute\identifier_attribute;
|
|
|
33 |
use block_dash\local\paginator;
|
|
|
34 |
use block_dash\local\data_source\data_source_interface;
|
|
|
35 |
use block_dash\local\data_source\form\preferences_form;
|
|
|
36 |
use html_writer;
|
|
|
37 |
use moodle_url;
|
|
|
38 |
|
|
|
39 |
/**
|
|
|
40 |
* Extend this class when creating new layouts.
|
|
|
41 |
*
|
|
|
42 |
* Then register the layout in a lib.php function: pluginname_register_layouts(). See blocks/dash/lib.php for an
|
|
|
43 |
* example.
|
|
|
44 |
*
|
|
|
45 |
* @package block_dash
|
|
|
46 |
*/
|
|
|
47 |
abstract class abstract_layout implements layout_interface, \templatable {
|
|
|
48 |
|
|
|
49 |
/**
|
|
|
50 |
* @var int Used for creating unique checkbox controller group IDs.
|
|
|
51 |
*/
|
|
|
52 |
private static $currentgroupid = null;
|
|
|
53 |
|
|
|
54 |
/**
|
|
|
55 |
* The data source used as a data/configuration source for this layout.
|
|
|
56 |
*
|
|
|
57 |
* @var data_source_interface
|
|
|
58 |
*/
|
|
|
59 |
private $datasource;
|
|
|
60 |
|
|
|
61 |
/**
|
|
|
62 |
* Layout constructor.
|
|
|
63 |
*
|
|
|
64 |
* @param data_source_interface $datasource
|
|
|
65 |
*/
|
|
|
66 |
public function __construct(data_source_interface $datasource) {
|
|
|
67 |
$this->datasource = $datasource;
|
|
|
68 |
}
|
|
|
69 |
|
|
|
70 |
/**
|
|
|
71 |
* If the layout supports field sorting.
|
|
|
72 |
*
|
|
|
73 |
* @return mixed
|
|
|
74 |
*/
|
|
|
75 |
public function supports_sorting() {
|
|
|
76 |
return false;
|
|
|
77 |
}
|
|
|
78 |
|
|
|
79 |
/**
|
|
|
80 |
* If the layout supports options.
|
|
|
81 |
*/
|
|
|
82 |
public function supports_download() {
|
|
|
83 |
return false;
|
|
|
84 |
}
|
|
|
85 |
|
|
|
86 |
/**
|
|
|
87 |
* Get the data source used as a data/configuration source for this layout.
|
|
|
88 |
*
|
|
|
89 |
* @return data_source_interface
|
|
|
90 |
*/
|
|
|
91 |
public function get_data_source() {
|
|
|
92 |
return $this->datasource;
|
|
|
93 |
}
|
|
|
94 |
|
|
|
95 |
/**
|
|
|
96 |
* Get data strategy.
|
|
|
97 |
*
|
|
|
98 |
* @return data_strategy_interface
|
|
|
99 |
*/
|
|
|
100 |
public function get_data_strategy() {
|
|
|
101 |
return new standard_strategy();
|
|
|
102 |
}
|
|
|
103 |
|
|
|
104 |
/**
|
|
|
105 |
* Modify objects before data is retrieved in the data source. This allows the layout to make decisions on the
|
|
|
106 |
* data source and data grid.
|
|
|
107 |
*/
|
|
|
108 |
public function before_data() {
|
|
|
109 |
|
|
|
110 |
}
|
|
|
111 |
|
|
|
112 |
/**
|
|
|
113 |
* Modify objects after data is retrieved in the data source. This allows the layout to make decisions on the
|
|
|
114 |
* data source and data grid.
|
|
|
115 |
*
|
|
|
116 |
* @param data_collection_interface $datacollection
|
|
|
117 |
*/
|
|
|
118 |
public function after_data(data_collection_interface $datacollection) {
|
|
|
119 |
|
|
|
120 |
}
|
|
|
121 |
|
|
|
122 |
/**
|
|
|
123 |
* Add form elements to the preferences form when a user is configuring a block.
|
|
|
124 |
*
|
|
|
125 |
* This extends the form built by the data source. When a user chooses a layout, specific form elements may be
|
|
|
126 |
* displayed after a quick refresh of the form.
|
|
|
127 |
*
|
|
|
128 |
* Be sure to call parent::build_preferences_form() if you override this method.
|
|
|
129 |
*
|
|
|
130 |
* @param \moodleform $form
|
|
|
131 |
* @param \MoodleQuickForm $mform
|
|
|
132 |
* @throws \coding_exception
|
|
|
133 |
*/
|
|
|
134 |
public function build_preferences_form(\moodleform $form, \MoodleQuickForm $mform) {
|
|
|
135 |
global $OUTPUT;
|
|
|
136 |
|
|
|
137 |
self::$currentgroupid = random_int(1, 10000);
|
|
|
138 |
|
|
|
139 |
$filtercollection = $this->get_data_source()->get_filter_collection();
|
|
|
140 |
|
|
|
141 |
if ($form->get_tab() == preferences_form::TAB_FIELDS) {
|
|
|
142 |
if ($this->supports_field_visibility()) {
|
|
|
143 |
$group = [];
|
|
|
144 |
foreach ($this->get_data_source()->get_sorted_fields() as $availablefield) {
|
|
|
145 |
if ($availablefield->has_attribute(identifier_attribute::class)) {
|
|
|
146 |
continue;
|
|
|
147 |
}
|
|
|
148 |
|
|
|
149 |
if ($availablefield->has_attribute(context_attribute::class)) {
|
|
|
150 |
continue;
|
|
|
151 |
}
|
|
|
152 |
|
|
|
153 |
$fieldname = 'config_preferences[available_fields][' . $availablefield->get_alias() .
|
|
|
154 |
'][visible]';
|
|
|
155 |
|
|
|
156 |
$title = $availablefield->get_table()->get_title();
|
|
|
157 |
|
|
|
158 |
$icon = $OUTPUT->pix_icon('i/dragdrop', get_string('dragitem', 'block_dash'), 'moodle',
|
|
|
159 |
['class' => 'drag-handle']);
|
|
|
160 |
$title = $icon . '<b>' . $title . '</b>: ' . $availablefield->get_title();
|
|
|
161 |
|
|
|
162 |
$totaratitle = block_dash_is_totara() ? $title : null;
|
|
|
163 |
$group[] = $mform->createElement('advcheckbox', $fieldname, $title, $totaratitle, [
|
|
|
164 |
'group' => self::$currentgroupid, // For legacy add_checkbox_controller().
|
|
|
165 |
'data-togglegroup' => 'group' . self::$currentgroupid, // For checkbox_toggleall.
|
|
|
166 |
'data-toggle' => 'slave', // For checkbox_toggleall.
|
|
|
167 |
'data-action' => 'toggle', // For checkbox_toggleall.
|
|
|
168 |
]);
|
|
|
169 |
$mform->setType($fieldname, PARAM_BOOL);
|
|
|
170 |
}
|
|
|
171 |
$mform->addGroup($group, 'available_fields', get_string('enabledfields', 'block_dash'),
|
|
|
172 |
[''], false);
|
|
|
173 |
|
|
|
174 |
$this->add_checkbox_toggleall(self::$currentgroupid, $form, $mform);
|
|
|
175 |
|
|
|
176 |
self::$currentgroupid++;
|
|
|
177 |
}
|
|
|
178 |
}
|
|
|
179 |
|
|
|
180 |
if ($this->supports_filtering()) {
|
|
|
181 |
if ($form->get_tab() == preferences_form::TAB_FILTERS) {
|
|
|
182 |
$mform->addElement('static', 'filterslabel', '', '<b>' . get_string('enabledfilters', 'block_dash') . '</b>');
|
|
|
183 |
$filtercollection->build_settings_form($form, $mform, 'filter', 'config_preferences[filters][%s]');
|
|
|
184 |
}
|
|
|
185 |
}
|
|
|
186 |
|
|
|
187 |
if ($form->get_tab() == preferences_form::TAB_CONDITIONS) {
|
|
|
188 |
$mform->addElement('static', 'conditionslabel', '', '<b>' . get_string('enabledconditions', 'block_dash') . '</b>');
|
|
|
189 |
$filtercollection->build_settings_form($form, $mform, 'condition', 'config_preferences[filters][%s]');
|
|
|
190 |
}
|
|
|
191 |
|
|
|
192 |
if (!$this->supports_filtering() && $form->get_tab() == preferences_form::TAB_FILTERS) {
|
|
|
193 |
$mform->addElement('html', $OUTPUT->notification(get_string('layoutdoesnotsupportfiltering', 'block_dash'), 'warning'));
|
|
|
194 |
}
|
|
|
195 |
}
|
|
|
196 |
|
|
|
197 |
/**
|
|
|
198 |
* Add button to select/deselect all checkboxes in group.
|
|
|
199 |
*
|
|
|
200 |
* @param string $uniqueid
|
|
|
201 |
* @param \moodleform $form
|
|
|
202 |
* @param \MoodleQuickForm $mform
|
|
|
203 |
*/
|
|
|
204 |
private function add_checkbox_toggleall($uniqueid, \moodleform $form, \MoodleQuickForm $mform) {
|
|
|
205 |
global $OUTPUT;
|
|
|
206 |
|
|
|
207 |
if (class_exists('\core\output\checkbox_toggleall')) {
|
|
|
208 |
$masterbutton = new \core\output\checkbox_toggleall('group' . $uniqueid, true, [], true);
|
|
|
209 |
|
|
|
210 |
// Then you can export for template.
|
|
|
211 |
$mform->addElement('static', 'toggleall' . $uniqueid, '', $OUTPUT->render($masterbutton));
|
|
|
212 |
} else {
|
|
|
213 |
// Moodle 3.7 and earlier support.
|
|
|
214 |
$form->add_checkbox_controller($uniqueid);
|
|
|
215 |
}
|
|
|
216 |
}
|
|
|
217 |
|
|
|
218 |
/**
|
|
|
219 |
* Allows layout to modified preferences values before exporting to mustache template.
|
|
|
220 |
*
|
|
|
221 |
* @param array $preferences
|
|
|
222 |
* @return array
|
|
|
223 |
*/
|
|
|
224 |
public function process_preferences(array $preferences) {
|
|
|
225 |
return $preferences;
|
|
|
226 |
}
|
|
|
227 |
|
|
|
228 |
/**
|
|
|
229 |
* Get data for layout mustache template.
|
|
|
230 |
*
|
|
|
231 |
* @param \renderer_base $output
|
|
|
232 |
* @return array|\stdClass
|
|
|
233 |
* @throws \coding_exception
|
|
|
234 |
*/
|
|
|
235 |
public function export_for_template(\renderer_base $output) {
|
|
|
236 |
global $OUTPUT, $PAGE;
|
|
|
237 |
|
|
|
238 |
$config = $this->get_data_source()->get_block_instance()->config;
|
|
|
239 |
$noresulttxt = \html_writer::tag('p', get_string('noresults'), ['class' => 'text-muted']);
|
|
|
240 |
|
|
|
241 |
$templatedata = [
|
|
|
242 |
'error' => '',
|
|
|
243 |
'paginator' => '',
|
|
|
244 |
'data' => null,
|
|
|
245 |
'uniqueid' => uniqid(),
|
|
|
246 |
'is_totara' => block_dash_is_totara(),
|
|
|
247 |
'bootstrap3' => get_config('block_dash', 'bootstrap_version') == 3,
|
|
|
248 |
'bootstrap4' => get_config('block_dash', 'bootstrap_version') == 4,
|
|
|
249 |
'noresult' => (isset($config->emptystate))
|
|
|
250 |
? format_text($config->emptystate['text'], FORMAT_HTML, ['noclean' => true]) : $noresulttxt,
|
|
|
251 |
];
|
|
|
252 |
|
|
|
253 |
if (!empty($this->get_data_source()->get_all_preferences())) {
|
|
|
254 |
try {
|
|
|
255 |
$templatedata['data'] = $this->get_data_source()->get_data();
|
|
|
256 |
} catch (\Exception $e) {
|
|
|
257 |
$error = \html_writer::tag('p', get_string('databaseerror', 'block_dash'));
|
|
|
258 |
if (is_siteadmin()) {
|
|
|
259 |
$error .= \html_writer::tag('p', $e->getMessage());
|
|
|
260 |
}
|
|
|
261 |
|
|
|
262 |
$templatedata['error'] .= $OUTPUT->notification($error, 'error');
|
|
|
263 |
}
|
|
|
264 |
|
|
|
265 |
if ($this->get_data_source()->get_paginator()->get_page_count() > 1) {
|
|
|
266 |
$templatedata['paginator'] = $OUTPUT->render_from_template(paginator::TEMPLATE, $this->get_data_source()
|
|
|
267 |
->get_paginator()
|
|
|
268 |
->export_for_template($OUTPUT));
|
|
|
269 |
}
|
|
|
270 |
}
|
|
|
271 |
|
|
|
272 |
$layout = isset($config->preferences['layout']) ? $config->preferences['layout'] : '';
|
|
|
273 |
$formhtml = $this->get_data_source()->get_filter_collection()->create_form_elements('', $layout);
|
|
|
274 |
// Get downloads butttons.
|
|
|
275 |
$downloadcontent = '';
|
|
|
276 |
if ($this->supports_download() && $this->get_data_source()->get_preferences('exportdata')) {
|
|
|
277 |
$downloadoptions = [];
|
|
|
278 |
$options = [];
|
|
|
279 |
$downloadlist = '';
|
|
|
280 |
$options['sesskey'] = sesskey();
|
|
|
281 |
$options["download"] = "csv";
|
|
|
282 |
$button = $OUTPUT->single_button(new moodle_url($PAGE->url, $options), get_string("downloadcsv", 'block_dash'), 'get');
|
|
|
283 |
$downloadoptions[] = html_writer::tag('li', $button, ['class' => 'reportoption list-inline-item']);
|
|
|
284 |
|
|
|
285 |
$options["download"] = "xls";
|
|
|
286 |
$button = $OUTPUT->single_button(new moodle_url($PAGE->url, $options), get_string("downloadexcel"), 'get');
|
|
|
287 |
$downloadoptions[] = html_writer::tag('li', $button, ['class' => 'reportoption list-inline-item']);
|
|
|
288 |
|
|
|
289 |
$downloadlist .= html_writer::tag('ul', implode('', $downloadoptions), ['class' => 'list-inline inline']);
|
|
|
290 |
$downloadlist .= html_writer::tag('div', '', ['class' => 'clearfloat']);
|
|
|
291 |
$downloadcontent .= html_writer::tag('div', $downloadlist, ['class' => 'downloadreport mt-1']);
|
|
|
292 |
}
|
|
|
293 |
|
|
|
294 |
if (!is_null($templatedata['data'])) {
|
|
|
295 |
$templatedata = array_merge($templatedata, [
|
|
|
296 |
'filter_form_html' => $formhtml,
|
|
|
297 |
'downloadcontent' => $downloadcontent,
|
|
|
298 |
'supports_filtering' => $this->supports_filtering(),
|
|
|
299 |
'supports_download' => $this->supports_download(),
|
|
|
300 |
'supports_pagination' => $this->supports_pagination(),
|
|
|
301 |
'preferences' => $this->process_preferences($this->get_data_source()->get_all_preferences()),
|
|
|
302 |
]);
|
|
|
303 |
}
|
|
|
304 |
return $templatedata;
|
|
|
305 |
}
|
|
|
306 |
|
|
|
307 |
/**
|
|
|
308 |
* Map data.
|
|
|
309 |
*
|
|
|
310 |
* @param array $mapping
|
|
|
311 |
* @param data_collection_interface $datacollection
|
|
|
312 |
* @return data_collection_interface
|
|
|
313 |
*/
|
|
|
314 |
protected function map_data($mapping, data_collection_interface $datacollection) {
|
|
|
315 |
foreach ($mapping as $newname => $fieldname) {
|
|
|
316 |
if ($fieldname && !is_array($fieldname) && isset($datacollection[$fieldname])) {
|
|
|
317 |
$datacollection->add_data(new field($newname, $datacollection[$fieldname], true));
|
|
|
318 |
} else if ($fieldname && is_array($fieldname)) {
|
|
|
319 |
$value = array_map(function($field) use ($datacollection) {
|
|
|
320 |
return $datacollection[$field];
|
|
|
321 |
}, $fieldname);
|
|
|
322 |
$datacollection->add_data(new field($newname, implode(" ", $value), true));
|
|
|
323 |
}
|
|
|
324 |
}
|
|
|
325 |
return $datacollection;
|
|
|
326 |
}
|
|
|
327 |
|
|
|
328 |
/**
|
|
|
329 |
* Returns supported icons.
|
|
|
330 |
*
|
|
|
331 |
* @return array
|
|
|
332 |
*/
|
|
|
333 |
protected function get_icon_list() {
|
|
|
334 |
global $PAGE;
|
|
|
335 |
|
|
|
336 |
$icons = [];
|
|
|
337 |
|
|
|
338 |
if (isset($PAGE->theme->iconsystem)) {
|
|
|
339 |
if ($iconsystem = \core\output\icon_system::instance($PAGE->theme->iconsystem)) {
|
|
|
340 |
if ($iconsystem instanceof \core\output\icon_system_fontawesome) {
|
|
|
341 |
foreach ($iconsystem->get_icon_name_map() as $pixname => $faname) {
|
|
|
342 |
$icons[$faname] = $pixname;
|
|
|
343 |
}
|
|
|
344 |
}
|
|
|
345 |
}
|
|
|
346 |
} else if (block_dash_is_totara()) {
|
|
|
347 |
foreach (\core\output\flex_icon_helper::get_icons($PAGE->theme->name) as $iconkey => $icon) {
|
|
|
348 |
$icons[$iconkey] = $iconkey;
|
|
|
349 |
}
|
|
|
350 |
}
|
|
|
351 |
|
|
|
352 |
return $icons;
|
|
|
353 |
}
|
|
|
354 |
}
|