Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
 * Abstract base indicator.
19
 *
20
 * @package   core_analytics
21
 * @copyright 2016 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\local\indicator;
26
 
27
defined('MOODLE_INTERNAL') || die();
28
 
29
/**
30
 * Abstract base indicator.
31
 *
32
 * @package   core_analytics
33
 * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
34
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35
 */
36
abstract class base extends \core_analytics\calculable {
37
 
38
    /**
39
     * Min value an indicator can return.
40
     */
41
    const MIN_VALUE = -1;
42
 
43
    /**
44
     * Max value an indicator can return.
45
     */
46
    const MAX_VALUE = 1;
47
 
48
    /**
49
     * Converts the calculated indicators to dataset feature/s.
50
     *
51
     * @param float|int[] $calculatedvalues
52
     * @return array
53
     */
54
    abstract protected function to_features($calculatedvalues);
55
 
56
    /**
57
     * Calculates the sample.
58
     *
59
     * Return a value from self::MIN_VALUE to self::MAX_VALUE or null if the indicator can not be calculated for this sample.
60
     *
61
     * @param int $sampleid
62
     * @param string $sampleorigin
63
     * @param integer $starttime Limit the calculation to this timestart
64
     * @param integer $endtime Limit the calculation to this timeend
65
     * @return float|null
66
     */
67
    abstract protected function calculate_sample($sampleid, $sampleorigin, $starttime, $endtime);
68
 
69
    /**
70
     * Should this value be displayed?
71
     *
72
     * Indicators providing multiple features can be used this method to discard some of them.
73
     *
74
     * @param float $value
75
     * @param string $subtype
76
     * @return bool
77
     */
78
    public function should_be_displayed($value, $subtype) {
79
        // We should everything by default.
80
        return true;
81
    }
82
 
83
    /**
84
     * Allows indicators to specify data they need.
85
     *
86
     * e.g. A model using courses as samples will not provide users data, but an indicator like
87
     * "user is hungry" needs user data.
88
     *
89
     * @return null|string[] Name of the required elements (use the database tablename)
90
     */
91
    public static function required_sample_data() {
92
        return null;
93
    }
94
 
95
    /**
96
     * Returns an instance of the indicator.
97
     *
98
     * Useful to reset cached data.
99
     *
100
     * @return \core_analytics\local\indicator\base
101
     */
102
    public static function instance() {
103
        return new static();
104
    }
105
 
106
    /**
107
     * Returns the maximum value an indicator calculation can return.
108
     *
109
     * @return float
110
     */
111
    public static function get_max_value() {
112
        return self::MAX_VALUE;
113
    }
114
 
115
    /**
116
     * Returns the minimum value an indicator calculation can return.
117
     *
118
     * @return float
119
     */
120
    public static function get_min_value() {
121
        return self::MIN_VALUE;
122
    }
123
 
124
    /**
125
     * Hook to allow indicators to pre-fill data that is shared accross time range calculations.
126
     *
127
     * Useful to fill analysable-dependant data that does not depend on the time ranges. Use
128
     * instance vars to cache data that can be re-used across samples calculations but changes
129
     * between time ranges (indicator instances are reset between time ranges to avoid unexpected
130
     * problems).
131
     *
132
     * You are also responsible of emptying previous analysable caches.
133
     *
134
     * @param \core_analytics\analysable $analysable
135
     * @return void
136
     */
137
    public function fill_per_analysable_caches(\core_analytics\analysable $analysable) {
138
    }
139
 
140
    /**
141
     * Calculates the indicator.
142
     *
143
     * Returns an array of values which size matches $sampleids size.
144
     *
145
     * @param int[] $sampleids
146
     * @param string $samplesorigin
147
     * @param integer $starttime Limit the calculation to this timestart
148
     * @param integer $endtime Limit the calculation to this timeend
149
     * @param array $existingcalculations Existing calculations of this indicator, indexed by sampleid.
150
     * @return array [0] = [$sampleid => int[]|float[]], [1] = [$sampleid => int|float], [2] = [$sampleid => $sampleid]
151
     */
152
    public function calculate($sampleids, $samplesorigin, $starttime = false, $endtime = false, $existingcalculations = array()) {
153
 
154
        if (!PHPUNIT_TEST && CLI_SCRIPT) {
155
            echo '.';
156
        }
157
 
158
        $calculations = array();
159
        $newcalculations = array();
160
        $notnulls = array();
161
        foreach ($sampleids as $sampleid => $unusedsampleid) {
162
 
163
            if (isset($existingcalculations[$sampleid])) {
164
                $calculatedvalue = $existingcalculations[$sampleid];
165
            } else {
166
                $calculatedvalue = $this->calculate_sample($sampleid, $samplesorigin, $starttime, $endtime);
167
                $newcalculations[$sampleid] = $calculatedvalue;
168
            }
169
 
170
            if (!is_null($calculatedvalue)) {
171
                $notnulls[$sampleid] = $sampleid;
172
                $this->validate_calculated_value($calculatedvalue);
173
            }
174
 
175
            $calculations[$sampleid] = $calculatedvalue;
176
        }
177
 
178
        $features = $this->to_features($calculations);
179
 
180
        return array($features, $newcalculations, $notnulls);
181
    }
182
 
183
    /**
184
     * Validates the calculated value.
185
     *
186
     * @throws \coding_exception
187
     * @param float $calculatedvalue
188
     * @return true
189
     */
190
    protected function validate_calculated_value($calculatedvalue) {
191
        if ($calculatedvalue > self::MAX_VALUE || $calculatedvalue < self::MIN_VALUE) {
192
            throw new \coding_exception('Calculated values should be higher than ' . self::MIN_VALUE .
193
                ' and lower than ' . self::MAX_VALUE . ' ' . $calculatedvalue . ' received');
194
        }
195
        return true;
196
    }
197
}