Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]
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 namespace tool_brickfield\output\printable; 18 19 use tool_brickfield\local\tool\bfpdf; 20 use core\chart_bar; 21 use core\chart_pie; 22 use core\chart_series; 23 use tool_brickfield\accessibility; 24 use tool_brickfield\area_base; 25 use tool_brickfield\local\tool\filter; 26 use tool_brickfield\manager; 27 28 /** 29 * tool_brickfield/printable renderer 30 * 31 * @package tool_brickfield 32 * @copyright 2020 onward: Brickfield Education Labs, https://www.brickfield.ie 33 * @author Mike Churchward 34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 */ 36 class renderer extends \tool_brickfield\output\renderer { 37 /** 38 * Render the page containing the Printable report. 39 * 40 * @param \stdClass $data Report data. 41 * @param filter $filter Display filters. 42 * @return String HTML showing charts. 43 * @throws \coding_exception 44 * @throws \dml_exception 45 * @throws \moodle_exception 46 */ 47 public function display(\stdClass $data, filter $filter): string { 48 $css = ''; 49 50 // Page data. 51 $out = ''; 52 53 if (empty($filter->target)) { 54 $linkname = get_string('printable:downloadpdf', 'tool_brickfield'); 55 $link = new \moodle_url( 56 accessibility::get_plugin_url(), 57 [ 58 'tab' => 'printable', 59 'courseid' => $filter->courseid, 60 'target' => 'pdf', 61 ] 62 ); 63 $htmlicon = new \pix_icon('t/print', $linkname); 64 $class = 'tool_brickfield_floatprinticon'; 65 $printlink = $this->action_link($link, $linkname, null, ['class' => $class, 'title' => $linkname], $htmlicon); 66 } 67 68 $out .= \html_writer::tag('h3', accessibility::get_title($filter, $data->countdata)); 69 $out .= !empty($printlink) ? $printlink : ''; 70 71 $div1 = \html_writer::div($this->pix_icon('f/award', 72 get_string('totalactivities', manager::PLUGINNAME), manager::PLUGINNAME). 73 get_string('totalactivitiescount', manager::PLUGINNAME, $data->combodata['total']), '', 74 ['class' => 'col-sm-3'.$css]); 75 $div2 = \html_writer::div($this->pix_icon('f/done2', 76 get_string('passed', manager::PLUGINNAME), manager::PLUGINNAME). 77 get_string('passedcount', manager::PLUGINNAME, $data->combodata['passed']), '', 78 ['class' => 'col-sm-3'.$css]); 79 $div3 = \html_writer::div($this->pix_icon('f/error', 80 get_string('failed', manager::PLUGINNAME), manager::PLUGINNAME). 81 get_string('failedcount', manager::PLUGINNAME, $data->combodata['failed']), '', 82 ['class' => 'col-sm-3'.$css]); 83 $out .= \html_writer::div($div1.$div2.$div3, '', ['id' => 'rowa', 'class' => 'row h4']); 84 85 $out .= \html_writer::div(' '); // Padding row. 86 $str1 = \html_writer::tag('h4', get_string('toperrors', manager::PLUGINNAME)); 87 88 $table = new \html_table(); 89 $table->head = [ 90 get_string('tblcheck', manager::PLUGINNAME), 91 get_string('count', manager::PLUGINNAME), 92 ]; 93 $table->size = ['80%', '20%']; 94 $table->align = ['left', 'center']; 95 $data->checkcountdata = !empty($data->checkcountdata) ? $data->checkcountdata : []; 96 foreach ($data->checkcountdata as $key => $value) { 97 if ($value->checkcount > 0) { 98 $table->data[] = [$value->checkname, $value->checkcount]; 99 } 100 } 101 102 if (count($data->checkcountdata) > 0) { 103 $str1 .= \html_writer::table($table, true); 104 } else { 105 $str1 .= \html_writer::tag('p', get_string('noerrorsfound', manager::PLUGINNAME)); 106 } 107 $out .= \html_writer::start_div('row', ['id' => 'row2']); 108 $out .= \html_writer::div($str1, '', ['class' => 'col-sm-4']); 109 110 $str2 = \html_writer::tag('h4', get_string('toptargets', manager::PLUGINNAME)); 111 $table = new \html_table(); 112 $table->head = [ 113 get_string('tbltarget', manager::PLUGINNAME), 114 get_string('count', manager::PLUGINNAME), 115 ]; 116 $table->size = ['80%', '20%']; 117 $table->align = ['left', 'center']; 118 $data->toptargetdata = !empty($data->toptargetdata) ? $data->toptargetdata : []; 119 $table->data = $data->toptargetdata; 120 if (count($data->toptargetdata) > 0) { 121 $str2 .= \html_writer::table($table, true); 122 } else { 123 $str2 .= \html_writer::tag('p', get_string('noerrorsfound', manager::PLUGINNAME)); 124 } 125 $out .= \html_writer::div($str2, '', ['class' => 'col-sm-4']); 126 127 $str3 = \html_writer::tag('h4', get_string('taberrors', manager::PLUGINNAME)); 128 $table = new \html_table(); 129 $table->head = [ 130 get_string('checktype', manager::PLUGINNAME), 131 get_string('count', manager::PLUGINNAME), 132 ]; 133 $table->size = ['80%', '20%']; 134 $table->align = ['left', 'center']; 135 foreach ($data->groupdata as $key => $group) { 136 $checkgroup = area_base::checkgroup_name($key); 137 $tmplabel = get_string('checktype:' . $checkgroup, manager::PLUGINNAME); 138 $icon = $this->pix_icon('f/' . $checkgroup, $tmplabel, manager::PLUGINNAME); 139 $table->data[] = [get_string('checktype:' . $checkgroup, manager::PLUGINNAME), $group->errorinstances]; 140 } 141 $str3 .= \html_writer::table($table, true); 142 $out .= \html_writer::div($str3, '', ['class' => 'col-sm-4']); 143 144 $out .= \html_writer::end_div(); // End row2. 145 146 $out .= \html_writer::start_div('row', ['id' => 'row3']); 147 148 foreach ($data->combotardata as $key => &$combotar) { 149 $combotar['passed'] = $combotar['total'] - $combotar['failed']; 150 $combos[] = $combotar['total'] - $combotar['failed']; 151 $combosf[] = $combotar['failed']; 152 } 153 154 $str4 = \html_writer::tag('h4', get_string('targetratio', manager::PLUGINNAME)); 155 $table = new \html_table(); 156 $table->head = [ 157 get_string('tbltarget', manager::PLUGINNAME), 158 get_string('passed', manager::PLUGINNAME), 159 get_string('failed', manager::PLUGINNAME), 160 get_string('total') 161 ]; 162 163 foreach ($data->combotardata as $tar => $tarvalue) { 164 $table->data[] = [$data->tarlabels[$tar], 165 $tarvalue['passed'], $tarvalue['failed'], $tarvalue['total']]; 166 } 167 168 $table->size = ['40%', '20%', '20%', '20%']; 169 $table->align = ['left', 'center', 'center', 'center']; 170 $str4 .= \html_writer::table($table, true); 171 $out .= \html_writer::div($str4, '', ['class' => 'col-sm-4']); 172 173 $str5 = \html_writer::tag('h4', get_string('titleerrorscount', manager::PLUGINNAME, $data->errordetailscount)); 174 $table = new \html_table(); 175 $table->head = [ 176 get_string('tbltarget', manager::PLUGINNAME), 177 get_string('tblcheck', manager::PLUGINNAME), 178 get_string('tblline', manager::PLUGINNAME), 179 get_string('tblhtmlcode', manager::PLUGINNAME) 180 ]; 181 $data->errordata = !empty($data->errordata) ? $data->errordata : []; 182 foreach ($data->errordata as $err) { 183 $err->htmlcode = htmlentities($err->htmlcode); 184 $row = [$data->tarlabels[$err->component], $err->shortname, $err->errline, $err->htmlcode]; 185 $table->data[] = $row; 186 } 187 188 $table->size = ['10%', '25%', '5%', '60%']; 189 if (count($data->errordata) > 0) { 190 $str5 .= \html_writer::table($table, true); 191 } else { 192 $str5 .= \html_writer::tag('p', get_string('noerrorsfound', manager::PLUGINNAME)); 193 } 194 $out .= \html_writer::div($str5, '', ['class' => 'col-sm-8']); 195 196 $out .= \html_writer::end_div(); // End row3. 197 198 if ($filter->target == 'pdf') { 199 // Converting divs to spans for better PDF display. 200 $out = str_replace(['<div>', '</div>'], ['<span>', '</span>'], $out); 201 } 202 203 return $out; 204 } 205 206 /** 207 * Return the path to use for PDF images. 208 * 209 * @return string 210 */ 211 private function image_path(): string { 212 global $CFG; 213 return $CFG->wwwroot . '/admin/tool/brickfield/pix/pdf/'; 214 } 215 216 /** 217 * Renders the accessability report using the pdflib. 218 * 219 * @param \stdClass $data Report data. 220 * @param filter $filter Display filters. 221 * @throws \coding_exception 222 * @throws \dml_exception 223 * @throws \moodle_exception 224 * @return void 225 */ 226 public function pdf_renderer(\stdClass $data, filter $filter) { 227 $pdf = new bfpdf(); 228 229 $pdf->setFooterFont(Array('Helvetica', '', 10)); 230 $pdf->setPrintHeader(false); 231 $pdf->SetCreator(PDF_CREATOR); 232 $pdf->SetAuthor('Brickfield Accessibility Report'); 233 $pdf->SetTitle('Brickfield Accessibility Report'); 234 $pdf->SetFont('Helvetica'); 235 236 // Set default monospaced font. 237 $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); 238 239 // Set margins. 240 $pdf->SetMargins(20, 20, 20, 100); 241 242 $pdf->AddPage('P'); 243 $errorreporting = error_reporting(0); 244 245 // Get current date for current user. 246 $date = new \DateTime("now", \core_date::get_user_timezone_object()); 247 $pdf->SetLineWidth(0.0); 248 249 $html = ' 250 <h1>' . get_string('accessibilityreport', manager::PLUGINNAME) . '</h1> 251 <h2>'. accessibility::get_title($filter, $data->countdata) .'</h2> 252 <p>' . userdate($date->getTimestamp()) . '</p> 253 <table cellspacing="0" cellpadding="1"> 254 <tr> 255 <td> 256 <img src="' . $this->image_path() . 'tachometer-alt-solid.svg" width="15" height="15">' . 257 ' <td style="line-height: 10px;"> ' . 258 get_string('totalactivitiescount', manager::PLUGINNAME, $data->combodata['total']) . 259 '</td></td> 260 <td> 261 <img src="' . $this->image_path() . 'check-square-regular.svg" width="15" height="15">' . 262 ' <td style="line-height: 10px;"> ' . 263 get_string('passedcount', manager::PLUGINNAME, $data->combodata['passed']) . 264 '</td></td> 265 <td> 266 <img src="' . $this->image_path() . 'times-circle-regular.svg" width="15" height="15">' . 267 ' <td style="line-height: 10px;"> ' . 268 get_string('failedcount', manager::PLUGINNAME, $data->combodata['failed']) . 269 '</td></td> 270 </tr> 271 </table>'; 272 273 $pdf->writeHTML($html); 274 275 if (!empty($data->checkcountdata)) { 276 $pdf->writeHTML($this->get_errors_table($data)); 277 278 $tablegroup = '<table><tr> 279 <td width="45%">'. $this->get_group_table($data) . '</td> 280 <td width="10%"></td> 281 <td width="45%">'. $this->get_inaccessible_table($data) . '</td> 282 </tr></table>'; 283 284 $pdf->writeHTML($tablegroup); 285 286 $pdf->AddPage('P'); 287 } else { 288 $pdf->writeHTML('<div>'.get_string('noerrorsfound', manager::PLUGINNAME).'</div><div></div>'); 289 } 290 291 $pdf->writeHTML($this->get_ratio_table($data)); 292 293 // Output the pdf. 294 @$pdf->Output(get_string('pdf:filename', 'tool_brickfield', $filter->courseid). 295 '_' . userdate($date->getTimestamp(), '%Y_%m_%d') . '.pdf', 'D'); 296 error_reporting($errorreporting); 297 298 } 299 300 /** 301 * Builds the HTML for a styled table used in the pdf report. 302 * 303 * @param array $headers The headers of the table. 304 * @param array $data The table data. 305 * @param string $title The title of the table. 306 * @param array $widths The widths of the table columns. 307 * @return string The HTML code of the table. 308 */ 309 public function render_table(array $headers, array $data, string $title, array $widths): string { 310 $numheaders = count($headers); 311 $html = ''; 312 $html .= '<table cellspacing="0" cellpadding="5" style="background-color: #ffffff;">'; 313 $html .= '<tr><td style="border-bottom:.1 solid #333333;" colspan="'.$numheaders.'"><h3>'.$title.'</h3></td></tr>'; 314 $html .= '<tr>'; 315 316 for ($i = 0; $i < $numheaders; ++$i) { 317 $align = $i > 0 ? "center" : "left"; 318 $html .= '<th style="text-align:'.$align.';" width="'.$widths[$i].'">'; 319 $html .= '<b>'.$headers[$i].'</b>'; 320 $html .= '</th>'; 321 } 322 $html .= '</tr>'; 323 $j = 1; 324 foreach ($data as $row) { 325 ++$j; 326 $color = $j % 2 == 1 ? "#FFFFFF" : "#F2F2F2"; 327 $html .= '<tr border ="1" style="background-color:'.$color.';">'; 328 for ($i = 0; $i < $numheaders; ++$i) { 329 $align = $i > 0 ? "center" : "left"; 330 $html .= '<td width="'.$widths[$i].'" style="text-align:'.$align.';, background-color:'.$color.';">'; 331 $html .= $row[$i]; 332 $html .= '</td>'; 333 } 334 $html .= '</tr>'; 335 } 336 $html .= '</table>'; 337 return $html; 338 } 339 340 /** 341 * Gets the Activity Pass Ratio table. 342 * 343 * @param \stdClass $data Report data. 344 * @return string The HTML code of the table. 345 */ 346 public function get_ratio_table(\stdClass $data): string { 347 $headers = [ 348 get_string('tbltarget', manager::PLUGINNAME), 349 get_string('passed', manager::PLUGINNAME), 350 get_string('failed', manager::PLUGINNAME), 351 get_string('total') 352 ]; 353 354 $tabledata = []; 355 foreach ($data->combotardata as $tar => $tarvalue) { 356 $tabledata[] = [ 357 $data->tarlabels[$tar], 358 $tarvalue['total'] - $tarvalue['failed'], 359 $tarvalue['failed'], 360 $tarvalue['total'] 361 ]; 362 } 363 364 return $this->render_table( 365 $headers, 366 $tabledata, 367 get_string('targetratio', manager::PLUGINNAME), 368 ["40%", "20%", "20%", "20%"] 369 ); 370 } 371 372 /** 373 * Gets the Check Errors table. 374 * 375 * @param \stdClass $data Report data. 376 * @return string The HTML code of the table. 377 */ 378 public function get_group_table(\stdClass $data): string { 379 $headers = [ 380 get_string('checktype', manager::PLUGINNAME), 381 get_string('count', manager::PLUGINNAME), 382 ]; 383 384 $tabledata = []; 385 386 // Numbers are constants from \tool_brickfield\area_base::checkgroup. 387 $icons = [ 388 area_base::CHECKGROUP_IMAGE => $this->image_path() . 'image-regular.svg', 389 area_base::CHECKGROUP_LAYOUT => $this->image_path() . 'th-large-solid.svg', 390 area_base::CHECKGROUP_LINK => $this->image_path() . 'link.png', 391 area_base::CHECKGROUP_MEDIA => $this->image_path() . 'play-circle-regular.svg', 392 area_base::CHECKGROUP_TABLE => $this->image_path() . 'table-solid.svg', 393 area_base::CHECKGROUP_TEXT => $this->image_path() . 'font-solid.svg', 394 ]; 395 396 foreach ($data->groupdata as $key => $group) { 397 $checkgroup = area_base::checkgroup_name($key); 398 $icon = $icons[$key]; 399 $tabledata[] = ['<img src="'.$icon.'" width="15" height="15">' . ' ' .' <td style="line-height: 10px;"> '. 400 get_string('checktype:' . $checkgroup, manager::PLUGINNAME).'</td>', $group->errorinstances]; 401 } 402 403 return $this->render_table( 404 $headers, 405 $tabledata, 406 get_string('taberrors', manager::PLUGINNAME), 407 ["70%", "30%"] 408 ); 409 } 410 411 /** 412 * Gets the Failed Activities table. 413 * 414 * @param \stdClass $data Report data. 415 * @return string The HTML code of the table. 416 */ 417 public function get_inaccessible_table(\stdClass $data): string { 418 $headers = [get_string('tbltarget', manager::PLUGINNAME), 419 get_string('count', manager::PLUGINNAME)]; 420 421 $tabledata = []; 422 423 foreach ($data->toptargetdata as $key => $value) { 424 if ($value->errorsum > 0) { 425 $tabledata[] = [$value->component, $value->errorsum]; 426 } 427 } 428 return $this->render_table( 429 $headers, 430 $tabledata, 431 get_string('toptargets', manager::PLUGINNAME), 432 ["70%", "30%"] 433 ); 434 } 435 436 /** 437 * Gets the Top Errors table. 438 * 439 * @param \stdClass $data Report data. 440 * @return string The HTML code of the table. 441 */ 442 public function get_errors_table(\stdClass $data): string { 443 $headers = [get_string('tblcheck', manager::PLUGINNAME), get_string('count', manager::PLUGINNAME)]; 444 $tabledata = []; 445 446 $data->checkcountdata = !empty($data->checkcountdata) ? $data->checkcountdata : []; 447 448 foreach ($data->checkcountdata as $value) { 449 if ($value->checkcount > 0) { 450 $tabledata[] = [$value->checkname, $value->checkcount]; 451 } 452 } 453 return $this->render_table($headers, $tabledata, get_string('toperrors', manager::PLUGINNAME), ["80%", "20%"]); 454 } 455 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body