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
namespace mod_questionnaire\responsetype;
18
 
19
use mod_questionnaire\db\bulk_sql_config;
20
 
21
/**
22
 * Class for date response types.
23
 *
24
 * @author Mike Churchward
25
 * @copyright 2016 onward Mike Churchward (mike.churchward@poetopensource.org)
26
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
27
 * @package mod_questionnaire
28
 */
29
class date extends responsetype {
30
    /**
31
     * Provide the necessary response data table name. Should probably always be used with late static binding 'static::' form
32
     * rather than 'self::' form to allow for class extending.
33
     *
34
     * @return string response table name.
35
     */
36
    public static function response_table() {
37
        return 'questionnaire_response_date';
38
    }
39
 
40
    /**
41
     * Provide an array of answer objects from web form data for the question.
42
     *
43
     * @param \stdClass $responsedata All of the responsedata as an object.
44
     * @param \mod_questionnaire\question\question $question
45
     * @return array \mod_questionnaire\responsetype\answer\answer An array of answer objects.
46
     */
47
    public static function answers_from_webform($responsedata, $question) {
48
        $answers = [];
49
        if (isset($responsedata->{'q'.$question->id}) && !empty($responsedata->{'q'.$question->id})) {
50
            $record = new \stdClass();
51
            $record->responseid = $responsedata->rid;
52
            $record->questionid = $question->id;
53
            $record->value = $responsedata->{'q' . $question->id};
54
            $answers[] = answer\answer::create_from_data($record);
55
        }
56
        return $answers;
57
    }
58
 
59
    /**
60
     * Provide an array of answer objects from mobile data for the question.
61
     *
62
     * @param \stdClass $responsedata All of the responsedata as an object.
63
     * @param \mod_questionnaire\question\question $question
64
     * @return array \mod_questionnaire\responsetype\answer\answer An array of answer objects.
65
     */
66
    public static function answers_from_appdata($responsedata, $question) {
67
        if (isset($responsedata->{'q'.$question->id}) && !empty($responsedata->{'q'.$question->id})) {
68
            // The app can send the date including time (e.g. 2021-06-28T09:03:46.613+02:00), get only the date.
69
            $responsedata->{'q'.$question->id} = substr($responsedata->{'q'.$question->id}[0], 0, 10);
70
        }
71
        return static::answers_from_webform($responsedata, $question);
72
    }
73
 
74
    /**
75
     * Insert a provided response to the question.
76
     *
77
     * @param object $responsedata All of the responsedata as an object.
78
     * @return int|bool - on error the subtype should call set_error and return false.
79
     */
80
    public function insert_response($responsedata) {
81
        global $DB;
82
 
83
        if (!$responsedata instanceof \mod_questionnaire\responsetype\response\response) {
84
            $response = \mod_questionnaire\responsetype\response\response::response_from_webform($responsedata, [$this->question]);
85
        } else {
86
            $response = $responsedata;
87
        }
88
 
89
        if (!empty($response) && isset($response->answers[$this->question->id][0])) {
90
            $thisdate = $response->answers[$this->question->id][0]->value;
91
            if (!$this->question->check_date_format($thisdate)) {
92
                return false;
93
            }
94
            // Now use ISO date formatting.
95
            $record = new \stdClass();
96
            $record->response_id = $response->id;
97
            $record->question_id = $this->question->id;
98
            $record->response = $thisdate;
99
            return $DB->insert_record(self::response_table(), $record);
100
        } else {
101
            return false;
102
        }
103
    }
104
 
105
    /**
106
     * Provide the result information for the specified result records.
107
     *
108
     * @param int|array $rids - A single response id, or array.
109
     * @param boolean $anonymous - Whether or not responses are anonymous.
110
     * @return array - Array of data records.
111
     */
112
    public function get_results($rids=false, $anonymous=false) {
113
        global $DB;
114
 
115
        $rsql = '';
116
        $params = array($this->question->id);
117
        if (!empty($rids)) {
118
            list($rsql, $rparams) = $DB->get_in_or_equal($rids);
119
            $params = array_merge($params, $rparams);
120
            $rsql = ' AND response_id ' . $rsql;
121
        }
122
 
123
        $sql = 'SELECT id, response ' .
124
               'FROM {'.static::response_table().'} ' .
125
               'WHERE question_id= ? ' . $rsql;
126
 
127
        return $DB->get_records_sql($sql, $params);
128
    }
129
 
130
    /**
131
     * Provide a template for results screen if defined.
132
     * @param bool $pdf
133
     * @return mixed The template string or false/
134
     */
135
    public function results_template($pdf = false) {
136
        if ($pdf) {
137
            return 'mod_questionnaire/resultspdf_date';
138
        } else {
139
            return 'mod_questionnaire/results_date';
140
        }
141
    }
142
 
143
    /**
144
     * Provide the result information for the specified result records.
145
     *
146
     * @param int|array $rids - A single response id, or array.
147
     * @param string $sort - Optional display sort.
148
     * @param boolean $anonymous - Whether or not responses are anonymous.
149
     * @return string - Display output.
150
     */
151
    public function display_results($rids=false, $sort='', $anonymous=false) {
152
        $numresps = count($rids);
153
        if ($rows = $this->get_results($rids, $anonymous)) {
154
            $numrespondents = count($rows);
155
            $counts = [];
156
            foreach ($rows as $row) {
157
                // Count identical answers (case insensitive).
158
                if (!empty($row->response)) {
159
                    $dateparts = preg_split('/-/', $row->response);
160
                    $text = make_timestamp($dateparts[0], $dateparts[1], $dateparts[2]); // Unix timestamp.
161
                    $textidx = clean_text($text);
162
                    $counts[$textidx] = !empty($counts[$textidx]) ? ($counts[$textidx] + 1) : 1;
163
                }
164
            }
165
            $pagetags = $this->get_results_tags($counts, $numresps, $numrespondents);
166
        } else {
167
            $pagetags = new \stdClass();
168
        }
169
        return $pagetags;
170
    }
171
 
172
    /**
173
     * Gets the results tags for templates for questions with defined choices (single, multiple, boolean).
174
     *
175
     * @param arrays $weights
176
     * @param int $participants Number of questionnaire participants.
177
     * @param int $respondents Number of question respondents.
178
     * @param int $showtotals
179
     * @param string $sort
180
     * @return \stdClass
181
     */
182
    public function get_results_tags($weights, $participants, $respondents, $showtotals = 1, $sort = '') {
183
        $dateformat = get_string('strfdate', 'questionnaire');
184
 
185
        $pagetags = new \stdClass();
186
        if ($respondents == 0) {
187
            return $pagetags;
188
        }
189
 
190
        if (!empty($weights) && is_array($weights)) {
191
            $pagetags->responses = [];
192
            $numresps = 0;
193
            ksort ($weights); // Sort dates into chronological order.
194
            $evencolor = false;
195
            foreach ($weights as $content => $num) {
196
                $response = new \stdClass();
197
                $response->text = userdate($content, $dateformat, '', false);    // Change timestamp into readable dates.
198
                $numresps += $num;
199
                $response->total = $num;
200
                // The 'evencolor' attribute is used by the PDF template.
201
                $response->evencolor = $evencolor;
202
                $pagetags->responses[] = (object)['response' => $response];
203
                $evencolor = !$evencolor;
204
            }
205
 
206
            if ($showtotals == 1) {
207
                $pagetags->total = new \stdClass();
208
                $pagetags->total->total = "$numresps/$participants";
209
            }
210
        }
211
 
212
        return $pagetags;
213
    }
214
 
215
    /**
216
     * Return an array of answers by question/choice for the given response. Must be implemented by the subclass.
217
     *
218
     * @param int $rid The response id.
219
     * @return array
220
     */
221
    public static function response_select($rid) {
222
        global $DB;
223
 
224
        $values = [];
225
        $sql = 'SELECT q.id, q.content, a.response as aresponse '.
226
            'FROM {'.static::response_table().'} a, {questionnaire_question} q '.
227
            'WHERE a.response_id=? AND a.question_id=q.id ';
228
        $records = $DB->get_records_sql($sql, [$rid]);
229
        $dateformat = get_string('strfdate', 'questionnaire');
230
        foreach ($records as $qid => $row) {
231
            unset ($row->id);
232
            $row = (array)$row;
233
            $newrow = array();
234
            foreach ($row as $key => $val) {
235
                if (!is_numeric($key)) {
236
                    $newrow[] = $val;
237
                    // Convert date from yyyy-mm-dd database format to actual questionnaire dateformat.
238
                    // does not work with dates prior to 1900 under Windows.
239
                    if (preg_match('/\d\d\d\d-\d\d-\d\d/', $val)) {
240
                        $dateparts = preg_split('/-/', $val);
241
                        $val = make_timestamp($dateparts[0], $dateparts[1], $dateparts[2]); // Unix timestamp.
242
                        $val = userdate ( $val, $dateformat);
243
                        $newrow[] = $val;
244
                    }
245
                }
246
            }
247
            $values["$qid"] = $newrow;
248
            $val = array_pop($values["$qid"]);
249
            array_push($values["$qid"], '', '', $val);
250
        }
251
 
252
        return $values;
253
    }
254
 
255
    /**
256
     * Return an array of answer objects by question for the given response id.
257
     * THIS SHOULD REPLACE response_select.
258
     *
259
     * @param int $rid The response id.
260
     * @return array array answer
261
     * @throws \dml_exception
262
     */
263
    public static function response_answers_by_question($rid) {
264
        global $DB;
265
 
266
        $answers = [];
267
        $sql = 'SELECT id, response_id as responseid, question_id as questionid, 0 as choiceid, response as value ' .
268
            'FROM {' . static::response_table() .'} ' .
269
            'WHERE response_id = ? ';
270
        $records = $DB->get_records_sql($sql, [$rid]);
271
        foreach ($records as $record) {
272
            // Leave the date format in data storage format.
273
            $answers[$record->questionid][] = answer\answer::create_from_data($record);
274
        }
275
 
276
        return $answers;
277
    }
278
 
279
    /**
280
     * Configure bulk sql
281
     * @return bulk_sql_config
282
     */
283
    protected function bulk_sql_config() {
284
        return new bulk_sql_config(static::response_table(), 'qrd', false, true, false);
285
    }
286
}