silverstripe-multiform/code/MultiFormStep.php

252 lines
6.7 KiB
PHP
Raw Normal View History

2008-04-18 00:03:51 +02:00
<?php
/**
* MultiFormStep controls the behaviour of a single from step in the multi-form
* process. All form steps should be subclasses of this class, as it encapsulates
* the functionality required for the step to be aware of itself in the form step
* process.
*
* @package multiform
*/
class MultiFormStep extends DataObject {
static $db = array(
'Data' => 'Text' // stores serialized maps with all session information
);
static $has_one = array(
'Session' => 'MultiFormSession'
);
/**
* Centerpiece of the flow control for the form.
* If set to a string, you pretty much have a linear
* form flow - if set to an array, you should
* use {@link getNextStep()} to enact flow control
* and branching to different form steps,
* most likely based on previously set session data
* (e.g. a checkbox field or a dropdown).
*
* @var array|string
*/
protected static $next_steps;
/**
2008-04-20 02:28:49 +02:00
* Each {@link MultiForm} subclass needs at least
* one step which is marked as the "final" one
2008-04-18 00:03:51 +02:00
* and triggers the {@link MultiForm->finish()}
* method that wraps up the whole submission.
*
* @var boolean
*/
protected static $is_final_step = false;
/**
* Title of this step, can be used by each step that sub-classes this.
* It's useful for creating a list of steps in your template.
*
* @var string
*/
protected $title;
/**
2008-04-20 02:28:49 +02:00
* Form fields to be rendered with this step.
2008-04-18 00:03:51 +02:00
* (Form object is created in {@link MultiForm}.
2008-04-20 02:28:49 +02:00
*
* This function needs to be implemented on your
* subclasses of MultiFormStep
2008-04-18 00:03:51 +02:00
*
* @return FieldSet
*/
public function getFields() {
user_error('Please implement getFields on your MultiFormStep subclass', E_USER_ERROR);
}
/**
2008-04-20 02:28:49 +02:00
* Additional form actions to be rendered with this step.
* (Form object is created in {@link MultiForm}.
*
* Note: This is optional, and is to be implemented
* on your subclasses of MultiFormStep
2008-04-18 00:03:51 +02:00
*
* @return FieldSet
*/
public function getExtraActions() {
return new FieldSet();
}
/**
* Get a validator specific to this form.
2008-04-20 02:28:49 +02:00
*
2008-04-18 00:03:51 +02:00
* @return Validator
*/
public function getValidator() {
2008-04-20 02:28:49 +02:00
return false;
2008-04-18 00:03:51 +02:00
}
/**
2008-04-20 02:28:49 +02:00
* Accessor method for $this->title
*
* @return string Title of this step
2008-04-18 00:03:51 +02:00
*/
public function getTitle() {
return $this->title;
}
/**
* Gets a direct link to this step (only works
* if you're allowed to skip steps, or this step
* has already been saved to the database
* for the current {@link MultiFormSession}).
*
* @return string Relative URL to this step
*/
public function Link() {
$id = $this->Session()->Hash ? $this->Session()->Hash : $this->Session()->ID;
return Controller::curr()->Link() . '?MultiFormSessionID=' . $id;
2008-04-18 00:03:51 +02:00
}
/**
* Unserialize stored session data and return it.
2008-04-21 10:54:48 +02:00
* This is used for loading data previously saved
* in session back into the form.
*
* You need to overload this method onto your own
* step if you require custom loading. An example
* would be selective loading specific fields, or
* filtering out fields that don't require loading.
*
* This method is called on {@link MultiForm} inside
* the init() method, to load the data by default (if
* it exists, back into the form).
*
* @return array
2008-04-18 00:03:51 +02:00
*/
public function loadData() {
return unserialize($this->Data);
}
/**
* Save the data for this step into session, serializing it first.
2008-04-21 10:54:48 +02:00
*
* To selectively save fields, instead of it all, this
* method would need to be overloaded on your step class.
2008-04-18 00:03:51 +02:00
*
2008-04-21 10:54:48 +02:00
* @param array $data The processed data from save() on {@link MultiForm}
2008-04-18 00:03:51 +02:00
*/
public function saveData($data) {
$this->Data = serialize($data);
$this->write();
}
/**
* Returns the first value of $next_step
*
* @return String Classname of a {@link MultiFormStep} subclass
*/
public function getNextStep() {
$nextSteps = $this->stat('next_steps');
// Check if next_steps have been implemented properly if not the final step
if(!$this->isFinalStep()) {
if(!isset($nextSteps)) user_error('MultiFormStep->getNextStep(): Please define at least one $next_steps on ' . $this->class, E_USER_ERROR);
}
if(is_string($nextSteps)) {
return $nextSteps;
} elseif(is_array($nextSteps) && count($nextSteps)) {
// custom flow control goes here
return $nextSteps[0];
} else {
return false;
}
}
/**
* Returns the next step to the current step in the database.
*
* This will only return something if you've previously visited
* the step ahead of the current step, and then gone back a step.
2008-04-18 00:03:51 +02:00
*
* @return MultiFormStep|boolean
*/
public function getNextStepFromDatabase() {
if($this->SessionID) {
$nextSteps = $this->stat('next_steps');
if(is_string($nextSteps)) {
return DataObject::get_one($nextSteps, "SessionID = {$this->SessionID}");
} elseif(is_array($nextSteps)) {
return DataObject::get_one($nextSteps[0], "SessionID = {$this->SessionID}");
} else {
return false;
}
2008-04-18 00:03:51 +02:00
}
}
/**
* Accessor method for self::$next_steps
*/
public function getNextSteps() {
return $this->stat('next_steps');
}
/**
* Returns the previous step, if there is one.
*
* To determine if there is a previous step, we check the database to see if there's
* a previous step for this multi form session ID.
*
* @return String Classname of a {@link MultiFormStep} subclass
*/
public function getPreviousStep() {
$steps = DataObject::get('MultiFormStep', "SessionID = {$this->SessionID}", 'LastEdited DESC');
if($steps) {
foreach($steps as $step) {
if($step->getNextStep()) {
if($step->getNextStep() == $this->class) {
return $step->class;
}
}
}
}
}
/**
2008-04-21 10:54:48 +02:00
* Retrieves the previous step class record from the database.
*
* @return MultiFormStep subclass
*/
public function getPreviousStepFromDatabase() {
if($prevStepClass = $this->getPreviousStep()) {
return DataObject::get_one($prevStepClass, "SessionID = {$this->SessionID}");
}
}
2008-04-18 00:03:51 +02:00
// ##################### Utility ####################
/**
* Determines whether this step is the final step in the multi-step process or not,
* based on the variable $is_final_step - to set the final step, create this variable
* on your form step class.
*
* @return boolean
*/
public function isFinalStep() {
return $this->stat('is_final_step');
}
/**
* Determines whether the currently viewed step is the current step set in the session.
* This assumes you are checking isCurrentStep() against a data record of a MultiFormStep
* subclass, otherwise it doesn't work. An example of this is using a singleton instance - it won't
* work because there's no data.
*
* @return boolean
*/
public function isCurrentStep() {
if($this->class == $this->Session()->CurrentStep()->class) return true;
}
}
?>