Merge remote branch 'origin/xorg/maint' into xorg/master
[platal.git] / modules / survey / survey.inc.php
CommitLineData
8fe81c50 1<?php
2/***************************************************************************
5e1513f6 3 * Copyright (C) 2003-2011 Polytechnique.org *
8fe81c50 4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
90343d1e
FB
22require_once dirname(__FILE__) . '/question.inc.php';
23require_once dirname(__FILE__) . '/answer.inc.php';
24
2f4b93be 25class Survey extends PlDBTableEntry implements SurveyQuestionContainer
8fe81c50 26{
2f4b93be
FB
27 private $fetchQuestions = true;
28 public $questions = array();
90343d1e
FB
29 public $viewerFilter = null;
30 public $voterFilter = null;
8fe81c50 31
2f4b93be 32 public function __construct()
8fe81c50 33 {
2f4b93be
FB
34 parent::__construct('surveys');
35 $this->registerFieldValidator('shortname', 'ShortNameFieldValidator');
36 $this->registerFieldFormatter('voters', 'JSonFieldFormatter');
37 $this->registerFieldFormatter('viewers', 'JSonFieldFormatter');
8fe81c50 38 }
39
2f4b93be 40 protected function postFetch()
8fe81c50 41 {
90343d1e
FB
42 if (!is_null($this->voters)) {
43 $this->voterFilter = UserFilter::fromExportedConditions($this->voters);
44 } else {
45 $this->voterFilter = null;
46 }
47 if (!is_null($this->viewers)) {
48 $this->viewerFilter = UserFilter::fromExportedConditions($this->viewers);
49 } else {
50 $this->viewerFilter = null;
51 }
2f4b93be 52 if (!$this->fetchQuestions) {
4b8c8634 53 return true;
54 }
2f4b93be
FB
55 $selector = new SurveyQuestion($this);
56 $selector->sid = $this->id;
57
58 $stack = array();
59 foreach ($selector as $question) {
60 $question = $question->typedInstance();
61 if (is_null($question->parent)) {
62 $this->addQuestion($question);
8fe81c50 63 } else {
2f4b93be
FB
64 $pos = count($stack) - 1;
65 while ($stack[$pos]->qid != $question->parent) {
66 --$pos;
67 array_pop($stack);
8fe81c50 68 }
2f4b93be
FB
69 Platal::assert(count($stack) > 0, "Invalid question structure");
70 Platal::assert($stack[$pos] instanceof SurveyQuestionContainer, "Invalid question type");
71 $stack[$pos]->addQuestion($question);
8fe81c50 72 }
2f4b93be 73 array_push($stack, $question);
8fe81c50 74 }
2f4b93be 75 return true;
8fe81c50 76 }
77
90343d1e
FB
78 protected function preSave()
79 {
80 if (!is_null($this->voterFilter)) {
81 $this->voters = $this->voterFilter->exportConditions();
82 } else {
83 $this->voters = null;
84 }
85 if (!is_null($this->viewerFilter)) {
86 $this->viewers = $this->viewerFilter->exportConditions();
87 } else {
88 $this->viewers = null;
89 }
90 return true;
91 }
92
2f4b93be 93 protected function postSave()
4b8c8634 94 {
2f4b93be
FB
95 $questions = array();
96 $selector = new SurveyQuestion($this);
97 $selector->sid = $this->id;
98 $selector->delete();
4b8c8634 99
2f4b93be
FB
100 $this->reassignQuestionIds();
101 foreach ($this->questions as $question) {
102 $question->sid = $this->id;
103 $question->insert();
8fe81c50 104 }
5c6e38d7 105 }
5c6e38d7 106
3ddf2584
FB
107 public function clearQuestions()
108 {
109 $this->fetchQuestions = true;
110 $this->questions = array();
111 }
112
2f4b93be 113 public function addQuestion(SurveyQuestion $question, $pos = null)
5c6e38d7 114 {
2f4b93be
FB
115 $question->parent = null;
116 if (is_null($pos)) {
117 $this->questions[] = $question;
5c6e38d7 118 } else {
2f4b93be 119 array_splice($this->questions, $pos, 0, $question);
8fe81c50 120 }
8fe81c50 121 }
122
2f4b93be 123 public function newQuestion($type, $pos = null)
8fe81c50 124 {
2f4b93be
FB
125 $question = SurveyQuestion::instanceForType($this, $type);
126 $this->addQuestion($question, $pos);
127 return $question;
8fe81c50 128 }
8fe81c50 129
90343d1e
FB
130 public function questionForId($qid)
131 {
132 $prev = null;
133 foreach ($this->questions as $question) {
134 if ($qid == $question->qid) {
135 return $question;
136 } else if ($qid < $question->qid) {
137 Platal::assert($prev instanceof SurveyQuestionGroup,
138 "Id gap must be caused by question groups");
139 return $prev->child($qid);
140 }
141 $prev = $question;
142 }
143 Platal::assert($prev instanceof SurveyQuestionGroup,
144 "Id gap must be caused by question groups");
145 return $prev->child($qid);
146 }
147
2f4b93be 148 public function reassignQuestionIds()
8fe81c50 149 {
2f4b93be
FB
150 $id = 0;
151 foreach ($this->questions as $question) {
152 $question->qid = $id;
153 if ($question instanceof SurveyQuestionContainer) {
154 $id = $question->reassignQuestionIds();
5c6e38d7 155 } else {
2f4b93be 156 $id++;
8fe81c50 157 }
8fe81c50 158 }
2f4b93be 159 return $id;
8fe81c50 160 }
161
2f4b93be 162 public function export()
8fe81c50 163 {
2f4b93be 164 $export = parent::export();
b46de52d
FB
165 $export['questions'] = $this->exportQuestions();
166 return $export;
167 }
168
169 public function exportQuestions()
170 {
171 $export = array();
2f4b93be 172 foreach ($this->questions as $question) {
b46de52d 173 $export[] = $question->export();
5c6e38d7 174 }
2f4b93be 175 return $export;
8fe81c50 176 }
8fe81c50 177
b46de52d
FB
178 public function exportQuestionsToJSON()
179 {
180 return json_encode($this->exportQuestions());
181 }
182
90343d1e
FB
183 /* Return an indicator of the progression of the survey:
184 * negative values means 'the survey is not started'
185 * 0 means 'the survey is in progress'
186 * positive values means 'the survey expired'
187 */
188 public function progression()
189 {
190 if (!$this->flags->hasFlag('validated')) {
191 return -2;
192 }
193 $now = time();
194 if ($this->begin->format('U') > $now) {
195 return -1;
196 }
197 if ($this->end->format('U') <= $now) {
198 return 1;
199 }
200 return 0;
201 }
202
2f4b93be 203 public function canSee(User $user)
8fe81c50 204 {
90343d1e 205 if ($this->canSeeResults($user) || $this->canVote($user)) {
2f4b93be 206 return true;
8fe81c50 207 }
2f4b93be 208 return false;
8fe81c50 209 }
8fe81c50 210
90343d1e
FB
211 public function canSeeResults(User $user)
212 {
213 if ($user->id() == $this->uid || $user->hasFlag('admin')) {
214 return true;
215 }
216 if (is_null($this->viewerFilter)) {
217 return $this->viewerFilter->checkUser($user);
218 }
219 return false;
220 }
221
222 public function canVote(User $user)
223 {
224 $status = $this->progression();
225 if ($status < 0) {
226 return "Ce sondage n'est pas encore commencé";
227 } else if ($status > 0) {
228 return "Ce sondage est terminé";
229 }
230 if (!is_null($this->voterFilter) && !$this->voterFilter->checkUser($user)) {
231 return "Ce sondage ne s'adresse pas à toi";
232 }
233 $vote = SurveyVote::getVote($this, $user, false);
234 if (is_null($vote)) {
235 return "Tu as déjà voté à ce sondage.";
236 }
237 return true;
238 }
239
240 public function vote(User $user, array $answers)
241 {
242 if (!$this->canVote($user)) {
243 return array('survey' => "Tu n'es pas autorisé à voter à ce sondage.");
244 }
245 $vote = SurveyVote::getVote($this, $user);
246 if (is_null($vote)) {
247 return $vote;
248 }
249 $answers = new PlDict($answers);
250 foreach ($this->questions as $question) {
251 $question->vote($vote, $answers);
252 }
253 return $vote;
254 }
255
2f4b93be 256 public static function get($name, $fetchQuestions = true)
797d27db 257 {
2f4b93be
FB
258 if (is_array($name)) {
259 $name = $name[0];
797d27db 260 }
2f4b93be
FB
261 $survey = new Survey();
262 $survey->fetchQuestions = $fetchQuestions;
263 if (can_convert_to_integer($name)) {
264 $survey->id = $name;
797d27db 265 } else {
2f4b93be 266 $survey->shortname = $name;
8fe81c50 267 }
2f4b93be
FB
268 if (!$survey->fetch()) {
269 return null;
5c6e38d7 270 }
2f4b93be 271 return $survey;
8fe81c50 272 }
273
2f4b93be 274 public static function iterActive()
8fe81c50 275 {
2f4b93be
FB
276 $survey = new Survey();
277 $survey->fetchQuestions = false;
278 return $survey->iterateOnCondition('begin <= CURDATE() AND end >= CURDATE()
279 AND FIND_IN_SET(\'validated\', flags)');
8fe81c50 280 }
5c6e38d7 281}
8fe81c50 282
2f4b93be 283class ShortNameFieldValidator implements PlDBTableFieldValidator
5c6e38d7 284{
2f4b93be 285 public function __construct(PlDBTableField $field, $value)
8fe81c50 286 {
2f4b93be
FB
287 if (can_convert_to_integer($value) || !preg_match('/^[a-z0-9]+[-_\.a-z0-9]*[a-z0-9]+$/i', $value)) {
288 throw new PlDBBadValueException($value, $field,
289 'The shortname can only contain alphanumerical caracters, dashes, underscores and dots');
290 }
4b8c8634 291 }
8fe81c50 292}
8fe81c50 293
8602c852 294// vim:set et sw=4 sts=4 ts=4 foldmethod=marker enc=utf-8:
8fe81c50 295?>