Stub of the new surveys.
[platal.git] / modules / survey / survey.inc.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2010 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 extends PlDBTableEntry implements SurveyQuestionContainer
23 {
24 private $fetchQuestions = true;
25 public $questions = array();
26
27 public function __construct()
28 {
29 parent::__construct('surveys');
30 $this->registerFieldValidator('shortname', 'ShortNameFieldValidator');
31 $this->registerFieldFormatter('voters', 'JSonFieldFormatter');
32 $this->registerFieldFormatter('viewers', 'JSonFieldFormatter');
33 }
34
35 protected function postFetch()
36 {
37 if (!$this->fetchQuestions) {
38 return true;
39 }
40 $selector = new SurveyQuestion($this);
41 $selector->sid = $this->id;
42
43 $stack = array();
44 foreach ($selector as $question) {
45 $question = $question->typedInstance();
46 if (is_null($question->parent)) {
47 $this->addQuestion($question);
48 } else {
49 $pos = count($stack) - 1;
50 while ($stack[$pos]->qid != $question->parent) {
51 --$pos;
52 array_pop($stack);
53 }
54 Platal::assert(count($stack) > 0, "Invalid question structure");
55 Platal::assert($stack[$pos] instanceof SurveyQuestionContainer, "Invalid question type");
56 $stack[$pos]->addQuestion($question);
57 }
58 array_push($stack, $question);
59 }
60 return true;
61 }
62
63 protected function postSave()
64 {
65 $questions = array();
66 $selector = new SurveyQuestion($this);
67 $selector->sid = $this->id;
68 $selector->delete();
69
70 $this->reassignQuestionIds();
71 foreach ($this->questions as $question) {
72 $question->sid = $this->id;
73 $question->insert();
74 }
75 }
76
77 public function addQuestion(SurveyQuestion $question, $pos = null)
78 {
79 $question->parent = null;
80 if (is_null($pos)) {
81 $this->questions[] = $question;
82 } else {
83 array_splice($this->questions, $pos, 0, $question);
84 }
85 }
86
87 public function newQuestion($type, $pos = null)
88 {
89 $question = SurveyQuestion::instanceForType($this, $type);
90 $this->addQuestion($question, $pos);
91 return $question;
92 }
93
94 public function reassignQuestionIds()
95 {
96 $id = 0;
97 foreach ($this->questions as $question) {
98 $question->qid = $id;
99 if ($question instanceof SurveyQuestionContainer) {
100 $id = $question->reassignQuestionIds();
101 } else {
102 $id++;
103 }
104 }
105 return $id;
106 }
107
108 public function export()
109 {
110 $export = parent::export();
111 $export['questions'] = array();
112 foreach ($this->questions as $question) {
113 $export['questions'][] = $question->export();
114 }
115 return $export;
116 }
117
118 public function canSee(User $user)
119 {
120 if ($this->uid == $user->id() || $user->hasFlag('admin')) {
121 return true;
122 }
123 return false;
124 }
125
126 public static function get($name, $fetchQuestions = true)
127 {
128 if (is_array($name)) {
129 $name = $name[0];
130 }
131 $survey = new Survey();
132 $survey->fetchQuestions = $fetchQuestions;
133 if (can_convert_to_integer($name)) {
134 $survey->id = $name;
135 } else {
136 $survey->shortname = $name;
137 }
138 if (!$survey->fetch()) {
139 return null;
140 }
141 return $survey;
142 }
143
144 public static function iterActive()
145 {
146 $survey = new Survey();
147 $survey->fetchQuestions = false;
148 return $survey->iterateOnCondition('begin <= CURDATE() AND end >= CURDATE()
149 AND FIND_IN_SET(\'validated\', flags)');
150 }
151 }
152
153 class ShortNameFieldValidator implements PlDBTableFieldValidator
154 {
155 public function __construct(PlDBTableField $field, $value)
156 {
157 if (can_convert_to_integer($value) || !preg_match('/^[a-z0-9]+[-_\.a-z0-9]*[a-z0-9]+$/i', $value)) {
158 throw new PlDBBadValueException($value, $field,
159 'The shortname can only contain alphanumerical caracters, dashes, underscores and dots');
160 }
161 }
162 }
163
164 interface SurveyQuestionContainer
165 {
166 public function addQuestion(SurveyQuestion $question, $pos = null);
167 public function newQuestion($type, $pos = null);
168 public function reassignQuestionIds();
169 }
170
171 class SurveyQuestion extends PlDBTableEntry
172 {
173 protected $survey;
174 protected $parentQuestion;
175
176 public function __construct(Survey $survey)
177 {
178 parent::__construct('survey_questions');
179 $this->registerFieldFormatter('parameters', 'JSonFieldFormatter');
180 $this->survey = $survey;
181 }
182
183 public function typedInstance()
184 {
185 $instance = self::instanceForType($this->survey, $this->type);
186 $instance->copy($this);
187 return $instance;
188 }
189
190 public static function instanceForType(Survey $survey, $type)
191 {
192 require_once dirname(__FILE__) . '/' . $type . '.inc.php';
193 $class = 'SurveyQuestion' . $type;
194 return new $class($survey);
195 }
196 }
197
198 class SurveyQuestionGroup extends SurveyQuestion implements SurveyQuestionContainer
199 {
200 public $children = array();
201
202 public function __construct(Survey $survey)
203 {
204 parent::__construct($survey);
205 }
206
207 public function addQuestion(SurveyQuestion $question, $pos = null)
208 {
209 $question->parentQuestion = $this;
210 if (is_null($pos)) {
211 $this->children[] = $question;
212 } else {
213 array_splice($this->children, $pos, 0, $question);
214 }
215 }
216
217 public function newQuestion($type, $pos = null)
218 {
219 $question = SurveyQuestion::instanceForType($this->survey, $type);
220 $this->addQuestion($question, $pos);
221 return $question;
222 }
223
224 public function reassignQuestionIds()
225 {
226 $id = $this->qid + 1;
227 foreach ($this->children as $question) {
228 $question->qid = $id;
229 if ($question instanceof SurveyQuestionContainer) {
230 $id = $question->reassignQuestionIds();
231 } else {
232 $id++;
233 }
234 }
235 return $id;
236 }
237
238 protected function postSave()
239 {
240 foreach ($this->children as $question) {
241 $question->sid = $this->sid;
242 $question->parent = $this->qid;
243 $question->insert();
244 }
245 }
246
247 public function export()
248 {
249 $export = parent::export();
250 $export['children'] = array();
251 foreach ($this->children as $child) {
252 $export['children'][] = $child->export();
253 }
254 return $export;
255 }
256 }
257
258 // vim:set et sw=4 sts=4 ts=4 foldmethod=marker enc=utf-8:
259 ?>