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 declare(strict_types=1); 18 19 namespace core_reportbuilder\local\report; 20 21 use action_menu_link; 22 use lang_string; 23 use moodle_url; 24 use pix_icon; 25 use popup_action; 26 use stdClass; 27 28 /** 29 * Class to represent a report action 30 * 31 * @package core_reportbuilder 32 * @copyright 2021 Paul Holden <paulh@moodle.com> 33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 */ 35 final class action { 36 37 /** @var moodle_url $url */ 38 protected $url; 39 40 /** @var pix_icon $icon */ 41 protected $icon; 42 43 /** @var array $attributes */ 44 protected $attributes; 45 46 /** @var bool $popup */ 47 protected $popup; 48 49 /** @var callable[] $callbacks */ 50 protected $callbacks = []; 51 52 /** @var lang_string|string $title */ 53 protected $title; 54 55 /** 56 * Create an instance of an action to be added to a report. Both the parameters of the URL, and the attributes parameter 57 * support placeholders which will be replaced with appropriate row values, e.g.: 58 * 59 * new action(new moodle_url('/', ['id' => ':id']), new pix_icon(...), ['data-id' => ':id']) 60 * 61 * Note that all expected placeholders should be added as base fields to the report 62 * 63 * @param moodle_url $url 64 * @param pix_icon $icon 65 * @param string[] $attributes Array of attributes to include in action, each will be cast to string prior to use 66 * @param bool $popup 67 * @param ?lang_string $title 68 */ 69 public function __construct( 70 moodle_url $url, 71 pix_icon $icon, 72 array $attributes = [], 73 bool $popup = false, 74 ?lang_string $title = null 75 ) { 76 $this->url = $url; 77 $this->icon = $icon; 78 $this->attributes = $attributes; 79 $this->popup = $popup; 80 // If title is not passed, check the title attribute from the icon. 81 $this->title = $title ?? $icon->attributes['title'] ?? ''; 82 } 83 84 /** 85 * Adds callback to the action. Used to verify action is available to current user, or preprocess values used in placeholders 86 * 87 * Multiple callbacks can be added. If at least one returns false then the action will not be displayed 88 * 89 * @param callable $callback 90 * @return self 91 */ 92 public function add_callback(callable $callback): self { 93 $this->callbacks[] = $callback; 94 return $this; 95 } 96 97 /** 98 * Return action menu link suitable for output, or null if the action cannot be displayed (because one of its callbacks 99 * returned false, {@see add_callback}) 100 * 101 * @param stdClass $row 102 * @return action_menu_link|null 103 */ 104 public function get_action_link(stdClass $row): ?action_menu_link { 105 106 foreach ($this->callbacks as $callback) { 107 $row = clone $row; // Clone so we don't modify the shared row inside a callback. 108 if (!$callback($row)) { 109 return null; 110 } 111 } 112 113 // Create a new moodle_url instance with our filled in placeholders for this row. 114 $url = new moodle_url( 115 $this->url->out_omit_querystring(true), 116 self::replace_placeholders($this->url->params(), $row) 117 ); 118 119 // Ensure we have a title attribute set, if one wasn't already provided. 120 if (!array_key_exists('title', $this->attributes)) { 121 $this->attributes['title'] = (string) $this->title; 122 } 123 $this->attributes['aria-label'] = $this->attributes['title']; 124 125 if ($this->popup) { 126 $this->attributes['data-action'] = 'report-action-popup'; 127 $this->attributes['data-popup-action'] = json_encode(new popup_action('click', $url)); 128 } 129 130 // Interpolate any placeholders with correct values. 131 $attributes = self::replace_placeholders($this->attributes, $row); 132 133 // Ensure title attribute isn't duplicated. 134 $title = $attributes['title']; 135 unset($attributes['title']); 136 137 return new action_menu_link($url, $this->icon, $title, null, $attributes); 138 } 139 140 /** 141 * Given an array of values, replace all placeholders with corresponding property of the given row 142 * 143 * @param string[] $values 144 * @param stdClass $row 145 * @return array 146 */ 147 private static function replace_placeholders(array $values, stdClass $row): array { 148 return array_map(static function($value) use ($row) { 149 return preg_replace_callback('/^:(?<property>.*)$/', static function(array $matches) use ($row): string { 150 return (string) ($row->{$matches['property']} ?? ''); 151 }, (string) $value); 152 }, $values); 153 } 154 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body