00001 <?php
00002
00033 class SQuestionnaire extends SObject
00034 {
00035 # Data
00036 # --------------------------------------------------
00037
00038 protected $surveyId;
00039 protected $questions;
00040 protected $responses;
00041 protected $refOrder;
00042
00043 protected $options;
00044 protected $DBI;
00045
00046 # temporary solution: figure out which items have been updated
00047 # by storing flags in array
00048 protected $responseUpdateFlags;
00049
00050 # Functions
00051 # --------------------------------------------------
00052
00061 public function __construct($id = "") {
00062 global $DBI;
00063 parent::__construct($id);
00064
00065 if (isset($DBI)) { $this->setDBI($DBI); }
00066
00067 $this->setOption('surveyClass', 'SSurvey');
00068 $this->setOption('questionClass', 'SQuestion');
00069 $this->setOption('responseClass', 'SResponse');
00070
00071 if ($id != "") {
00072 $this->populate($id);
00073 }
00074 }
00075
00084 public function setDBI($DBI) {
00085 $this->DBI = &$DBI;
00086 }
00087
00095 public function getDBI() {
00096 return $this->DBI;
00097 }
00098
00108 public function setOption($key, $value) {
00109 $this->options[$key] = $value;
00110 }
00111
00120 public function getOption($key) {
00121 if (!isset($this->options[$key])) return null;
00122 return $this->options[$key];
00123 }
00124
00125 # Populate the questionnaire with questions. If there is a review id set,
00126 # also populate it with the responses for that review.
00127
00135 public function populate($surveyId = "") {
00136 $rClass = $this->getOption('responseClass');
00137 $qClass = $this->getOption('questionClass');
00138 $sClass = $this->getOption('surveyClass');
00139
00140 # If a survey is specified, check to see if the requested survey
00141 # object exists by trying to populate it. If not, throw an error.
00142 if ($surveyId != ""){
00143 $s = new $sClass($surveyId);
00144 if ($s->hasError()) {
00145 $this->setPrettyError('populate', 'Specified survey object with id ' . $surveyId
00146 . ' could not be populated.');
00147 $this->getErrorFrom($s);
00148 return false;
00149 }
00150 $this->setSurveyId($surveyId);
00151 }
00152
00153 # Populate a list of all available questions
00154 $qProvider = new $qClass();
00155 $qList = $qProvider->getList(array('active' => 1, 'order' => 'qOrder'));
00156 if ($qProvider->hasError()) {
00157 $this->setPrettyError('populate', 'Could not populate a list of questions.');
00158 $this->getErrorFrom($qProvider);
00159 return false;
00160 }
00161
00162 # prepare to update our collection of questions and responses--
00163 # clear the arrays
00164 $this->questions = array();
00165 $this->responses = array();
00166 $this->refOrder = array();
00167
00168 # loop through the results and add an object to the questionnaire for each
00169 foreach ($qList as $q) {
00170 $this->addQuestion($q);
00171 }
00172
00173 # If there is a survey set, load in the responses as well
00174 if ($surveyId != "") {
00175
00176 # assemble the components we'll need for the left join
00177 $q = new $qClass();
00178 $r = new $rClass();
00179 $qId = $q->getUniqueAttributes();
00180 $rId = $r->getUniqueAttributes();
00181 $rEntity = $r->getEntity();
00182 $qEntity = $q->getEntity();
00183 $sId = $s->getUniqueAttributes();
00184
00185 # build the query - left join response onto question (get the question Id
00186 # for each response), limit by responses only related to this survey.
00187 $query = "SELECT $rEntity.$rId[0] AS responseId, $qEntity.ref as qRef FROM"
00188 . " $rEntity LEFT JOIN $qEntity ON $rEntity.questionId = $qEntity.$qId[0]"
00189 . " WHERE $sId[0] = '$surveyId' AND $qEntity.active = '1'";
00190 print($query);
00191 # run the query
00192 $result = $this->queryOrSetError($query);
00193 if ($result === false) return false;
00194
00195 # loop through the results and add them to the questionnaire object
00196 for ($i = 0; $i < count($result); $i++) {
00197 $ref = $result[$i]["qRef"];
00198 $rid = $result[$i]["responseId"];
00199
00200 if ($ref == "") {
00201 $this->setPrettyError('populate', 'Encountered a blank ref value while '
00202 . ' reading responses. Ref value was for response id ' . $rid);
00203 return false;
00204 }
00205
00206 $r = new $rClass($rid);
00207 if(!$this->addResponseForRef($ref, $r)){
00208 return false;
00209 }
00210 }
00211 }
00212 return true;
00213 }
00214
00223 public function addQuestion($question) {
00224 # store it in the array, and create the corresponding
00225 # responses array. There should never be two questions with
00226 # the same ref, so we can hash them by ref.
00227 #
00228 # store the ordering of the refs in a separate array
00229 # since we've ordered the query by order, we can just push the
00230 # ref values on here.
00231
00232 if (!$question->isValidQuestion())
00233 {
00234 $this->setError("Attempt to addQuestion() failed: question is not valid");
00235 return false;
00236 }
00237 $ref = $question->getRef();
00238 if (isset($this->questions[$ref]))
00239 {
00240 $this->setWarning("addQuestion() is replacing a question that already exists for ref $ref");
00241 return false;
00242 }
00243 $this->questions[$ref] = $question;
00244 $this->responses[$ref] = array();
00245
00246 array_push($this->refOrder, $ref);
00247 }
00248
00257 public function getQuestionByRef($ref) {
00258 if (!isset($this->questions[$ref])) {
00259 $this->setError("Attempt to getQuestionByRef() failed: the ref '$ref' does not exist.");
00260 return false;
00261 }
00262 return $this->questions[$ref];
00263 }
00264
00274 public function addResponseForRef($ref, $response) {
00275 if (!isset($this->responses[$ref])) {
00276 $this->setError("Attempt to setResponse() failed: the array of responses for ref '$ref' does not exist.");
00277 return false;
00278 }
00279 array_push($this->responses[$ref], $response);
00280 if(isset($this->responseUpdateFlags[$ref])){
00281 array_push($this->responseUpdateFlags[$ref], 1);
00282 }
00283 return true;
00284 }
00285
00294 public function getResponsesForRef($ref) {
00295 if (!isset($this->responses[$ref])) {
00296 $this->setError("Attempt to getResponsesForRef() failed: the array of responses for ref '$ref' does not exist.");
00297 return false;
00298 }
00299 return $this->responses[$ref];
00300 }
00301
00311 public function getResponseByRefAndId($ref, $responseId) {
00312 if (!isset($this->responses[$ref])) {
00313 $this->setError("Attempt to getResponseByRefAndId() failed: the array of responses for ref '$ref' does not exist.");
00314 return false;
00315 }
00316 foreach($this->responses[$ref] as $response) {
00317 if ($response->getResponseId() == $responseId) {
00318 return $response;
00319 }
00320 }
00321 $this->setError("Attempt to getResponseByRefAndId() failed: a response with that Id was not found in responses for ref '$ref'.");
00322 return false;
00323 }
00324
00325
00326
00327
00328
00329
00337 public function commit() {
00338 if (count($this->getError()) != 0) {
00339 $this->setError("Attempt to call commit() Questionnaire failed: "
00340 . "error count for object is not zero");
00341 return false;
00342 }
00343
00344 if ($this->surveyId == "") {
00345 # commit only the questions back to the database
00346 $questions = $this->getQuestions();
00347 foreach($questions as $ref => $question) {
00348 $question->commit();
00349 }
00350 } else {
00351 # commit only the responses back to the database
00352 $responses = $this->getResponses();
00353 foreach($responses as $respRef) {
00354 foreach($respRef as $response) {
00355 $response->commit();
00356 }
00357 }
00358 }
00359 return true;
00360 }
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00378 public function getXFormsModel()
00379 {
00380 if (count($this->getError()) != 0)
00381 {
00382 $this->setError("Attempt to call getXFormsModel on Questionnaire failed: "
00383 . "error count for object is not zero");
00384 return false;
00385 }
00386
00387 $ret = " <model>\n <instance>\n ";
00388 $order = $this->getRefOrder();
00389 $questions = $this->getQuestions();
00390
00391
00392 foreach($order as $ref)
00393 {
00394
00395 $question = $questions[$ref];
00396
00397
00398
00399
00400
00401 $responses = $this->getResponsesForRef($ref);
00402
00403
00404 if ($responses === false) {
00405 $this->setError("Attempt to getXFormsModel() failed: "
00406 . "call to getResponsesByRef() failed for ref $ref");
00407 return false;
00408 }
00409
00410
00411 if (count($responses) > 0) {
00412 foreach($responses as $response) {
00413
00414 $ret .= $question->getXFormsOpenTag($response->getResponseId())
00415 . $response->getResponse() . $question->getXFormsCloseTag() . "\n";
00416 }
00417 } else {
00418
00419
00420 $ret .= $question->getXFormsOpenCloseTag() . "\n";
00421 }
00422 }
00423 $ret .= " </instance>\n </model>\n";
00424 return $ret;
00425 }
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00446 public function setXFormsModel($xml) {
00447
00448
00449
00450
00451 if ($this->getSurveyId() == "" || !ctype_digit((string) $this->getSurveyId())) {
00452 $this->setError("Attempt to call setXFormsModel() failed: "
00453 . "questionnaire object must have a reviewId");
00454 return false;
00455 }
00456
00457
00458 $x = $this->parseXML($xml);
00459 if ($x === false) {
00460 $this->setError("Attempt to setXFormsModel() failed: could not parse input XML.");
00461 print_r($this->getError());
00462 return false;
00463 }
00464
00465
00466 if (!isset($x->instance)){
00467 $this->setError("Attempt to setXFormsModel() failed: input XML lacks instance node.");
00468 return false;
00469 }
00470 $instance = $x->instance;
00471
00472
00473 $this->responseUpdateFlags = array();
00474
00475
00476
00477
00478 foreach($instance->children() as $ref => $value) {
00479
00480
00481 $responsesForRef = $this->getResponsesForRef($ref);
00482 if ($responsesForRef === false) {
00483 $this->setError("Attempt to setXFormsModel() failed: unable to"
00484 . " get responses array for ref $ref in Questionnaire.");
00485 return false;
00486 }
00487
00488
00489
00490
00491
00492 if (!isset($this->responseUpdateFlags[$ref])) {
00493 $this->responseUpdateFlags[$ref] = array();
00494 foreach($responsesForRef as $aResponse){
00495 $aResponse->setResponse("");
00496 }
00497 }
00498
00499
00500 $numFilledForRef = count($this->responseUpdateFlags[$ref]);
00501
00502
00503 $numRespObjsForRef = count($responsesForRef);
00504
00505
00506
00507 if ($numFilledForRef < $numRespObjsForRef) {
00508 $aResponse = $responsesForRef[$numFilledForRef];
00509 $aResponse->setResponse($value);
00510 array_push($this->responseUpdateFlags[$ref], true);
00511
00512 } else {
00513
00514 $q = $this->getQuestionByRef($ref);
00515 if ($q === false) {
00516 $this->setError("Attempt to setXFormsModel() failed: unable"
00517 . " to getQuestionByRef $ref in Questionnaire.");
00518 return false;
00519 }
00520 # creating a new response that's not already in database/memory
00521 # store in array of responses at [ref][dbid]
00522 $rClass = $this->getOption('responseClass');
00523 $r = new $rClass();
00524 $r->setSurveyId($this->getSurveyId());
00525 $r->setQuestionId($q->getQuestionId());
00526 $r->setResponse($value);
00527
00528 # this is not gonna work because it does not yet have an ID.
00529 $this->addResponseForRef($ref, $r);
00530 }
00531 }
00532 return true;
00533 }
00534
00535
00536
00537
00538
00546 protected function getQuestions() {
00547 return $this->questions;
00548 }
00549
00557 protected function getRefOrder() {
00558 return $this->refOrder;
00559 }
00560
00568 protected function getResponses() {
00569 return $this->responses;
00570 }
00571
00579 public function getSurveyId() {
00580 return $this->surveyId;
00581 }
00582
00591 protected function setSurveyId($surveyId) {
00592 $this->surveyId = $surveyId;
00593 }
00594
00603 protected function queryOrSetError($query) {
00604 if (!isset($this->DBI)) {
00605 $this->setPrettyError('queryOrSetError',
00606 'No DBI found on questionnaire object.');
00607 return false;
00608 }
00609 $result = $this->DBI->query($query);
00610 if (count($this->DBI->getError()) != 0){
00611 $this->setError($this->DBI->getError());
00612 return false;
00613 }
00614 return $result;
00615 }
00616 }
00617
00618 ?>