PageRenderTime 46ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/reportbuilder/classes/local/audiences/base.php

https://bitbucket.org/moodle/moodle
PHP | 273 lines | 203 code | 13 blank | 57 comment | 2 complexity | a4eb34977d575d446b0abba1aa68ed5d MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, BSD-3-Clause, MIT, GPL-3.0
  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. declare(strict_types=1);
  17. namespace core_reportbuilder\local\audiences;
  18. use core_plugin_manager;
  19. use MoodleQuickForm;
  20. use stdClass;
  21. use core\output\notification;
  22. use core_reportbuilder\local\models\audience;
  23. use core_reportbuilder\report_access_exception;
  24. /**
  25. * Audience base class
  26. *
  27. * @package core_reportbuilder
  28. * @copyright 2021 David Matamoros <davidmc@moodle.com>
  29. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30. */
  31. abstract class base {
  32. /** @var int Maximim number of multi-select elements to show in description, before appending "plus X more" */
  33. private const MULTI_SELECT_LIMIT = 5;
  34. /** @var audience The persistent object associated with this audience */
  35. protected $audience;
  36. /**
  37. * Protected constructor, please use the static instance method.
  38. */
  39. protected function __construct() {
  40. }
  41. /**
  42. * Loads an existing instance of audience with persistent
  43. *
  44. * @param int $id
  45. * @param null|stdClass $record
  46. * @return self|null
  47. */
  48. final public static function instance(int $id = 0, ?stdClass $record = null): ?self {
  49. $persistent = new audience($id, $record);
  50. // Needed for get_audience_types() method.
  51. if (!$classname = $persistent->get('classname')) {
  52. // Use the called class name.
  53. $classname = get_called_class();
  54. $persistent->set('classname', $classname);
  55. }
  56. // Check if audience type class still exists in the system.
  57. if (!class_exists($classname)) {
  58. return null;
  59. }
  60. $instance = new $classname();
  61. $instance->audience = $persistent;
  62. return $instance;
  63. }
  64. /**
  65. * Creates a new audience and saves it to database
  66. *
  67. * @param int $reportid
  68. * @param array $configdata
  69. * @return self
  70. */
  71. final public static function create(int $reportid, array $configdata): self {
  72. $record = new stdClass();
  73. $record->reportid = $reportid;
  74. $record->classname = get_called_class();
  75. $record->configdata = json_encode($configdata);
  76. $instance = self::instance(0, $record);
  77. $instance->audience->save();
  78. return $instance;
  79. }
  80. /**
  81. * Helps to build SQL to retrieve users that matches the current audience
  82. *
  83. * Implementations must use api::generate_alias() for table/column aliases
  84. * and api::generate_param_name() for named parameters
  85. *
  86. * @param string $usertablealias
  87. * @return array array of three elements [$join, $where, $params]
  88. */
  89. abstract public function get_sql(string $usertablealias): array;
  90. /**
  91. * Returns string for audience category.
  92. *
  93. * @return string
  94. */
  95. final public function get_category(): string {
  96. [$component] = explode('\\', get_class($this));
  97. if ($plugininfo = core_plugin_manager::instance()->get_plugin_info($component)) {
  98. return $plugininfo->displayname;
  99. }
  100. return get_string('site');
  101. }
  102. /**
  103. * If the current user is able to add this audience type
  104. *
  105. * @return bool
  106. */
  107. abstract public function user_can_add(): bool;
  108. /**
  109. * If the current user is able to edit this audience type
  110. *
  111. * @return bool
  112. */
  113. abstract public function user_can_edit(): bool;
  114. /**
  115. * If the current user is able to use this audience type
  116. *
  117. * This method needs to return true if audience type is available to user for
  118. * reasons other than permission check, which is done in {@see user_can_add}.
  119. * (e.g. user can add cohort audience type only if there is at least one cohort
  120. * they can access).
  121. *
  122. * @return bool
  123. */
  124. public function is_available(): bool {
  125. return true;
  126. }
  127. /**
  128. * Return user friendly name of the audience type
  129. *
  130. * @return string
  131. */
  132. abstract public function get_name(): string;
  133. /**
  134. * Return the description of this audience type
  135. *
  136. * @return string
  137. */
  138. abstract public function get_description(): string;
  139. /**
  140. * Helper to format descriptions for audience types that may contain many selected elements, limiting number show according
  141. * to {@see MULTI_SELECT_LIMIT} constant value
  142. *
  143. * @param array $elements
  144. * @return string
  145. */
  146. protected function format_description_for_multiselect(array $elements): string {
  147. global $OUTPUT;
  148. // Warn user if there are no elements (because they may no longer exist).
  149. $elementcount = count($elements);
  150. if ($elementcount === 0) {
  151. $notification = new notification(get_string('nothingtodisplay'), notification::NOTIFY_WARNING);
  152. return $OUTPUT->render($notification);
  153. }
  154. $listseparator = get_string('listsep', 'langconfig') . ' ';
  155. if ($elementcount > self::MULTI_SELECT_LIMIT) {
  156. $elements = array_slice($elements, 0, self::MULTI_SELECT_LIMIT);
  157. // Append overflow element.
  158. $elementoverflow = $elementcount - self::MULTI_SELECT_LIMIT;
  159. $params = [
  160. 'elements' => implode($listseparator, $elements),
  161. 'morecount' => $elementoverflow,
  162. ];
  163. $description = get_string('audiencemultiselectpostfix', 'core_reportbuilder', $params);
  164. } else {
  165. $description = implode($listseparator, $elements);
  166. }
  167. return $description;
  168. }
  169. /**
  170. * Adds audience-specific form elements
  171. *
  172. * @param MoodleQuickForm $mform The form to add elements to
  173. */
  174. abstract public function get_config_form(MoodleQuickForm $mform): void;
  175. /**
  176. * Validates the configform of the condition.
  177. *
  178. * @param array $data Data from the form
  179. * @return array Array with errors for each element
  180. */
  181. public function validate_config_form(array $data): array {
  182. return [];
  183. }
  184. /**
  185. * Returns configdata as an associative array
  186. *
  187. * @return array decoded configdata
  188. */
  189. final public function get_configdata(): array {
  190. return json_decode($this->audience->get('configdata'), true);
  191. }
  192. /**
  193. * Update configdata in audience persistent
  194. *
  195. * @param array $configdata
  196. */
  197. final public function update_configdata(array $configdata): void {
  198. $this->audience->set('configdata', json_encode($configdata));
  199. $this->audience->save();
  200. }
  201. /**
  202. * Returns $configdata from form data suitable for use in DB record.
  203. *
  204. * @param stdClass $data data obtained from $mform->get_data()
  205. * @return array $configdata
  206. */
  207. final public static function retrieve_configdata(stdClass $data): array {
  208. $configdata = (array) $data;
  209. $invalidkeys = array_fill_keys(['id', 'reportid', 'classname'], '');
  210. return array_diff_key($configdata, $invalidkeys);
  211. }
  212. /**
  213. * Return audience persistent.
  214. *
  215. * @return audience
  216. */
  217. public function get_persistent(): audience {
  218. return $this->audience;
  219. }
  220. /**
  221. * Require current user is able to add this audience type
  222. *
  223. * @throws report_access_exception
  224. */
  225. final public function require_user_can_add(): void {
  226. if (!$this->user_can_add()) {
  227. throw new report_access_exception('errorreportedit');
  228. }
  229. }
  230. /**
  231. * Require current user is able to edit this audience type
  232. *
  233. * @throws report_access_exception
  234. */
  235. final public function require_user_can_edit(): void {
  236. if (!$this->user_can_edit()) {
  237. throw new report_access_exception('errorreportedit');
  238. }
  239. }
  240. }