Last active
August 29, 2015 14:01
-
-
Save briceburg/12235673995d2eb3888f to your computer and use it in GitHub Desktop.
MultiFormMultiStep > A SilverStripe MultiForm Step allowing for a dynamic number of questions/answers. Useful for CMS generated surveys &c.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* MultiFormMultiStep allows answers to be collected for a dynamic number of | |
* questions as a single MultiFormStep. This is useful if you have an unknown | |
* amount of questions (e.g. dynamically generated by a CMS based survey maker). | |
* | |
* Define the next and previous steps as usual -- but to get to the next step, | |
* isLastQuestion must return true. Similarly, to get to the previous step | |
* isLastQuestion must return true. | |
* | |
* The following is simplified example assuming Questions are contained in a | |
* DataList of MultiFormQuestion objects. Answers can be yes/no. I have | |
* extended to for more complicated scenarios such as dynamic answer texts | |
* and user-selectable questionnaires. | |
* | |
* MultiFormQuestion extends DataObject with QuestionText and ID fields | |
* QuestionnaireFormStepFirst extends MultiFormStep and is the previous step | |
* QuestionnaireFormStepLast extends MultiFormStep and is is the next step | |
* | |
* @author Brice Burgess @iceburg.net | |
* | |
*/ | |
class MultiFormMultiStep extends MultiFormStep { | |
private $initialized = false; | |
private $answers = null; | |
private $skip_fields = array('question-id'); | |
/** | |
* @var RIMQuestionnaire $questionnaire | |
*/ | |
private $questionnaire = null; | |
/** | |
* | |
* @var RIMQuestion $current_question | |
*/ | |
private $current_question = null; | |
public function setForm($form) { | |
$ret = parent::setForm($form); | |
$this->initializeStep(); | |
return $ret; | |
} | |
public function getNextStep() { | |
return ($this->isLastQuestion()) ? | |
'QuestionnaireFormStepLast' : | |
__CLASS__; | |
} | |
public function getPreviousStep() { | |
return($this->isFirstQuestion()) ? | |
'QuestionnaireFormStepFirst' : | |
__CLASS__; | |
} | |
public function getFields() { | |
if(!$this->initialized) { | |
$this->initializeStep(); | |
} | |
if(!$this->current_question) { | |
return $this->redirectHome('Questionnaire reached an invalid state.'); | |
} | |
$answer_key = 'answer:' . $this->current_question->ID; | |
$fields = new FieldList( | |
new LiteralField('question-text', $this->current_question->QuestionText), | |
new HiddenField('question-id','question-id',$this->current_question->ID) | |
); | |
$fields->add( | |
new OptionsetField($answer_key, 'Please Choose', array(1 => 'yes', 0 => 'no'))); | |
return $fields; | |
} | |
public function loadData() { | |
// cache loadData as $this->answers to avoid successive serialization | |
if(!$this->answers) { | |
$this->answers = parent::loadData(); | |
} | |
return $this->answers; | |
} | |
public function saveData($data) { | |
// save multiple answers for this step | |
$answers = $this->loadData(); | |
$data = array_merge((array) $answers, $data); | |
foreach($this->skip_fields as $key) { | |
if(isset($data[$key])) { | |
unset($data[$key]); | |
} | |
} | |
return parent::saveData($data); | |
} | |
public function Link() { | |
$question_id = null; | |
$request = $this->getForm()->getController()->getRequest(); | |
if($request->requestVar('action_prev')) { | |
$question_id = ($this->current_question) ? | |
$this->getPreviousQuestionID() : | |
$this->getLastQuestionID(); | |
} | |
elseif($request->requestVar('action_next')) { | |
$question_id = ($this->current_question) ? | |
$this->getNextQuestionID() : | |
$this->getFirstQuestionID(); | |
} | |
return ($question_id) ? | |
Controller::join_links($this->form->getDisplayLink(), "?question-id={$question_id}&MultiFormSessionID={$this->Session()->Hash}") : | |
Controller::join_links($this->form->getDisplayLink(), "?MultiFormSessionID={$this->Session()->Hash}"); | |
} | |
public function getNextQuestionID() { | |
$next = false; | |
foreach(MultiFormQuestion::get() as $question) { | |
if($next) { | |
return $question->ID; | |
} | |
if($question->ID == $this->current_question->ID) { | |
$next = true; | |
} | |
} | |
return 0; | |
} | |
public function getPreviousQuestionID() { | |
$prev_question_id = 0; | |
foreach(MultiFormQuestion::get() as $question) { | |
if($question->ID == $this->current_question->ID) { | |
return $prev_question_id; | |
} | |
$prev_question_id = $question->ID; | |
} | |
return 0; | |
} | |
/** | |
* Set the current question by ID | |
* @param int $id | |
*/ | |
public function setQuestionByID($id) { | |
if($question = DataObject::get_by_id('MultiFormQuestion', $id)) | |
$this->setQuestion($question); | |
} | |
/** | |
* Set the current question | |
* @param MultiFormQuestion $question | |
*/ | |
public function setQuestion($question) { | |
$this->current_question = $question; | |
} | |
public function initializeStep() { | |
if($this->initialized) return; | |
// set the question | |
$request = $this->getForm()->getController()->getRequest(); | |
if($question_id = $request->requestVar('question-id')) { | |
$this->setQuestionByID((int) $question_id); | |
} | |
// mark initialized | |
$this->initialized = true; | |
} | |
public function isLastQuestion() { | |
return ($this->getLastQuestionID() == $this->current_question->ID); | |
} | |
public function isFirstQuestion() { | |
return ($this->getFirstQuestionID() == $this->current_question->ID); | |
} | |
public function getFirstQuestionID() { | |
$first = MultiFormQuestion::get()->first(); | |
return $first->ID; | |
} | |
public function getLastQuestionID() { | |
$last = MultiFormQuestion::get()->last(); | |
return $last->ID; | |
} | |
public function redirectHome($msg = null) { | |
$msg = ($msg) ? '?msg=' . urlencode($msg) : ''; | |
$controller = $this->getForm()->getController(); | |
$controller->redirect($controller->Link() . $msg); | |
return new FieldList(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment