MDL-59106 report_insights: Fix predicted value styling
[moodle.git] / report / insights / classes / output / insight.php
CommitLineData
373b1de1
DM
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/**
f9e7447f 18 * Single insight view page.
373b1de1
DM
19 *
20 * @package report_insights
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
25namespace report_insights\output;
26
27defined('MOODLE_INTERNAL') || die();
28
29/**
f9e7447f 30 * Single insight view page.
373b1de1
DM
31 *
32 * @package report_insights
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 */
f9e7447f 36class insight implements \renderable, \templatable {
373b1de1
DM
37
38 /**
39 * @var \core_analytics\model
40 */
41 protected $model;
42
43 /**
44 * @var \core_analytics\prediction
45 */
46 protected $prediction;
47
1611308b
DM
48 /**
49 * @var bool
50 */
51 protected $includedetailsaction = false;
52
413f19bc
DM
53 /**
54 * Constructor
55 *
56 * @param \core_analytics\prediction $prediction
57 * @param \core_analytics\model $model
58 * @param bool $includedetailsaction
59 * @return void
60 */
1611308b 61 public function __construct(\core_analytics\prediction $prediction, \core_analytics\model $model, $includedetailsaction = false) {
373b1de1
DM
62 $this->prediction = $prediction;
63 $this->model = $model;
1611308b 64 $this->includedetailsaction = $includedetailsaction;
373b1de1
DM
65 }
66
67 /**
68 * Exports the data.
69 *
70 * @param \renderer_base $output
71 * @return \stdClass
72 */
73 public function export_for_template(\renderer_base $output) {
c6140739
MN
74 // Get the prediction data.
75 $predictiondata = $this->prediction->get_prediction_data();
373b1de1
DM
76
77 $data = new \stdClass();
1d5b1d01 78 $data->insightname = format_string($this->model->get_target()->get_name());
373b1de1 79
c6140739
MN
80 // Get the details.
81 $data->timecreated = userdate($predictiondata->timecreated);
82 $data->timerange = '';
83
84 if (!empty($predictiondata->timestart) && !empty($predictiondata->timeend)) {
85 $timerange = new \stdClass();
86 $timerange->timestart = userdate($predictiondata->timestart);
87 $timerange->timeend = userdate($predictiondata->timeend);
88 $data->timerange = get_string('timerangewithdata', 'report_insights', $timerange);
89 }
90
373b1de1 91 // Sample info (determined by the analyser).
357507b4 92 list($data->sampledescription, $samplerenderable) = $this->model->prediction_sample_description($this->prediction);
373b1de1
DM
93
94 // Sampleimage is a renderable we should pass it to HTML.
357507b4 95 if ($samplerenderable) {
1d5b1d01 96 $data->sampleimage = $output->render($samplerenderable);
373b1de1
DM
97 }
98
99 // Prediction info.
c6140739
MN
100 $predictedvalue = $predictiondata->prediction;
101 $predictionid = $predictiondata->id;
373b1de1 102 $data->predictiondisplayvalue = $this->model->get_target()->get_display_value($predictedvalue);
c6140739 103 list($data->style, $data->outcomeicon) = self::get_calculation_display($this->model->get_target(),
7c37e56f 104 floatval($predictedvalue), $output);
373b1de1 105
1611308b 106 $actions = $this->model->get_target()->prediction_actions($this->prediction, $this->includedetailsaction);
373b1de1
DM
107 if ($actions) {
108 $actionsmenu = new \action_menu();
109 $actionsmenu->set_menu_trigger(get_string('actions'));
110 $actionsmenu->set_owner_selector('prediction-actions-' . $predictionid);
111 $actionsmenu->set_alignment(\action_menu::TL, \action_menu::BL);
112
113 // Add all actions defined by the target.
114 foreach ($actions as $action) {
115 $actionsmenu->add($action->get_action_link());
116 }
117 $data->actions = $actionsmenu->export_for_template($output);
118 } else {
119 $data->actions = false;
120 }
121
122 // Calculated indicators values.
123 $data->calculations = array();
124 $calculations = $this->prediction->get_calculations();
125 foreach ($calculations as $calculation) {
126
127 // Hook for indicators with extra features that should not be displayed (e.g. discrete indicators).
128 if (!$calculation->indicator->should_be_displayed($calculation->value, $calculation->subtype)) {
129 continue;
130 }
131
132 if ($calculation->value === null) {
133 // We don't show values that could not be calculated.
134 continue;
135 }
136
137 $obj = new \stdClass();
1611308b 138 $obj->name = call_user_func(array($calculation->indicator, 'get_name'));
373b1de1 139 $obj->displayvalue = $calculation->indicator->get_display_value($calculation->value, $calculation->subtype);
c6140739 140 list($obj->style, $obj->outcomeicon) = self::get_calculation_display($calculation->indicator,
7c37e56f 141 floatval($calculation->value), $output, $calculation->subtype);
373b1de1
DM
142
143 $data->calculations[] = $obj;
144 }
145
1d5b1d01
DM
146 if (empty($data->calculations)) {
147 $data->nocalculations = (object)array(
148 'message' => get_string('nodetailsavailable', 'report_insights'),
149 'closebutton' => false
150 );
151 }
152
373b1de1
DM
153 return $data;
154 }
27ae9af4
DM
155
156 /**
1d5b1d01 157 * Returns display info for the calculated value outcome.
27ae9af4
DM
158 *
159 * @param \core_analytics\calculable $calculable
5c5cb3ee 160 * @param float $value
1d5b1d01 161 * @param \renderer_base $output
27ae9af4 162 * @param string|false $subtype
1d5b1d01 163 * @return array The style as 'success', 'info', 'warning' or 'danger' and pix_icon
27ae9af4 164 */
c6140739 165 public static function get_calculation_display(\core_analytics\calculable $calculable, $value, $output, $subtype = false) {
27ae9af4
DM
166 $outcome = $calculable->get_calculation_outcome($value, $subtype);
167 switch ($outcome) {
168 case \core_analytics\calculable::OUTCOME_NEUTRAL:
169 $style = '';
1d5b1d01
DM
170 $text = get_string('outcomeneutral', 'report_insights');
171 $icon = 't/check';
27ae9af4
DM
172 break;
173 case \core_analytics\calculable::OUTCOME_VERY_POSITIVE:
1d5b1d01
DM
174 $style = 'success';
175 $text = get_string('outcomeverypositive', 'report_insights');
176 $icon = 't/approve';
27ae9af4
DM
177 break;
178 case \core_analytics\calculable::OUTCOME_OK:
1d5b1d01
DM
179 $style = 'info';
180 $text = get_string('outcomeok', 'report_insights');
181 $icon = 't/check';
27ae9af4
DM
182 break;
183 case \core_analytics\calculable::OUTCOME_NEGATIVE:
1d5b1d01
DM
184 $style = 'warning';
185 $text = get_string('outcomenegative', 'report_insights');
186 $icon = 'i/warning';
27ae9af4
DM
187 break;
188 case \core_analytics\calculable::OUTCOME_VERY_NEGATIVE:
1d5b1d01
DM
189 $style = 'danger';
190 $text = get_string('outcomeverynegative', 'report_insights');
191 $icon = 'i/warning';
27ae9af4
DM
192 break;
193 default:
194 throw new \coding_exception('The outcome returned by ' . get_class($calculable) . '::get_calculation_outcome is ' .
195 'not one of the accepted values. Please use \core_analytics\calculable::OUTCOME_VERY_POSITIVE, ' .
5c5cb3ee
DM
196 '\core_analytics\calculable::OUTCOME_OK, \core_analytics\calculable::OUTCOME_NEGATIVE, ' .
197 '\core_analytics\calculable::OUTCOME_VERY_NEGATIVE or \core_analytics\calculable::OUTCOME_NEUTRAL');
27ae9af4 198 }
1d5b1d01
DM
199 $icon = new \pix_icon($icon, $text);
200 return array($style, $icon->export_for_template($output));
27ae9af4 201 }
373b1de1 202}