8 Fakoli::usingFile(
"/cms/components/questionnaire/abstract_questionnaire_manager.inc");
38 define(
"questionnaire_sent",
"1");
39 define(
"questionnaire_send_failed",
"2");
40 define(
"questionnaire_opened",
"3");
41 define(
"questionnaire_no_additional",
"4");
42 define(
"questionnaire_reminder_sent",
"5");
43 define(
"questionnaire_reminder_failed",
"6");
44 define(
"questionnaire_test_sent",
"7");
45 define(
"questionnaire_test_failed",
"8");
52 var $excludes = array();
53 var $addl_recipients = array();
55 function AbstractQuestionnaireSendManager($item)
60 $sendId = $this->getSendPageIdentifier();
62 if($sendId == $_REQUEST[
"identifier"])
64 $this->validateSend();
68 abstract function getComponentName();
75 abstract function getCreateManager();
81 abstract function getResponseClass();
87 abstract function getResultsManager();
94 function getClassName()
96 return $this->item->prettifyClassName();
105 function getSendTestEmailDialog()
107 return "send_test_email_dialog";
115 function getSendTestEmailHandler()
117 return "send_test_email";
126 function getReminderDialog()
128 return "reminder_dialog";
136 function getSendAdditionalHandler()
138 return "send_additional_emails";
148 function getRecipientsDialog()
150 return "recipients_dialog";
159 function getOpenHandler()
161 $class = codify(strtolower($this->getClassName()));
162 return "open_{$class}";
171 function getCloseHandler()
173 $class = codify(strtolower($this->getClassName()));
174 return "close_{$class}";
183 function getMessageSelectDialog()
185 return "message_select_dialog";
193 function getSendPageIdentifier()
195 $class = codify(strtolower($this->getClassName()));
196 return "{$class}_preview";
204 function getConfirmationPage()
206 $class = codify(strtolower($this->getClassName()));
207 return "{$class}_confirmation";
215 function getEmailForm()
217 $class = codify(strtolower($this->getClassName()));
218 return "{$class}_email";
227 function getQuestionForm()
229 $mgr = $this->getCreateManager();
230 return $mgr->getQuestionForm();
239 function getQuestionnaireFormIdentifier()
241 $mgr = $this->getCreateManager();
242 return $mgr->getQuestionnaireFormIdentifier();
251 function getQuestionListIdentifier()
253 $mgr = $this->getCreateManager();
254 return $mgr->getQuestionListIdentifier();
263 function getSenderEmail()
265 $item = clone $this->item;
266 $item->filter =
null;
267 $component_name = $this->getComponentName();
271 if($item->hasField(
"sender_email") && $item->sender_email)
273 return $item->sender_email;
305 function getAllRecipients()
308 $item->filter =
null;
312 if($item->hasField(
"sender_email") && $item->sender_email)
314 if(array_search($item->sender_email,
$recipients !== FALSE))
316 $this->excludes[] = $item->sender_email;
320 if($item->hasField(
"user_id") && $item->user_id)
322 $user = $item->Author();
325 $this->excludes[] =
$user->email;
329 if($item->hasField(
"cc_recipients") && $item->cc_recipients)
331 $ccs = explode(
",", $item->cc_recipients);
335 $this->excludes[] = $cc;
351 $responseClass = $this->getResponseClass();
352 $itemPk = $item->getPrimaryKey();
355 $indexedResponses = IndexedQuery::create($responseClass,
"WHERE {$itemPk}=:{$itemPk}",
"email")
356 ->bind(
":{$itemPk}", $item->$itemPk)
361 if(!array_key_exists($recipient, $indexedResponses))
363 $response = $this->generateToken($recipient);
368 $response = $indexedResponses[$recipient];
386 function generateToken(
$email)
388 $surveyResponse =
null;
389 $itemPk = $this->item->getPrimaryKey();
390 $responseClass = $this->getResponseClass();
400 for($i = 0; $i < 5; ++$i)
402 $code .= chr(rand(ord(
'A'), ord(
'Z')));
408 $response->$itemPk = $this->item->$itemPk;
425 function getSampleResponse()
429 $author = $this->item->Author();
430 $email = ($author) ? $author->email :
$user->email;
454 function findResponseByEmail(
$email)
456 $response_class = $this->getResponseClass();
459 $responses = Query::create($response_class,
"WHERE {$pk}=:{$pk} AND email=:email")
460 ->bind(
":{$pk}", $this->item->$pk,
":email",
$email)
472 function setExcluded()
476 $indexedResponses = reindexList($this->responses,
"email");
478 if(!count($this->excludes))
483 foreach($this->excludes as $excludeEmail)
485 if(!array_key_exists($excludeEmail, $indexedResponses))
continue;
487 $response = $indexedResponses[$excludeEmail];
505 function sendRequests(
$form)
507 $rtn = $this->sendToRecipients();
510 $this->item->setStatus(
"open");
516 function sendToRecipients()
518 if($this->item->additional_recipients)
520 return $this->sendToAdditional();
527 if($this->allowAnonymous())
529 $this->item->setStatus(
"open");
535 $this->responses = $this->generateResponses(
$recipients);
537 $this->setExcluded();
539 if(!count($this->responses))
544 $rtn = $this->sendEmails();
549 function allowAnonymous()
551 $item = clone $this->item;
552 $item->filter =
null;
554 return ($item->hasField(
"allow_anonymous_responses") && $item->allow_anonymous_responses) ?
true :
false;
557 function sendActions()
559 $class = $this->getClassName();
561 "send_additional" =>
"Send Additional Emails",
562 "send_test" =>
"Send Test Email To...",
563 "send" =>
"Preview & Send",
564 "close" =>
"Close $class",
565 "reopen" =>
"ReOpen $class",
566 "send_reminders" =>
"Send Reminders",
575 function getSendActions()
577 $item = clone $this->item;
578 $item->filter =
null;
581 if(!$this->isValid())
return;
583 $sendActions = $this->sendActions();
585 if(!is_array($sendActions) || !count($sendActions))
595 $send_identifier = $this->getSendPageIdentifier();
597 if(($item->isSent() && !$this->hasAdditional()) ||
$identifier == $send_identifier || $item->isClosed())
599 unset($sendActions[
"send"]);
606 if(!$this->hasAdditional() ||
$identifier != $send_identifier)
608 unset($sendActions[
"send_additional"]);
613 unset($sendActions[
"close"]);
616 if(!$item->isClosed())
618 unset($sendActions[
"reopen"]);
621 $nonResponseCount = count($this->getNonResponsives());
622 if($nonResponseCount == 0 || $item->isClosed())
624 unset($sendActions[
"send_reminders"]);
630 function hasAdditional()
632 $item = clone $this->item;
633 $item->filter =
null;
635 if($item->hasField(
"additional_recipients") && $item->additional_recipients)
649 function sendToAdditional()
652 $item->filter =
null;
654 if(!$this->hasAdditional())
659 $addl_recipients = explode(
",", $item->additional_recipients);
660 $addl_recipients = array_unique($addl_recipients);
663 $new_recipients = array();
664 foreach($addl_recipients as $addl_recipient)
666 if(!preg_match(
"/$addl_recipient/", $item->recipients))
668 $new_recipients[] = $addl_recipient;
672 $addl_recipients = $new_recipients;
674 if(!count($addl_recipients))
676 $item->additional_recipients =
'';
677 $item->filter =
new InclusionFilter(
"additional_recipients");
682 $this->excludes = $addl_recipients;
683 $this->addl_recipients = $addl_recipients;
685 $this->responses = $this->generateResponses($addl_recipients);
687 $this->setExcluded();
689 if(!count($this->responses))
694 $rtn = $this->sendEmails();
696 $this->moveAdditionalToRecipientList();
710 function sendEmails()
717 $sender_email = $this->getSenderEmail();
724 $this->moveAdditionalToRecipientList();
729 function getSubject()
731 $item = clone $this->item;
732 $item->filter =
null;
733 $component_name = $this->getComponentName();
735 if($item && $item->hasField(
"subject") && $item->subject)
737 return $item->subject;
743 function getMessage()
745 $component_name = $this->getComponentName();
760 $responseClass = $this->getResponseClass();
763 $recipientMessage = $mergeMgr->searchAndReplace(
$message);
766 return $emailHandler->send();
774 function moveAdditionalToRecipientList()
777 $item->filter =
null;
779 if(!$item->hasField(
"additional_recipients"))
784 if(!count($this->addl_recipients))
790 foreach($this->addl_recipients as $ar)
796 $item->additional_recipients =
'';
797 $item->filter =
new InclusionFilter(
"recipients",
"additional_recipients");
814 $this->responses = $this->generateResponses(
$recipients);
818 $this->setExcluded();
820 if(!count($this->responses))
825 return $this->sendEmails();
831 function getNonResponsives()
833 return $this->item->getNonResponders();
843 function sendReminderEmails()
849 $this->responses = $this->generateResponses(
$recipients);
851 if(!count($this->responses))
return;
853 return $this->sendEmails();
859 function buildSendTestEmailForm(
$dashboard = 0)
864 $component_name = $this->getComponentName();
865 $dialog = $this->getSendTestEmailDialog();
869 $email->filter =
new InclusionFilter(
"recipients");
872 $form =
new AutoForm(
$email,
"POST",
"/action/{$component_name}/{$dialog}?{$itemPk}={$item->$itemPk}&dashboard=$dashboard",
"SendTestEmail_form");
873 $form->ajaxSubmit(
"function(result) {questionnaireSendMgr.testEmailResult(result);}",
"function() {document.id('{$form->id}_error').set('text','Failed to communicate with server'); }");
874 $form->required(
"recipients");
876 $recipientRenderer->removeDuplicates =
true;
877 $form->submitLabel =
"Send Test Email";
878 $form->button(
"Cancel",
"questionnaireSendMgr.closeDialog()",
null,
true);
879 $form->annotate(
"recipients",
"Recipients of a test email will receive a valid response token but their responses will not be counted in the results. (separate email addresses with a comma ',')");
890 $component_name = $this->getComponentName();
891 $handler = $this->getReminderDialog();
893 $id = $this->item->$pk;
895 $mgr = $this->getResultsManager();
896 $nonResponsives = $item->getNonResponders();
898 $item->set(
"nonresponsive_count", count($nonResponsives));
899 $item->recipients = formatItems($nonResponsives,
"{token}",
", ");
901 $this->
recipients = formatItems($nonResponsives,
"{email}",
",");
903 $item->filter =
new InclusionFilter(
"title",
"recipients",
"sender_email",
"message",
"subject");
904 $form =
new AutoForm($item,
"POST",
"/action/{$component_name}/{$handler}?{$pk}={$id}&dashboard=$dashboard",
"Reminder_form");
905 $form->ajaxSubmit(
"function(result) {questionnaireSendMgr.reminderDialogResult(result);}",
"function() {document.id('{$form->id}_error').set('text','Failed to communicate with server'); }");
907 $form->getRenderer(
"message")->rows = 10;
908 $form->submitLabel =
"Send Reminders";
909 $form->annotate(
"message",
"You can use the email template message as is or customize it for this reminder.");
910 $form->readOnly(
"sender_email",
"recipients",
"title");
911 $form->required(
"message",
"subject");
912 $form->button(
"Cancel",
"questionnaireSendMgr.closeDialog()",
null,
true);
913 $form->alias(
"recipients",
"Recipient Tokens");
939 $item_id = $item->$pk;
940 $response_class = $this->getResponseClass();
942 $out =
"<div class='questionnaire_tester_block'>\n";
943 $out .=
"<p id='action_result' class='questionnaire_action_result' style='display: none'></p>\n";
956 if(
$user && $item->isAuthor())
958 $out .=
"Since you have access privileges to this survey, ";
962 $out .=
"Since you are a test user, ";
967 $out .=
"you can override the closed survey status to try out this survey. ";
968 $out .=
"</br></br><a href=\"#\" onclick=\"questionnaireMgr.showResponseTokenDialog();\">{$item->title}</a>\n";
972 $out .=
"you can access this survey using a test access token.\n";
980 $out .=
$response->format(
"Your survey response token <b>{token}</b> has been submitted. You can reset the token to start over.");
984 $out .=
$response->format(
"You can use the link above to enter your survey token <b>{token}</b> or use this direct link $editLink.");
986 elseif(
$user && $item->isAuthor())
988 $out .=
"If you would like to receive a survey token, send a test survey request email using one of the buttons below.";
993 $out .=
" Your responses will be excluded from the survey results. ";
997 $out .=
" Your response token is currently set to be included in the results. We recommend you set your response to be <a href='#' onclick=\"questionnaireMgr.excludeResponse({$response->response_id}); return false\">excluded</a> from results tabulation. ";
1001 $out .=
"<div class='button_row' style='text-align: middle;'>\n";
1004 $out .=
"<a class='button' href='#' onclick=\"questionnaireSendMgr.sendTestEmail(); return false;\">Send Test Email to {$user->email}</a>\n";
1008 $out .=
$response->format(
"<a class='button' href='#' onclick=\"questionnaireMgr.resetToken({response_id}, 1); return false\">Reset Token</a>\n");
1021 function getSendPageHeading(
$tabs =
null)
1023 $item = $this->item;
1026 $out =
"<div id='questionnaire_heading'>";
1030 if(
$tabs && $item->isSent())
1032 $nextPage =
$tabs->getNextPage();
1033 $out .=
"<button id='next_page_button' class='button' onclick=\"go('$nextPage')\">Next Page »</button>\n";
1036 if (!$item->isSent())
1038 $out .=
"<h3>Survey Preview & Send</h3>\n";
1042 $out .=
"<h3>Manage Survey</h3>\n";
1045 $out .= $this->getStatusMessage();
1050 $out .=
"<h4>Responses Received</h4>\n";
1051 $out .= $this->getProgressBar();
1061 function getResultsPageButtons()
1063 $item = clone $this->item;
1064 $item->filter =
null;
1066 $mgr = $this->getResultsManager();
1067 $recipientCount =
$mgr->getRecipientCount();
1068 $responseCount =
$mgr->getResponseCount();
1071 if($item->isOpen() AND $recipientCount > 0 AND $responseCount < $recipientCount)
1073 $buttons[] =
"<a class=\"button\" href='#' onclick=\"questionnaireSendMgr.showReminderDialog(); return false;\">Send Survey Reminders</a> \n";
1076 if ($this->allowAnonymous())
1078 $buttons[] = $item->format(
"<a target='_blank' href='anonymous_response?{$pk}={{$pk}}' class='button'>Enter an Anonymous Survey Response</a>\n");
1083 $out =
"<p>" . implode(
"  ", $buttons) .
"</p>\n";
1090 function getProgressBar()
1092 $mgr = $this->getResultsManager();
1093 return $mgr->getProgressBar();
1096 function formatDefaultConfirmationMessage()
1100 return "<p>Thank you for submitting your survey.</p><p>Continue to the <a href='/'>{$sitename} home page.</a></p>";
1104 function getStatusMessage()
1106 $item = clone $this->item;
1107 $item->filter =
null;
1109 $class = strtolower($this->getClassName());
1111 if (!$item->isSent())
1113 if(!$this->allowAnonymous())
1115 $out =
"<p>This survey has not yet been sent.</p>";
1119 $out =
"<p>Since this $class allows anonymous responses, the recipient field is not required. However, if you specify one or more recipients, you must provide an email message.</p>\n";
1124 $out .= $item->format(
"<p>This survey was opened on {start_date:F d, Y}");
1125 if($item->isClosed())
1127 $out .= $item->format(
" and closed on {end_date:F d, Y}");
1135 function getEmailPageHeading()
1137 $item = $this->item;
1138 $out =
"<div id='questionnaire_heading'>";
1140 $out .= $this->getStatusMessage();
1142 if($item->isAuthor() && $item->isClosed())
1144 $out .=
" If you wish to send additional survey requests, you must first
1145 <a href='#' onclick=\"questionnaireSendMgr.openToRespondents(); return false;\">reopen</a>
1154 function getCCRecipientsAnnotation()
1156 if($this->item->isClosed())
return "";
1160 return "CC Recipients will receive a copy of the email with a valid survey response token but their responses
1161 will not be counted in the results. (separate email addresses with a comma ',')</br>
1162 <div class='button_row'>\n<a class='button' onclick=\"questionnaireSendMgr.addEmailToCCRecipients('{$user->email}'); return false;\">Add Me To CC Recipients</a>
1163 <a class='button' onclick=\"questionnaireSendMgr.addEmailToCCRecipients('sender'); return false;\">Add Sender Email to CC Recipients</a>\n</div>\n";
1166 function getMessageAnnotation()
1168 if($this->item->isClosed())
return "";
1170 return "Select from a set of boilerplate messages which you can then customize for this survey.<br>
1171 <div class='button_row'>\n<a href='#' class='button' onclick=\"questionnaireSendMgr.showMessageSelectDialog(); return false;\">Select a Message</span></a> 
1172 <a href='#' class='button' onclick=\"questionnaireSendMgr.showAdvancedFeaturesDialog(); return false\">Advanced Features</a>\n</div>\n";
1183 function getManageLinks()
1185 $item = clone $this->item;
1186 $item->filter =
null;
1187 $class = $this->getClassName();
1189 $actions = $this->getSendActions();
1191 if(count($actions) > 0)
1193 foreach($actions as
$name => $label)
1195 $buttons[] =
"<a class='button' href=\"#\" onclick=\"questionnaireSendMgr.handleSendAction('{$name}'); return false;\">{$label}</a>";
1199 $out =
"<p>" . implode(
" ", $buttons) .
"</p>\n";
1220 $this->validation_msg =
"";
1221 $mgr = $this->getCreateManager();
1223 $msg = $this->validateSend();
1225 if(
$msg)
return false;
1227 $msg =
$mgr->validateQuestionnaire();
1229 if(
$msg)
return false;
1238 function getSendSubmitLabel()
1240 $item = clone $this->item;
1241 $item->filter =
null;
1242 $class = $this->getClassName();
1244 if($item->recipients || ($item->hasField(
"cc_recipients") && $item->cc_recipients))
1246 $label =
"Send $class Emails";
1250 $label =
"Open to Anonymous Respondents";
1258 $this->validation_msg =
"";
1259 $mgr = $this->getCreateManager();
1261 $msg =
$mgr->validateQuestionnaire();
1263 $msg .= $this->validateSend();
1264 $this->validation_msg =
$msg;
1267 function writeSendValidationMsg()
1269 $msg = $this->validateSend();
1270 echo
"<div id='warning'>{$msg}</div>\n";
1273 function writeQuestionnaireValidationMsg()
1275 $mgr = $this->getCreateManager();
1276 $mgr->writeQuestionnaireValidationMsg();
1279 function validateSend()
1281 $item = clone $this->item;
1282 $item->filter =
null;
1286 $email_form = $this->getEmailForm();
1289 if(!$item->recipients && !$this->allowAnonymous())
1292 $msg .=
"You must enter at least one recipient email address.";
1295 $recipientFields[] =
"recipients";
1296 $this->validateRecipients(
$msg, $item->recipients);
1298 if($item->hasField(
"cc_recipients"))
1300 $this->validateRecipients(
$msg, $item->cc_recipients);
1301 $recipientFields[] =
"recipients";
1304 if($item->hasField(
"additional_recipients"))
1306 $this->validateRecipients(
$msg, $item->cc_recipients);
1307 $recipientFields[] =
"recipients";
1311 foreach($recipientsFields as
$field)
1319 if(!$item->message && (!$this->allowAnonymous() || !$empty))
1322 $msg .=
"You must enter a message for the email.";
1328 function validateRecipients(&
$msg, $values)
1330 if(!$values)
return $msg;
1336 if(!preg_match(
'/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i', $recipient))
1339 $msg .=
"<warning>$recipient</warning> is an invalid email address.<br>";
1355 $sent = checkNumeric($_GET[
"sent"]);
1356 if(!
$sent)
return "";
1364 function getSendResultMessages(
$dashboard =
false)
1366 $class = strtolower($this->getClassName());
1410 function writeScript()
1412 $item = $this->item;
1413 $itemPk = $item->getPrimaryKey();
1414 $item_id = ($item->$itemPk) ? $item->$itemPk : 0;
1415 $component_name = $this->getComponentName();
1416 $item_label = $item->prettifyClassName();
1417 $send_test_email_dialog = $this->getSendTestEmailDialog();
1418 $send_test_email_handler = $this->getSendTestEmailHandler();
1419 $send_additional_handler = $this->getSendAdditionalHandler();
1421 $open_handler = $this->getOpenHandler();
1422 $reminder_dialog = $this->getReminderDialog();
1423 $close_handler = $this->getCloseHandler();
1424 $send_page_identifier = $this->getSendPageIdentifier();
1425 $recipients_dialog = $this->getRecipientsDialog();
1426 $message_select_dialog = $this->getMessageSelectDialog();
1427 $info_msg = $this->getInfoMsg();
1431 <script type=
"text/javascript" src=
"/components/questionnaire/js/questionnaire_send.js"></script>
1432 <script type=
"text/javascript">
1433 var questionnaireSendMgr;
1435 window.addEvent(
'domready',
function()
1437 questionnaireSendMgr =
new QuestionnaireSendManager(
1438 '<?php echo $itemPk ?>',
1439 <?php echo $item_id ?>,
1440 '<?php echo $component_name ?>',
1441 '<?php echo $item_label ?>',
1442 '<?php echo $send_test_email_dialog ?>',
1443 '<?php echo $send_test_email_handler ?>',
1444 '<?php echo $send_additional_handler ?>',
1445 '<?php echo $open_handler ?>',
1446 '<?php echo $close_handler ?>',
1447 '<?php echo $reminder_dialog ?>',
1448 '<?php echo $send_page_identifier ?>',
1449 '<?php echo $recipients_dialog ?>',
1450 '<?php echo $message_select_dialog ?>',
1451 '<?php echo $info_msg ?>'
Questionnaire/Survey Implementation instructions.
static using()
Import the datamodels, views and manifest for the specified component(s).
static usingFile()
Uses the specified framework file(s) from the framework directory.
static getValue($component, $name)
Retrieve the value of the specified Setting.
const questionnaire_sent
Optional - for surveys/questionnaires that send requests for responses via email.
const questionnaire_reminder_failed
const questionnaire_test_failed
const questionnaire_no_additional
const questionnaire_send_failed
const questionnaire_opened
const questionnaire_reminder_sent
const questionnaire_test_sent
if(! $user) if(! $response_id) $response
$table column("Redirect From", "<a href='redirect_form?redirect_id={redirect_id}'>{redirect_from}</a>", true, "width: 30%") -> column("Redirect To", "<a href='{redirect_to}' target='_blank'>{redirect_to}</a>", true, "width: 30%") ->column("Last Modified", "{last_modified}", true, "width: 20%; text-align: center") ->column("Override", "{ override true