Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 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 declare(strict_types=1); 18 19 namespace core_reportbuilder\local\helpers; 20 21 use cache; 22 use core_collator; 23 use core_component; 24 use core_plugin_manager; 25 use core_reportbuilder\local\audiences\base; 26 use core_reportbuilder\local\models\audience as audience_model; 27 28 /** 29 * Class containing report audience helper methods 30 * 31 * @package core_reportbuilder 32 * @copyright 2021 David Matamoros <davidmc@moodle.com> 33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 */ 35 class audience { 36 37 /** 38 * Return audience instances for a given report. Note that any records pointing to invalid audience types will be excluded 39 * 40 * @param int $reportid 41 * @return base[] 42 */ 43 public static function get_base_records(int $reportid): array { 44 $records = audience_model::get_records(['reportid' => $reportid], 'id'); 45 46 $instances = array_map(static function(audience_model $audience): ?base { 47 return base::instance(0, $audience->to_record()); 48 }, $records); 49 50 // Filter and remove null elements (invalid audience types). 51 return array_filter($instances); 52 } 53 54 /** 55 * Returns list of reports that the specified user can access. Note this is potentially very expensive to calculate if a 56 * site has lots of reports, with lots of audiences, so we cache the result for the duration of the users session 57 * 58 * @param int|null $userid User ID to check, or the current user if omitted 59 * @return array 60 */ 61 public static function get_allowed_reports(?int $userid = null): array { 62 global $USER, $DB; 63 64 $userid = $userid ?: (int) $USER->id; 65 66 // Prepare cache, if we previously stored the users allowed reports then return that. 67 $cache = cache::make('core', 'reportbuilder_allowed_reports'); 68 $cachedreports = $cache->get($userid); 69 if ($cachedreports !== false) { 70 return $cachedreports; 71 } 72 73 $allowedreports = []; 74 $reportaudiences = []; 75 76 // Retrieve all audiences and group them by report for convenience. 77 $audiences = audience_model::get_records(); 78 foreach ($audiences as $audience) { 79 $reportaudiences[$audience->get('reportid')][] = $audience; 80 } 81 82 foreach ($reportaudiences as $reportid => $audiences) { 83 84 // Generate audience SQL based on those for the current report. 85 [$wheres, $params] = self::user_audience_sql($audiences); 86 $allwheres = implode(' OR ', $wheres); 87 88 $paramuserid = database::generate_param_name(); 89 $params[$paramuserid] = $userid; 90 91 $sql = "SELECT DISTINCT(u.id) 92 FROM {user} u 93 WHERE ({$allwheres}) 94 AND u.id = :{$paramuserid}"; 95 96 // If we have a matching record, user can view the report. 97 if ($DB->record_exists_sql($sql, $params)) { 98 $allowedreports[] = $reportid; 99 } 100 } 101 102 // Store users allowed reports in cache. 103 $cache->set($userid, $allowedreports); 104 105 return $allowedreports; 106 } 107 108 /** 109 * Purge the audience cache of allowed reports 110 */ 111 public static function purge_caches(): void { 112 cache::make('core', 'reportbuilder_allowed_reports')->purge(); 113 } 114 115 /** 116 * Generate SQL select clause and params for selecting reports specified user can access 117 * 118 * @param string $reporttablealias 119 * @param int|null $userid User ID to check, or the current user if omitted 120 * @return array 121 */ 122 public static function user_reports_list_sql(string $reporttablealias, ?int $userid = null): array { 123 global $DB; 124 125 $allowedreports = self::get_allowed_reports($userid); 126 127 if (empty($allowedreports)) { 128 return ['1=0', []]; 129 } 130 131 // Get all sql audiences. 132 $prefix = database::generate_param_name() . '_'; 133 [$select, $params] = $DB->get_in_or_equal($allowedreports, SQL_PARAMS_NAMED, $prefix); 134 $sql = "{$reporttablealias}.id {$select}"; 135 136 return [$sql, $params]; 137 } 138 139 /** 140 * Return list of report ID's specified user can access 141 * 142 * @param int|null $userid User ID to check, or the current user if omitted 143 * @return int[] 144 */ 145 public static function user_reports_list(?int $userid = null): array { 146 global $DB; 147 148 [$select, $params] = self::user_reports_list_sql('rb', $userid); 149 $sql = "SELECT rb.id 150 FROM {reportbuilder_report} rb 151 WHERE {$select}"; 152 153 return $DB->get_fieldset_sql($sql, $params); 154 } 155 156 /** 157 * Return appropriate list of where clauses and params for given audiences 158 * 159 * @param audience_model[] $audiences 160 * @param string $usertablealias 161 * @return array[] [$wheres, $params] 162 */ 163 public static function user_audience_sql(array $audiences, string $usertablealias = 'u'): array { 164 $wheres = $params = []; 165 166 foreach ($audiences as $audience) { 167 if ($instance = base::instance(0, $audience->to_record())) { 168 $instancetablealias = database::generate_alias(); 169 [$instancejoin, $instancewhere, $instanceparams] = $instance->get_sql($instancetablealias); 170 171 $wheres[] = "{$usertablealias}.id IN ( 172 SELECT {$instancetablealias}.id 173 FROM {user} {$instancetablealias} 174 {$instancejoin} 175 WHERE {$instancewhere} 176 )"; 177 $params += $instanceparams; 178 } 179 } 180 181 return [$wheres, $params]; 182 } 183 184 /** 185 * Returns the list of audiences types in the system. 186 * 187 * @return array 188 */ 189 private static function get_audience_types(): array { 190 $sources = []; 191 192 $audiences = core_component::get_component_classes_in_namespace(null, 'reportbuilder\\audience'); 193 foreach ($audiences as $class => $path) { 194 $audienceclass = $class::instance(); 195 if (is_subclass_of($class, base::class) && $audienceclass->user_can_add()) { 196 [$component] = explode('\\', $class); 197 198 if ($plugininfo = core_plugin_manager::instance()->get_plugin_info($component)) { 199 $componentname = $plugininfo->displayname; 200 } else { 201 $componentname = get_string('site'); 202 } 203 204 $sources[$componentname][$class] = $audienceclass->get_name(); 205 } 206 } 207 208 return $sources; 209 } 210 211 /** 212 * Get all the audiences types the current user can add to, organised by categories. 213 * 214 * @return array 215 */ 216 public static function get_all_audiences_menu_types(): array { 217 $menucardsarray = []; 218 $notavailablestr = get_string('notavailable', 'moodle'); 219 220 $audiencetypes = self::get_audience_types(); 221 $audiencetypeindex = 0; 222 foreach ($audiencetypes as $categoryname => $audience) { 223 $menucards = [ 224 'name' => $categoryname, 225 'key' => 'index' . ++$audiencetypeindex, 226 ]; 227 228 foreach ($audience as $classname => $name) { 229 $class = $classname::instance(); 230 $title = $class->is_available() ? get_string('addaudience', 'core_reportbuilder', $class->get_name()) : 231 $notavailablestr; 232 $menucard['title'] = $title; 233 $menucard['name'] = $class->get_name(); 234 $menucard['disabled'] = !$class->is_available(); 235 $menucard['identifier'] = get_class($class); 236 $menucard['action'] = 'add-audience'; 237 $menucards['items'][] = $menucard; 238 } 239 240 // Order audience types on each category alphabetically. 241 core_collator::asort_array_of_arrays_by_key($menucards['items'], 'name'); 242 $menucards['items'] = array_values($menucards['items']); 243 244 $menucardsarray[] = $menucards; 245 } 246 247 return $menucardsarray; 248 } 249 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body