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\local\tool; 18 19 use tool_brickfield\manager; 20 21 /** 22 * Brickfield accessibility tool base class. 23 * 24 * All common properties and methods for all tool types. 25 * 26 * @package tool_brickfield 27 * @copyright 2020 onward: Brickfield Education Labs, www.brickfield.ie 28 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 29 */ 30 abstract class tool { 31 32 /** @var string[] All of the tools provided. */ 33 const TOOLNAMES = ['errors', 'activityresults', 'checktyperesults', 'printable', 'advanced']; 34 35 /** @var string base64 bitmap image type */ 36 const BASE64_BMP = 'data:image/bmp;base64'; 37 38 /** @var string base64 gif image type */ 39 const BASE64_GIF = 'data:image/gif;base64'; 40 41 /** @var string base64 jpg image type */ 42 const BASE64_JPG = 'data:image/jpeg;base64'; 43 44 /** @var string base64 png image type */ 45 const BASE64_PNG = 'data:image/png;base64'; 46 47 /** @var string base64 svg image type */ 48 const BASE64_SVG = 'data:image/svg+xml;base64'; 49 50 /** @var string base64 webp image type */ 51 const BASE64_WEBP = 'data:image/webp;base64'; 52 53 /** @var string base64 ico image type */ 54 const BASE64_ICO = 'data:image/x-icon;base64'; 55 56 /** @var null Generic object for data used in tool renderers/templates. */ 57 private $data = null; 58 59 /** @var filter Any filter being used for tool display. */ 60 private $filter; 61 62 /** @var string Error message if there is one. */ 63 private $errormessage = ''; 64 65 /** 66 * Get a mapping of tool shortname => class name. 67 * 68 * @return string[] 69 */ 70 protected static function get_tool_classnames(): array { 71 $tools = []; 72 73 foreach (self::TOOLNAMES as $toolname) { 74 $tools[$toolname] = "tool_brickfield\\local\\tool\\{$toolname}"; 75 } 76 77 return $tools; 78 } 79 80 /** 81 * Return an array with one of each tool instance. 82 * 83 * @return tool[] 84 */ 85 public static function build_all_accessibilitytools(): array { 86 return array_map(function($classname) { 87 return new $classname(); 88 }, self::get_tool_classnames()); 89 } 90 91 /** 92 * Get a list of formal tool names for each tool. 93 * 94 * @return string[] 95 */ 96 public static function get_tool_names(): array { 97 return array_map(function($classname) { 98 return $classname::toolname(); 99 }, self::get_tool_classnames()); 100 } 101 102 /** 103 * Provide a lowercase name identifying this plugin. Should really be the same as the directory name. 104 * @return string 105 */ 106 abstract public function pluginname(); 107 108 /** 109 * Provide a name for this tool, suitable for display on pages. 110 * @return mixed 111 */ 112 abstract public static function toolname(); 113 114 /** 115 * Provide a short name for this tool, suitable for menus and selectors. 116 * @return mixed 117 */ 118 abstract public static function toolshortname(); 119 120 /** 121 * Fetch the data for renderer / template display. Classes must implement this. 122 * @return \stdClass 123 */ 124 abstract protected function fetch_data(): \stdClass; 125 126 /** 127 * Return the data needed for the renderer. 128 * @return \stdClass 129 * @throws \coding_exception 130 */ 131 public function get_data(): \stdClass { 132 if (!$this->filter) { 133 throw new \coding_exception('Filter has not been set.'); 134 } 135 136 if (empty($this->data)) { 137 $this->data = $this->fetch_data(); 138 } 139 140 return $this->data; 141 } 142 143 /** 144 * Implementing class should set the 'valid' property when get_data is called. 145 * @return bool 146 */ 147 public function data_is_valid(): bool { 148 $data = $this->get_data(); 149 return (!empty($data->valid)); 150 } 151 152 /** 153 * Implementing class should set an error string if data is invalidated in 'get_data'; 154 * @return string 155 */ 156 public function data_error(): string { 157 if (!$this->data_is_valid()) { 158 return $this->data->error; 159 } else { 160 return ''; 161 } 162 } 163 164 /** 165 * Setter for filter property. 166 * @param filter $filter 167 * @throws \coding_exception 168 */ 169 public function set_filter(filter $filter): void { 170 if ($this->filter) { 171 throw new \coding_exception('Filter can only be set once.'); 172 } 173 174 $this->filter = $filter; 175 } 176 177 /** 178 * Getter for filter property. 179 * @return filter|null 180 */ 181 public function get_filter(): ?filter { 182 return $this->filter; 183 } 184 185 /** 186 * Returns the output target for this tool's filter. 187 * 188 * @return string 189 * @throws \coding_exception 190 */ 191 public function get_output_target() { 192 $filter = $this->get_filter(); 193 if (!$filter) { 194 throw new \coding_exception('Filter has not been set.'); 195 } 196 return $filter->target; 197 } 198 199 /** 200 * Get the HTML output for display. 201 * 202 * @return mixed 203 */ 204 public function get_output() { 205 global $PAGE; 206 207 $data = $this->get_data(); 208 $filter = $this->get_filter(); 209 $renderer = $PAGE->get_renderer('tool_brickfield', $this->pluginname()); 210 return $renderer->display($data, $filter); 211 } 212 213 /** 214 * Return the defined toolname. 215 * 216 * @return mixed 217 */ 218 public function get_toolname(): string { 219 return static::toolname(); 220 } 221 222 /** 223 * Return the defined toolshortname. 224 * 225 * @return mixed 226 */ 227 public function get_toolshortname(): string { 228 return static::toolshortname(); 229 } 230 231 /** 232 * Verify that accessibility tools can be accessed in the provided context. 233 * @param filter $filter 234 * @param \context $context 235 * @return bool 236 * @throws \coding_exception 237 * @throws \dml_exception 238 */ 239 public function can_access(filter $filter, \context $context = null): bool { 240 return $filter->can_access($context); 241 } 242 243 /** 244 * Return any defined error message. 245 * 246 * @return string 247 */ 248 public function get_error_message(): string { 249 return $this->errormessage; 250 } 251 252 /** 253 * Get module label for display 254 * @param string $modulename 255 * @return string 256 * @throws \coding_exception 257 */ 258 public static function get_module_label(string $modulename): string { 259 if (get_string_manager()->string_exists('pluginname', $modulename)) { 260 $modulename = get_string('pluginname', $modulename); 261 } else { 262 $modulename = get_string($modulename, manager::PLUGINNAME); 263 } 264 return($modulename); 265 } 266 267 /** 268 * Get instance name for display 269 * @param string $component 270 * @param string $table 271 * @param int $cmid 272 * @param int $courseid 273 * @param int $categoryid 274 * @return string 275 */ 276 public static function get_instance_name(string $component, string $table, ?int $cmid, ?int $courseid, 277 ?int $categoryid): string { 278 global $DB; 279 280 $instancename = ''; 281 if (empty($component)) { 282 return $instancename; 283 } 284 if ($component == 'core_course') { 285 if (($table == 'course_categories') && ($categoryid != 0) && ($categoryid != null)) { 286 $instancename = $DB->get_field($table, 'name', ['id' => $categoryid]); 287 return get_string('category') . ' - ' . $instancename; 288 } 289 if (($courseid == 0) || ($courseid == null)) { 290 return $instancename; 291 } 292 $thiscourse = get_fast_modinfo($courseid)->get_course(); 293 $instancename = $thiscourse->shortname; 294 } else if ($component == 'core_question') { 295 $instancename = get_string('questions', 'question'); 296 } else { 297 if (($cmid == 0) || ($cmid == null)) { 298 return $instancename; 299 } 300 $cm = get_fast_modinfo($courseid)->cms[$cmid]; 301 $instancename = $cm->name; 302 } 303 $instancename = static::get_module_label($component).' - '.$instancename; 304 return($instancename); 305 } 306 307 /** 308 * Provide arguments required for the toplevel page, using any provided filter. 309 * @param filter|null $filter 310 * @return array 311 */ 312 public static function toplevel_arguments(filter $filter = null): array { 313 if ($filter !== null) { 314 return ['courseid' => $filter->courseid, 'categoryid' => $filter->categoryid]; 315 } else { 316 return []; 317 } 318 } 319 320 /** 321 * Override this to return any tool specific perpage limits. 322 * @param int $perpage 323 * @return int 324 */ 325 public function perpage_limits(int $perpage): int { 326 return $perpage; 327 } 328 329 /** 330 * Return array of base64 image formats. 331 * @return array 332 */ 333 public static function base64_img_array(): array { 334 $base64 = []; 335 $base64[] = self::BASE64_BMP; 336 $base64[] = self::BASE64_GIF; 337 $base64[] = self::BASE64_JPG; 338 $base64[] = self::BASE64_PNG; 339 $base64[] = self::BASE64_SVG; 340 $base64[] = self::BASE64_WEBP; 341 $base64[] = self::BASE64_ICO; 342 return $base64; 343 } 344 345 /** 346 * Detects if htmlcode contains base64 img data, for HTML display, such as errors page. 347 * @param string $htmlcode 348 * @return boolean 349 */ 350 public static function base64_img_detected(string $htmlcode): bool { 351 $detected = false; 352 353 // Grab defined base64 img array. 354 $base64 = self::base64_img_array(); 355 foreach ($base64 as $type) { 356 // Need to detect this within an img tag. 357 $pos = stripos($htmlcode, '<img src="'.$type); 358 if ($pos !== false) { 359 $detected = true; 360 return $detected; 361 } 362 } 363 return $detected; 364 } 365 366 /** 367 * Truncate base64-containing htmlcode for HTML display, such as errors page. 368 * @param string $htmlcode 369 * @return string 370 */ 371 public static function truncate_base64(string $htmlcode): string { 372 $newhtmlcode = ''; 373 // Parse HTML by " characters. 374 $sections = explode('"', $htmlcode); 375 $base64 = self::base64_img_array(); 376 foreach ($sections as $section) { 377 foreach ($base64 as $type) { 378 $pos = stripos($section, $type); 379 if ($pos !== false) { 380 $section = substr($section, 0, $pos + strlen($type)).'...'; 381 } 382 } 383 $newhtmlcode .= $section.'"'; 384 } 385 return $newhtmlcode; 386 } 387 388 /** 389 * Return the correct language string for the provided check. 390 * 391 * @param string $check 392 * @return string 393 */ 394 public static function get_check_description(string $check): string { 395 return get_string('checkdesc:' . str_replace('_', '', $check), manager::PLUGINNAME); 396 } 397 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body