1<?php 2 3/* Copyright (c) 1998-2019 ILIAS open source, Extended GPL, see docs/LICENSE */ 4 5/** 6 * Text survey question 7 * 8 * The SurveyTextQuestion class defines and encapsulates basic methods and attributes 9 * for text survey question types. 10 * 11 * @author Helmut Schottmüller <helmut.schottmueller@mac.com> 12 */ 13class SurveyTextQuestion extends SurveyQuestion 14{ 15 public $maxchars; 16 public $textwidth; 17 public $textheight; 18 19 /** 20 * The constructor takes possible arguments an creates an instance of the SurveyTextQuestion object. 21 * 22 * @param string $title A title string to describe the question 23 * @param string $description A description string to describe the question 24 * @param string $author A string containing the name of the questions author 25 * @param integer $owner A numerical ID to identify the owner/creator 26 * @access public 27 */ 28 public function __construct($title = "", $description = "", $author = "", $questiontext = "", $owner = -1) 29 { 30 global $DIC; 31 32 $this->db = $DIC->database(); 33 parent::__construct($title, $description, $author, $questiontext, $owner); 34 35 $this->maxchars = 0; 36 $this->textwidth = 50; 37 $this->textheight = 5; 38 } 39 40 /** 41 * Returns the question data fields from the database 42 * 43 * @param integer $id The question ID from the database 44 * @return array Array containing the question fields and data from the database 45 * @access public 46 */ 47 public function getQuestionDataArray($id) 48 { 49 $ilDB = $this->db; 50 $result = $ilDB->queryF( 51 "SELECT svy_question.*, " . $this->getAdditionalTableName() . ".* FROM svy_question, " . $this->getAdditionalTableName() . " WHERE svy_question.question_id = %s AND svy_question.question_id = " . $this->getAdditionalTableName() . ".question_fi", 52 array('integer'), 53 array($id) 54 ); 55 if ($result->numRows() == 1) { 56 return $ilDB->fetchAssoc($result); 57 } else { 58 return array(); 59 } 60 } 61 62 /** 63 * Loads a SurveyTextQuestion object from the database 64 * 65 * @param integer $id The database id of the text survey question 66 * @access public 67 */ 68 public function loadFromDb($id) 69 { 70 $ilDB = $this->db; 71 72 $result = $ilDB->queryF( 73 "SELECT svy_question.*, " . $this->getAdditionalTableName() . ".* FROM svy_question LEFT JOIN " . $this->getAdditionalTableName() . " ON " . $this->getAdditionalTableName() . ".question_fi = svy_question.question_id WHERE svy_question.question_id = %s", 74 array('integer'), 75 array($id) 76 ); 77 if ($result->numRows() == 1) { 78 $data = $ilDB->fetchAssoc($result); 79 $this->setId($data["question_id"]); 80 $this->setTitle($data["title"]); 81 $this->label = $data['label']; 82 $this->setDescription($data["description"]); 83 $this->setObjId($data["obj_fi"]); 84 $this->setAuthor($data["author"]); 85 $this->setOwner($data["owner_fi"]); 86 $this->setQuestiontext(ilRTE::_replaceMediaObjectImageSrc($data["questiontext"], 1)); 87 $this->setObligatory($data["obligatory"]); 88 $this->setComplete($data["complete"]); 89 $this->setOriginalId($data["original_id"]); 90 91 $this->setMaxChars($data["maxchars"]); 92 $this->setTextWidth($data["width"]); 93 $this->setTextHeight($data["height"]); 94 } 95 parent::loadFromDb($id); 96 } 97 98 /** 99 * Returns true if the question is complete for use 100 * 101 * @result boolean True if the question is complete for use, otherwise false 102 * @access public 103 */ 104 public function isComplete() 105 { 106 if ( 107 strlen($this->getTitle()) && 108 strlen($this->getAuthor()) && 109 strlen($this->getQuestiontext()) 110 ) { 111 return 1; 112 } else { 113 return 0; 114 } 115 } 116 117 /** 118 * Sets the maximum number of allowed characters for the text answer 119 * 120 * @access public 121 */ 122 public function setMaxChars($maxchars = 0) 123 { 124 $this->maxchars = $maxchars; 125 } 126 127 /** 128 * Returns the maximum number of allowed characters for the text answer 129 * 130 * @access public 131 */ 132 public function getMaxChars() 133 { 134 return ($this->maxchars) ? $this->maxchars : null; 135 } 136 137 /** 138 * Saves a SurveyTextQuestion object to a database 139 * 140 * @access public 141 */ 142 public function saveToDb($original_id = "") 143 { 144 $ilDB = $this->db; 145 146 $affectedRows = parent::saveToDb($original_id); 147 if ($affectedRows == 1) { 148 $affectedRows = $ilDB->manipulateF( 149 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s", 150 array('integer'), 151 array($this->getId()) 152 ); 153 $affectedRows = $ilDB->manipulateF( 154 "INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, maxchars, width, height) VALUES (%s, %s, %s, %s)", 155 array('integer', 'integer', 'integer', 'integer'), 156 array($this->getId(), $this->getMaxChars(), $this->getTextWidth(), $this->getTextHeight()) 157 ); 158 159 $this->saveMaterial(); 160 } 161 } 162 163 /** 164 * Returns an xml representation of the question 165 * 166 * @return string The xml representation of the question 167 * @access public 168 */ 169 public function toXML($a_include_header = true, $obligatory_state = "") 170 { 171 $a_xml_writer = new ilXmlWriter; 172 $a_xml_writer->xmlHeader(); 173 $this->insertXML($a_xml_writer, $a_include_header, $obligatory_state); 174 $xml = $a_xml_writer->xmlDumpMem(false); 175 if (!$a_include_header) { 176 $pos = strpos($xml, "?>"); 177 $xml = substr($xml, $pos + 2); 178 } 179 return $xml; 180 } 181 182 /** 183 * Adds the question XML to a given XMLWriter object 184 * 185 * @param object $a_xml_writer The XMLWriter object 186 * @param boolean $a_include_header Determines wheather or not the XML should be used 187 * @access public 188 */ 189 public function insertXML(&$a_xml_writer, $a_include_header = true) 190 { 191 $attrs = array( 192 "id" => $this->getId(), 193 "title" => $this->getTitle(), 194 "type" => $this->getQuestiontype(), 195 "obligatory" => $this->getObligatory() 196 ); 197 $a_xml_writer->xmlStartTag("question", $attrs); 198 199 $a_xml_writer->xmlElement("description", null, $this->getDescription()); 200 $a_xml_writer->xmlElement("author", null, $this->getAuthor()); 201 if (strlen($this->label)) { 202 $attrs = array( 203 "label" => $this->label, 204 ); 205 } else { 206 $attrs = array(); 207 } 208 $a_xml_writer->xmlStartTag("questiontext", $attrs); 209 $this->addMaterialTag($a_xml_writer, $this->getQuestiontext()); 210 $a_xml_writer->xmlEndTag("questiontext"); 211 212 $a_xml_writer->xmlStartTag("responses"); 213 $attrs = array( 214 "id" => "0", 215 "rows" => $this->getTextHeight(), 216 "columns" => $this->getTextWidth() 217 ); 218 if ($this->getMaxChars() > 0) { 219 $attrs["maxlength"] = $this->getMaxChars(); 220 } 221 $a_xml_writer->xmlElement("response_text", $attrs); 222 $a_xml_writer->xmlEndTag("responses"); 223 224 if (count($this->material)) { 225 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $this->material["internal_link"], $matches)) { 226 $attrs = array( 227 "label" => $this->material["title"] 228 ); 229 $a_xml_writer->xmlStartTag("material", $attrs); 230 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3]; 231 if (strcmp($matches[1], "") != 0) { 232 $intlink = $this->material["internal_link"]; 233 } 234 $a_xml_writer->xmlElement("mattext", null, $intlink); 235 $a_xml_writer->xmlEndTag("material"); 236 } 237 } 238 239 $a_xml_writer->xmlEndTag("question"); 240 } 241 242 /** 243 * Returns the question type of the question 244 * 245 * @return integer The question type of the question 246 * @access public 247 */ 248 public function getQuestionType() 249 { 250 return "SurveyTextQuestion"; 251 } 252 253 /** 254 * Returns the name of the additional question data table in the database 255 * 256 * @return string The additional table name 257 * @access public 258 */ 259 public function getAdditionalTableName() 260 { 261 return "svy_qst_text"; 262 } 263 264 /** 265 * Creates the user data of the svy_answer table from the POST data 266 * 267 * @return array User data according to the svy_answer table 268 * @access public 269 */ 270 public function &getWorkingDataFromUserInput($post_data) 271 { 272 $entered_value = $post_data[$this->getId() . "_text_question"]; 273 $data = array(); 274 if (strlen($entered_value)) { 275 array_push($data, array("textanswer" => $entered_value)); 276 } 277 return $data; 278 } 279 280 /** 281 * Checks the input of the active user for obligatory status 282 * and entered values 283 * 284 * @param array $post_data The contents of the $_POST array 285 * @param integer $survey_id The database ID of the active survey 286 * @return string Empty string if the input is ok, an error message otherwise 287 * @access public 288 */ 289 public function checkUserInput($post_data, $survey_id) 290 { 291 $entered_value = $post_data[$this->getId() . "_text_question"]; 292 293 if ((!$this->getObligatory($survey_id)) && (strlen($entered_value) == 0)) { 294 return ""; 295 } 296 297 if (strlen($entered_value) == 0) { 298 return $this->lng->txt("text_question_not_filled_out"); 299 } 300 301 // see bug #22648 302 if ($this->getMaxChars() > 0 && ilStr::strLen($entered_value) > $this->getMaxChars()) { 303 return str_replace("%s", ilStr::strLen($entered_value), $this->lng->txt("svy_answer_too_long")); 304 } 305 306 return ""; 307 } 308 309 public function saveUserInput($post_data, $active_id, $a_return = false) 310 { 311 $ilDB = $this->db; 312 313 $entered_value = $this->stripSlashesAddSpaceFallback($post_data[$this->getId() . "_text_question"]); 314 $maxchars = $this->getMaxChars(); 315 316 if ($maxchars > 0) { 317 $entered_value = ilStr::subStr($entered_value, 0, $maxchars); 318 } 319 320 if ($a_return) { 321 return array(array("value" => null, "textanswer" => $entered_value)); 322 } 323 if (strlen($entered_value) == 0) { 324 return; 325 } 326 327 $next_id = $ilDB->nextId('svy_answer'); 328 #20216 329 $fields = array(); 330 $fields['answer_id'] = array("integer", $next_id); 331 $fields['question_fi'] = array("integer", $this->getId()); 332 $fields['active_fi'] = array("integer", $active_id); 333 $fields['value'] = array("float", null); 334 $fields['textanswer'] = array("clob", (strlen($entered_value)) ? $entered_value : null); 335 $fields['tstamp'] = array("integer", time()); 336 337 $affectedRows = $ilDB->insert("svy_answer", $fields); 338 } 339 340 /** 341 * Import response data from the question import file 342 * 343 * @return array $a_data Array containing the response data 344 * @access public 345 */ 346 public function importResponses($a_data) 347 { 348 foreach ($a_data as $id => $data) { 349 if ($data["maxlength"] > 0) { 350 $this->setMaxChars($data["maxlength"]); 351 } 352 if ($data["rows"] > 0) { 353 $this->setTextHeight($data["rows"]); 354 } 355 if ($data["columns"] > 0) { 356 $this->setTextWidth($data["columns"]); 357 } 358 } 359 } 360 361 /** 362 * Returns if the question is usable for preconditions 363 * 364 * @return boolean TRUE if the question is usable for a precondition, FALSE otherwise 365 * @access public 366 */ 367 public function usableForPrecondition() 368 { 369 return false; 370 } 371 372 /** 373 * Returns the width of the answer field 374 * 375 * @return integer The width of the answer field in characters 376 * @access public 377 */ 378 public function getTextWidth() 379 { 380 return ($this->textwidth) ? $this->textwidth : null; 381 } 382 383 /** 384 * Returns the height of the answer field 385 * 386 * @return integer The height of the answer field in characters 387 * @access public 388 */ 389 public function getTextHeight() 390 { 391 return ($this->textheight) ? $this->textheight : null; 392 } 393 394 /** 395 * Sets the width of the answer field 396 * 397 * @param integer $a_textwidth The width of the answer field in characters 398 * @access public 399 */ 400 public function setTextWidth($a_textwidth) 401 { 402 if ($a_textwidth < 1) { 403 $this->textwidth = 50; 404 } else { 405 $this->textwidth = $a_textwidth; 406 } 407 } 408 409 /** 410 * Sets the height of the answer field 411 * 412 * @param integer $a_textheight The height of the answer field in characters 413 * @access public 414 */ 415 public function setTextHeight($a_textheight) 416 { 417 if ($a_textheight < 1) { 418 $this->textheight = 5; 419 } else { 420 $this->textheight = $a_textheight; 421 } 422 } 423} 424