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 /** 18 * Representation of a prediction. 19 * 20 * @package core_analytics 21 * @copyright 2017 David Monllao {@link http://www.davidmonllao.com} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace core_analytics; 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 /** 30 * Representation of a prediction. 31 * 32 * @package core_analytics 33 * @copyright 2017 David Monllao {@link http://www.davidmonllao.com} 34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 */ 36 class prediction { 37 38 /** 39 * Prediction details (one of the default prediction actions) 40 */ 41 const ACTION_PREDICTION_DETAILS = 'predictiondetails'; 42 43 /** 44 * Prediction useful (one of the default prediction actions) 45 */ 46 const ACTION_USEFUL = 'useful'; 47 48 /** 49 * Prediction not useful (one of the default prediction actions) 50 */ 51 const ACTION_NOT_USEFUL = 'notuseful'; 52 53 /** 54 * Prediction already fixed (one of the default prediction actions) 55 */ 56 const ACTION_FIXED = 'fixed'; 57 58 /** 59 * Prediction not applicable. 60 */ 61 const ACTION_NOT_APPLICABLE = 'notapplicable'; 62 63 /** 64 * Prediction incorrectly flagged. 65 */ 66 const ACTION_INCORRECTLY_FLAGGED = 'incorrectlyflagged'; 67 68 /** 69 * @var \stdClass 70 */ 71 private $prediction; 72 73 /** 74 * @var array 75 */ 76 private $sampledata; 77 78 /** 79 * @var array 80 */ 81 private $calculations = array(); 82 83 /** 84 * Constructor 85 * 86 * @param \stdClass|int $prediction 87 * @param array $sampledata 88 * @return void 89 */ 90 public function __construct($prediction, $sampledata) { 91 global $DB; 92 93 if (is_scalar($prediction)) { 94 $prediction = $DB->get_record('analytics_predictions', array('id' => $prediction), '*', MUST_EXIST); 95 } 96 $this->prediction = $prediction; 97 98 $this->sampledata = $sampledata; 99 100 $this->format_calculations(); 101 } 102 103 /** 104 * Get prediction object data. 105 * 106 * @return \stdClass 107 */ 108 public function get_prediction_data() { 109 return $this->prediction; 110 } 111 112 /** 113 * Get prediction sample data. 114 * 115 * @return array 116 */ 117 public function get_sample_data() { 118 return $this->sampledata; 119 } 120 121 /** 122 * Gets the prediction calculations 123 * 124 * @return array 125 */ 126 public function get_calculations() { 127 return $this->calculations; 128 } 129 130 /** 131 * Stores the executed action. 132 133 * Prediction instances should be retrieved using \core_analytics\manager::get_prediction, 134 * It is the caller responsability to check that the user can see the prediction. 135 * 136 * @param string $actionname 137 * @param \core_analytics\local\target\base $target 138 */ 139 public function action_executed($actionname, \core_analytics\local\target\base $target) { 140 global $USER, $DB; 141 142 $context = \context::instance_by_id($this->get_prediction_data()->contextid, IGNORE_MISSING); 143 if (!$context) { 144 throw new \moodle_exception('errorpredictioncontextnotavailable', 'analytics'); 145 } 146 147 // Check that the provided action exists. 148 $actions = $target->prediction_actions($this, true); 149 foreach ($actions as $action) { 150 if ($action->get_action_name() === $actionname) { 151 $found = true; 152 } 153 } 154 $bulkactions = $target->bulk_actions([$this]); 155 foreach ($bulkactions as $action) { 156 if ($action->get_action_name() === $actionname) { 157 $found = true; 158 } 159 } 160 if (empty($found)) { 161 throw new \moodle_exception('errorunknownaction', 'analytics'); 162 } 163 164 $predictionid = $this->get_prediction_data()->id; 165 166 $action = new \stdClass(); 167 $action->predictionid = $predictionid; 168 $action->userid = $USER->id; 169 $action->actionname = $actionname; 170 $action->timecreated = time(); 171 $DB->insert_record('analytics_prediction_actions', $action); 172 173 $eventdata = array ( 174 'context' => $context, 175 'objectid' => $predictionid, 176 'other' => array('actionname' => $actionname) 177 ); 178 \core\event\prediction_action_started::create($eventdata)->trigger(); 179 } 180 181 /** 182 * Get the executed actions. 183 * 184 * Actions could be filtered by actionname. 185 * 186 * @param array $actionnamefilter Limit the results obtained to this list of action names. 187 * @param int $userid the user id. Current user by default. 188 * @return array of actions. 189 */ 190 public function get_executed_actions(array $actionnamefilter = null, int $userid = 0): array { 191 global $USER, $DB; 192 193 $conditions[] = "predictionid = :predictionid"; 194 $params['predictionid'] = $this->get_prediction_data()->id; 195 if (!$userid) { 196 $userid = $USER->id; 197 } 198 $conditions[] = "userid = :userid"; 199 $params['userid'] = $userid; 200 if ($actionnamefilter) { 201 list($actionsql, $actionparams) = $DB->get_in_or_equal($actionnamefilter, SQL_PARAMS_NAMED); 202 $conditions[] = "actionname $actionsql"; 203 $params = $params + $actionparams; 204 } 205 return $DB->get_records_select('analytics_prediction_actions', implode(' AND ', $conditions), $params); 206 } 207 208 /** 209 * format_calculations 210 * 211 * @return \stdClass[] 212 */ 213 private function format_calculations() { 214 215 $calculations = json_decode($this->prediction->calculations, true); 216 217 foreach ($calculations as $featurename => $value) { 218 219 list($indicatorclass, $subtype) = $this->parse_feature_name($featurename); 220 221 if ($indicatorclass === 'range') { 222 // Time range indicators don't belong to any indicator class, we don't store them. 223 continue; 224 } else if (!\core_analytics\manager::is_valid($indicatorclass, '\core_analytics\local\indicator\base')) { 225 throw new \moodle_exception('errorpredictionformat', 'analytics'); 226 } 227 228 $this->calculations[$featurename] = new \stdClass(); 229 $this->calculations[$featurename]->subtype = $subtype; 230 $this->calculations[$featurename]->indicator = \core_analytics\manager::get_indicator($indicatorclass); 231 $this->calculations[$featurename]->value = $value; 232 } 233 } 234 235 /** 236 * parse_feature_name 237 * 238 * @param string $featurename 239 * @return string[] 240 */ 241 private function parse_feature_name($featurename) { 242 243 $indicatorclass = $featurename; 244 $subtype = false; 245 246 // Some indicator result in more than 1 feature, we need to see which feature are we dealing with. 247 $separatorpos = strpos($featurename, '/'); 248 if ($separatorpos !== false) { 249 $subtype = substr($featurename, ($separatorpos + 1)); 250 $indicatorclass = substr($featurename, 0, $separatorpos); 251 } 252 253 return array($indicatorclass, $subtype); 254 } 255 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body