Improves index page.
[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 158 $export = parent::export();
b46de52d
FB
159 $export['questions'] = $this->exportQuestions();
160 return $export;
161 }
162
163 public function exportQuestions()
164 {
165 $export = array();
2f4b93be 166 foreach ($this->questions as $question) {
b46de52d 167 $export[] = $question->export();
5c6e38d7 168 }
2f4b93be 169 return $export;
8fe81c50 170 }
8fe81c50 171
b46de52d
FB
172 public function exportQuestionsToJSON()
173 {
174 return json_encode($this->exportQuestions());
175 }
176
90343d1e
FB
177 /* Return an indicator of the progression of the survey:
178 * negative values means 'the survey is not started'
179 * 0 means 'the survey is in progress'
180 * positive values means 'the survey expired'
181 */
182 public function progression()
183 {
184 if (!$this->flags->hasFlag('validated')) {
185 return -2;
186 }
187 $now = time();
188 if ($this->begin->format('U') > $now) {
189 return -1;
190 }
191 if ($this->end->format('U') <= $now) {
192 return 1;
193 }
194 return 0;
195 }
196
2f4b93be 197 public function canSee(User $user)
8fe81c50 198 {
90343d1e 199 if ($this->canSeeResults($user) || $this->canVote($user)) {
2f4b93be 200 return true;
8fe81c50 201 }
2f4b93be 202 return false;
8fe81c50 203 }
8fe81c50 204
90343d1e
FB
205 public function canSeeResults(User $user)
206 {
207 if ($user->id() == $this->uid || $user->hasFlag('admin')) {
208 return true;
209 }
210 if (is_null($this->viewerFilter)) {
211 return $this->viewerFilter->checkUser($user);
212 }
213 return false;
214 }
215
216 public function canVote(User $user)
217 {
218 $status = $this->progression();
219 if ($status < 0) {
220 return "Ce sondage n'est pas encore commencé";
221 } else if ($status > 0) {
222 return "Ce sondage est terminé";
223 }
224 if (!is_null($this->voterFilter) && !$this->voterFilter->checkUser($user)) {
225 return "Ce sondage ne s'adresse pas à toi";
226 }
227 $vote = SurveyVote::getVote($this, $user, false);
228 if (is_null($vote)) {
229 return "Tu as déjà voté à ce sondage.";
230 }
231 return true;
232 }
233
234 public function vote(User $user, array $answers)
235 {
236 if (!$this->canVote($user)) {
237 return array('survey' => "Tu n'es pas autorisé à voter à ce sondage.");
238 }
239 $vote = SurveyVote::getVote($this, $user);
240 if (is_null($vote)) {
241 return $vote;
242 }
243 $answers = new PlDict($answers);
244 foreach ($this->questions as $question) {
245 $question->vote($vote, $answers);
246 }
247 return $vote;
248 }
249
2f4b93be 250 public static function get($name, $fetchQuestions = true)
797d27db 251 {
2f4b93be
FB
252 if (is_array($name)) {
253 $name = $name[0];
797d27db 254 }
2f4b93be
FB
255 $survey = new Survey();
256 $survey->fetchQuestions = $fetchQuestions;
257 if (can_convert_to_integer($name)) {
258 $survey->id = $name;
797d27db 259 } else {
2f4b93be 260 $survey->shortname = $name;
8fe81c50 261 }
2f4b93be
FB
262 if (!$survey->fetch()) {
263 return null;
5c6e38d7 264 }
2f4b93be 265 return $survey;
8fe81c50 266 }
267
2f4b93be 268 public static function iterActive()
8fe81c50 269 {
2f4b93be
FB
270 $survey = new Survey();
271 $survey->fetchQuestions = false;
272 return $survey->iterateOnCondition('begin <= CURDATE() AND end >= CURDATE()
273 AND FIND_IN_SET(\'validated\', flags)');
8fe81c50 274 }
5c6e38d7 275}
8fe81c50 276
2f4b93be 277class ShortNameFieldValidator implements PlDBTableFieldValidator
5c6e38d7 278{
2f4b93be 279 public function __construct(PlDBTableField $field, $value)
8fe81c50 280 {
2f4b93be
FB
281 if (can_convert_to_integer($value) || !preg_match('/^[a-z0-9]+[-_\.a-z0-9]*[a-z0-9]+$/i', $value)) {
282 throw new PlDBBadValueException($value, $field,
283 'The shortname can only contain alphanumerical caracters, dashes, underscores and dots');
284 }
4b8c8634 285 }
8fe81c50 286}
8fe81c50 287
8602c852 288// vim:set et sw=4 sts=4 ts=4 foldmethod=marker enc=utf-8:
8fe81c50 289?>