Fix authentication on wiki RSS
[platal.git] / modules / survey / survey.inc.php
CommitLineData
8fe81c50 1<?php
2/***************************************************************************
3 * Copyright (C) 2003-2007 Polytechnique.org *
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
22// {{{ class Survey : static database managing functions
23class SurveyDB
24{
25 // {{{ static function retrieveList() : gets the list of available survey (current, old and not validated surveys)
26 public static function retrieveList($type, $tpl = true)
27 {
28 switch ($type) {
29 case 'w':
30 case 'waiting' :
31 $where = 'valid=0';
32 break;
33 case 'c':
34 case 'current':
35 $where = 'valid=1 AND end > NOW()';
36 break;
37 case 'o':
38 case 'old':
39 $where = 'valid=1 AND end <= NOW()';
40 break;
41 default:
42 return null;
43 }
44 $sql = 'SELECT survey_id, title, end
45 FROM survey_questions
46 WHERE '.$where.';';
47 if ($tpl) {
48 return XDB::iterator($sql);
49 } else {
50 return XDB::iterRow($sql);
51 }
52 }
53 // }}}
54
55 // {{{ static function proposeSurvey() : stores a proposition of survey in database (before validation)
56 public static function proposeSurvey($survey)
57 {
58 $sql = 'INSERT INTO survey_questions
59 SET questions={?},
60 title={?},
61 description={?},
62 author_id={?},
63 end={?},
64 promos={?},
65 valid=0;';
66 $data = $survey->storeArray();
67 return XDB::execute($sql, serialize($survey), $data['question'], $data['comment'], S::v('uid'), $data['end'], $data['promos']);
68 }
69 // }}}
70
71 // {{{ static function updateSurvey() : updates a survey in database (before validation)
72 public static function updateSurvey($survey, $sid)
73 {
74 $sql = 'UPDATE survey_questions
75 SET questions={?},
76 title={?},
77 description={?},
78 end={?},
79 promos={?}
80 WHERE survey_id={?};';
81 $data = $survey->storeArray();
82 return XDB::execute($sql, serialize($survey), $data['question'], $data['comment'], $data['end'], $data['promos'], $sid);
83 }
84 // }}}
85
86 // {{{ static function retrieveSurvey() : gets a survey in database (and unserialize the survey object structure)
87 public static function retrieveSurvey($sid)
88 {
89 $sql = 'SELECT questions, title, description, end, promos, valid
90 FROM survey_questions
91 WHERE survey_id={?}';
92 $res = XDB::query($sql, $sid);
93 $data = $res->fetchOneAssoc();
56c6950a 94 if (is_null($data) || !is_array($data)) {
95 return null;
96 }
8fe81c50 97 $survey = unserialize($data['questions']);
98 if (isset($data['end'])) {
99 $data['end'] = preg_replace('#^(\d{4})-(\d{2})-(\d{2})$#', '\3/\2/\1', $data['end']);
100 }
101 $survey->update(array('question' => $data['title'], 'comment' => $data['description'], 'end' => $data['end'], 'promos' => $data['promos']));
102 $survey->setValid($data['valid']);
103 return $survey;
104 }
105 // }}}
106
107 // {{{ static function retrieveSurveyInfo() : gets information about a survey (title, description, end date, restrictions) but does not unserialize the survey object structure
108 public static function retrieveSurveyInfo($sid)
109 {
110 $sql = 'SELECT title, description, end, promos, valid
111 FROM survey_questions
112 WHERE survey_id={?}';
113 $res = XDB::query($sql, $sid);
114 return $res->fetchOneAssoc();
115 }
116 // }}}
117
118 // {{{ static function validateSurvey() : validates a survey
119 public static function validateSurvey($sid)
120 {
121 $sql = 'UPDATE survey_questions
122 SET valid=1
123 WHERE survey_id={?};';
124 return XDB::execute($sql, $sid);
125 }
126 // }}}
127
128 // {{{ static function deleteSurvey() : deletes a survey (and all its votes)
129 public static function deleteSurvey($sid)
130 {
131 $sql1 = 'DELETE FROM survey_questions
132 WHERE survey_id={?};';
133 $sql2 = 'DELETE FROM survey_answers
134 WHERE survey_id={?};';
135 $sql3 = 'DELETE FROM survey_votes
136 WHERE survey_id={?};';
137 return (XDB::execute($sql1, $sid) && XDB::execute($sql2, $sid) && XDB::execute($sql3, $sid));
138 }
139 // }}}
140}
141// }}}
142
143// {{{ abstract class SurveyQuestion
144abstract class SurveyQuestion
145{
146 // {{{ static properties and methods regarding question types
147 private static $types = array('text' => 'texte court',
148 'textarea' => 'texte long',
149 'num' => 'num&#233;rique',
150 'radio' => 'radio',
151 'checkbox' => 'checkbox',
152 'personal' => 'informations personnelles');
153
154 public static function getTypes()
155 {
156 return self::$types;
157 }
158
159 public static function isType($t)
160 {
161 return array_key_exists($t, self::$types);
162 }
163 // }}}
164
165 // {{{ common properties, constructor, and basic methods
166 private $survey_id;
167 private $id;
168 private $question;
169 private $comment;
170
8b0fa81e 171 protected function __construct($i, $args)
8fe81c50 172 {
173 $this->id = $i;
174 $this->update($args);
175 }
176
177 protected function update($a)
178 {
179 $this->question = $a['question'];
180 $this->comment = $a['comment'];
181 }
182
183 protected function getId()
184 {
185 return $this->id;
186 }
187
188 abstract protected function getQuestionType();
189 // }}}
190
191 // {{{ tree manipulation methods : not implemented here (but definition needed)
192 protected function addChildNested($i, $c)
193 {
194 return false;
195 }
196
197 protected function addChildAfter($i, $c)
198 {
199 return false;
200 }
201
202 protected function delChild($i)
203 {
204 return false;
205 }
206 // }}}
207
208 // {{{ function edit($i, $a) : searches and edits question $i
209 protected function edit($i, $a)
210 {
211 if ($this->id == $i) {
212 $this->update($a);
213 return true;
214 } else {
215 return false;
216 }
217 }
218 // }}}
219
220 // {{{ functions toArray() and searchToArray($i) : (searches and) converts to array
221 protected function toArray()
222 {
223 return $this->storeArray();
224 }
225
226 protected function searchToArray($i)
227 {
228 if ($this->id == $i) {
229 return $this->storeArray();
230 } else {
231 return null;
232 }
233 }
234
235 protected function storeArray()
236 {
237 return array('type' => $this->getQuestionType(), 'id' => $this->id, 'question' => $this->question, 'comment' => $this->comment);
238 }
239 // }}}
240
241 // {{{ function checkSyntax() : checks question elements (before storing into database)
242 protected function checkSyntax()
243 {
244 return null;
245 }
246 // }}}
247
248 // {{{ function vote() : handles vote
249 protected function checkAnswer($ans)
250 {
251 return "";
252 }
253
254 function vote($sid, $vid, $a)
255 {
256 $ans = $this->checkAnswer($a[$this->getId]);
257 if ($ans != "") {
258 XDB::execute(
259 'INSERT INTO survey_answers
260 SET survey_id = {?},
261 vote_id = {?},
262 question_id = {?},
263 answer = "{?}"', $sid, $vid, $id, $ans);
264 }
265 }
266 // }}}
267}
268// }}}
269
270// {{{ abstract class SurveyTreeable extends SurveyQuestion : questions that allow nested ones
271abstract class SurveyTreeable extends SurveyQuestion
272{
273 // {{{ common properties, constructor
274 private $children;
275
8b0fa81e 276 protected function __construct($i, $args)
8fe81c50 277 {
278 parent::__construct($i, $args);
279 $this->children = array();
280 }
281 // }}}
282
283 // {{{ tree manipulation functions : actual implementation
284 protected function hasChild()
285 {
286 return !is_null($this->children) && is_array($this->children);
287 }
288
289 protected function addChildNested($i, $c)
290 {
291 if ($this->getId() == $i) {
292 if ($this->hasChild()) {
293 array_unshift($this->children, $c);
294 } else {
295 $this->children = array($c);
296 }
297 return true;
298 } else {
299 foreach ($this->children as $child) {
300 if ($child->addChildNested($i, $c)) {
301 return true;
302 }
303 }
304 return false;
305 }
306 }
307
308 protected function addChildAfter($i, $c)
309 {
310 $found = false;
311 for ($k = 0; $k < count($this->children); $k++) {
312 if ($this->children[$k]->getId() == $i) {
313 $found = true;
314 break;
315 } else {
316 if ($this->children[$k]->addChildAfter($i, $c)) {
317 return true;
318 }
319 }
320 }
321 if ($found) {
322 array_splice($this->children, $k+1, 0, array($c));
323 return true;
324 }
325 return false;
326 }
327
328 protected function delChild($i)
329 {
330 $found = false;
331 for ($k = 0; $k < count($this->children); $k++) {
332 if ($this->children[$k]->getId() == $i) {
333 $found = true;
334 break;
335 } else {
336 if ($this->children[$k]->delChild($i)) {
337 return true;
338 }
339 }
340 }
341 if ($found) {
342 array_splice($this->children, $k, 1);
343 return true;
344 }
345 return false;
346 }
347 // }}}
348
349 // {{{ function edit() with tree support
350 protected function edit($i, $a)
351 {
352 if ($this->getId() == $i) {
353 $this->update($a);
354 return true;
355 } else {
356 foreach ($this->children as $child) {
357 if ($child->edit($i, $a)) {
358 return true;
359 }
360 }
361 return false;
362 }
363 }
364 // }}}
365
366 // {{{ functions toArray() and searchToArray() with tree support
367 protected function toArray()
368 {
369 if ($this->hasChild()) {
370 $cArr = array();
371 foreach ($this->children as $child) {
372 $cArr[] = $child->toArray();
373 }
374 $a = $this->storeArray();
375 $a['children'] = $cArr;
376 return $a;
377 } else {
378 return $this->storeArray();
379 }
380 }
381
382 protected function searchToArray($i)
383 {
384 if ($this->getId() == $i) {
385 return $this->storeArray();
386 } else {
387 foreach ($this->children as $child) {
388 $a = $child->searchToArray($i);
389 if (!is_null($a) && is_array($a)) {
390 return $a;
391 }
392 }
393 return null;
394 }
395 }
396 // }}}
397
398 // {{{ function checkSyntax()
399 protected function checkSyntax()
400 {
401 $rArr = array();
402 foreach ($this->children as $child) {
403 $a = $child->checkSyntax();
404 if ($a != null) {
405 $rArr[] = $a;
406 }
407 }
408 return (empty($rArr))? null : $rArr;
409 }
410 // }}}
411
412 // {{{ function vote()
413 function vote($sid, $vid, $a)
414 {
415 parent::vote($sid, $vid, $a);
416 if ($this->hasChild()) {
417 foreach ($this->children as $c) {
418 $c->vote($sid, $vid, $a);
419 }
420 }
421 }
422 // }}}
423}
424// }}}
425
426// {{{ class SurveyRoot extends SurveyTreeable : root of any survey, actually the only entry point (no public methods outside this class)
427class SurveyRoot extends SurveyTreeable
428{
429 // {{{ properties, constructor and basic methods
430 private $last_id;
431 private $beginning;
432 private $end;
433 private $promos;
434 private $valid;
435
8b0fa81e 436 public function __construct($args)
8fe81c50 437 {
438 parent::__construct(0, $args);
439 $this->last_id = 0;
440 }
441
442 public function update($args)
443 {
444 parent::update($args);
445 //$this->beginning = $args['beginning_year'] . "-" . $args['beginning_month'] . "-" . $args['beginning_day'];
446 //$this->end = $args['end_year'] . "-" . $args['end_year'] . "-" . $args['end_day'];
447 if (preg_match('#^\d{2}/\d{2}/\d{4}$#', $args['end'])) {
448 $this->end = preg_replace('#^(\d{2})/(\d{2})/(\d{4})$#', '\3-\2-\1', $args['end']);
449 } else {
450 $this->end = (preg_match('#^\d{4}-\d{2}-\d{2}$#', $args['end']))? $args['end'] : '#';
451 }
452 $this->promos = ($args['promos'] == '' || preg_match('#^(\d{4}-?|(\d{4})?-\d{4})(,(\d{4}-?|(\d{4})?-\d{4}))*$#', $args['promos']))? $args['promos'] : '#';
453 }
454
455 private function getNextId()
456 {
457 $this->last_id++;
458 return $this->last_id;
459 }
460
461 public function setValid($v)
462 {
56c6950a 463 $this->valid = (boolean) $v;
8fe81c50 464 }
465
466 public function isValid()
467 {
468 return $this->valid;
469 }
470
471 protected function getQuestionType()
472 {
473 return "root";
474 }
475 // }}}
476
477 // {{{ function factory($type, $args) : builds a question according to the given type
478 public function factory($t, $args)
479 {
480 $i = $this->getNextId();
481 switch ($t) {
482 case 'text':
483 return new SurveyText($i, $args);
484 case 'textarea':
485 return new SurveyTextarea($i, $args);
486 case 'num':
487 return new SurveyNum($i, $args);
488 case 'radio':
489 return new SurveyRadio($i, $args);
490 case 'checkbox':
491 return new SurveyCheckbox($i, $args);
492 case 'personal':
493 return new SurveyPersonal($i, $args);
494 default:
495 return null;
496 }
497 }
498 // }}}
499
500 // {{{ methods needing public access
501 public function addChildNested($i, $c)
502 {
56c6950a 503 return !$this->isValid() && parent::addChildNested($i, $c);
8fe81c50 504 }
505
506 public function addChildAfter($i, $c)
507 {
56c6950a 508 return !$this->isValid() && parent::addChildAfter($i, $c);
8fe81c50 509 }
510
511 public function delChild($i)
512 {
56c6950a 513 return !$this->isValid() && parent::delChild($i);
8fe81c50 514 }
515
516 public function edit($i, $a)
517 {
56c6950a 518 return (!$this->isValid() || $this->getId() == $i) && parent::edit($i, $a);
8fe81c50 519 }
520
521 public function toArray()
522 {
523 return parent::toArray();
524 }
525
526 public function searchToArray($i)
527 {
528 return parent::searchToArray($i);
529 }
530 // }}}
531
532 // {{{ function storeArray()
533 public function storeArray()
534 {
535 $rArr = parent::storeArray();
536 $rArr['beginning'] = $this->beginning;
537 $rArr['end'] = $this->end;
538 $rArr['promos'] = $this->promos;
56c6950a 539 $rArr['valid'] = $this->valid;
8fe81c50 540 return $rArr;
541 }
542 // }}}
543
544 // {{{ function checkSyntax()
545 private static $errorMessages = array(
546 "dateformat" => "la date de fin de sondage est mal formatt&#233;e : elle doit respecter la syntaxe dd/mm/aaaa",
547 "datepassed" => "la date de fin de sondage est d&#233;j&#224; d&#233;pass&#233;e : vous devez pr&#233;ciser une date future",
548 "promoformat" => "les restrictions &#224; certaines promotions sont mal formatt&#233;es"
549 );
550
551 public function checkSyntax()
552 {
553 $rArr = parent::checkSyntax();
554 if (!preg_match('#^\d{4}-\d{2}-\d{2}$#', $this->end)) {
555 $rArr[] = array('question' => $this->getId(), 'error' => self::$errorMessages["dateformat"]);
556 } else {
557 if (strtotime($this->end) - time() <= 0) {
558 $rArr[] = array('question' => $this->getId(), 'error' => self::$errorMessages["datepassed"]);
559 }
560 }
561 if ($this->promos != '' && !preg_match('#^(\d{4}-?|(\d{4})?-\d{4})(,(\d{4}-?|(\d{4})?-\d{4}))*$#', $this->promos)) {
562 $rArr[] = array('question' => $this->getId(), 'error' => self::$errorMessages["promoformat"]);
563 }
564 return (empty($rArr))? null : $rArr;
565 }
566 // }}}
567}
568// }}}
569
570// {{{ abstract class SurveySimple extends SurveyQuestion : "opened" questions
571abstract class SurveySimple extends SurveyQuestion
572{
573 protected function checkAnswer($ans)
574 {
575 return $ans;
576 }
577}
578
579// {{{ class SurveyText extends SurveySimple : simple text field, allowing a few words
580class SurveyText extends SurveySimple
581{
582 protected function getQuestionType()
583 {
584 return "text";
585 }
586}
587// }}}
588
589// {{{ class SurveyTextarea extends SurveySimple : textarea field, allowing longer comments
590class SurveyTextarea extends SurveySimple
591{
592 protected function getQuestionType()
593 {
594 return "textarea";
595 }
596}
597// }}}
598
599// {{{ class SurveyNum extends SurveySimple : allows numerical answers
600class SurveyNum extends SurveySimple
601{
602 protected function checkAnswer($ans)
603 {
604 return intval($ans);
605 }
606
607 protected function getQuestionType()
608 {
609 return "num";
610 }
611}
612// }}}
613// }}}
614
615// {{{ abstract class SurveyList extends SurveyTreeable : restricted questions that allows only a list of possible answers
616abstract class SurveyList extends SurveyTreeable
617{
618 private $choices;
619
620 protected function update($args)
621 {
622 parent::update($args);
623 $this->choices = explode('|', $args['options']);
624 }
625
626 protected function storeArray()
627 {
628 $rArr = parent::storeArray();
629 $rArr['choices'] = $this->choices;
630 $rArr['options'] = implode('|', $this->choices);
631 return $rArr;
632 }
633
634}
635
636// {{{ class SurveyRadio extends SurveyList : radio question, allows one answer among the list offered
637class SurveyRadio extends SurveyList
638{
639 protected function checkAnswer($ans)
640 {
641 return (in_array($ans, $this->choices)) ? $ans : "";
642 }
643
644 protected function getQuestionType()
645 {
646 return "radio";
647 }
648}
649// }}}
650
651// {{{ class SurveyCheckbox extends SurveyList : checkbox question, allows any number of answers among the list offered
652class SurveyCheckbox extends SurveyList
653{
654 protected function checkAnswer($ans)
655 {
656 $rep = "";
657 foreach ($this->choices as $key => $value) {
658 if (array_key_exists($key,$v[$id]) && $v[$id][$key]) {
659 $rep .= "|" . $key;
660 }
661 }
662 $rep = (strlen($rep) >= 4) ? substr($rep, 4) : "";
663 return $rep;
664 }
665
666 protected function getQuestionType()
667 {
668 return "checkbox";
669 }
670}
671// }}}
672// }}}
673
674// {{{ class SurveyPersonal extends SurveyQuestion : allows easy and verified access to user's personal data (promotion, name...)
675class SurveyPersonal extends SurveyQuestion
676{
677 private $perm;
678
679 protected function update($args)
680 {
681 $args['question'] = "Informations personnelles";
682 parent::update($args);
683 $this->perm['promo'] = isset($args['promo'])? 1 : 0;
684 $this->perm['name'] = isset($args['name'])? 1 : 0;
685 }
686
687 protected function checkAnswer($ans)
688 {
689 if (intval($ans) == 1) {
690 // requete mysql qvb
691 return "";
692 } else {
693 return "";
694 }
695 }
696
697 protected function getQuestionType()
698 {
699 return "personal";
700 }
701
702 protected function storeArray()
703 {
704 $a = parent::storeArray();
705 $a['promo'] = $this->perm['promo'];
706 $a['name'] = $this->perm['name'];
707 return $a;
708 }
709}
710// }}}
711
712// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
713?>