PageRenderTime 69ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/concreteOLD/blocks/form/controller.php

https://bitbucket.org/selfeky/xclusivescardwebsite
PHP | 841 lines | 725 code | 65 blank | 51 comment | 34 complexity | 82941afc75217c52d7e686c818248edd MD5 | raw file
  1. <?php
  2. defined('C5_EXECUTE') or die("Access Denied.");
  3. class FormBlockController extends BlockController {
  4. public $btTable = 'btForm';
  5. public $btQuestionsTablename = 'btFormQuestions';
  6. public $btAnswerSetTablename = 'btFormAnswerSet';
  7. public $btAnswersTablename = 'btFormAnswers';
  8. public $btInterfaceWidth = '420';
  9. public $btInterfaceHeight = '430';
  10. public $thankyouMsg='';
  11. public $noSubmitFormRedirect=0;
  12. protected $btExportTables = array('btForm', 'btFormQuestions');
  13. protected $btExportPageColumns = array('redirectCID');
  14. protected $lastAnswerSetId=0;
  15. /**
  16. * Used for localization. If we want to localize the name/description we have to include this
  17. */
  18. public function getBlockTypeDescription() {
  19. return t("Build simple forms and surveys.");
  20. }
  21. public function getBlockTypeName() {
  22. return t("Form");
  23. }
  24. public function getJavaScriptStrings() {
  25. return array(
  26. 'delete-question' => t('Are you sure you want to delete this question?'),
  27. 'form-name' => t('Your form must have a name.'),
  28. 'complete-required' => t('Please complete all required fields.'),
  29. 'ajax-error' => t('AJAX Error.'),
  30. 'form-min-1' => t('Please add at least one question to your form.')
  31. );
  32. }
  33. protected function importAdditionalData($b, $blockNode) {
  34. if (isset($blockNode->data)) {
  35. foreach($blockNode->data as $data) {
  36. if ($data['table'] != $this->getBlockTypeDatabaseTable()) {
  37. $table = (string) $data['table'];
  38. if (isset($data->record)) {
  39. foreach($data->record as $record) {
  40. $aar = new ADODB_Active_Record($table);
  41. $aar->bID = $b->getBlockID();
  42. foreach($record->children() as $node) {
  43. $nodeName = $node->getName();
  44. $aar->{$nodeName} = (string) $node;
  45. }
  46. if ($table == 'btFormQuestions') {
  47. $db = Loader::db();
  48. $aar->questionSetId = $db->GetOne('select questionSetId from btForm where bID = ?', array($b->getBlockID()));
  49. }
  50. $aar->Save();
  51. }
  52. }
  53. }
  54. }
  55. }
  56. }
  57. public function __construct($b = null){
  58. parent::__construct($b);
  59. //$this->bID = intval($this->_bID);
  60. if(is_string($this->thankyouMsg) && !strlen($this->thankyouMsg)){
  61. $this->thankyouMsg = $this->getDefaultThankYouMsg();
  62. }
  63. }
  64. public function view(){
  65. $pURI = ($_REQUEST['pURI']) ? $_REQUEST['pURI'] : str_replace(array('&ccm_token='.$_REQUEST['ccm_token'],'&btask=passthru','&method=submit_form'),'',$_SERVER['REQUEST_URI']);
  66. $this->set('pURI', htmlentities( $pURI, ENT_COMPAT, APP_CHARSET));
  67. }
  68. public function getDefaultThankYouMsg() {
  69. return t("Thanks!");
  70. }
  71. //form add or edit submit
  72. //(run after the duplicate method on first block edit of new page version)
  73. function save( $data=array() ) {
  74. if( !$data || count($data)==0 ) $data=$_POST;
  75. $b=$this->getBlockObject();
  76. $c=$b->getBlockCollectionObject();
  77. $db = Loader::db();
  78. if(intval($this->bID)>0){
  79. $q = "select count(*) as total from {$this->btTable} where bID = ".intval($this->bID);
  80. $total = $db->getOne($q);
  81. }else $total = 0;
  82. if($_POST['qsID']) $data['qsID']=$_POST['qsID'];
  83. if( !$data['qsID'] ) $data['qsID']=time();
  84. if(!$data['oldQsID']) $data['oldQsID']=$data['qsID'];
  85. $data['bID']=intval($this->bID);
  86. if(!empty($data['redirectCID'])) {
  87. $data['redirect'] = 1;
  88. } else {
  89. $data['redirect'] = 0;
  90. $data['redirectCID'] = 0;
  91. }
  92. if(empty($data['addFilesToSet'])) {
  93. $data['addFilesToSet'] = 0;
  94. }
  95. $v = array( $data['qsID'], $data['surveyName'], intval($data['notifyMeOnSubmission']), $data['recipientEmail'], $data['thankyouMsg'], intval($data['displayCaptcha']), intval($data['redirectCID']), intval($data['addFilesToSet']), intval($this->bID) );
  96. //is it new?
  97. if( intval($total)==0 ){
  98. $q = "insert into {$this->btTable} (questionSetId, surveyName, notifyMeOnSubmission, recipientEmail, thankyouMsg, displayCaptcha, redirectCID, addFilesToSet, bID) values (?, ?, ?, ?, ?, ?, ?, ?, ?)";
  99. }else{
  100. $q = "update {$this->btTable} set questionSetId = ?, surveyName=?, notifyMeOnSubmission=?, recipientEmail=?, thankyouMsg=?, displayCaptcha=?, redirectCID=?, addFilesToSet=? where bID = ? AND questionSetId=".$data['qsID'];
  101. }
  102. $rs = $db->query($q,$v);
  103. //Add Questions (for programmatically creating forms, such as during the site install)
  104. if( count($data['questions'])>0 ){
  105. $miniSurvey = new MiniSurvey();
  106. foreach( $data['questions'] as $questionData )
  107. $miniSurvey->addEditQuestion($questionData,0);
  108. }
  109. $this->questionVersioning($data);
  110. return true;
  111. }
  112. //Ties the new or edited questions to the new block number
  113. //New and edited questions are temporarily given bID=0, until the block is saved... painfully complicated
  114. protected function questionVersioning( $data=array() ){
  115. $db = Loader::db();
  116. $oldBID = intval($data['bID']);
  117. //if this block is being edited a second time, remove edited questions with the current bID that are pending replacement
  118. //if( intval($oldBID) == intval($this->bID) ){
  119. $vals=array( intval($data['oldQsID']) );
  120. $pendingQuestions=$db->getAll('SELECT msqID FROM btFormQuestions WHERE bID=0 && questionSetId=?',$vals);
  121. foreach($pendingQuestions as $pendingQuestion){
  122. $vals=array( intval($this->bID), intval($pendingQuestion['msqID']) );
  123. $db->query('DELETE FROM btFormQuestions WHERE bID=? AND msqID=?',$vals);
  124. }
  125. //}
  126. //assign any new questions the new block id
  127. $vals=array( intval($data['bID']), intval($data['qsID']), intval($data['oldQsID']) );
  128. $rs=$db->query('UPDATE btFormQuestions SET bID=?, questionSetId=? WHERE bID=0 && questionSetId=?',$vals);
  129. //These are deleted or edited questions. (edited questions have already been created with the new bID).
  130. $ignoreQuestionIDsDirty=explode( ',', $data['ignoreQuestionIDs'] );
  131. $ignoreQuestionIDs=array(0);
  132. foreach($ignoreQuestionIDsDirty as $msqID)
  133. $ignoreQuestionIDs[]=intval($msqID);
  134. $ignoreQuestionIDstr=join(',',$ignoreQuestionIDs);
  135. //remove any questions that are pending deletion, that already have this current bID
  136. $pendingDeleteQIDsDirty=explode( ',', $data['pendingDeleteIDs'] );
  137. $pendingDeleteQIDs=array();
  138. foreach($pendingDeleteQIDsDirty as $msqID)
  139. $pendingDeleteQIDs[]=intval($msqID);
  140. $vals=array( $this->bID, intval($data['qsID']), join(',',$pendingDeleteQIDs) );
  141. $unchangedQuestions=$db->query('DELETE FROM btFormQuestions WHERE bID=? AND questionSetId=? AND msqID IN (?)',$vals);
  142. }
  143. //Duplicate will run when copying a page with a block, or editing a block for the first time within a page version (before the save).
  144. function duplicate($newBID) {
  145. $b=$this->getBlockObject();
  146. $c=$b->getBlockCollectionObject();
  147. $db = Loader::db();
  148. $v = array($this->bID);
  149. $q = "select * from {$this->btTable} where bID = ? LIMIT 1";
  150. $r = $db->query($q, $v);
  151. $row = $r->fetchRow();
  152. //if the same block exists in multiple collections with the same questionSetID
  153. if(count($row)>0){
  154. $oldQuestionSetId=$row['questionSetId'];
  155. //It should only generate a new question set id if the block is copied to a new page,
  156. //otherwise it will loose all of its answer sets (from all the people who've used the form on this page)
  157. $questionSetCIDs=$db->getCol("SELECT distinct cID FROM {$this->btTable} AS f, CollectionVersionBlocks AS cvb ".
  158. "WHERE f.bID=cvb.bID AND questionSetId=".intval($row['questionSetId']) );
  159. //this question set id is used on other pages, so make a new one for this page block
  160. if( count( $questionSetCIDs ) >1 || !in_array( $c->cID, $questionSetCIDs ) ){
  161. $newQuestionSetId=time();
  162. $_POST['qsID']=$newQuestionSetId;
  163. }else{
  164. //otherwise the question set id stays the same
  165. $newQuestionSetId=$row['questionSetId'];
  166. }
  167. //duplicate survey block record
  168. //with a new Block ID and a new Question
  169. $v = array($newQuestionSetId,$row['surveyName'],$newBID,$row['thankyouMsg'],intval($row['notifyMeOnSubmission']),$row['recipientEmail'],$row['displayCaptcha'], $row['addFilesToSet']);
  170. $q = "insert into {$this->btTable} ( questionSetId, surveyName, bID,thankyouMsg,notifyMeOnSubmission,recipientEmail,displayCaptcha,addFilesToSet) values (?, ?, ?, ?, ?, ?, ?,?)";
  171. $result=$db->Execute($q, $v);
  172. $rs=$db->query("SELECT * FROM {$this->btQuestionsTablename} WHERE questionSetId=$oldQuestionSetId AND bID=".intval($this->bID) );
  173. while( $row=$rs->fetchRow() ){
  174. $v=array($newQuestionSetId,intval($row['msqID']), intval($newBID), $row['question'],$row['inputType'],$row['options'],$row['position'],$row['width'],$row['height'],$row['required']);
  175. $sql= "INSERT INTO {$this->btQuestionsTablename} (questionSetId,msqID,bID,question,inputType,options,position,width,height,required) VALUES (?,?,?,?,?,?,?,?,?,?)";
  176. $db->Execute($sql, $v);
  177. }
  178. return $newQuestionSetId;
  179. }
  180. return 0;
  181. }
  182. //users submits the completed survey
  183. function action_submit_form() {
  184. $ip = Loader::helper('validation/ip');
  185. Loader::library("file/importer");
  186. if (!$ip->check()) {
  187. $this->set('invalidIP', $ip->getErrorMessage());
  188. return;
  189. }
  190. $txt = Loader::helper('text');
  191. $db = Loader::db();
  192. //question set id
  193. $qsID=intval($_POST['qsID']);
  194. if($qsID==0)
  195. throw new Exception(t("Oops, something is wrong with the form you posted (it doesn't have a question set id)."));
  196. //get all questions for this question set
  197. $rows=$db->GetArray("SELECT * FROM {$this->btQuestionsTablename} WHERE questionSetId=? AND bID=? order by position asc, msqID", array( $qsID, intval($this->bID)));
  198. // check captcha if activated
  199. if ($this->displayCaptcha) {
  200. $captcha = Loader::helper('validation/captcha');
  201. if (!$captcha->check()) {
  202. $errors['captcha'] = t("Incorrect captcha code");
  203. $_REQUEST['ccmCaptchaCode']='';
  204. }
  205. }
  206. //checked required fields
  207. foreach($rows as $row){
  208. if( intval($row['required'])==1 ){
  209. $notCompleted=0;
  210. if($row['inputType']=='checkboxlist'){
  211. $answerFound=0;
  212. foreach($_POST as $key=>$val){
  213. if( strstr($key,'Question'.$row['msqID'].'_') && strlen($val) ){
  214. $answerFound=1;
  215. }
  216. }
  217. if(!$answerFound) $notCompleted=1;
  218. }elseif($row['inputType']=='fileupload'){
  219. if( !isset($_FILES['Question'.$row['msqID']]) || !is_uploaded_file($_FILES['Question'.$row['msqID']]['tmp_name']) )
  220. $notCompleted=1;
  221. }elseif( !strlen(trim($_POST['Question'.$row['msqID']])) ){
  222. $notCompleted=1;
  223. }
  224. if($notCompleted) $errors['CompleteRequired'] = t("Complete required fields *") ;
  225. }
  226. }
  227. //try importing the file if everything else went ok
  228. $tmpFileIds=array();
  229. if(!count($errors)) foreach($rows as $row){
  230. if( $row['inputType']!='fileupload' ) continue;
  231. $questionName='Question'.$row['msqID'];
  232. if ( !intval($row['required']) &&
  233. (
  234. !isset($_FILES[$questionName]['tmp_name']) || !is_uploaded_file($_FILES[$questionName]['tmp_name'])
  235. )
  236. ){
  237. continue;
  238. }
  239. $fi = new FileImporter();
  240. $resp = $fi->import($_FILES[$questionName]['tmp_name'], $_FILES[$questionName]['name']);
  241. if (!($resp instanceof FileVersion)) {
  242. switch($resp) {
  243. case FileImporter::E_FILE_INVALID_EXTENSION:
  244. $errors['fileupload'] = t('Invalid file extension.');
  245. break;
  246. case FileImporter::E_FILE_INVALID:
  247. $errors['fileupload'] = t('Invalid file.');
  248. break;
  249. }
  250. }else{
  251. $tmpFileIds[intval($row['msqID'])] = $resp->getFileID();
  252. if(intval($this->addFilesToSet)) {
  253. Loader::model('file_set');
  254. $fs = new FileSet();
  255. $fs = $fs->getByID($this->addFilesToSet);
  256. if($fs->getFileSetID()) {
  257. $fs->addFileToSet($resp);
  258. }
  259. }
  260. }
  261. }
  262. if(count($errors)){
  263. $this->set('formResponse', t('Please correct the following errors:') );
  264. $this->set('errors',$errors);
  265. $this->set('Entry',$E);
  266. }else{ //no form errors
  267. //save main survey record
  268. $u = new User();
  269. $uID = 0;
  270. if ($u->isRegistered()) {
  271. $uID = $u->getUserID();
  272. }
  273. $q="insert into {$this->btAnswerSetTablename} (questionSetId, uID) values (?,?)";
  274. $db->query($q,array($qsID, $uID));
  275. $answerSetID=$db->Insert_ID();
  276. $this->lastAnswerSetId=$answerSetID;
  277. $questionAnswerPairs=array();
  278. //loop through each question and get the answers
  279. foreach( $rows as $row ){
  280. //save each answer
  281. if($row['inputType']=='checkboxlist'){
  282. $answer = Array();
  283. $answerLong="";
  284. $keys = array_keys($_POST);
  285. foreach ($keys as $key){
  286. if (strpos($key, 'Question'.$row['msqID'].'_') === 0){
  287. $answer[]=$txt->sanitize($_POST[$key]);
  288. }
  289. }
  290. }elseif($row['inputType']=='text'){
  291. $answerLong=$txt->sanitize($_POST['Question'.$row['msqID']]);
  292. $answer='';
  293. }elseif($row['inputType']=='fileupload'){
  294. $answer=intval( $tmpFileIds[intval($row['msqID'])] );
  295. }elseif($row['inputType']=='url'){
  296. $answerLong="";
  297. $answer=$txt->sanitize($_POST['Question'.$row['msqID']]);
  298. }elseif($row['inputType']=='email'){
  299. $answerLong="";
  300. $answer=$txt->sanitize($_POST['Question'.$row['msqID']]);
  301. }elseif($row['inputType']=='telephone'){
  302. $answerLong="";
  303. $answer=$txt->sanitize($_POST['Question'.$row['msqID']]);
  304. }else{
  305. $answerLong="";
  306. $answer=$txt->sanitize($_POST['Question'.$row['msqID']]);
  307. }
  308. if( is_array($answer) )
  309. $answer=join(',',$answer);
  310. $questionAnswerPairs[$row['msqID']]['question']=$row['question'];
  311. $questionAnswerPairs[$row['msqID']]['answer']=$txt->sanitize( $answer.$answerLong );
  312. $v=array($row['msqID'],$answerSetID,$answer,$answerLong);
  313. $q="insert into {$this->btAnswersTablename} (msqID,asID,answer,answerLong) values (?,?,?,?)";
  314. $db->query($q,$v);
  315. }
  316. $refer_uri=$_POST['pURI'];
  317. if(!strstr($refer_uri,'?')) $refer_uri.='?';
  318. $foundSpam = false;
  319. $submittedData = '';
  320. foreach($questionAnswerPairs as $questionAnswerPair){
  321. $submittedData .= $questionAnswerPair['question']."\r\n".$questionAnswerPair['answer']."\r\n"."\r\n";
  322. }
  323. $antispam = Loader::helper('validation/antispam');
  324. if (!$antispam->check($submittedData, 'form_block')) {
  325. // found to be spam. We remove it
  326. $foundSpam = true;
  327. $q="delete from {$this->btAnswerSetTablename} where asID = ?";
  328. $v = array($this->lastAnswerSetId);
  329. $db->Execute($q, $v);
  330. $db->Execute('delete from {$this->btAnswersTablename} where asID = ?', array($this->lastAnswerSetId));
  331. }
  332. if(intval($this->notifyMeOnSubmission)>0 && !$foundSpam){
  333. if( strlen(FORM_BLOCK_SENDER_EMAIL)>1 && strstr(FORM_BLOCK_SENDER_EMAIL,'@') ){
  334. $formFormEmailAddress = FORM_BLOCK_SENDER_EMAIL;
  335. }else{
  336. $adminUserInfo=UserInfo::getByID(USER_SUPER_ID);
  337. $formFormEmailAddress = $adminUserInfo->getUserEmail();
  338. }
  339. $mh = Loader::helper('mail');
  340. $mh->to( $this->recipientEmail );
  341. $mh->from( $formFormEmailAddress );
  342. $mh->addParameter('formName', $this->surveyName);
  343. $mh->addParameter('questionSetId', $this->questionSetId);
  344. $mh->addParameter('questionAnswerPairs', $questionAnswerPairs);
  345. $mh->load('block_form_submission');
  346. $mh->setSubject(t('%s Form Submission', $this->surveyName));
  347. //echo $mh->body.'<br>';
  348. @$mh->sendMail();
  349. }
  350. //$_REQUEST=array();
  351. if($this->redirectCID > 0) {
  352. $pg = Page::getByID($this->redirectCID);
  353. if(is_object($pg)) {
  354. $this->redirect($pg->getCollectionPath());
  355. } else { // page didn't exist, we'll just do the default action
  356. header("Location: ".$refer_uri."&surveySuccess=1&qsid=".$this->questionSetId."#".$this->questionSetId);
  357. exit;
  358. }
  359. }
  360. if(!$this->noSubmitFormRedirect){
  361. header("Location: ".$refer_uri."&surveySuccess=1&qsid=".$this->questionSetId."#".$this->questionSetId);
  362. die;
  363. }
  364. }
  365. }
  366. function delete() {
  367. $db = Loader::db();
  368. $deleteData['questionsIDs']=array();
  369. $deleteData['strandedAnswerSetIDs']=array();
  370. $miniSurvey=new MiniSurvey();
  371. $info=$miniSurvey->getMiniSurveyBlockInfo($this->bID);
  372. //get all answer sets
  373. $q = "SELECT asID FROM {$this->btAnswerSetTablename} WHERE questionSetId = ".intval($info['questionSetId']);
  374. $answerSetsRS = $db->query($q);
  375. //delete the questions
  376. $deleteData['questionsIDs']=$db->getAll( "SELECT qID FROM {$this->btQuestionsTablename} WHERE questionSetId = ".intval($info['questionSetId']).' AND bID='.intval($this->bID) );
  377. foreach($deleteData['questionsIDs'] as $questionData)
  378. $db->query("DELETE FROM {$this->btQuestionsTablename} WHERE qID=".intval($questionData['qID']));
  379. //delete left over answers
  380. $strandedAnswerIDs = $db->getAll('SELECT fa.aID FROM `btFormAnswers` AS fa LEFT JOIN btFormQuestions as fq ON fq.msqID=fa.msqID WHERE fq.msqID IS NULL');
  381. foreach($strandedAnswerIDs as $strandedAnswerIDs)
  382. $db->query('DELETE FROM `btFormAnswers` WHERE aID='.intval($strandedAnswer['aID']));
  383. //delete the left over answer sets
  384. $deleteData['strandedAnswerSetIDs'] = $db->getAll('SELECT aset.asID FROM btFormAnswerSet AS aset LEFT JOIN btFormAnswers AS fa ON aset.asID=fa.asID WHERE fa.asID IS NULL');
  385. foreach($deleteData['strandedAnswerSetIDs'] as $strandedAnswerSetIDs)
  386. $db->query('DELETE FROM btFormAnswerSet WHERE asID='.intval($strandedAnswerSetIDs['asID']));
  387. //delete the form block
  388. $q = "delete from {$this->btTable} where bID = '{$this->bID}'";
  389. $r = $db->query($q);
  390. parent::delete();
  391. return $deleteData;
  392. }
  393. }
  394. /**
  395. * Namespace for statistics-related functions used by the form block.
  396. *
  397. * @package Blocks
  398. * @subpackage BlockTypes
  399. * @author Tony Trupp <tony@concrete5.org>
  400. * @copyright Copyright (c) 2003-2008 Concrete5. (http://www.concrete5.org)
  401. * @license http://www.concrete5.org/license/ MIT License
  402. *
  403. */
  404. class FormBlockStatistics {
  405. public static function getTotalSubmissions($date = null) {
  406. $db = Loader::db();
  407. if ($date != null) {
  408. return $db->GetOne("select count(asID) from btFormAnswerSet where DATE_FORMAT(created, '%Y-%m-%d') = ?", array($date));
  409. } else {
  410. return $db->GetOne("select count(asID) from btFormAnswerSet");
  411. }
  412. }
  413. public static function loadSurveys($MiniSurvey){
  414. $db = Loader::db();
  415. return $db->query('SELECT s.* FROM '.$MiniSurvey->btTable.' AS s, Blocks AS b, BlockTypes AS bt '.
  416. 'WHERE s.bID=b.bID AND b.btID=bt.btID AND bt.btHandle="form" ' );
  417. }
  418. public static $sortChoices=array('newest'=>'created DESC','chrono'=>'created');
  419. public static function buildAnswerSetsArray( $questionSet, $orderBy='', $limit='' ){
  420. $db = Loader::db();
  421. if( strlen(trim($limit))>0 && !strstr(strtolower($limit),'limit') )
  422. $limit=' LIMIT '.$limit;
  423. if( strlen(trim($orderBy))>0 && array_key_exists($orderBy, self::$sortChoices) ){
  424. $orderBySQL=self::$sortChoices[$orderBy];
  425. }else $orderBySQL=self::$sortChoices['newest'];
  426. //get answers sets
  427. $sql='SELECT * FROM btFormAnswerSet AS aSet '.
  428. 'WHERE aSet.questionSetId='.$questionSet.' ORDER BY '.$orderBySQL.' '.$limit;
  429. $answerSetsRS=$db->query($sql);
  430. //load answers into a nicer multi-dimensional array
  431. $answerSets=array();
  432. $answerSetIds=array(0);
  433. while( $answer = $answerSetsRS->fetchRow() ){
  434. //answer set id - question id
  435. $answerSets[$answer['asID']]=$answer;
  436. $answerSetIds[]=$answer['asID'];
  437. }
  438. //get answers
  439. $sql='SELECT * FROM btFormAnswers AS a WHERE a.asID IN ('.join(',',$answerSetIds).')';
  440. $answersRS=$db->query($sql);
  441. //load answers into a nicer multi-dimensional array
  442. while( $answer = $answersRS->fetchRow() ){
  443. //answer set id - question id
  444. $answerSets[$answer['asID']]['answers'][$answer['msqID']]=$answer;
  445. }
  446. return $answerSets;
  447. }
  448. }
  449. /**
  450. * Namespace for other functions used by the form block.
  451. *
  452. * @package Blocks
  453. * @subpackage BlockTypes
  454. * @author Tony Trupp <tony@concrete5.org>
  455. * @copyright Copyright (c) 2003-2008 Concrete5. (http://www.concrete5.org)
  456. * @license http://www.concrete5.org/license/ MIT License
  457. *
  458. */
  459. class MiniSurvey{
  460. public $btTable = 'btForm';
  461. public $btQuestionsTablename = 'btFormQuestions';
  462. public $btAnswerSetTablename = 'btFormAnswerSet';
  463. public $btAnswersTablename = 'btFormAnswers';
  464. public $lastSavedMsqID=0;
  465. public $lastSavedqID=0;
  466. function __construct(){
  467. $db = Loader::db();
  468. $this->db=$db;
  469. }
  470. function addEditQuestion($values,$withOutput=1){
  471. $jsonVals=array();
  472. $values['options']=str_replace(array("\r","\n"),'%%',$values['options']);
  473. if(strtolower($values['inputType'])=='undefined') $values['inputType']='field';
  474. //set question set id, or create a new one if none exists
  475. if(intval($values['qsID'])==0) $values['qsID']=time();
  476. //validation
  477. if( strlen($values['question'])==0 || strlen($values['inputType'])==0 || $values['inputType']=='null' ){
  478. //complete required fields
  479. $jsonVals['success']=0;
  480. $jsonVals['noRequired']=1;
  481. }else{
  482. if( intval($values['msqID']) ){
  483. $jsonVals['mode']='"Edit"';
  484. //questions that are edited are given a placeholder row in btFormQuestions with bID=0, until a bID is assign on block update
  485. $pendingEditExists = $this->db->getOne( "select count(*) as total from btFormQuestions where bID=0 AND msqID=".intval($values['msqID']) );
  486. //hideQID tells the interface to hide the old version of the question in the meantime
  487. $vals=array( intval($values['msqID']));
  488. $jsonVals['hideQID']=intval($this->db->GetOne("SELECT MAX(qID) FROM btFormQuestions WHERE bID!=0 AND msqID=?",$vals));
  489. }else{
  490. $jsonVals['mode']='"Add"';
  491. }
  492. if( $pendingEditExists ){
  493. $width = $height = 0;
  494. if ($values['inputType'] == 'text'){
  495. $width = $this->limitRange(intval($values['width']), 20, 500);
  496. $height = $this->limitRange(intval($values['height']), 1, 100);
  497. }
  498. $dataValues=array(intval($values['qsID']), trim($values['question']), $values['inputType'],
  499. $values['options'], intval($values['position']), $width, $height, intval($values['required']), intval($values['msqID']) );
  500. $sql='UPDATE btFormQuestions SET questionSetId=?, question=?, inputType=?, options=?, position=?, width=?, height=?, required=? WHERE msqID=? AND bID=0';
  501. }else{
  502. if( !isset($values['position']) ) $values['position']=1000;
  503. if(!intval($values['msqID']))
  504. $values['msqID']=intval($this->db->GetOne("SELECT MAX(msqID) FROM btFormQuestions")+1);
  505. $dataValues=array($values['msqID'],intval($values['qsID']), trim($values['question']), $values['inputType'],
  506. $values['options'], intval($values['position']), intval($values['width']), intval($values['height']), intval($values['required']) );
  507. $sql='INSERT INTO btFormQuestions (msqID,questionSetId,question,inputType,options,position,width,height,required) VALUES (?,?,?,?,?,?,?,?,?)';
  508. }
  509. $result=$this->db->query($sql,$dataValues);
  510. $this->lastSavedMsqID=intval($values['msqID']);
  511. $this->lastSavedqID=intval($this->db->GetOne("SELECT MAX(qID) FROM btFormQuestions WHERE bID=0 AND msqID=?", array($values['msqID']) ));
  512. $jsonVals['qID']=$this->lastSavedqID;
  513. $jsonVals['success']=1;
  514. }
  515. $jsonVals['qsID']=$values['qsID'];
  516. $jsonVals['msqID']=intval($values['msqID']);
  517. //create json response object
  518. $jsonPairs=array();
  519. foreach($jsonVals as $key=>$val) $jsonPairs[]=$key.':'.$val;
  520. if($withOutput) echo '{'.join(',',$jsonPairs).'}';
  521. }
  522. function getQuestionInfo($qsID,$qID){
  523. $questionRS=$this->db->query('SELECT * FROM btFormQuestions WHERE questionSetId='.intval($qsID).' AND qID='.intval($qID).' LIMIT 1' );
  524. $questionRow=$questionRS->fetchRow();
  525. $jsonPairs=array();
  526. foreach($questionRow as $key=>$val){
  527. if($key=='options') $key='optionVals';
  528. $jsonPairs[]=$key.':"'.str_replace(array("\r","\n"),'%%',addslashes($val)).'"';
  529. }
  530. echo '{'.join(',',$jsonPairs).'}';
  531. }
  532. function deleteQuestion($qsID,$msqID){
  533. $sql='DELETE FROM btFormQuestions WHERE questionSetId='.intval($qsID).' AND msqID='.intval($msqID).' AND bID=0';
  534. $this->db->query($sql,$dataValues);
  535. }
  536. function loadQuestions($qsID, $bID=0, $showPending=0 ){
  537. $db = Loader::db();
  538. if( intval($bID) ){
  539. $bIDClause=' AND ( bID='.intval($bID).' ';
  540. if( $showPending )
  541. $bIDClause.=' OR bID=0) ';
  542. else $bIDClause.=' ) ';
  543. }
  544. return $db->query('SELECT * FROM btFormQuestions WHERE questionSetId='.intval($qsID).' '.$bIDClause.' ORDER BY position, msqID');
  545. }
  546. static function getAnswerCount($qsID){
  547. $db = Loader::db();
  548. return $db->getOne( 'SELECT count(*) FROM btFormAnswerSet WHERE questionSetId='.intval($qsID) );
  549. }
  550. function loadSurvey( $qsID, $showEdit=false, $bID=0, $hideQIDs=array(), $showPending=0 ){
  551. //loading questions
  552. $questionsRS=$this->loadQuestions( $qsID, $bID, $showPending);
  553. if(!$showEdit){
  554. echo '<table class="formBlockSurveyTable">';
  555. while( $questionRow=$questionsRS->fetchRow() ){
  556. if( in_array($questionRow['qID'], $hideQIDs) ) continue;
  557. // this special view logic for the checkbox list isn't doing it for me
  558. /*
  559. if ($questionRow['inputType'] == 'checkboxlist' && strpos($questionRow['options'], '%%') === false){
  560. echo '<tr>
  561. <td valign="top" colspan="2" class="question">
  562. <div class="checkboxItem">
  563. <div class="checkboxPair">'.$this->loadInputType($questionRow,$showEdit).$questionRow['question'].'</div>
  564. </div>
  565. </td>
  566. </tr>';
  567. } else { */
  568. $requiredSymbol=($questionRow['required'])?'&nbsp;<span class="required">*</span>':'';
  569. echo '<tr>
  570. <td valign="top" class="question"><label for="Question'.intval($questionRow['msqID']).'">'.$questionRow['question'].''.$requiredSymbol.'</label></td>
  571. <td valign="top">'.$this->loadInputType($questionRow,showEdit).'</td>
  572. </tr>';
  573. //}
  574. }
  575. $surveyBlockInfo = $this->getMiniSurveyBlockInfoByQuestionId($qsID,intval($bID));
  576. if($surveyBlockInfo['displayCaptcha']) {
  577. echo '<tr><td colspan="2">';
  578. $captcha = Loader::helper('validation/captcha');
  579. echo $captcha->label();
  580. echo '</td></tr><tr><td>&nbsp;</td><td>';
  581. $captcha->showInput();
  582. $captcha->display();
  583. //echo isset($errors['captcha'])?'<span class="error">' . $errors['captcha'] . '</span>':'';
  584. echo '</td></tr>';
  585. }
  586. echo '<tr><td>&nbsp;</td><td><input class="formBlockSubmitButton ccm-input-button" name="Submit" type="submit" value="'.t('Submit').'" /></td></tr>';
  587. echo '</table>';
  588. }else{
  589. echo '<div id="miniSurveyTableWrap"><div id="miniSurveyPreviewTable" class="miniSurveyTable">';
  590. while( $questionRow=$questionsRS->fetchRow() ){
  591. if( in_array($questionRow['qID'], $hideQIDs) ) continue;
  592. $requiredSymbol=($questionRow['required'])?'<span class="required">*</span>':'';
  593. ?>
  594. <div id="miniSurveyQuestionRow<?php echo $questionRow['msqID']?>" class="miniSurveyQuestionRow">
  595. <div class="miniSurveyQuestion"><?php echo $questionRow['question'].' '.$requiredSymbol?></div>
  596. <?php /* <div class="miniSurveyResponse"><?php echo $this->loadInputType($questionRow,$showEdit)?></div> */ ?>
  597. <div class="miniSurveyOptions">
  598. <div style="float:right">
  599. <a href="#" onclick="miniSurvey.moveUp(this,<?php echo $questionRow['msqID']?>);return false" class="moveUpLink"></a>
  600. <a href="#" onclick="miniSurvey.moveDown(this,<?php echo $questionRow['msqID']?>);return false" class="moveDownLink"></a>
  601. </div>
  602. <a href="#" onclick="miniSurvey.reloadQuestion(<?php echo intval($questionRow['qID']) ?>);return false"><?php echo t('edit')?></a> &nbsp;&nbsp;
  603. <a href="#" onclick="miniSurvey.deleteQuestion(this,<?php echo intval($questionRow['msqID']) ?>,<?php echo intval($questionRow['qID'])?>);return false"><?php echo t('remove')?></a>
  604. </div>
  605. <div class="miniSurveySpacer"></div>
  606. </div>
  607. <?php }
  608. echo '</div></div>';
  609. }
  610. }
  611. function loadInputType($questionData,$showEdit){
  612. $options=explode('%%',$questionData['options']);
  613. $msqID=intval($questionData['msqID']);
  614. switch($questionData['inputType']){
  615. case 'checkboxlist':
  616. // this is looking really crappy so i'm going to make it behave the same way all the time - andrew
  617. /*
  618. if (count($options) == 1){
  619. if(strlen(trim($options[0]))==0) continue;
  620. $checked=($_REQUEST['Question'.$msqID.'_0']==trim($options[0]))?'checked':'';
  621. $html.= '<input name="Question'.$msqID.'_0" type="checkbox" value="'.trim($options[0]).'" '.$checked.' />';
  622. }else{
  623. */
  624. $html.= '<div class="checkboxList">'."\r\n";
  625. for ($i = 0; $i < count($options); $i++) {
  626. if(strlen(trim($options[$i]))==0) continue;
  627. $checked=($_REQUEST['Question'.$msqID.'_'.$i]==trim($options[$i]))?'checked':'';
  628. $html.= ' <div class="checkboxPair"><input name="Question'.$msqID.'_'.$i.'" type="checkbox" value="'.trim($options[$i]).'" '.$checked.' />&nbsp;'.$options[$i].'</div>'."\r\n";
  629. }
  630. $html.= '</div>';
  631. //}
  632. return $html;
  633. case 'select':
  634. if($this->frontEndMode){
  635. $selected=(!$_REQUEST['Question'.$msqID])?'selected="selected"':'';
  636. $html.= '<option value="" '.$selected.'>----</option>';
  637. }
  638. foreach($options as $option){
  639. $checked=($_REQUEST['Question'.$msqID]==trim($option))?'selected="selected"':'';
  640. $html.= '<option '.$checked.'>'.trim($option).'</option>';
  641. }
  642. return '<select name="Question'.$msqID.'" id="Question'.$msqID.'" >'.$html.'</select>';
  643. case 'radios':
  644. foreach($options as $option){
  645. if(strlen(trim($option))==0) continue;
  646. $checked=($_REQUEST['Question'.$msqID]==trim($option))?'checked':'';
  647. $html.= '<div class="radioPair"><input name="Question'.$msqID.'" type="radio" value="'.trim($option).'" '.$checked.' />&nbsp;'.$option.'</div>';
  648. }
  649. return $html;
  650. case 'fileupload':
  651. $html='<input type="file" name="Question'.$msqID.'" id="Question'.$msqID.'" />';
  652. return $html;
  653. case 'text':
  654. $val=($_REQUEST['Question'.$msqID])?Loader::helper('text')->entities($_REQUEST['Question'.$msqID]):'';
  655. return '<textarea name="Question'.$msqID.'" id="Question'.$msqID.'" cols="'.$questionData['width'].'" rows="'.$questionData['height'].'" style="width:95%">'.$val.'</textarea>';
  656. case 'url':
  657. $val=($_REQUEST['Question'.$msqID])?$_REQUEST['Question'.$msqID]:'';
  658. return '<input name="Question'.$msqID.'" id="Question'.$msqID.'" type="url" value="'.stripslashes(htmlspecialchars($val)).'" />';
  659. case 'telephone':
  660. $val=($_REQUEST['Question'.$msqID])?$_REQUEST['Question'.$msqID]:'';
  661. return '<input name="Question'.$msqID.'" id="Question'.$msqID.'" type="tel" value="'.stripslashes(htmlspecialchars($val)).'" />';
  662. case 'email':
  663. $val=($_REQUEST['Question'.$msqID])?$_REQUEST['Question'.$msqID]:'';
  664. return '<input name="Question'.$msqID.'" id="Question'.$msqID.'" type="email" value="'.stripslashes(htmlspecialchars($val)).'" />';
  665. case 'field':
  666. default:
  667. $val=($_REQUEST['Question'.$msqID])?$_REQUEST['Question'.$msqID]:'';
  668. return '<input name="Question'.$msqID.'" id="Question'.$msqID.'" type="text" value="'.stripslashes(htmlspecialchars($val)).'" />';
  669. }
  670. }
  671. function getMiniSurveyBlockInfo($bID){
  672. $rs=$this->db->query('SELECT * FROM btForm WHERE bID='.intval($bID).' LIMIT 1' );
  673. return $rs->fetchRow();
  674. }
  675. function getMiniSurveyBlockInfoByQuestionId($qsID,$bID=0){
  676. $sql='SELECT * FROM btForm WHERE questionSetId='.intval($qsID);
  677. if(intval($bID)>0) $sql.=' AND bID='.$bID;
  678. $sql.=' LIMIT 1';
  679. $rs=$this->db->query( $sql );
  680. return $rs->fetchRow();
  681. }
  682. function reorderQuestions($qsID=0,$qIDs){
  683. $qIDs=explode(',',$qIDs);
  684. if(!is_array($qIDs)) $qIDs=array($qIDs);
  685. $positionNum=0;
  686. foreach($qIDs as $qID){
  687. $vals=array( $positionNum,intval($qID), intval($qsID) );
  688. $sql='UPDATE btFormQuestions SET position=? WHERE msqID=? AND questionSetId=?';
  689. $rs=$this->db->query($sql,$vals);
  690. $positionNum++;
  691. }
  692. }
  693. function limitRange($val, $min, $max){
  694. $val = ($val < $min) ? $min : $val;
  695. $val = ($val > $max) ? $max : $val;
  696. return $val;
  697. }
  698. //Run on Form block edit
  699. static function questionCleanup( $qsID=0, $bID=0 ){
  700. $db = Loader::db();
  701. //First make sure that the bID column has been set for this questionSetId (for backwards compatibility)
  702. $vals=array( intval($qsID) );
  703. $questionsWithBIDs=$db->getOne('SELECT count(*) FROM btFormQuestions WHERE bID!=0 AND questionSetId=? ',$vals);
  704. //form block was just upgraded, so set the bID column
  705. if(!$questionsWithBIDs){
  706. $vals=array( intval($bID), intval($qsID) );
  707. $rs=$db->query('UPDATE btFormQuestions SET bID=? WHERE bID=0 AND questionSetId=?',$vals);
  708. return;
  709. }
  710. //Then remove all temp/placeholder questions for this questionSetId that haven't been assigned to a block
  711. $vals=array( intval($qsID) );
  712. $rs=$db->query('DELETE FROM btFormQuestions WHERE bID=0 AND questionSetId=?',$vals);
  713. }
  714. }
  715. ?>