Commit | Line | Data |
---|---|---|
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 |
22 | require_once dirname(__FILE__) . '/question.inc.php'; |
23 | require_once dirname(__FILE__) . '/answer.inc.php'; | |
24 | ||
2f4b93be | 25 | class 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 | 283 | class 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 | ?> |