Merge close_on_esc.js into xorg.js.
[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
2f4b93be 107 public function addQuestion(SurveyQuestion $question, $pos = null)
5c6e38d7 108 {
2f4b93be
FB
109 $question->parent = null;
110 if (is_null($pos)) {
111 $this->questions[] = $question;
5c6e38d7 112 } else {
2f4b93be 113 array_splice($this->questions, $pos, 0, $question);
8fe81c50 114 }
8fe81c50 115 }
116
2f4b93be 117 public function newQuestion($type, $pos = null)
8fe81c50 118 {
2f4b93be
FB
119 $question = SurveyQuestion::instanceForType($this, $type);
120 $this->addQuestion($question, $pos);
121 return $question;
8fe81c50 122 }
8fe81c50 123
90343d1e
FB
124 public function questionForId($qid)
125 {
126 $prev = null;
127 foreach ($this->questions as $question) {
128 if ($qid == $question->qid) {
129 return $question;
130 } else if ($qid < $question->qid) {
131 Platal::assert($prev instanceof SurveyQuestionGroup,
132 "Id gap must be caused by question groups");
133 return $prev->child($qid);
134 }
135 $prev = $question;
136 }
137 Platal::assert($prev instanceof SurveyQuestionGroup,
138 "Id gap must be caused by question groups");
139 return $prev->child($qid);
140 }
141
2f4b93be 142 public function reassignQuestionIds()
8fe81c50 143 {
2f4b93be
FB
144 $id = 0;
145 foreach ($this->questions as $question) {
146 $question->qid = $id;
147 if ($question instanceof SurveyQuestionContainer) {
148 $id = $question->reassignQuestionIds();
5c6e38d7 149 } else {
2f4b93be 150 $id++;
8fe81c50 151 }
8fe81c50 152 }
2f4b93be 153 return $id;
8fe81c50 154 }
155
2f4b93be 156 public function export()
8fe81c50 157 {
2f4b93be
FB
158 $export = parent::export();
159 $export['questions'] = array();
160 foreach ($this->questions as $question) {
161 $export['questions'][] = $question->export();
5c6e38d7 162 }
2f4b93be 163 return $export;
8fe81c50 164 }
8fe81c50 165
90343d1e
FB
166 /* Return an indicator of the progression of the survey:
167 * negative values means 'the survey is not started'
168 * 0 means 'the survey is in progress'
169 * positive values means 'the survey expired'
170 */
171 public function progression()
172 {
173 if (!$this->flags->hasFlag('validated')) {
174 return -2;
175 }
176 $now = time();
177 if ($this->begin->format('U') > $now) {
178 return -1;
179 }
180 if ($this->end->format('U') <= $now) {
181 return 1;
182 }
183 return 0;
184 }
185
2f4b93be 186 public function canSee(User $user)
8fe81c50 187 {
90343d1e 188 if ($this->canSeeResults($user) || $this->canVote($user)) {
2f4b93be 189 return true;
8fe81c50 190 }
2f4b93be 191 return false;
8fe81c50 192 }
8fe81c50 193
90343d1e
FB
194 public function canSeeResults(User $user)
195 {
196 if ($user->id() == $this->uid || $user->hasFlag('admin')) {
197 return true;
198 }
199 if (is_null($this->viewerFilter)) {
200 return $this->viewerFilter->checkUser($user);
201 }
202 return false;
203 }
204
205 public function canVote(User $user)
206 {
207 $status = $this->progression();
208 if ($status < 0) {
209 return "Ce sondage n'est pas encore commencé";
210 } else if ($status > 0) {
211 return "Ce sondage est terminé";
212 }
213 if (!is_null($this->voterFilter) && !$this->voterFilter->checkUser($user)) {
214 return "Ce sondage ne s'adresse pas à toi";
215 }
216 $vote = SurveyVote::getVote($this, $user, false);
217 if (is_null($vote)) {
218 return "Tu as déjà voté à ce sondage.";
219 }
220 return true;
221 }
222
223 public function vote(User $user, array $answers)
224 {
225 if (!$this->canVote($user)) {
226 return array('survey' => "Tu n'es pas autorisé à voter à ce sondage.");
227 }
228 $vote = SurveyVote::getVote($this, $user);
229 if (is_null($vote)) {
230 return $vote;
231 }
232 $answers = new PlDict($answers);
233 foreach ($this->questions as $question) {
234 $question->vote($vote, $answers);
235 }
236 return $vote;
237 }
238
2f4b93be 239 public static function get($name, $fetchQuestions = true)
797d27db 240 {
2f4b93be
FB
241 if (is_array($name)) {
242 $name = $name[0];
797d27db 243 }
2f4b93be
FB
244 $survey = new Survey();
245 $survey->fetchQuestions = $fetchQuestions;
246 if (can_convert_to_integer($name)) {
247 $survey->id = $name;
797d27db 248 } else {
2f4b93be 249 $survey->shortname = $name;
8fe81c50 250 }
2f4b93be
FB
251 if (!$survey->fetch()) {
252 return null;
5c6e38d7 253 }
2f4b93be 254 return $survey;
8fe81c50 255 }
256
2f4b93be 257 public static function iterActive()
8fe81c50 258 {
2f4b93be
FB
259 $survey = new Survey();
260 $survey->fetchQuestions = false;
261 return $survey->iterateOnCondition('begin <= CURDATE() AND end >= CURDATE()
262 AND FIND_IN_SET(\'validated\', flags)');
8fe81c50 263 }
5c6e38d7 264}
8fe81c50 265
2f4b93be 266class ShortNameFieldValidator implements PlDBTableFieldValidator
5c6e38d7 267{
2f4b93be 268 public function __construct(PlDBTableField $field, $value)
8fe81c50 269 {
2f4b93be
FB
270 if (can_convert_to_integer($value) || !preg_match('/^[a-z0-9]+[-_\.a-z0-9]*[a-z0-9]+$/i', $value)) {
271 throw new PlDBBadValueException($value, $field,
272 'The shortname can only contain alphanumerical caracters, dashes, underscores and dots');
273 }
4b8c8634 274 }
8fe81c50 275}
8fe81c50 276
8602c852 277// vim:set et sw=4 sts=4 ts=4 foldmethod=marker enc=utf-8:
8fe81c50 278?>