diff --git a/README.md b/README.md
index 50d1a95..e4ca932 100644
--- a/README.md
+++ b/README.md
@@ -83,7 +83,7 @@ Using [Composer](https://getcomposer.org/), you can install multiform into your
SilverStripe site using this command (while in the directory where your site is
currently located)
- composer require "silverstripe/multiform:*"
+`composer require "silverstripe/multiform:*"`
### 2. Create subclass of MultiForm
@@ -91,13 +91,11 @@ First of all, we need to create a new subclass of *MultiForm*.
For the above example, our multi-form will be called *SurveyForm*
- :::php
- 'Thank you for your submission',
- 'Content' => '
You have successfully submitted the form!
'
- );
- }
-
- // ...
-
- }
+}
+class Page_Controller extends ContentController {
+
+// ...
+
+ //
+ private static $allowed_actions = array(
+ 'SurveyForm',
+ 'finished'
+ );
+
+ public function SurveyForm() {
+ return new SurveyForm($this, 'Form');
+ }
+
+ public function finished() {
+ return array(
+ 'Title' => 'Thank you for your submission',
+ 'Content' => 'You have successfully submitted the form!
'
+ );
+ }
+
+// ...
+
+}
+```
The `SurveyForm()` function will create a new instance our subclass of
MultiForm, which in this example, is *SurveyForm*. This in turn will then set
@@ -242,21 +230,21 @@ like.
Your template should look something like this, to render the form in:
- :::html
-
- <% if $Content %>
- $Content
- <% end_if %>
-
- <% if $SurveyForm %>
- $SurveyForm
- <% end_if %>
-
- <% if $Form %>
- $Form
- <% end_if %>
-
-
+```html
+
+ <% if $Content %>
+ $Content
+ <% end_if %>
+
+ <% if $SurveyForm %>
+ $SurveyForm
+ <% end_if %>
+
+ <% if $Form %>
+ $Form
+ <% end_if %>
+
+```
In this case, the above template example is a *sub-template* inside the *Layout*
directory for the templates. Note that we have also included `$Form`, so
@@ -281,11 +269,11 @@ To include these with our instance of multiform, we just need to add an
For example:
- :::html
- <% with $SurveyForm %>
- <% include MultiFormProgressList %>
- <% end_with %>
-
+```html
+<% with $SurveyForm %>
+ <% include MultiFormProgressList %>
+<% end_with %>
+```
This means the included template is rendered within the scope of the
SurveyForm instance returned, instead of the top level controller context.
@@ -293,24 +281,24 @@ This gives us the data to show the progression of the steps.
Putting it together, we might have something looking like this:
- :::html
-
- <% if $Content %>
- $Content
- <% end_if %>
-
- <% if $SurveyForm %>
- <% with $SurveyForm %>
- <% include MultiFormProgressList %>
- <% end_with %>
-
- $SurveyForm
- <% end_if %>
- <% if $Form %>
- $Form
- <% end_if %>
-
+```html
+
+ <% if $Content %>
+ $Content
+ <% end_if %>
+
+ <% if $SurveyForm %>
+ <% with $SurveyForm %>
+ <% include MultiFormProgressList %>
+ <% end_with %>
+ $SurveyForm
+ <% end_if %>
+ <% if $Form %>
+ $Form
+ <% end_if %>
+
+```
Feel free to play around with the progress indicators. If you need something
specific to your project, just create a new "Include" template inside your own
@@ -343,37 +331,35 @@ based on the submission value of another step. There are two methods supporting
Here is an example of how to populate the email address from step 1 in step2 :
- :::php
- copyValueFromOtherStep($fields, 'Step1', 'Email');
-
- return $fields;
- }
- }
+ // set the email field to the input from Step 1
+ $this->copyValueFromOtherStep($fields, 'Step1', 'Email');
+ return $fields;
+ }
+}
+```
### 8. Finishing it up
@@ -389,56 +375,54 @@ So, we must write some code on our subclass of *MultiForm*, overloading
Here is an example of what we could do here:
- :::php
- session->ID}"
- );
-
- if($steps) {
- foreach($steps as $step) {
- if($step->class == 'SurveyFormPersonalDetailsStep') {
- $member = new Member();
- $data = $step->loadData();
+ $steps = DataObject::get(
+ 'MultiFormStep',
+ "SessionID = {$this->session->ID}"
+ );
+
+ if($steps) {
+ foreach($steps as $step) {
+ if($step->class == 'SurveyFormPersonalDetailsStep') {
+ $member = new Member();
+ $data = $step->loadData();
- if($data) {
- $member->update($data);
- $member->write();
- }
- }
-
- if($step->class == 'SurveyOrganisationDetailsStep') {
- $organisation = new Organisation();
- $data = $step->loadData();
+ if($data) {
+ $member->update($data);
+ $member->write();
+ }
+ }
- if($data) {
- $organisation->update($data);
+ if($step->class == 'SurveyOrganisationDetailsStep') {
+ $organisation = new Organisation();
+ $data = $step->loadData();
- if($member && $member->ID) {
- $organisation->MemberID = $member->ID;
- }
+ if($data) {
+ $organisation->update($data);
- $organisation->write();
- }
- }
- // Shows the step data (unserialized by loadData)
- // Debug::show($step->loadData());
- }
- }
+ if($member && $member->ID) {
+ $organisation->MemberID = $member->ID;
+ }
- $this->controller->redirect($this->controller->Link() . 'finished');
- }
- }
+ $organisation->write();
+ }
+ }
+ // Shows the step data (unserialized by loadData)
+ // Debug::show($step->loadData());
+ }
+ }
+ $this->controller->redirect($this->controller->Link() . 'finished');
+ }
+}
+```
#### 9. Organisation data model
@@ -449,17 +433,14 @@ groups in SilverStripe) so we need to create it:
This example has been chosen as a separate DataObject but you may wish to change
the code and add the data to the Member class instead.
- :::php
- session->delete();
-
+```php
+$this->session->delete();
+```
This will also go through each of it's steps and delete them as well.
@@ -517,24 +498,24 @@ be something different based on a user's choice of input during the step, you
can override getNextStep() on any given step to manually override what the next
step should be. An example:
- :::php
- class MyStep extends MultiFormStep
-
- // ...
-
- public function getNextStep() {
- $data = $this->loadData();
- if(@$data['Gender'] == 'Male') {
- return 'TestThirdCase1Step';
- } else {
- return 'TestThirdCase2Step';
- }
- }
-
- // ...
-
- }
+```php
+class MyStep extends MultiFormStep
+// ...
+
+ public function getNextStep() {
+ $data = $this->loadData();
+ if(@$data['Gender'] == 'Male') {
+ return 'TestThirdCase1Step';
+ } else {
+ return 'TestThirdCase2Step';
+ }
+ }
+
+// ...
+
+}
+```
### Validation
To define validation on a step-by-step basis, please define getValidator() and
@@ -543,22 +524,22 @@ validation see [:form](http://doc.silverstripe.org/form-validation).
e.g.
- :::php
- class MyStep extends MultiFormStep {
-
- ...
-
- public function getValidator() {
- return new RequiredFields(array(
- 'Name',
- 'Email'
- ));
- }
-
- ...
-
- }
+```php
+class MyStep extends MultiFormStep {
+ ...
+
+ public function getValidator() {
+ return new RequiredFields(array(
+ 'Name',
+ 'Email'
+ ));
+ }
+
+ ...
+
+}
+```
### finish()
@@ -573,29 +554,27 @@ won't be saved.
For example:
- :::php
- filter(array(
- "SessionID" => $this->session->ID
- ));
+ public static $start_step = 'SurveyFormPersonalDetailsStep';
- if($steps) {
- foreach($steps as $step) {
- // Shows the step data (unserialized by loadData)
- Debug::show($step->loadData());
- }
- }
- }
- }
+ public function finish($data, $form) {
+ parent::finish($data, $form);
+ $steps = MultiFormStep::get()->filter(array(
+ "SessionID" => $this->session->ID
+ ));
+
+ if($steps) {
+ foreach($steps as $step) {
+ // Shows the step data (unserialized by loadData)
+ Debug::show($step->loadData());
+ }
+ }
+ }
+}
+```
The above is a sample bit of code that simply fetches all the steps in the
database that were saved. Further refinement could include getting steps only
@@ -613,9 +592,9 @@ idea to immediately delete this data after the user has submitted.
This can be easily achieved by adding the following line at the end of your
`finish()` method on your MultiForm subclass.
- :::php
- $this->session->delete();
-
+```php
+$this->session->delete();
+```
### Expiring old session data
diff --git a/_config.php b/_config.php
index a4abe2d..b3d9bbc 100644
--- a/_config.php
+++ b/_config.php
@@ -1,2 +1 @@
\ No newline at end of file
diff --git a/lang/bg_BG.php b/lang/bg_BG.php
index eeed11d..f11b98c 100644
--- a/lang/bg_BG.php
+++ b/lang/bg_BG.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('bg_BG', $lang) && is_array($lang['bg_BG'])) {
- $lang['bg_BG'] = array_merge($lang['en_US'], $lang['bg_BG']);
+if (array_key_exists('bg_BG', $lang) && is_array($lang['bg_BG'])) {
+ $lang['bg_BG'] = array_merge($lang['en_US'], $lang['bg_BG']);
} else {
- $lang['bg_BG'] = $lang['en_US'];
+ $lang['bg_BG'] = $lang['en_US'];
}
$lang['bg_BG']['MultiForm']['BACK'] = 'Назад';
@@ -23,5 +23,3 @@ $lang['bg_BG']['MultiFormSession']['plural_name'] = '(никакви)';
$lang['bg_BG']['MultiFormSession']['singular_name'] = '(никакво)';
$lang['bg_BG']['MultiFormStep']['plural_name'] = '(никакви)';
$lang['bg_BG']['MultiFormStep']['singular_name'] = '(никакво)';
-
-?>
\ No newline at end of file
diff --git a/lang/bs_BA.php b/lang/bs_BA.php
index 9ce2a26..1bb4b7a 100644
--- a/lang/bs_BA.php
+++ b/lang/bs_BA.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('bs_BA', $lang) && is_array($lang['bs_BA'])) {
- $lang['bs_BA'] = array_merge($lang['en_US'], $lang['bs_BA']);
+if (array_key_exists('bs_BA', $lang) && is_array($lang['bs_BA'])) {
+ $lang['bs_BA'] = array_merge($lang['en_US'], $lang['bs_BA']);
} else {
- $lang['bs_BA'] = $lang['en_US'];
+ $lang['bs_BA'] = $lang['en_US'];
}
$lang['bs_BA']['MultiFormSession']['db_Hash'] = 'Hash';
@@ -24,5 +24,3 @@ $lang['bs_BA']['MultiFormSession']['singular_name'] = '(ništa)';
$lang['bs_BA']['MultiFormStep']['db_Data'] = 'Podaci';
$lang['bs_BA']['MultiFormStep']['plural_name'] = '(ništa)';
$lang['bs_BA']['MultiFormStep']['singular_name'] = '(ništa)';
-
-?>
\ No newline at end of file
diff --git a/lang/cs_CZ.php b/lang/cs_CZ.php
index 42f1857..ebeafed 100644
--- a/lang/cs_CZ.php
+++ b/lang/cs_CZ.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('cs_CZ', $lang) && is_array($lang['cs_CZ'])) {
- $lang['cs_CZ'] = array_merge($lang['en_US'], $lang['cs_CZ']);
+if (array_key_exists('cs_CZ', $lang) && is_array($lang['cs_CZ'])) {
+ $lang['cs_CZ'] = array_merge($lang['en_US'], $lang['cs_CZ']);
} else {
- $lang['cs_CZ'] = $lang['en_US'];
+ $lang['cs_CZ'] = $lang['en_US'];
}
$lang['cs_CZ']['MultiForm']['BACK'] = 'Zpět';
@@ -27,5 +27,3 @@ $lang['cs_CZ']['MultiFormSession']['singular_name'] = '(žádný)';
$lang['cs_CZ']['MultiFormStep']['db_Data'] = 'Data';
$lang['cs_CZ']['MultiFormStep']['plural_name'] = '(žádný)';
$lang['cs_CZ']['MultiFormStep']['singular_name'] = '(žádný)';
-
-?>
\ No newline at end of file
diff --git a/lang/da_DK.php b/lang/da_DK.php
index 9ef3bb1..4a3e435 100644
--- a/lang/da_DK.php
+++ b/lang/da_DK.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('da_DK', $lang) && is_array($lang['da_DK'])) {
- $lang['da_DK'] = array_merge($lang['en_US'], $lang['da_DK']);
+if (array_key_exists('da_DK', $lang) && is_array($lang['da_DK'])) {
+ $lang['da_DK'] = array_merge($lang['en_US'], $lang['da_DK']);
} else {
- $lang['da_DK'] = $lang['en_US'];
+ $lang['da_DK'] = $lang['en_US'];
}
$lang['da_DK']['MultiFormSession']['db_Hash'] = 'Havelåge';
@@ -24,5 +24,3 @@ $lang['da_DK']['MultiFormSession']['singular_name'] = '(ingen)';
$lang['da_DK']['MultiFormStep']['db_Data'] = 'Data';
$lang['da_DK']['MultiFormStep']['plural_name'] = '(ingen)';
$lang['da_DK']['MultiFormStep']['singular_name'] = '(none)';
-
-?>
\ No newline at end of file
diff --git a/lang/de_DE.php b/lang/de_DE.php
index 73232b4..8ad2e62 100644
--- a/lang/de_DE.php
+++ b/lang/de_DE.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('de_DE', $lang) && is_array($lang['de_DE'])) {
- $lang['de_DE'] = array_merge($lang['en_US'], $lang['de_DE']);
+if (array_key_exists('de_DE', $lang) && is_array($lang['de_DE'])) {
+ $lang['de_DE'] = array_merge($lang['en_US'], $lang['de_DE']);
} else {
- $lang['de_DE'] = $lang['en_US'];
+ $lang['de_DE'] = $lang['en_US'];
}
$lang['de_DE']['MultiForm']['BACK'] = 'Zurück';
@@ -27,5 +27,3 @@ $lang['de_DE']['MultiFormSession']['singular_name'] = 'Multi-Formular';
$lang['de_DE']['MultiFormStep']['db_Data'] = 'Daten';
$lang['de_DE']['MultiFormStep']['plural_name'] = 'Multi-Formular-Schritte';
$lang['de_DE']['MultiFormStep']['singular_name'] = 'Multi-Formular-Schritt';
-
-?>
\ No newline at end of file
diff --git a/lang/en_US.php b/lang/en_US.php
index 37832ff..5cbbfb8 100644
--- a/lang/en_US.php
+++ b/lang/en_US.php
@@ -6,24 +6,22 @@ $lang['en_US']['MultiForm']['BACK'] = 'Back';
$lang['en_US']['MultiForm']['NEXT'] = 'Next';
$lang['en_US']['MultiForm']['SUBMIT'] = 'Submit';
$lang['en_US']['MultiFormSession']['PLURALNAME'] = array(
- 'Multi Form Sessions',
- 50,
- 'Pural name of the object, used in dropdowns and to generally identify a collection of this object in the interface'
+ 'Multi Form Sessions',
+ 50,
+ 'Pural name of the object, used in dropdowns and to generally identify a collection of this object in the interface'
);
$lang['en_US']['MultiFormSession']['SINGULARNAME'] = array(
- 'Multi Form Session',
- 50,
- 'Singular name of the object, used in dropdowns and to generally identify a single object in the interface'
+ 'Multi Form Session',
+ 50,
+ 'Singular name of the object, used in dropdowns and to generally identify a single object in the interface'
);
$lang['en_US']['MultiFormStep']['PLURALNAME'] = array(
- 'Multi Form Steps',
- 50,
- 'Pural name of the object, used in dropdowns and to generally identify a collection of this object in the interface'
+ 'Multi Form Steps',
+ 50,
+ 'Pural name of the object, used in dropdowns and to generally identify a collection of this object in the interface'
);
$lang['en_US']['MultiFormStep']['SINGULARNAME'] = array(
- 'Multi Form Step',
- 50,
- 'Singular name of the object, used in dropdowns and to generally identify a single object in the interface'
+ 'Multi Form Step',
+ 50,
+ 'Singular name of the object, used in dropdowns and to generally identify a single object in the interface'
);
-
-?>
\ No newline at end of file
diff --git a/lang/eo_XX.php b/lang/eo_XX.php
index 732acaa..3fd7083 100644
--- a/lang/eo_XX.php
+++ b/lang/eo_XX.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('eo_XX', $lang) && is_array($lang['eo_XX'])) {
- $lang['eo_XX'] = array_merge($lang['en_US'], $lang['eo_XX']);
+if (array_key_exists('eo_XX', $lang) && is_array($lang['eo_XX'])) {
+ $lang['eo_XX'] = array_merge($lang['en_US'], $lang['eo_XX']);
} else {
- $lang['eo_XX'] = $lang['en_US'];
+ $lang['eo_XX'] = $lang['en_US'];
}
$lang['eo_XX']['MultiForm']['BACK'] = 'Retro';
@@ -27,5 +27,3 @@ $lang['eo_XX']['MultiFormSession']['singular_name'] = '(neniu)';
$lang['eo_XX']['MultiFormStep']['db_Data'] = 'Datumoj';
$lang['eo_XX']['MultiFormStep']['plural_name'] = '(neniu)';
$lang['eo_XX']['MultiFormStep']['singular_name'] = '(neniu)';
-
-?>
\ No newline at end of file
diff --git a/lang/es_419.php b/lang/es_419.php
index 3e853d7..7a49f61 100644
--- a/lang/es_419.php
+++ b/lang/es_419.php
@@ -10,11 +10,8 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('es_', $lang) && is_array($lang['es_'])) {
- $lang['es_'] = array_merge($lang['en_US'], $lang['es_']);
+if (array_key_exists('es_', $lang) && is_array($lang['es_'])) {
+ $lang['es_'] = array_merge($lang['en_US'], $lang['es_']);
} else {
- $lang['es_'] = $lang['en_US'];
+ $lang['es_'] = $lang['en_US'];
}
-
-
-?>
\ No newline at end of file
diff --git a/lang/es_AR.php b/lang/es_AR.php
index 03c4768..6bc9c5e 100644
--- a/lang/es_AR.php
+++ b/lang/es_AR.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('es_AR', $lang) && is_array($lang['es_AR'])) {
- $lang['es_AR'] = array_merge($lang['en_US'], $lang['es_AR']);
+if (array_key_exists('es_AR', $lang) && is_array($lang['es_AR'])) {
+ $lang['es_AR'] = array_merge($lang['en_US'], $lang['es_AR']);
} else {
- $lang['es_AR'] = $lang['en_US'];
+ $lang['es_AR'] = $lang['en_US'];
}
$lang['es_AR']['MultiForm']['BACK'] = 'Volver';
@@ -27,5 +27,3 @@ $lang['es_AR']['MultiFormSession']['singular_name'] = '(ninguno)';
$lang['es_AR']['MultiFormStep']['db_Data'] = 'Datos';
$lang['es_AR']['MultiFormStep']['plural_name'] = '(ninguno)';
$lang['es_AR']['MultiFormStep']['singular_name'] = '(ninguno)';
-
-?>
\ No newline at end of file
diff --git a/lang/es_MX.php b/lang/es_MX.php
index 6689c66..f790cbc 100644
--- a/lang/es_MX.php
+++ b/lang/es_MX.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('es_MX', $lang) && is_array($lang['es_MX'])) {
- $lang['es_MX'] = array_merge($lang['en_US'], $lang['es_MX']);
+if (array_key_exists('es_MX', $lang) && is_array($lang['es_MX'])) {
+ $lang['es_MX'] = array_merge($lang['en_US'], $lang['es_MX']);
} else {
- $lang['es_MX'] = $lang['en_US'];
+ $lang['es_MX'] = $lang['en_US'];
}
$lang['es_MX']['MultiForm']['BACK'] = 'Atrás';
@@ -27,5 +27,3 @@ $lang['es_MX']['MultiFormSession']['singular_name'] = '(ningún)';
$lang['es_MX']['MultiFormStep']['db_Data'] = 'Datos';
$lang['es_MX']['MultiFormStep']['plural_name'] = '(ningunos)';
$lang['es_MX']['MultiFormStep']['singular_name'] = '(ningún)';
-
-?>
\ No newline at end of file
diff --git a/lang/et_EE.php b/lang/et_EE.php
index 9311d8b..7f836c6 100644
--- a/lang/et_EE.php
+++ b/lang/et_EE.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('et_EE', $lang) && is_array($lang['et_EE'])) {
- $lang['et_EE'] = array_merge($lang['en_US'], $lang['et_EE']);
+if (array_key_exists('et_EE', $lang) && is_array($lang['et_EE'])) {
+ $lang['et_EE'] = array_merge($lang['en_US'], $lang['et_EE']);
} else {
- $lang['et_EE'] = $lang['en_US'];
+ $lang['et_EE'] = $lang['en_US'];
}
$lang['et_EE']['MultiForm']['BACK'] = 'Tagasi';
@@ -27,5 +27,3 @@ $lang['et_EE']['MultiFormSession']['singular_name'] = '(none)';
$lang['et_EE']['MultiFormStep']['db_Data'] = 'Andmed';
$lang['et_EE']['MultiFormStep']['plural_name'] = '(none)';
$lang['et_EE']['MultiFormStep']['singular_name'] = '(none)';
-
-?>
\ No newline at end of file
diff --git a/lang/fr_FR.php b/lang/fr_FR.php
index 5aecb8d..0486d56 100644
--- a/lang/fr_FR.php
+++ b/lang/fr_FR.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('fr_FR', $lang) && is_array($lang['fr_FR'])) {
- $lang['fr_FR'] = array_merge($lang['en_US'], $lang['fr_FR']);
+if (array_key_exists('fr_FR', $lang) && is_array($lang['fr_FR'])) {
+ $lang['fr_FR'] = array_merge($lang['en_US'], $lang['fr_FR']);
} else {
- $lang['fr_FR'] = $lang['en_US'];
+ $lang['fr_FR'] = $lang['en_US'];
}
$lang['fr_FR']['MultiForm']['BACK'] = 'Retour';
@@ -27,5 +27,3 @@ $lang['fr_FR']['MultiFormSession']['singular_name'] = '(aucun)';
$lang['fr_FR']['MultiFormStep']['db_Data'] = 'Data';
$lang['fr_FR']['MultiFormStep']['plural_name'] = '(aucun)';
$lang['fr_FR']['MultiFormStep']['singular_name'] = '(aucun)';
-
-?>
\ No newline at end of file
diff --git a/lang/id_ID.php b/lang/id_ID.php
index 54362d2..f784d53 100644
--- a/lang/id_ID.php
+++ b/lang/id_ID.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('id_ID', $lang) && is_array($lang['id_ID'])) {
- $lang['id_ID'] = array_merge($lang['en_US'], $lang['id_ID']);
+if (array_key_exists('id_ID', $lang) && is_array($lang['id_ID'])) {
+ $lang['id_ID'] = array_merge($lang['en_US'], $lang['id_ID']);
} else {
- $lang['id_ID'] = $lang['en_US'];
+ $lang['id_ID'] = $lang['en_US'];
}
$lang['id_ID']['MultiForm']['BACK'] = 'Kembali';
@@ -26,5 +26,3 @@ $lang['id_ID']['MultiFormSession']['singular_name'] = '(tidak ada)';
$lang['id_ID']['MultiFormStep']['db_Data'] = 'Data';
$lang['id_ID']['MultiFormStep']['plural_name'] = '(tidak ada)';
$lang['id_ID']['MultiFormStep']['singular_name'] = '(tidak ada)';
-
-?>
\ No newline at end of file
diff --git a/lang/is_IS.php b/lang/is_IS.php
index e8d422e..63f80d4 100644
--- a/lang/is_IS.php
+++ b/lang/is_IS.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('is_IS', $lang) && is_array($lang['is_IS'])) {
- $lang['is_IS'] = array_merge($lang['en_US'], $lang['is_IS']);
+if (array_key_exists('is_IS', $lang) && is_array($lang['is_IS'])) {
+ $lang['is_IS'] = array_merge($lang['en_US'], $lang['is_IS']);
} else {
- $lang['is_IS'] = $lang['en_US'];
+ $lang['is_IS'] = $lang['en_US'];
}
$lang['is_IS']['MultiFormSession']['plural_name'] = '(ekkert)';
@@ -21,5 +21,3 @@ $lang['is_IS']['MultiFormSession']['singular_name'] = '(ekkert)';
$lang['is_IS']['MultiFormStep']['db_Data'] = 'Gögn';
$lang['is_IS']['MultiFormStep']['plural_name'] = '(ekkert)';
$lang['is_IS']['MultiFormStep']['singular_name'] = '(ekkert)';
-
-?>
\ No newline at end of file
diff --git a/lang/it_IT.php b/lang/it_IT.php
index b5980fe..f658361 100644
--- a/lang/it_IT.php
+++ b/lang/it_IT.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('it_IT', $lang) && is_array($lang['it_IT'])) {
- $lang['it_IT'] = array_merge($lang['en_US'], $lang['it_IT']);
+if (array_key_exists('it_IT', $lang) && is_array($lang['it_IT'])) {
+ $lang['it_IT'] = array_merge($lang['en_US'], $lang['it_IT']);
} else {
- $lang['it_IT'] = $lang['en_US'];
+ $lang['it_IT'] = $lang['en_US'];
}
$lang['it_IT']['MultiForm']['BACK'] = 'Indietro';
@@ -27,5 +27,3 @@ $lang['it_IT']['MultiFormSession']['singular_name'] = '(nessuno)';
$lang['it_IT']['MultiFormStep']['db_Data'] = 'Dati';
$lang['it_IT']['MultiFormStep']['plural_name'] = '(nessuno)';
$lang['it_IT']['MultiFormStep']['singular_name'] = '(nessuno)';
-
-?>
\ No newline at end of file
diff --git a/lang/ja_JP.php b/lang/ja_JP.php
index 4bebaf3..1ee4235 100644
--- a/lang/ja_JP.php
+++ b/lang/ja_JP.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('ja_JP', $lang) && is_array($lang['ja_JP'])) {
- $lang['ja_JP'] = array_merge($lang['en_US'], $lang['ja_JP']);
+if (array_key_exists('ja_JP', $lang) && is_array($lang['ja_JP'])) {
+ $lang['ja_JP'] = array_merge($lang['en_US'], $lang['ja_JP']);
} else {
- $lang['ja_JP'] = $lang['en_US'];
+ $lang['ja_JP'] = $lang['en_US'];
}
$lang['ja_JP']['MultiForm']['BACK'] = '戻る';
@@ -21,5 +21,3 @@ $lang['ja_JP']['MultiForm']['NEXT'] = '次へ';
$lang['ja_JP']['MultiForm']['SUBMIT'] = '送信';
$lang['ja_JP']['MultiFormSession']['db_Hash'] = 'ハッシュ';
$lang['ja_JP']['MultiFormStep']['db_Data'] = 'データ';
-
-?>
\ No newline at end of file
diff --git a/lang/ms_MY.php b/lang/ms_MY.php
index f43ee01..b46c4dd 100644
--- a/lang/ms_MY.php
+++ b/lang/ms_MY.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('ms_MY', $lang) && is_array($lang['ms_MY'])) {
- $lang['ms_MY'] = array_merge($lang['en_US'], $lang['ms_MY']);
+if (array_key_exists('ms_MY', $lang) && is_array($lang['ms_MY'])) {
+ $lang['ms_MY'] = array_merge($lang['en_US'], $lang['ms_MY']);
} else {
- $lang['ms_MY'] = $lang['en_US'];
+ $lang['ms_MY'] = $lang['en_US'];
}
$lang['ms_MY']['MultiFormSession']['db_Hash'] = 'Cincangan';
@@ -24,5 +24,3 @@ $lang['ms_MY']['MultiFormSession']['singular_name'] = '(tiada)';
$lang['ms_MY']['MultiFormStep']['db_Data'] = 'Data';
$lang['ms_MY']['MultiFormStep']['plural_name'] = '(tiada)';
$lang['ms_MY']['MultiFormStep']['singular_name'] = '(tiada)';
-
-?>
\ No newline at end of file
diff --git a/lang/nb_NO.php b/lang/nb_NO.php
index 91a50ae..40ab72e 100644
--- a/lang/nb_NO.php
+++ b/lang/nb_NO.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('nb_NO', $lang) && is_array($lang['nb_NO'])) {
- $lang['nb_NO'] = array_merge($lang['en_US'], $lang['nb_NO']);
+if (array_key_exists('nb_NO', $lang) && is_array($lang['nb_NO'])) {
+ $lang['nb_NO'] = array_merge($lang['en_US'], $lang['nb_NO']);
} else {
- $lang['nb_NO'] = $lang['en_US'];
+ $lang['nb_NO'] = $lang['en_US'];
}
$lang['nb_NO']['MultiForm']['BACK'] = 'Forrige';
@@ -27,5 +27,3 @@ $lang['nb_NO']['MultiFormSession']['singular_name'] = '(ingen)';
$lang['nb_NO']['MultiFormStep']['db_Data'] = 'Data';
$lang['nb_NO']['MultiFormStep']['plural_name'] = '(ingen)';
$lang['nb_NO']['MultiFormStep']['singular_name'] = '(ingen)';
-
-?>
\ No newline at end of file
diff --git a/lang/nl_NL.php b/lang/nl_NL.php
index cb7c7e8..3b6cf87 100644
--- a/lang/nl_NL.php
+++ b/lang/nl_NL.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('nl_NL', $lang) && is_array($lang['nl_NL'])) {
- $lang['nl_NL'] = array_merge($lang['en_US'], $lang['nl_NL']);
+if (array_key_exists('nl_NL', $lang) && is_array($lang['nl_NL'])) {
+ $lang['nl_NL'] = array_merge($lang['en_US'], $lang['nl_NL']);
} else {
- $lang['nl_NL'] = $lang['en_US'];
+ $lang['nl_NL'] = $lang['en_US'];
}
$lang['nl_NL']['MultiForm']['BACK'] = 'Terug';
@@ -27,5 +27,3 @@ $lang['nl_NL']['MultiFormSession']['singular_name'] = '(geen)';
$lang['nl_NL']['MultiFormStep']['db_Data'] = 'Data';
$lang['nl_NL']['MultiFormStep']['plural_name'] = '(geen)';
$lang['nl_NL']['MultiFormStep']['singular_name'] = '(geen)';
-
-?>
\ No newline at end of file
diff --git a/lang/pl_PL.php b/lang/pl_PL.php
index a5ee74b..06b90a6 100644
--- a/lang/pl_PL.php
+++ b/lang/pl_PL.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('pl_PL', $lang) && is_array($lang['pl_PL'])) {
- $lang['pl_PL'] = array_merge($lang['en_US'], $lang['pl_PL']);
+if (array_key_exists('pl_PL', $lang) && is_array($lang['pl_PL'])) {
+ $lang['pl_PL'] = array_merge($lang['en_US'], $lang['pl_PL']);
} else {
- $lang['pl_PL'] = $lang['en_US'];
+ $lang['pl_PL'] = $lang['en_US'];
}
$lang['pl_PL']['MultiForm']['BACK'] = 'Wstecz';
@@ -27,5 +27,3 @@ $lang['pl_PL']['MultiFormSession']['singular_name'] = '(brak)';
$lang['pl_PL']['MultiFormStep']['db_Data'] = 'Dane';
$lang['pl_PL']['MultiFormStep']['plural_name'] = '(brak)';
$lang['pl_PL']['MultiFormStep']['singular_name'] = '(brak)';
-
-?>
\ No newline at end of file
diff --git a/lang/pt_PT.php b/lang/pt_PT.php
index 524dc95..dc4aa7d 100644
--- a/lang/pt_PT.php
+++ b/lang/pt_PT.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('pt_PT', $lang) && is_array($lang['pt_PT'])) {
- $lang['pt_PT'] = array_merge($lang['en_US'], $lang['pt_PT']);
+if (array_key_exists('pt_PT', $lang) && is_array($lang['pt_PT'])) {
+ $lang['pt_PT'] = array_merge($lang['en_US'], $lang['pt_PT']);
} else {
- $lang['pt_PT'] = $lang['en_US'];
+ $lang['pt_PT'] = $lang['en_US'];
}
$lang['pt_PT']['MultiFormSession']['db_IsComplete'] = 'Está completa';
@@ -23,5 +23,3 @@ $lang['pt_PT']['MultiFormSession']['singular_name'] = '(nenhum)';
$lang['pt_PT']['MultiFormStep']['db_Data'] = 'Dados';
$lang['pt_PT']['MultiFormStep']['plural_name'] = '(nenhum)';
$lang['pt_PT']['MultiFormStep']['singular_name'] = '(nenhum)';
-
-?>
\ No newline at end of file
diff --git a/lang/sr_RS.php b/lang/sr_RS.php
index a9aa411..991ed0d 100644
--- a/lang/sr_RS.php
+++ b/lang/sr_RS.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('sr_RS', $lang) && is_array($lang['sr_RS'])) {
- $lang['sr_RS'] = array_merge($lang['en_US'], $lang['sr_RS']);
+if (array_key_exists('sr_RS', $lang) && is_array($lang['sr_RS'])) {
+ $lang['sr_RS'] = array_merge($lang['en_US'], $lang['sr_RS']);
} else {
- $lang['sr_RS'] = $lang['en_US'];
+ $lang['sr_RS'] = $lang['en_US'];
}
$lang['sr_RS']['MultiFormSession']['db_IsComplete'] = 'ЈеЗавршен';
@@ -22,5 +22,3 @@ $lang['sr_RS']['MultiFormSession']['singular_name'] = '(без)';
$lang['sr_RS']['MultiFormStep']['db_Data'] = 'Подаци';
$lang['sr_RS']['MultiFormStep']['plural_name'] = '(без)';
$lang['sr_RS']['MultiFormStep']['singular_name'] = '(без)';
-
-?>
\ No newline at end of file
diff --git a/lang/sv_SE.php b/lang/sv_SE.php
index ef01aa4..f51b787 100644
--- a/lang/sv_SE.php
+++ b/lang/sv_SE.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('sv_SE', $lang) && is_array($lang['sv_SE'])) {
- $lang['sv_SE'] = array_merge($lang['en_US'], $lang['sv_SE']);
+if (array_key_exists('sv_SE', $lang) && is_array($lang['sv_SE'])) {
+ $lang['sv_SE'] = array_merge($lang['en_US'], $lang['sv_SE']);
} else {
- $lang['sv_SE'] = $lang['en_US'];
+ $lang['sv_SE'] = $lang['en_US'];
}
$lang['sv_SE']['MultiForm']['BACK'] = 'Tillbaka';
@@ -24,5 +24,3 @@ $lang['sv_SE']['MultiFormSession']['plural_name'] = '(ingen)';
$lang['sv_SE']['MultiFormStep']['db_Data'] = 'Data';
$lang['sv_SE']['MultiFormStep']['plural_name'] = '(inga)';
$lang['sv_SE']['MultiFormStep']['singular_name'] = '(ingen)';
-
-?>
\ No newline at end of file
diff --git a/lang/tr_TR.php b/lang/tr_TR.php
index 9d29af8..e998f87 100644
--- a/lang/tr_TR.php
+++ b/lang/tr_TR.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('tr_TR', $lang) && is_array($lang['tr_TR'])) {
- $lang['tr_TR'] = array_merge($lang['en_US'], $lang['tr_TR']);
+if (array_key_exists('tr_TR', $lang) && is_array($lang['tr_TR'])) {
+ $lang['tr_TR'] = array_merge($lang['en_US'], $lang['tr_TR']);
} else {
- $lang['tr_TR'] = $lang['en_US'];
+ $lang['tr_TR'] = $lang['en_US'];
}
$lang['tr_TR']['MultiForm']['BACK'] = 'Geri';
@@ -27,5 +27,3 @@ $lang['tr_TR']['MultiFormSession']['singular_name'] = '(hiçbiri)';
$lang['tr_TR']['MultiFormStep']['db_Data'] = 'Veri';
$lang['tr_TR']['MultiFormStep']['plural_name'] = '(hiçbiri)';
$lang['tr_TR']['MultiFormStep']['singular_name'] = '(hiçbiri)';
-
-?>
\ No newline at end of file
diff --git a/lang/zh_CN.php b/lang/zh_CN.php
index 120de77..c350786 100644
--- a/lang/zh_CN.php
+++ b/lang/zh_CN.php
@@ -10,10 +10,10 @@ i18n::include_locale_file('modules: multiform', 'en_US');
global $lang;
-if(array_key_exists('zh_CN', $lang) && is_array($lang['zh_CN'])) {
- $lang['zh_CN'] = array_merge($lang['en_US'], $lang['zh_CN']);
+if (array_key_exists('zh_CN', $lang) && is_array($lang['zh_CN'])) {
+ $lang['zh_CN'] = array_merge($lang['en_US'], $lang['zh_CN']);
} else {
- $lang['zh_CN'] = $lang['en_US'];
+ $lang['zh_CN'] = $lang['en_US'];
}
$lang['zh_CN']['MultiForm']['BACK'] = '区域';
@@ -27,5 +27,3 @@ $lang['zh_CN']['MultiFormSession']['singular_name'] = '单名称';
$lang['zh_CN']['MultiFormStep']['db_Data'] = '数据';
$lang['zh_CN']['MultiFormStep']['plural_name'] = '多名称';
$lang['zh_CN']['MultiFormStep']['singular_name'] = '单名称';
-
-?>
\ No newline at end of file
diff --git a/src/extensions/MultiFormObjectDecorator.php b/src/extensions/MultiFormObjectDecorator.php
index 3168538..3423a65 100644
--- a/src/extensions/MultiFormObjectDecorator.php
+++ b/src/extensions/MultiFormObjectDecorator.php
@@ -14,56 +14,58 @@
*
* @package multiform
*/
-class MultiFormObjectDecorator extends DataExtension {
+class MultiFormObjectDecorator extends DataExtension
+{
- private static $db = array(
- 'MultiFormIsTemporary' => 'Boolean',
- );
+ private static $db = array(
+ 'MultiFormIsTemporary' => 'Boolean',
+ );
- private static $has_one = array(
- 'MultiFormSession' => 'MultiFormSession',
- );
+ private static $has_one = array(
+ 'MultiFormSession' => 'MultiFormSession',
+ );
- /**
- * Augment any queries to MultiFormObjectDecorator and only
- * return anything that isn't considered temporary.
- */
- public function augmentSQL(SQLQuery &$query) {
- $where = $query->getWhere();
- if(!$where && !$this->wantsTemporary($query)) {
- $from = array_values($query->getFrom());
- $query->addWhere("{$from[0]}.\"MultiFormIsTemporary\" = '0'");
- return;
- }
+ /**
+ * Augment any queries to MultiFormObjectDecorator and only
+ * return anything that isn't considered temporary.
+ */
+ public function augmentSQL(SQLQuery &$query)
+ {
+ $where = $query->getWhere();
+ if (!$where && !$this->wantsTemporary($query)) {
+ $from = array_values($query->getFrom());
+ $query->addWhere("{$from[0]}.\"MultiFormIsTemporary\" = '0'");
+ return;
+ }
- if(
- strpos($where[0], ".`ID` = ") === false
- && strpos($where[0], ".ID = ") === false
- && strpos($where[0], "ID = ") !== 0
- && !$this->wantsTemporary($query)
- ) {
- $from = array_values($query->getFrom());
- $query->addWhere("{$from[0]}.\"MultiFormIsTemporary\" = '0'");
- }
- }
+ if (strpos($where[0], ".`ID` = ") === false
+ && strpos($where[0], ".ID = ") === false
+ && strpos($where[0], "ID = ") !== 0
+ && !$this->wantsTemporary($query)
+ ) {
+ $from = array_values($query->getFrom());
+ $query->addWhere("{$from[0]}.\"MultiFormIsTemporary\" = '0'");
+ }
+ }
- /**
- * Determines if the current query is supposed
- * to be exempt from the automatic filtering out
- * of temporary records.
- *
- * @param SQLQuery $query
- * @return boolean
- */
- protected function wantsTemporary($query) {
- foreach($query->getWhere() as $whereClause) {
- $from = array_values($query->getFrom());
- // SQLQuery will automatically add double quotes and single quotes to values, so check against that.
- if($whereClause == "{$from[0]}.\"MultiFormIsTemporary\" = '1'") {
- return true;
- }
- }
+ /**
+ * Determines if the current query is supposed
+ * to be exempt from the automatic filtering out
+ * of temporary records.
+ *
+ * @param SQLQuery $query
+ * @return boolean
+ */
+ protected function wantsTemporary($query)
+ {
+ foreach ($query->getWhere() as $whereClause) {
+ $from = array_values($query->getFrom());
+ // SQLQuery will automatically add double quotes and single quotes to values, so check against that.
+ if ($whereClause == "{$from[0]}.\"MultiFormIsTemporary\" = '1'") {
+ return true;
+ }
+ }
- return false;
- }
+ return false;
+ }
}
diff --git a/src/model/MultiForm.php b/src/model/MultiForm.php
index 8a3978a..547fdd7 100644
--- a/src/model/MultiForm.php
+++ b/src/model/MultiForm.php
@@ -14,686 +14,721 @@
*
* @package multiform
*/
-abstract class MultiForm extends Form {
-
- /**
- * A session object stored in the database, to identify and store
- * data for this MultiForm instance.
- *
- * @var MultiFormSession
- */
- protected $session;
-
- /**
- * The current encrypted MultiFormSession identification.
- *
- * @var string
- */
- protected $currentSessionHash;
-
- /**
- * Defines which subclass of {@link MultiFormStep} should be the first
- * step in the multi-step process.
- *
- * @var string Classname of a {@link MultiFormStep} subclass
- */
- public static $start_step;
-
- /**
- * Set the casting for these fields.
- *
- * @var array
- */
- private static $casting = array(
- 'CompletedStepCount' => 'Int',
- 'TotalStepCount' => 'Int',
- 'CompletedPercent' => 'Float'
- );
-
- /**
- * @var string
- */
- private static $get_var = 'MultiFormSessionID';
-
- /**
- * These fields are ignored when saving the raw form data into session.
- * This ensures only field data is saved, and nothing else that's useless
- * or potentially dangerous.
- *
- * @var array
- */
- public static $ignored_fields = array(
- 'url',
- 'executeForm',
- 'SecurityID'
- );
-
- /**
- * Any of the actions defined in this variable are exempt from
- * being validated.
- *
- * This is most useful for the "Back" (action_prev) action, as
- * you typically don't validate the form when the user is going
- * back a step.
- *
- * @var array
- */
- public static $actions_exempt_from_validation = array(
- 'action_prev'
- );
-
- /**
- * @var string
- */
- protected $displayLink;
-
- /**
- * Flag which is being used in getAllStepsRecursive() to allow adding the completed flag on the steps
- *
- * @var boolean
- */
- protected $currentStepHasBeenFound = false;
-
- /**
- * Start the MultiForm instance.
- *
- * @param Controller instance $controller Controller this form is created on
- * @param string $name The form name, typically the same as the method name
- */
- public function __construct($controller, $name) {
- // First set the controller and name manually so they are available for
- // field construction.
- $this->controller = $controller;
- $this->name = $name;
-
- // Set up the session for this MultiForm instance
- $this->setSession();
-
- // Get the current step available (Note: either returns an existing
- // step or creates a new one if none available)
- $currentStep = $this->getCurrentStep();
-
- // Set the step returned above as the current step
- $this->setCurrentStep($currentStep);
-
- // Set the form of the step to this form instance
- $currentStep->setForm($this);
-
- // Set up the fields for the current step
- $fields = $currentStep->getFields();
-
- // Set up the actions for the current step
- $actions = $this->actionsFor($currentStep);
-
- // Set up validation (if necessary)
- $validator = null;
- $applyValidation = true;
-
- $actionNames = static::$actions_exempt_from_validation;
-
- if($actionNames) {
- foreach ($actionNames as $exemptAction) {
- if(!empty($_REQUEST[$exemptAction])) {
- $applyValidation = false;
- break;
- }
- }
- }
-
- // Apply validation if the current step requires validation (is not exempt)
- if($applyValidation) {
- if($currentStep->getValidator()) {
- $validator = $currentStep->getValidator();
- }
- }
-
- // Give the fields, actions, and validation for the current step back to the parent Form class
- parent::__construct($controller, $name, $fields, $actions, $validator);
-
- $getVar = $this->config()->get_var;
-
- // Set a hidden field in our form with an encrypted hash to identify this session.
- $this->fields->push(new HiddenField($getVar, false, $this->session->Hash));
-
- // If there is saved data for the current step, we load it into the form it here
- //(CAUTION: loadData() MUST unserialize first!)
- if($data = $currentStep->loadData()) {
- $this->loadDataFrom($data);
- }
-
- // Disable security token - we tie a form to a session ID instead
- $this->disableSecurityToken();
-
- self::$ignored_fields[] = $getVar;
- }
-
- /**
- * Accessor method to $this->controller.
- *
- * @return Controller this MultiForm was instanciated on.
- */
- public function getController() {
- return $this->controller;
- }
-
- /**
- * Returns the get_var to the template engine
- *
- * @return string
- */
- public function getGetVar() {
- return $this->config()->get_var;
- }
-
- /**
- * Get the current step.
- *
- * If StepID has been set in the URL, we attempt to get that record
- * by the ID. Otherwise, we check if there's a current step ID in
- * our session record. Failing those cases, we assume that the form has
- * just been started, and so we create the first step and return it.
- *
- * @return MultiFormStep subclass
- */
- public function getCurrentStep() {
- $startStepClass = static::$start_step;
-
- // Check if there was a start step defined on the subclass of MultiForm
- if(!isset($startStepClass)) user_error(
- 'MultiForm::init(): Please define a $start_step on ' . $this->class,
- E_USER_ERROR
- );
-
- // Determine whether we use the current step, or create one if it doesn't exist
- $currentStep = null;
- $StepID = $this->controller->request->getVar('StepID');
- if(isset($StepID)) {
- $currentStep = DataObject::get_one(
- 'MultiFormStep',
- array(
- 'SessionID' => $this->session->ID,
- 'ID' => $StepID
- )
- );
- } elseif($this->session->CurrentStepID) {
- $currentStep = $this->session->CurrentStep();
- }
-
- // Always fall back to creating a new step (in case the session or request data is invalid)
- if(!$currentStep || !$currentStep->ID) {
- $currentStep = Object::create($startStepClass);
- $currentStep->SessionID = $this->session->ID;
- $currentStep->write();
- $this->session->CurrentStepID = $currentStep->ID;
- $this->session->write();
- $this->session->flushCache();
- }
-
- if($currentStep) $currentStep->setForm($this);
-
- return $currentStep;
- }
-
- /**
- * Set the step passed in as the current step.
- *
- * @param MultiFormStep $step A subclass of MultiFormStep
- * @return boolean The return value of write()
- */
- protected function setCurrentStep($step) {
- $this->session->CurrentStepID = $step->ID;
- $step->setForm($this);
-
- return $this->session->write();
- }
-
- /**
- * Accessor method to $this->session.
- *
- * @return MultiFormSession
- */
- public function getSession() {
- return $this->session;
- }
-
- /**
- * Set up the session.
- *
- * If MultiFormSessionID isn't set, we assume that this is a new
- * multiform that requires a new session record to be created.
- *
- * @TODO Fix the fact you can continually refresh and create new records
- * if MultiFormSessionID isn't set.
- *
- * @TODO Not sure if we should bake the session stuff directly into MultiForm.
- * Perhaps it would be best dealt with on a separate class?
- */
- protected function setSession() {
- $this->session = $this->getCurrentSession();
-
- // If there was no session found, create a new one instead
- if(!$this->session) {
- $this->session = new MultiFormSession();
- }
-
- // Create encrypted identification to the session instance if it doesn't exist
- if(!$this->session->Hash) {
- $this->session->Hash = sha1($this->session->ID . '-' . microtime());
- $this->session->write();
- }
- }
-
- /**
- * Set the currently used encrypted hash to identify
- * the MultiFormSession.
- *
- * @param string $hash Encrypted identification to session
- */
- public function setCurrentSessionHash($hash) {
- $this->currentSessionHash = $hash;
- $this->setSession();
- }
-
- /**
- * Return the currently used {@link MultiFormSession}
- * @return MultiFormSession|boolean FALSE
- */
- public function getCurrentSession() {
- if(!$this->currentSessionHash) {
- $this->currentSessionHash = $this->controller->request->getVar($this->config()->get_var);
-
- if(!$this->currentSessionHash) {
- return false;
- }
- }
-
- $this->session = MultiFormSession::get()->filter(array(
- "Hash" => $this->currentSessionHash,
- "IsComplete" => 0
- ))->first();
-
- return $this->session;
- }
-
- /**
- * Get all steps saved in the database for the currently active session,
- * in the order they were saved, oldest to newest (automatically ordered by ID).
- * If you want a full chain of steps regardless if they've already been saved
- * to the database, use {@link getAllStepsLinear()}.
- *
- * @param string $filter SQL WHERE statement
- * @return DataObjectSet|boolean A set of MultiFormStep subclasses
- */
- public function getSavedSteps($filter = null) {
- $filter .= ($filter) ? ' AND ' : '';
- $filter .= sprintf("\"SessionID\" = '%s'", $this->session->ID);
- return DataObject::get('MultiFormStep', $filter);
- }
-
- /**
- * Get a step which was previously saved to the database in the current session.
- * Caution: This might cause unexpected behaviour if you have multiple steps
- * in your chain with the same classname.
- *
- * @param string $className Classname of a {@link MultiFormStep} subclass
- * @return MultiFormStep
- */
- public function getSavedStepByClass($className) {
- return DataObject::get_one(
- 'MultiFormStep',
- sprintf("\"SessionID\" = '%s' AND \"ClassName\" = '%s'",
- $this->session->ID,
- Convert::raw2sql($className)
- )
- );
- }
-
- /**
- * Build a FieldList of the FormAction fields for the given step.
- *
- * If the current step is the final step, we push in a submit button, which
- * calls the action {@link finish()} to finalise the submission. Otherwise,
- * we push in a next button which calls the action {@link next()} to determine
- * where to go next in our step process, and save any form data collected.
- *
- * If there's a previous step (a step that has the current step as it's next
- * step class), then we allow a previous button, which calls the previous action
- * to determine which step to go back to.
- *
- * If there are any extra actions defined in MultiFormStep->getExtraActions()
- * then that set of actions is appended to the end of the actions FieldSet we
- * have created in this method.
- *
- * @param $currentStep Subclass of MultiFormStep
- * @return FieldList of FormAction objects
- */
- public function actionsFor($step) {
- // Create default multi step actions (next, prev), and merge with extra actions, if any
- $actions = (class_exists('FieldList')) ? new FieldList() : new FieldSet();
-
- // If the form is at final step, create a submit button to perform final actions
- // The last step doesn't have a next button, so add that action to any step that isn't the final one
- if($step->isFinalStep()) {
- $actions->push(new FormAction('finish', $step->getSubmitText()));
- } else {
- $actions->push(new FormAction('next', $step->getNextText()));
- }
-
- // If there is a previous step defined, add the back button
- if($step->getPreviousStep() && $step->canGoBack()) {
- // If there is a next step, insert the action before the next action
- if($step->getNextStep()) {
- $actions->insertBefore($prev = new FormAction('prev', $step->getPrevText()), 'action_next');
- // Assume that this is the last step, insert the action before the finish action
- } else {
- $actions->insertBefore($prev = new FormAction('prev', $step->getPrevText()), 'action_finish');
- }
- //remove browser validation from prev action
- $prev->setAttribute("formnovalidate", "formnovalidate");
- }
-
- // Merge any extra action fields defined on the step
- $actions->merge($step->getExtraActions());
-
- return $actions;
- }
-
- /**
- * Return a rendered version of this form, with a specific template.
- * Looks through the step ancestory templates (MultiFormStep, current step
- * subclass template) to see if one is available to render the form with. If
- * any of those don't exist, look for a default Form template to render
- * with instead.
- *
- * @return SSViewer object to render the template with
- */
- public function forTemplate() {
- $return = $this->renderWith(array(
- $this->getCurrentStep()->class,
- 'MultiFormStep',
- $this->class,
- 'MultiForm',
- 'Form'
- ));
-
- $this->clearMessage();
-
- return $return;
- }
-
- /**
- * This method saves the data on the final step, after submitting.
- * It should always be overloaded with parent::finish($data, $form)
- * so you can create your own functionality which handles saving
- * of all the data collected through each step of the form.
- *
- * @param array $data The request data returned from the form
- * @param object $form The form that the action was called on
- */
- public function finish($data, $form) {
- // Save the form data for the current step
- $this->save($data);
-
- if(!$this->getCurrentStep()->isFinalStep()) {
- $this->controller->redirectBack();
- return false;
- }
-
- if(!$this->getCurrentStep()->validateStep($data, $form)) {
- Session::set("FormInfo.{$form->FormName()}.data", $form->getData());
- $this->controller->redirectBack();
- return false;
- }
- }
-
- /**
- * Determine what to do when the next action is called.
- *
- * Saves the current step session data to the database, creates the
- * new step based on getNextStep() of the current step (or fetches
- * an existing one), resets the current step to the next step,
- * then redirects to the newly set step.
- *
- * @param array $data The request data returned from the form
- * @param object $form The form that the action was called on
- */
- public function next($data, $form) {
- // Save the form data for the current step
- $this->save($form->getData());
-
- // Get the next step class
- $nextStepClass = $this->getCurrentStep()->getNextStep();
-
- if(!$nextStepClass) {
- $this->controller->redirectBack();
- return false;
- }
-
- // Perform custom step validation (use MultiFormStep->getValidator() for
- // built-in functionality). The data needs to be manually saved on error
- // so the form is re-populated.
- if(!$this->getCurrentStep()->validateStep($data, $form)) {
- Session::set("FormInfo.{$form->FormName()}.data", $form->getData());
- $this->controller->redirectBack();
- return false;
- }
-
- // validation succeeded so we reset it to remove errors and messages
- $this->resetValidation();
-
- // Determine whether we can use a step already in the DB, or have to create a new one
- if(!$nextStep = DataObject::get_one($nextStepClass, "\"SessionID\" = {$this->session->ID}")) {
- $nextStep = Object::create($nextStepClass);
- $nextStep->SessionID = $this->session->ID;
- $nextStep->write();
- }
-
- // Set the next step found as the current step
- $this->setCurrentStep($nextStep);
-
- // Redirect to the next step
- $this->controller->redirect($nextStep->Link());
- }
-
- /**
- * Determine what to do when the previous action is called.
- *
- * Retrieves the previous step class, finds the record for that
- * class in the DB, and sets the current step to that step found.
- * Finally, it redirects to that step.
- *
- * @param array $data The request data returned from the form
- * @param object $form The form that the action was called on
- */
- public function prev($data, $form) {
- // Save the form data for the current step
- $this->save($form->getData());
-
- // Get the previous step class
- $prevStepClass = $this->getCurrentStep()->getPreviousStep();
-
- if(!$prevStepClass && !$this->getCurrentStep()->canGoBack()) {
- $this->controller->redirectBack();
- return false;
- }
-
- // Get the previous step of the class instance returned from $currentStep->getPreviousStep()
- $prevStep = DataObject::get_one($prevStepClass, "\"SessionID\" = {$this->session->ID}");
-
- // Set the current step as the previous step
- $this->setCurrentStep($prevStep);
-
- // Redirect to the previous step
- $this->controller->redirect($prevStep->Link());
- }
-
- /**
- * Save the raw data given back from the form into session.
- *
- * Take the submitted form data for the current step, removing
- * any key => value pairs that shouldn't be saved, then saves
- * the data into the session.
- *
- * @param array $data An array of data to save
- */
- protected function save($data) {
- $currentStep = $this->getCurrentStep();
- if(is_array($data)) {
- foreach($data as $field => $value) {
- if(in_array($field, static::$ignored_fields)) {
- unset($data[$field]);
- }
- }
- $currentStep->saveData($data);
- }
- return;
- }
-
- // ############ Misc ############
-
- /**
- * Add the MultiFormSessionID variable to the URL on form submission.
- * This is a means to persist the session, by adding it's identification
- * to the URL, which ties it back to this MultiForm instance.
- *
- * @return string
- */
- public function FormAction() {
- $action = parent::FormAction();
- $action .= (strpos($action, '?')) ? '&' : '?';
- $action .= "{$this->config()->get_var}={$this->session->Hash}";
-
- return $action;
- }
-
- /**
- * Returns the link to the page where the form is displayed. The user is
- * redirected to this link with a session param after each step is
- * submitted.
- *
- * @return string
- */
- public function getDisplayLink() {
- return $this->displayLink ? $this->displayLink : Controller::curr()->Link();
- }
-
- /**
- * Set the link to the page on which the form is displayed.
- *
- * The link defaults to the controllers current link. However if the form
- * is displayed inside an action the display link must be explicitly set.
- *
- * @param string $link
- */
- public function setDisplayLink($link) {
- $this->displayLink = $link;
- }
-
- /**
- * Determine the steps to show in a linear fashion, starting from the
- * first step. We run {@link getAllStepsRecursive} passing the steps found
- * by reference to get a listing of the steps.
- *
- * @return DataObjectSet of MultiFormStep instances
- */
- public function getAllStepsLinear() {
- $stepsFound = (class_exists('ArrayList')) ? new ArrayList() : new DataObjectSet();
-
- $firstStep = DataObject::get_one(static::$start_step, "\"SessionID\" = {$this->session->ID}");
- $firstStep->LinkingMode = ($firstStep->ID == $this->getCurrentStep()->ID) ? 'current' : 'link';
- $firstStep->setForm($this);
- $stepsFound->push($firstStep);
-
- // mark the further steps as non-completed if the first step is the current
- if ($firstStep->ID == $this->getCurrentStep()->ID) {
- $this->currentStepHasBeenFound = true;
- } else {
- $firstStep->addExtraClass('completed');
- }
-
- $this->getAllStepsRecursive($firstStep, $stepsFound);
-
- return $stepsFound;
- }
-
- /**
- * Recursively run through steps using the getNextStep() method on each step
- * to determine what the next step is, gathering each step along the way.
- * We stop on the last step, and return the results.
- * If a step in the chain was already saved to the database in the current
- * session, its used - otherwise a singleton of this step is used.
- * Caution: Doesn't consider branching for steps which aren't in the database yet.
- *
- * @param $step Subclass of MultiFormStep to find the next step of
- * @param $stepsFound $stepsFound DataObjectSet reference, the steps found to call back on
- * @return DataObjectSet of MultiFormStep instances
- */
- protected function getAllStepsRecursive($step, &$stepsFound) {
- // Find the next step to the current step, the final step has no next step
- if(!$step->isFinalStep()) {
- if($step->getNextStep()) {
- // Is this step in the DB? If it is, we use that
- $nextStep = $step->getNextStepFromDatabase();
- if(!$nextStep) {
- // If it's not in the DB, we use a singleton instance of it instead -
- // - this step hasn't been accessed yet
- $nextStep = singleton($step->getNextStep());
- }
-
- // once the current steps has been found we won't add the completed class anymore.
- if ($nextStep->ID == $this->getCurrentStep()->ID) $this->currentStepHasBeenFound = true;
-
- $nextStep->LinkingMode = ($nextStep->ID == $this->getCurrentStep()->ID) ? 'current' : 'link';
-
- // add the completed class
- if (!$this->currentStepHasBeenFound) $nextStep->addExtraClass('completed');
-
- $nextStep->setForm($this);
-
- // Add the array data, and do a callback
- $stepsFound->push($nextStep);
- $this->getAllStepsRecursive($nextStep, $stepsFound);
- }
- // Once we've reached the final step, we just return what we've collected
- } else {
- return $stepsFound;
- }
- }
-
- /**
- * Number of steps already completed (excluding currently started step).
- * The way we determine a step is complete is to check if it has the Data
- * field filled out with a serialized value, then we know that the user has
- * clicked next on the given step, to proceed.
- *
- * @TODO Not sure if it's entirely appropriate to check if Data is set as a
- * way to determine a step is "completed".
- *
- * @return int
- */
- public function getCompletedStepCount() {
- $steps = DataObject::get('MultiFormStep', "\"SessionID\" = {$this->session->ID} && \"Data\" IS NOT NULL");
-
- return $steps ? $steps->Count() : 0;
- }
-
- /**
- * Total number of steps in the shortest path (only counting straight path without any branching)
- * The way we determine this is to check if each step has a next_step string variable set. If it's
- * anything else (like an array, for defining multiple branches) then it gets counted as a single step.
- *
- * @return int
- */
- public function getTotalStepCount() {
- return $this->getAllStepsLinear() ? $this->getAllStepsLinear()->Count() : 0;
- }
-
- /**
- * Percentage of steps completed (excluding currently started step)
- *
- * @return float
- */
- public function getCompletedPercent() {
- return (float) $this->getCompletedStepCount() * 100 / $this->getTotalStepCount();
- }
+abstract class MultiForm extends Form
+{
+
+ /**
+ * A session object stored in the database, to identify and store
+ * data for this MultiForm instance.
+ *
+ * @var MultiFormSession
+ */
+ protected $session;
+
+ /**
+ * The current encrypted MultiFormSession identification.
+ *
+ * @var string
+ */
+ protected $currentSessionHash;
+
+ /**
+ * Defines which subclass of {@link MultiFormStep} should be the first
+ * step in the multi-step process.
+ *
+ * @var string Classname of a {@link MultiFormStep} subclass
+ */
+ public static $start_step;
+
+ /**
+ * Set the casting for these fields.
+ *
+ * @var array
+ */
+ private static $casting = array(
+ 'CompletedStepCount' => 'Int',
+ 'TotalStepCount' => 'Int',
+ 'CompletedPercent' => 'Float'
+ );
+
+ /**
+ * @var string
+ */
+ private static $get_var = 'MultiFormSessionID';
+
+ /**
+ * These fields are ignored when saving the raw form data into session.
+ * This ensures only field data is saved, and nothing else that's useless
+ * or potentially dangerous.
+ *
+ * @var array
+ */
+ public static $ignored_fields = array(
+ 'url',
+ 'executeForm',
+ 'SecurityID'
+ );
+
+ /**
+ * Any of the actions defined in this variable are exempt from
+ * being validated.
+ *
+ * This is most useful for the "Back" (action_prev) action, as
+ * you typically don't validate the form when the user is going
+ * back a step.
+ *
+ * @var array
+ */
+ public static $actions_exempt_from_validation = array(
+ 'action_prev'
+ );
+
+ /**
+ * @var string
+ */
+ protected $displayLink;
+
+ /**
+ * Flag which is being used in getAllStepsRecursive() to allow adding the completed flag on the steps
+ *
+ * @var boolean
+ */
+ protected $currentStepHasBeenFound = false;
+
+ /**
+ * Start the MultiForm instance.
+ *
+ * @param Controller instance $controller Controller this form is created on
+ * @param string $name The form name, typically the same as the method name
+ */
+ public function __construct($controller, $name)
+ {
+ // First set the controller and name manually so they are available for
+ // field construction.
+ $this->controller = $controller;
+ $this->name = $name;
+
+ // Set up the session for this MultiForm instance
+ $this->setSession();
+
+ // Get the current step available (Note: either returns an existing
+ // step or creates a new one if none available)
+ $currentStep = $this->getCurrentStep();
+
+ // Set the step returned above as the current step
+ $this->setCurrentStep($currentStep);
+
+ // Set the form of the step to this form instance
+ $currentStep->setForm($this);
+
+ // Set up the fields for the current step
+ $fields = $currentStep->getFields();
+
+ // Set up the actions for the current step
+ $actions = $this->actionsFor($currentStep);
+
+ // Set up validation (if necessary)
+ $validator = null;
+ $applyValidation = true;
+
+ $actionNames = static::$actions_exempt_from_validation;
+
+ if ($actionNames) {
+ foreach ($actionNames as $exemptAction) {
+ if (!empty($_REQUEST[$exemptAction])) {
+ $applyValidation = false;
+ break;
+ }
+ }
+ }
+
+ // Apply validation if the current step requires validation (is not exempt)
+ if ($applyValidation) {
+ if ($currentStep->getValidator()) {
+ $validator = $currentStep->getValidator();
+ }
+ }
+
+ // Give the fields, actions, and validation for the current step back to the parent Form class
+ parent::__construct($controller, $name, $fields, $actions, $validator);
+
+ $getVar = $this->config()->get_var;
+
+ // Set a hidden field in our form with an encrypted hash to identify this session.
+ $this->fields->push(new HiddenField($getVar, false, $this->session->Hash));
+
+ // If there is saved data for the current step, we load it into the form it here
+ //(CAUTION: loadData() MUST unserialize first!)
+ if ($data = $currentStep->loadData()) {
+ $this->loadDataFrom($data);
+ }
+
+ // Disable security token - we tie a form to a session ID instead
+ $this->disableSecurityToken();
+
+ self::$ignored_fields[] = $getVar;
+ }
+
+ /**
+ * Accessor method to $this->controller.
+ *
+ * @return Controller this MultiForm was instanciated on.
+ */
+ public function getController()
+ {
+ return $this->controller;
+ }
+
+ /**
+ * Returns the get_var to the template engine
+ *
+ * @return string
+ */
+ public function getGetVar()
+ {
+ return $this->config()->get_var;
+ }
+
+ /**
+ * Get the current step.
+ *
+ * If StepID has been set in the URL, we attempt to get that record
+ * by the ID. Otherwise, we check if there's a current step ID in
+ * our session record. Failing those cases, we assume that the form has
+ * just been started, and so we create the first step and return it.
+ *
+ * @return MultiFormStep subclass
+ */
+ public function getCurrentStep()
+ {
+ $startStepClass = static::$start_step;
+
+ // Check if there was a start step defined on the subclass of MultiForm
+ if (!isset($startStepClass)) {
+ user_error(
+ 'MultiForm::init(): Please define a $start_step on ' . $this->class,
+ E_USER_ERROR
+ );
+ }
+
+ // Determine whether we use the current step, or create one if it doesn't exist
+ $currentStep = null;
+ $StepID = $this->controller->request->getVar('StepID');
+ if (isset($StepID)) {
+ $currentStep = DataObject::get_one(
+ 'MultiFormStep',
+ array(
+ 'SessionID' => $this->session->ID,
+ 'ID' => $StepID
+ )
+ );
+ } elseif ($this->session->CurrentStepID) {
+ $currentStep = $this->session->CurrentStep();
+ }
+
+ // Always fall back to creating a new step (in case the session or request data is invalid)
+ if (!$currentStep || !$currentStep->ID) {
+ $currentStep = Object::create($startStepClass);
+ $currentStep->SessionID = $this->session->ID;
+ $currentStep->write();
+ $this->session->CurrentStepID = $currentStep->ID;
+ $this->session->write();
+ $this->session->flushCache();
+ }
+
+ if ($currentStep) {
+ $currentStep->setForm($this);
+ }
+
+ return $currentStep;
+ }
+
+ /**
+ * Set the step passed in as the current step.
+ *
+ * @param MultiFormStep $step A subclass of MultiFormStep
+ * @return boolean The return value of write()
+ */
+ protected function setCurrentStep($step)
+ {
+ $this->session->CurrentStepID = $step->ID;
+ $step->setForm($this);
+
+ return $this->session->write();
+ }
+
+ /**
+ * Accessor method to $this->session.
+ *
+ * @return MultiFormSession
+ */
+ public function getSession()
+ {
+ return $this->session;
+ }
+
+ /**
+ * Set up the session.
+ *
+ * If MultiFormSessionID isn't set, we assume that this is a new
+ * multiform that requires a new session record to be created.
+ *
+ * @TODO Fix the fact you can continually refresh and create new records
+ * if MultiFormSessionID isn't set.
+ *
+ * @TODO Not sure if we should bake the session stuff directly into MultiForm.
+ * Perhaps it would be best dealt with on a separate class?
+ */
+ protected function setSession()
+ {
+ $this->session = $this->getCurrentSession();
+
+ // If there was no session found, create a new one instead
+ if (!$this->session) {
+ $this->session = new MultiFormSession();
+ }
+
+ // Create encrypted identification to the session instance if it doesn't exist
+ if (!$this->session->Hash) {
+ $this->session->Hash = sha1($this->session->ID . '-' . microtime());
+ $this->session->write();
+ }
+ }
+
+ /**
+ * Set the currently used encrypted hash to identify
+ * the MultiFormSession.
+ *
+ * @param string $hash Encrypted identification to session
+ */
+ public function setCurrentSessionHash($hash)
+ {
+ $this->currentSessionHash = $hash;
+ $this->setSession();
+ }
+
+ /**
+ * Return the currently used {@link MultiFormSession}
+ * @return MultiFormSession|boolean FALSE
+ */
+ public function getCurrentSession()
+ {
+ if (!$this->currentSessionHash) {
+ $this->currentSessionHash = $this->controller->request->getVar($this->config()->get_var);
+
+ if (!$this->currentSessionHash) {
+ return false;
+ }
+ }
+
+ $this->session = MultiFormSession::get()->filter(array(
+ "Hash" => $this->currentSessionHash,
+ "IsComplete" => 0
+ ))->first();
+
+ return $this->session;
+ }
+
+ /**
+ * Get all steps saved in the database for the currently active session,
+ * in the order they were saved, oldest to newest (automatically ordered by ID).
+ * If you want a full chain of steps regardless if they've already been saved
+ * to the database, use {@link getAllStepsLinear()}.
+ *
+ * @param string $filter SQL WHERE statement
+ * @return DataObjectSet|boolean A set of MultiFormStep subclasses
+ */
+ public function getSavedSteps($filter = null)
+ {
+ $filter .= ($filter) ? ' AND ' : '';
+ $filter .= sprintf("\"SessionID\" = '%s'", $this->session->ID);
+ return DataObject::get('MultiFormStep', $filter);
+ }
+
+ /**
+ * Get a step which was previously saved to the database in the current session.
+ * Caution: This might cause unexpected behaviour if you have multiple steps
+ * in your chain with the same classname.
+ *
+ * @param string $className Classname of a {@link MultiFormStep} subclass
+ * @return MultiFormStep
+ */
+ public function getSavedStepByClass($className)
+ {
+ return DataObject::get_one(
+ 'MultiFormStep',
+ sprintf(
+ "\"SessionID\" = '%s' AND \"ClassName\" = '%s'",
+ $this->session->ID,
+ Convert::raw2sql($className)
+ )
+ );
+ }
+
+ /**
+ * Build a FieldList of the FormAction fields for the given step.
+ *
+ * If the current step is the final step, we push in a submit button, which
+ * calls the action {@link finish()} to finalise the submission. Otherwise,
+ * we push in a next button which calls the action {@link next()} to determine
+ * where to go next in our step process, and save any form data collected.
+ *
+ * If there's a previous step (a step that has the current step as it's next
+ * step class), then we allow a previous button, which calls the previous action
+ * to determine which step to go back to.
+ *
+ * If there are any extra actions defined in MultiFormStep->getExtraActions()
+ * then that set of actions is appended to the end of the actions FieldSet we
+ * have created in this method.
+ *
+ * @param $currentStep Subclass of MultiFormStep
+ * @return FieldList of FormAction objects
+ */
+ public function actionsFor($step)
+ {
+ // Create default multi step actions (next, prev), and merge with extra actions, if any
+ $actions = (class_exists('FieldList')) ? new FieldList() : new FieldSet();
+
+ // If the form is at final step, create a submit button to perform final actions
+ // The last step doesn't have a next button, so add that action to any step that isn't the final one
+ if ($step->isFinalStep()) {
+ $actions->push(new FormAction('finish', $step->getSubmitText()));
+ } else {
+ $actions->push(new FormAction('next', $step->getNextText()));
+ }
+
+ // If there is a previous step defined, add the back button
+ if ($step->getPreviousStep() && $step->canGoBack()) {
+ // If there is a next step, insert the action before the next action
+ if ($step->getNextStep()) {
+ $actions->insertBefore($prev = new FormAction('prev', $step->getPrevText()), 'action_next');
+ // Assume that this is the last step, insert the action before the finish action
+ } else {
+ $actions->insertBefore($prev = new FormAction('prev', $step->getPrevText()), 'action_finish');
+ }
+ //remove browser validation from prev action
+ $prev->setAttribute("formnovalidate", "formnovalidate");
+ }
+
+ // Merge any extra action fields defined on the step
+ $actions->merge($step->getExtraActions());
+
+ return $actions;
+ }
+
+ /**
+ * Return a rendered version of this form, with a specific template.
+ * Looks through the step ancestory templates (MultiFormStep, current step
+ * subclass template) to see if one is available to render the form with. If
+ * any of those don't exist, look for a default Form template to render
+ * with instead.
+ *
+ * @return SSViewer object to render the template with
+ */
+ public function forTemplate()
+ {
+ $return = $this->renderWith(array(
+ $this->getCurrentStep()->class,
+ 'MultiFormStep',
+ $this->class,
+ 'MultiForm',
+ 'Form'
+ ));
+
+ $this->clearMessage();
+
+ return $return;
+ }
+
+ /**
+ * This method saves the data on the final step, after submitting.
+ * It should always be overloaded with parent::finish($data, $form)
+ * so you can create your own functionality which handles saving
+ * of all the data collected through each step of the form.
+ *
+ * @param array $data The request data returned from the form
+ * @param object $form The form that the action was called on
+ */
+ public function finish($data, $form)
+ {
+ // Save the form data for the current step
+ $this->save($data);
+
+ if (!$this->getCurrentStep()->isFinalStep()) {
+ $this->controller->redirectBack();
+ return false;
+ }
+
+ if (!$this->getCurrentStep()->validateStep($data, $form)) {
+ Session::set("FormInfo.{$form->FormName()}.data", $form->getData());
+ $this->controller->redirectBack();
+ return false;
+ }
+ }
+
+ /**
+ * Determine what to do when the next action is called.
+ *
+ * Saves the current step session data to the database, creates the
+ * new step based on getNextStep() of the current step (or fetches
+ * an existing one), resets the current step to the next step,
+ * then redirects to the newly set step.
+ *
+ * @param array $data The request data returned from the form
+ * @param object $form The form that the action was called on
+ */
+ public function next($data, $form)
+ {
+ // Save the form data for the current step
+ $this->save($form->getData());
+
+ // Get the next step class
+ $nextStepClass = $this->getCurrentStep()->getNextStep();
+
+ if (!$nextStepClass) {
+ $this->controller->redirectBack();
+ return false;
+ }
+
+ // Perform custom step validation (use MultiFormStep->getValidator() for
+ // built-in functionality). The data needs to be manually saved on error
+ // so the form is re-populated.
+ if (!$this->getCurrentStep()->validateStep($data, $form)) {
+ Session::set("FormInfo.{$form->FormName()}.data", $form->getData());
+ $this->controller->redirectBack();
+ return false;
+ }
+
+ // validation succeeded so we reset it to remove errors and messages
+ $this->resetValidation();
+
+ // Determine whether we can use a step already in the DB, or have to create a new one
+ if (!$nextStep = DataObject::get_one($nextStepClass, "\"SessionID\" = {$this->session->ID}")) {
+ $nextStep = Object::create($nextStepClass);
+ $nextStep->SessionID = $this->session->ID;
+ $nextStep->write();
+ }
+
+ // Set the next step found as the current step
+ $this->setCurrentStep($nextStep);
+
+ // Redirect to the next step
+ $this->controller->redirect($nextStep->Link());
+ }
+
+ /**
+ * Determine what to do when the previous action is called.
+ *
+ * Retrieves the previous step class, finds the record for that
+ * class in the DB, and sets the current step to that step found.
+ * Finally, it redirects to that step.
+ *
+ * @param array $data The request data returned from the form
+ * @param object $form The form that the action was called on
+ */
+ public function prev($data, $form)
+ {
+ // Save the form data for the current step
+ $this->save($form->getData());
+
+ // Get the previous step class
+ $prevStepClass = $this->getCurrentStep()->getPreviousStep();
+
+ if (!$prevStepClass && !$this->getCurrentStep()->canGoBack()) {
+ $this->controller->redirectBack();
+ return false;
+ }
+
+ // Get the previous step of the class instance returned from $currentStep->getPreviousStep()
+ $prevStep = DataObject::get_one($prevStepClass, "\"SessionID\" = {$this->session->ID}");
+
+ // Set the current step as the previous step
+ $this->setCurrentStep($prevStep);
+
+ // Redirect to the previous step
+ $this->controller->redirect($prevStep->Link());
+ }
+
+ /**
+ * Save the raw data given back from the form into session.
+ *
+ * Take the submitted form data for the current step, removing
+ * any key => value pairs that shouldn't be saved, then saves
+ * the data into the session.
+ *
+ * @param array $data An array of data to save
+ */
+ protected function save($data)
+ {
+ $currentStep = $this->getCurrentStep();
+ if (is_array($data)) {
+ foreach ($data as $field => $value) {
+ if (in_array($field, static::$ignored_fields)) {
+ unset($data[$field]);
+ }
+ }
+ $currentStep->saveData($data);
+ }
+ return;
+ }
+
+ // ############ Misc ############
+
+ /**
+ * Add the MultiFormSessionID variable to the URL on form submission.
+ * This is a means to persist the session, by adding it's identification
+ * to the URL, which ties it back to this MultiForm instance.
+ *
+ * @return string
+ */
+ public function FormAction()
+ {
+ $action = parent::FormAction();
+ $action .= (strpos($action, '?')) ? '&' : '?';
+ $action .= "{$this->config()->get_var}={$this->session->Hash}";
+
+ return $action;
+ }
+
+ /**
+ * Returns the link to the page where the form is displayed. The user is
+ * redirected to this link with a session param after each step is
+ * submitted.
+ *
+ * @return string
+ */
+ public function getDisplayLink()
+ {
+ return $this->displayLink ? $this->displayLink : Controller::curr()->Link();
+ }
+
+ /**
+ * Set the link to the page on which the form is displayed.
+ *
+ * The link defaults to the controllers current link. However if the form
+ * is displayed inside an action the display link must be explicitly set.
+ *
+ * @param string $link
+ */
+ public function setDisplayLink($link)
+ {
+ $this->displayLink = $link;
+ }
+
+ /**
+ * Determine the steps to show in a linear fashion, starting from the
+ * first step. We run {@link getAllStepsRecursive} passing the steps found
+ * by reference to get a listing of the steps.
+ *
+ * @return DataObjectSet of MultiFormStep instances
+ */
+ public function getAllStepsLinear()
+ {
+ $stepsFound = (class_exists('ArrayList')) ? new ArrayList() : new DataObjectSet();
+
+ $firstStep = DataObject::get_one(static::$start_step, "\"SessionID\" = {$this->session->ID}");
+ $firstStep->LinkingMode = ($firstStep->ID == $this->getCurrentStep()->ID) ? 'current' : 'link';
+ $firstStep->setForm($this);
+ $stepsFound->push($firstStep);
+
+ // mark the further steps as non-completed if the first step is the current
+ if ($firstStep->ID == $this->getCurrentStep()->ID) {
+ $this->currentStepHasBeenFound = true;
+ } else {
+ $firstStep->addExtraClass('completed');
+ }
+
+ $this->getAllStepsRecursive($firstStep, $stepsFound);
+
+ return $stepsFound;
+ }
+
+ /**
+ * Recursively run through steps using the getNextStep() method on each step
+ * to determine what the next step is, gathering each step along the way.
+ * We stop on the last step, and return the results.
+ * If a step in the chain was already saved to the database in the current
+ * session, its used - otherwise a singleton of this step is used.
+ * Caution: Doesn't consider branching for steps which aren't in the database yet.
+ *
+ * @param $step Subclass of MultiFormStep to find the next step of
+ * @param $stepsFound $stepsFound DataObjectSet reference, the steps found to call back on
+ * @return DataObjectSet of MultiFormStep instances
+ */
+ protected function getAllStepsRecursive($step, &$stepsFound)
+ {
+ // Find the next step to the current step, the final step has no next step
+ if (!$step->isFinalStep()) {
+ if ($step->getNextStep()) {
+ // Is this step in the DB? If it is, we use that
+ $nextStep = $step->getNextStepFromDatabase();
+ if (!$nextStep) {
+ // If it's not in the DB, we use a singleton instance of it instead -
+ // - this step hasn't been accessed yet
+ $nextStep = singleton($step->getNextStep());
+ }
+
+ // once the current steps has been found we won't add the completed class anymore.
+ if ($nextStep->ID == $this->getCurrentStep()->ID) {
+ $this->currentStepHasBeenFound = true;
+ }
+
+ $nextStep->LinkingMode = ($nextStep->ID == $this->getCurrentStep()->ID) ? 'current' : 'link';
+
+ // add the completed class
+ if (!$this->currentStepHasBeenFound) {
+ $nextStep->addExtraClass('completed');
+ }
+
+ $nextStep->setForm($this);
+
+ // Add the array data, and do a callback
+ $stepsFound->push($nextStep);
+ $this->getAllStepsRecursive($nextStep, $stepsFound);
+ }
+ // Once we've reached the final step, we just return what we've collected
+ } else {
+ return $stepsFound;
+ }
+ }
+
+ /**
+ * Number of steps already completed (excluding currently started step).
+ * The way we determine a step is complete is to check if it has the Data
+ * field filled out with a serialized value, then we know that the user has
+ * clicked next on the given step, to proceed.
+ *
+ * @TODO Not sure if it's entirely appropriate to check if Data is set as a
+ * way to determine a step is "completed".
+ *
+ * @return int
+ */
+ public function getCompletedStepCount()
+ {
+ $steps = DataObject::get('MultiFormStep', "\"SessionID\" = {$this->session->ID} && \"Data\" IS NOT NULL");
+
+ return $steps ? $steps->Count() : 0;
+ }
+
+ /**
+ * Total number of steps in the shortest path (only counting straight path without any branching)
+ * The way we determine this is to check if each step has a next_step string variable set. If it's
+ * anything else (like an array, for defining multiple branches) then it gets counted as a single step.
+ *
+ * @return int
+ */
+ public function getTotalStepCount()
+ {
+ return $this->getAllStepsLinear() ? $this->getAllStepsLinear()->Count() : 0;
+ }
+
+ /**
+ * Percentage of steps completed (excluding currently started step)
+ *
+ * @return float
+ */
+ public function getCompletedPercent()
+ {
+ return (float) $this->getCompletedStepCount() * 100 / $this->getTotalStepCount();
+ }
}
diff --git a/src/model/MultiFormSession.php b/src/model/MultiFormSession.php
index 3858848..dbd3cf7 100644
--- a/src/model/MultiFormSession.php
+++ b/src/model/MultiFormSession.php
@@ -10,59 +10,66 @@
*
* @package multiform
*/
-class MultiFormSession extends DataObject {
+class MultiFormSession extends DataObject
+{
- private static $db = array(
- 'Hash' => 'Varchar(40)', // cryptographic hash identification to this session
- 'IsComplete' => 'Boolean' // flag to determine if this session is marked completed
- );
+ private static $db = array(
+ 'Hash' => 'Varchar(40)', // cryptographic hash identification to this session
+ 'IsComplete' => 'Boolean' // flag to determine if this session is marked completed
+ );
- private static $has_one = array(
- 'Submitter' => 'Member',
- 'CurrentStep' => 'MultiFormStep'
- );
+ private static $has_one = array(
+ 'Submitter' => 'Member',
+ 'CurrentStep' => 'MultiFormStep'
+ );
- private static $has_many = array(
- 'FormSteps' => 'MultiFormStep'
- );
+ private static $has_many = array(
+ 'FormSteps' => 'MultiFormStep'
+ );
- /**
- * Mark this session as completed.
- *
- * This sets the flag "IsComplete" to true,
- * and writes the session back.
- */
- public function markCompleted() {
- $this->IsComplete = 1;
- $this->write();
- }
+ /**
+ * Mark this session as completed.
+ *
+ * This sets the flag "IsComplete" to true,
+ * and writes the session back.
+ */
+ public function markCompleted()
+ {
+ $this->IsComplete = 1;
+ $this->write();
+ }
- /**
- * These actions are performed when write() is called on this object.
- */
- public function onBeforeWrite() {
- // save submitter if a Member is logged in
- $currentMember = Member::currentUser();
- if(!$this->SubmitterID && $currentMember) $this->SubmitterID = $currentMember->ID;
+ /**
+ * These actions are performed when write() is called on this object.
+ */
+ public function onBeforeWrite()
+ {
+ // save submitter if a Member is logged in
+ $currentMember = Member::currentUser();
+ if (!$this->SubmitterID && $currentMember) {
+ $this->SubmitterID = $currentMember->ID;
+ }
- parent::onBeforeWrite();
- }
+ parent::onBeforeWrite();
+ }
- /**
- * These actions are performed when delete() is called on this object.
- */
- public function onBeforeDelete() {
- // delete dependent form steps and relation
- $steps = $this->FormSteps();
- if($steps) foreach($steps as $step) {
- if($step && $step->exists()) {
- $steps->remove($step);
- $step->delete();
- $step->destroy();
- }
- }
-
- parent::onBeforeDelete();
- }
+ /**
+ * These actions are performed when delete() is called on this object.
+ */
+ public function onBeforeDelete()
+ {
+ // delete dependent form steps and relation
+ $steps = $this->FormSteps();
+ if ($steps) {
+ foreach ($steps as $step) {
+ if ($step && $step->exists()) {
+ $steps->remove($step);
+ $step->delete();
+ $step->destroy();
+ }
+ }
+ }
+ parent::onBeforeDelete();
+ }
}
diff --git a/src/model/MultiFormStep.php b/src/model/MultiFormStep.php
index 49ebe6d..f08adf7 100644
--- a/src/model/MultiFormStep.php
+++ b/src/model/MultiFormStep.php
@@ -9,457 +9,489 @@
*
* @package multiform
*/
-class MultiFormStep extends DataObject {
+class MultiFormStep extends DataObject
+{
- private static $db = array(
- 'Data' => 'Text' // stores serialized maps with all session information
- );
+ private static $db = array(
+ 'Data' => 'Text' // stores serialized maps with all session information
+ );
- private static $has_one = array(
- 'Session' => 'MultiFormSession'
- );
+ private static $has_one = array(
+ 'Session' => 'MultiFormSession'
+ );
- /**
- * Centerpiece of the flow control for the form.
- *
- * If set to a string, you 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
- */
- public static $next_steps;
-
- /**
- * Each {@link MultiForm} subclass needs at least
- * one step which is marked as the "final" one
- * and triggers the {@link MultiForm->finish()}
- * method that wraps up the whole submission.
- *
- * @var boolean
- */
- public static $is_final_step = false;
-
- /**
- * This variable determines whether a user can use
- * the "back" action from this step.
- *
- * @TODO This does not check if the arbitrarily chosen step
- * using the step indicator is actually a previous step, so
- * unless you remove the link from the indicator template, or
- * type in StepID=23 to the address bar you can still go back
- * using the step indicator.
- *
- * @var boolean
- */
- protected static $can_go_back = true;
-
- /**
- * Title of this step.
- *
- * Used for the step indicator templates.
- *
- * @var string
- */
- protected $title;
-
- /**
- * Form class that this step is directly related to.
- *
- * @var MultiForm subclass
- */
- protected $form;
-
- /**
- * List of additional CSS classes for this step
- *
- * @var array $extraClasses
- */
- protected $extraClasses = array();
-
- /**
- * Temporary cache to increase the performance for repeated look ups.
- *
- * @var array $cache
- */
- protected $step_data_cache = array();
-
- /**
- * Form fields to be rendered with this step.
- * (Form object is created in {@link MultiForm}.
- *
- * This function needs to be implemented on your
- * subclasses of MultiFormStep.
- *
- * @return FieldList
- */
- public function getFields() {
- user_error('Please implement getFields on your MultiFormStep subclass', E_USER_ERROR);
- }
-
- /**
- * Additional form actions to be added to this step.
- * (Form object is created in {@link MultiForm}.
- *
- * Note: This is optional, and is to be implemented
- * on your subclasses of MultiFormStep.
- *
- * @return FieldList
- */
- public function getExtraActions() {
- return (class_exists('FieldList')) ? new FieldList() : new FieldSet();
- }
-
- /**
- * Get a validator specific to this form.
- * The form is automatically validated in {@link Form->httpSubmission()}.
- *
- * @return Validator
- */
- public function getValidator() {
- return false;
- }
-
- /**
- * Accessor method for $this->title
- *
- * @return string Title of this step
- */
- public function getTitle() {
- return $this->title ? $this->title : $this->class;
- }
-
- /**
- * 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() {
- $form = $this->form;
- return Controller::join_links($form->getDisplayLink(), "?{$form->config()->get_var}={$this->Session()->Hash}");
- }
-
- /**
- * Unserialize stored session data and return it.
- * 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, leaving
- * others that are not required.
- *
- * @return array
- */
- public function loadData() {
- return ($this->Data && is_string($this->Data)) ? unserialize($this->Data) : array();
- }
-
- /**
- * Save the data for this step into session, serializing it first.
- *
- * To selectively save fields, instead of it all, this
- * method would need to be overloaded on your step class.
- *
- * @param array $data The processed data from save() on {@link MultiForm}
- */
- public function saveData($data) {
- $this->Data = serialize($data);
- $this->write();
- }
-
- /**
- * Save the data on this step into an object,
- * similiar to {@link Form->saveInto()} - by building
- * a stub form from {@link getFields()}. This is necessary
- * to trigger each {@link FormField->saveInto()} method
- * individually, rather than assuming that all data
- * serialized through {@link saveData()} can be saved
- * as a simple value outside of the original FormField context.
- *
- * @param DataObject $obj
- */
- public function saveInto($obj) {
- $form = new Form(
- Controller::curr(),
- 'Form',
- $this->getFields(),
- ((class_exists('FieldList')) ? new FieldList() : new FieldSet())
- );
- $form->loadDataFrom($this->loadData());
- $form->saveInto($obj);
- return $obj;
- }
-
- /**
- * Custom validation for a step. In most cases, it should be sufficient
- * to have built-in validation through the {@link Validator} class
- * on the {@link getValidator()} method.
- *
- * Use {@link Form->sessionMessage()} to feed back validation messages
- * to the user. Please don't redirect from this method,
- * this is taken care of in {@link next()}.
- *
- * @param array $data Request data
- * @param Form $form
- * @return boolean Validation success
- */
- public function validateStep($data, $form) {
- return true;
- }
-
- /**
- * Returns the first value of $next_step
- *
- * @return string Classname of a {@link MultiFormStep} subclass
- */
- public function getNextStep() {
- $nextSteps = static::$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.
- *
- * @return MultiFormStep|boolean
- */
- public function getNextStepFromDatabase() {
- if($this->SessionID && is_numeric($this->SessionID)) {
- $nextSteps = static::$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;
- }
- }
- }
-
- /**
- * Accessor method for self::$next_steps
- *
- * @return string|array
- */
- public function getNextSteps() {
- return static::$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) {
- $step->setForm($this->form);
-
- if($step->getNextStep()) {
- if($step->getNextStep() == $this->class) {
- return $step->class;
- }
- }
- }
- }
- }
-
- /**
- * Retrieves the previous step class record from the database.
- *
- * This will only return a record if you've previously been on the step.
- *
- * @return MultiFormStep subclass
- */
- public function getPreviousStepFromDatabase() {
- if($prevStepClass = $this->getPreviousStep()) {
- return DataObject::get_one($prevStepClass, "\"SessionID\" = {$this->SessionID}");
- }
- }
-
- /**
- * Get the text to the use on the button to the previous step.
- * @return string
- */
- public function getPrevText() {
- return _t('MultiForm.BACK', 'Back');
- }
-
- /**
- * Get the text to use on the button to the next step.
- * @return string
- */
- public function getNextText() {
- return _t('MultiForm.NEXT', 'Next');
- }
-
- /**
- * Get the text to use on the button to submit the form.
- * @return string
- */
- public function getSubmitText() {
- return _t('MultiForm.SUBMIT', 'Submit');
- }
-
- /**
- * Sets the form that this step is directly related to.
- *
- * @param MultiForm subclass $form
- */
- public function setForm($form) {
- $this->form = $form;
- }
-
- /**
- * @return Form
- */
- public function getForm() {
- return $this->form;
- }
-
- // ##################### Utility ####################
-
- /**
- * Determines whether the user is able to go back using the "action_back"
- * Determines whether the user is able to go back using the "action_back"
- * Determines whether the user is able to go back using the "action_back"
- * form action, based on the boolean value of $can_go_back.
- *
- * @return boolean
- */
- public function canGoBack() {
- return static::$can_go_back;
- }
-
- /**
- * Determines whether this step is the final step in the multi-step process or not,
- * based on the variable $is_final_step - which must be defined on at least one step.
- *
- * @return boolean
- */
- public function isFinalStep() {
- return static::$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() {
- return ($this->class == $this->Session()->CurrentStep()->class) ? true : false;
- }
-
- /**
- * Add a CSS-class to the step. If needed, multiple classes can be added by delimiting a string with spaces.
- *
- * @param string $class A string containing a classname or several class names delimited by a space.
- * @return MultiFormStep
- */
- public function addExtraClass($class) {
- // split at white space
- $classes = preg_split('/\s+/', $class);
- foreach($classes as $class) {
- // add classes one by one
- $this->extraClasses[$class] = $class;
- }
- return $this;
- }
-
- /**
- * Remove a CSS-class from the step. Multiple classes names can be passed through as a space delimited string.
- *
- * @param string $class
- * @return MultiFormStep
- */
- public function removeExtraClass($class) {
- // split at white space
- $classes = preg_split('/\s+/', $class);
- foreach ($classes as $class) {
- // unset one by one
- unset($this->extraClasses[$class]);
- }
- return $this;
- }
-
- /**
- * @return string
- */
- public function getExtraClasses() {
- return join(' ', array_keys($this->extraClasses));
- }
-
- /**
- * Returns the submitted value, if any, of any steps.
- *
- * @param string $fromStep (classname)
- * @param string $key
+ /**
+ * Centerpiece of the flow control for the form.
*
- * @return mixed
- */
- public function getValueFromOtherStep($fromStep, $key) {
- // load the steps in the cache, if this one doesn't exist
- if (!array_key_exists('steps_' . $fromStep, $this->step_data_cache)) {
- $steps = MultiFormStep::get()->filter('SessionID', $this->form->session->ID);
+ * If set to a string, you 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
+ */
+ public static $next_steps;
- if($steps) {
- foreach($steps as $step) {
- $this->step_data_cache['steps_' . $step->ClassName] = $step->loadData();
+ /**
+ * Each {@link MultiForm} subclass needs at least
+ * one step which is marked as the "final" one
+ * and triggers the {@link MultiForm->finish()}
+ * method that wraps up the whole submission.
+ *
+ * @var boolean
+ */
+ public static $is_final_step = false;
+
+ /**
+ * This variable determines whether a user can use
+ * the "back" action from this step.
+ *
+ * @TODO This does not check if the arbitrarily chosen step
+ * using the step indicator is actually a previous step, so
+ * unless you remove the link from the indicator template, or
+ * type in StepID=23 to the address bar you can still go back
+ * using the step indicator.
+ *
+ * @var boolean
+ */
+ protected static $can_go_back = true;
+
+ /**
+ * Title of this step.
+ *
+ * Used for the step indicator templates.
+ *
+ * @var string
+ */
+ protected $title;
+
+ /**
+ * Form class that this step is directly related to.
+ *
+ * @var MultiForm subclass
+ */
+ protected $form;
+
+ /**
+ * List of additional CSS classes for this step
+ *
+ * @var array $extraClasses
+ */
+ protected $extraClasses = array();
+
+ /**
+ * Temporary cache to increase the performance for repeated look ups.
+ *
+ * @var array $cache
+ */
+ protected $step_data_cache = array();
+
+ /**
+ * Form fields to be rendered with this step.
+ * (Form object is created in {@link MultiForm}.
+ *
+ * This function needs to be implemented on your
+ * subclasses of MultiFormStep.
+ *
+ * @return FieldList
+ */
+ public function getFields()
+ {
+ user_error('Please implement getFields on your MultiFormStep subclass', E_USER_ERROR);
+ }
+
+ /**
+ * Additional form actions to be added to this step.
+ * (Form object is created in {@link MultiForm}.
+ *
+ * Note: This is optional, and is to be implemented
+ * on your subclasses of MultiFormStep.
+ *
+ * @return FieldList
+ */
+ public function getExtraActions()
+ {
+ return (class_exists('FieldList')) ? new FieldList() : new FieldSet();
+ }
+
+ /**
+ * Get a validator specific to this form.
+ * The form is automatically validated in {@link Form->httpSubmission()}.
+ *
+ * @return Validator
+ */
+ public function getValidator()
+ {
+ return false;
+ }
+
+ /**
+ * Accessor method for $this->title
+ *
+ * @return string Title of this step
+ */
+ public function getTitle()
+ {
+ return $this->title ? $this->title : $this->class;
+ }
+
+ /**
+ * 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()
+ {
+ $form = $this->form;
+ return Controller::join_links($form->getDisplayLink(), "?{$form->config()->get_var}={$this->Session()->Hash}");
+ }
+
+ /**
+ * Unserialize stored session data and return it.
+ * 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, leaving
+ * others that are not required.
+ *
+ * @return array
+ */
+ public function loadData()
+ {
+ return ($this->Data && is_string($this->Data)) ? unserialize($this->Data) : array();
+ }
+
+ /**
+ * Save the data for this step into session, serializing it first.
+ *
+ * To selectively save fields, instead of it all, this
+ * method would need to be overloaded on your step class.
+ *
+ * @param array $data The processed data from save() on {@link MultiForm}
+ */
+ public function saveData($data)
+ {
+ $this->Data = serialize($data);
+ $this->write();
+ }
+
+ /**
+ * Save the data on this step into an object,
+ * similiar to {@link Form->saveInto()} - by building
+ * a stub form from {@link getFields()}. This is necessary
+ * to trigger each {@link FormField->saveInto()} method
+ * individually, rather than assuming that all data
+ * serialized through {@link saveData()} can be saved
+ * as a simple value outside of the original FormField context.
+ *
+ * @param DataObject $obj
+ */
+ public function saveInto($obj)
+ {
+ $form = new Form(
+ Controller::curr(),
+ 'Form',
+ $this->getFields(),
+ ((class_exists('FieldList')) ? new FieldList() : new FieldSet())
+ );
+ $form->loadDataFrom($this->loadData());
+ $form->saveInto($obj);
+ return $obj;
+ }
+
+ /**
+ * Custom validation for a step. In most cases, it should be sufficient
+ * to have built-in validation through the {@link Validator} class
+ * on the {@link getValidator()} method.
+ *
+ * Use {@link Form->sessionMessage()} to feed back validation messages
+ * to the user. Please don't redirect from this method,
+ * this is taken care of in {@link next()}.
+ *
+ * @param array $data Request data
+ * @param Form $form
+ * @return boolean Validation success
+ */
+ public function validateStep($data, $form)
+ {
+ return true;
+ }
+
+ /**
+ * Returns the first value of $next_step
+ *
+ * @return string Classname of a {@link MultiFormStep} subclass
+ */
+ public function getNextStep()
+ {
+ $nextSteps = static::$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.
+ *
+ * @return MultiFormStep|boolean
+ */
+ public function getNextStepFromDatabase()
+ {
+ if ($this->SessionID && is_numeric($this->SessionID)) {
+ $nextSteps = static::$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;
+ }
+ }
+ }
+
+ /**
+ * Accessor method for self::$next_steps
+ *
+ * @return string|array
+ */
+ public function getNextSteps()
+ {
+ return static::$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) {
+ $step->setForm($this->form);
+
+ if ($step->getNextStep()) {
+ if ($step->getNextStep() == $this->class) {
+ return $step->class;
+ }
}
}
- }
+ }
+ }
- // check both as PHP isn't recursive
- if(isset($this->step_data_cache['steps_' . $fromStep])) {
- if(isset($this->step_data_cache['steps_' . $fromStep][$key])) {
+ /**
+ * Retrieves the previous step class record from the database.
+ *
+ * This will only return a record if you've previously been on the step.
+ *
+ * @return MultiFormStep subclass
+ */
+ public function getPreviousStepFromDatabase()
+ {
+ if ($prevStepClass = $this->getPreviousStep()) {
+ return DataObject::get_one($prevStepClass, "\"SessionID\" = {$this->SessionID}");
+ }
+ }
+
+ /**
+ * Get the text to the use on the button to the previous step.
+ * @return string
+ */
+ public function getPrevText()
+ {
+ return _t('MultiForm.BACK', 'Back');
+ }
+
+ /**
+ * Get the text to use on the button to the next step.
+ * @return string
+ */
+ public function getNextText()
+ {
+ return _t('MultiForm.NEXT', 'Next');
+ }
+
+ /**
+ * Get the text to use on the button to submit the form.
+ * @return string
+ */
+ public function getSubmitText()
+ {
+ return _t('MultiForm.SUBMIT', 'Submit');
+ }
+
+ /**
+ * Sets the form that this step is directly related to.
+ *
+ * @param MultiForm subclass $form
+ */
+ public function setForm($form)
+ {
+ $this->form = $form;
+ }
+
+ /**
+ * @return Form
+ */
+ public function getForm()
+ {
+ return $this->form;
+ }
+
+ // ##################### Utility ####################
+
+ /**
+ * Determines whether the user is able to go back using the "action_back"
+ * Determines whether the user is able to go back using the "action_back"
+ * Determines whether the user is able to go back using the "action_back"
+ * form action, based on the boolean value of $can_go_back.
+ *
+ * @return boolean
+ */
+ public function canGoBack()
+ {
+ return static::$can_go_back;
+ }
+
+ /**
+ * Determines whether this step is the final step in the multi-step process or not,
+ * based on the variable $is_final_step - which must be defined on at least one step.
+ *
+ * @return boolean
+ */
+ public function isFinalStep()
+ {
+ return static::$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()
+ {
+ return ($this->class == $this->Session()->CurrentStep()->class) ? true : false;
+ }
+
+ /**
+ * Add a CSS-class to the step. If needed, multiple classes can be added by delimiting a string with spaces.
+ *
+ * @param string $class A string containing a classname or several class names delimited by a space.
+ * @return MultiFormStep
+ */
+ public function addExtraClass($class)
+ {
+ // split at white space
+ $classes = preg_split('/\s+/', $class);
+ foreach ($classes as $class) {
+ // add classes one by one
+ $this->extraClasses[$class] = $class;
+ }
+ return $this;
+ }
+
+ /**
+ * Remove a CSS-class from the step. Multiple classes names can be passed through as a space delimited string.
+ *
+ * @param string $class
+ * @return MultiFormStep
+ */
+ public function removeExtraClass($class)
+ {
+ // split at white space
+ $classes = preg_split('/\s+/', $class);
+ foreach ($classes as $class) {
+ // unset one by one
+ unset($this->extraClasses[$class]);
+ }
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getExtraClasses()
+ {
+ return join(' ', array_keys($this->extraClasses));
+ }
+
+ /**
+ * Returns the submitted value, if any, of any steps.
+ *
+ * @param string $fromStep (classname)
+ * @param string $key
+ *
+ * @return mixed
+ */
+ public function getValueFromOtherStep($fromStep, $key)
+ {
+ // load the steps in the cache, if this one doesn't exist
+ if (!array_key_exists('steps_' . $fromStep, $this->step_data_cache)) {
+ $steps = MultiFormStep::get()->filter('SessionID', $this->form->session->ID);
+
+ if ($steps) {
+ foreach ($steps as $step) {
+ $this->step_data_cache['steps_' . $step->ClassName] = $step->loadData();
+ }
+ }
+ }
+
+ // check both as PHP isn't recursive
+ if (isset($this->step_data_cache['steps_' . $fromStep])) {
+ if (isset($this->step_data_cache['steps_' . $fromStep][$key])) {
return $this->step_data_cache['steps_' . $fromStep][$key];
}
}
return null;
- }
+ }
- /**
- * allows to get a value from another step copied over
- *
- * @param FieldList $fields
- * @param string $formStep
- * @param string $fieldName
- * @param string $fieldNameTarget (optional)
- */
- public function copyValueFromOtherStep(FieldList $fields, $formStep, $fieldName, $fieldNameTarget = null) {
- // if a target field isn't defined use the same fieldname
- if (!$fieldNameTarget) $fieldNameTarget = $fieldName;
+ /**
+ * allows to get a value from another step copied over
+ *
+ * @param FieldList $fields
+ * @param string $formStep
+ * @param string $fieldName
+ * @param string $fieldNameTarget (optional)
+ */
+ public function copyValueFromOtherStep(FieldList $fields, $formStep, $fieldName, $fieldNameTarget = null)
+ {
+ // if a target field isn't defined use the same fieldname
+ if (!$fieldNameTarget) {
+ $fieldNameTarget = $fieldName;
+ }
- $fields->fieldByName($fieldNameTarget)->setValue($this->getValueFromOtherStep($formStep, $fieldName));
- }
+ $fields->fieldByName($fieldNameTarget)->setValue($this->getValueFromOtherStep($formStep, $fieldName));
+ }
}
diff --git a/src/tasks/MultiFormPurgeTask.php b/src/tasks/MultiFormPurgeTask.php
index dfe2d87..c761e98 100644
--- a/src/tasks/MultiFormPurgeTask.php
+++ b/src/tasks/MultiFormPurgeTask.php
@@ -12,44 +12,48 @@
*
* @package multiform
*/
-class MultiFormPurgeTask extends BuildTask {
+class MultiFormPurgeTask extends BuildTask
+{
- /**
- * Days after which sessions expire and
- * are automatically deleted.
- *
- * @var int
- */
- public static $session_expiry_days = 7;
+ /**
+ * Days after which sessions expire and
+ * are automatically deleted.
+ *
+ * @var int
+ */
+ public static $session_expiry_days = 7;
- /**
- * Run this cron task.
- *
- * Go through all MultiFormSession records that
- * are older than the days specified in $session_expiry_days
- * and delete them.
- */
- public function run($request) {
- $sessions = $this->getExpiredSessions();
- $delCount = 0;
- if($sessions) foreach($sessions as $session) {
- $session->delete();
- $delCount++;
- }
- echo $delCount . ' session records deleted that were older than ' . self::$session_expiry_days . ' days.';
- }
-
- /**
- * Return all MultiFormSession database records that are older than
- * the days specified in $session_expiry_days
- *
- * @return DataObjectSet
- */
- protected function getExpiredSessions() {
- return DataObject::get(
- 'MultiFormSession',
- "DATEDIFF(NOW(), \"MultiFormSession\".\"Created\") > " . self::$session_expiry_days
- );
- }
+ /**
+ * Run this cron task.
+ *
+ * Go through all MultiFormSession records that
+ * are older than the days specified in $session_expiry_days
+ * and delete them.
+ */
+ public function run($request)
+ {
+ $sessions = $this->getExpiredSessions();
+ $delCount = 0;
+ if ($sessions) {
+ foreach ($sessions as $session) {
+ $session->delete();
+ $delCount++;
+ }
+ }
+ echo $delCount . ' session records deleted that were older than ' . self::$session_expiry_days . ' days.';
+ }
+ /**
+ * Return all MultiFormSession database records that are older than
+ * the days specified in $session_expiry_days
+ *
+ * @return DataObjectSet
+ */
+ protected function getExpiredSessions()
+ {
+ return DataObject::get(
+ 'MultiFormSession',
+ "DATEDIFF(NOW(), \"MultiFormSession\".\"Created\") > " . self::$session_expiry_days
+ );
+ }
}
diff --git a/tests/MultiFormObjectDecoratorTest.php b/tests/MultiFormObjectDecoratorTest.php
index f935f93..15f9b8a 100644
--- a/tests/MultiFormObjectDecoratorTest.php
+++ b/tests/MultiFormObjectDecoratorTest.php
@@ -1,44 +1,45 @@
array('MultiFormObjectDecorator')
- );
+ protected $requiredExtensions = array(
+ 'MultiFormObjectDecorator_DataObject' => array('MultiFormObjectDecorator')
+ );
- protected $extraDataObjects = array(
- 'MultiFormObjectDecorator_DataObject'
- );
+ protected $extraDataObjects = array(
+ 'MultiFormObjectDecorator_DataObject'
+ );
- public function testTemporaryDataFilteredQuery() {
- $records = MultiFormObjectDecorator_DataObject::get()
- ->map('Name')
- ->toArray();
+ public function testTemporaryDataFilteredQuery()
+ {
+ $records = MultiFormObjectDecorator_DataObject::get()
+ ->map('Name')
+ ->toArray();
- $this->assertContains('Test 1', $records);
- $this->assertContains('Test 2', $records);
- $this->assertNotContains('Test 3', $records);
+ $this->assertContains('Test 1', $records);
+ $this->assertContains('Test 2', $records);
+ $this->assertNotContains('Test 3', $records);
+ }
- }
-
- public function testTemporaryDataQuery() {
- $records = MultiFormObjectDecorator_DataObject::get()
- ->filter(array('MultiFormIsTemporary' => 1))
- ->map('Name')
- ->toArray();
-
- $this->assertNotContains('Test 1', $records);
- $this->assertNotContains('Test 2', $records);
- $this->assertContains('Test 3', $records);
- }
+ public function testTemporaryDataQuery()
+ {
+ $records = MultiFormObjectDecorator_DataObject::get()
+ ->filter(array('MultiFormIsTemporary' => 1))
+ ->map('Name')
+ ->toArray();
+ $this->assertNotContains('Test 1', $records);
+ $this->assertNotContains('Test 2', $records);
+ $this->assertContains('Test 3', $records);
+ }
}
-class MultiFormObjectDecorator_DataObject extends DataObject {
-
- private static $db = array(
- 'Name' => 'Varchar'
- );
+class MultiFormObjectDecorator_DataObject extends DataObject
+{
+ private static $db = array(
+ 'Name' => 'Varchar'
+ );
}
diff --git a/tests/MultiFormTest.php b/tests/MultiFormTest.php
index fbadf2e..589a485 100644
--- a/tests/MultiFormTest.php
+++ b/tests/MultiFormTest.php
@@ -17,162 +17,181 @@
* @package multiform
* @subpackage tests
*/
-class MultiFormTest extends FunctionalTest {
+class MultiFormTest extends FunctionalTest
+{
- public static $fixture_file = 'multiform/tests/MultiFormTest.yml';
+ public static $fixture_file = 'multiform/tests/MultiFormTest.yml';
- protected $controller;
+ protected $controller;
- public function setUp() {
- parent::setUp();
+ public function setUp()
+ {
+ parent::setUp();
- $this->controller = new MultiFormTest_Controller();
- $this->form = $this->controller->Form();
- }
+ $this->controller = new MultiFormTest_Controller();
+ $this->form = $this->controller->Form();
+ }
- public function testInitialisingForm() {
- $this->assertTrue(is_numeric($this->form->getCurrentStep()->ID) && ($this->form->getCurrentStep()->ID > 0));
- $this->assertTrue(is_numeric($this->form->getSession()->ID) && ($this->form->getSession()->ID > 0));
- $this->assertEquals('MultiFormTest_StepOne', $this->form->getStartStep());
- }
+ public function testInitialisingForm()
+ {
+ $this->assertTrue(is_numeric($this->form->getCurrentStep()->ID) && ($this->form->getCurrentStep()->ID > 0));
+ $this->assertTrue(is_numeric($this->form->getSession()->ID) && ($this->form->getSession()->ID > 0));
+ $this->assertEquals('MultiFormTest_StepOne', $this->form->getStartStep());
+ }
- public function testSessionGeneration() {
- $this->assertTrue($this->form->session->ID > 0);
- }
+ public function testSessionGeneration()
+ {
+ $this->assertTrue($this->form->session->ID > 0);
+ }
- public function testMemberLogging() {
- // Grab any user to fake being logged in as, and ensure that after a session is written it has
- // that user as the submitter.
- $userId = Member::get_one("Member")->ID;
- $this->session()->inst_set('loggedInAs', $userId);
+ public function testMemberLogging()
+ {
+ // Grab any user to fake being logged in as, and ensure that after a session is written it has
+ // that user as the submitter.
+ $userId = Member::get_one("Member")->ID;
+ $this->session()->inst_set('loggedInAs', $userId);
- $session = $this->form->session;
- $session->write();
+ $session = $this->form->session;
+ $session->write();
- $this->assertEquals($userId, $session->SubmitterID);
- }
+ $this->assertEquals($userId, $session->SubmitterID);
+ }
- public function testSecondStep() {
- $this->assertEquals('MultiFormTest_StepTwo', $this->form->getCurrentStep()->getNextStep());
- }
+ public function testSecondStep()
+ {
+ $this->assertEquals('MultiFormTest_StepTwo', $this->form->getCurrentStep()->getNextStep());
+ }
- public function testParentForm() {
- $currentStep = $this->form->getCurrentStep();
- $this->assertEquals($currentStep->getForm()->class, $this->form->class);
- }
+ public function testParentForm()
+ {
+ $currentStep = $this->form->getCurrentStep();
+ $this->assertEquals($currentStep->getForm()->class, $this->form->class);
+ }
- public function testTotalStepCount() {
- $this->assertEquals(3, $this->form->getAllStepsLinear()->Count());
- }
+ public function testTotalStepCount()
+ {
+ $this->assertEquals(3, $this->form->getAllStepsLinear()->Count());
+ }
- public function testCompletedSession() {
- $this->form->setCurrentSessionHash($this->form->session->Hash);
- $this->assertInstanceOf('MultiFormSession', $this->form->getCurrentSession());
- $this->form->session->markCompleted();
- $this->assertNull($this->form->getCurrentSession());
- }
+ public function testCompletedSession()
+ {
+ $this->form->setCurrentSessionHash($this->form->session->Hash);
+ $this->assertInstanceOf('MultiFormSession', $this->form->getCurrentSession());
+ $this->form->session->markCompleted();
+ $this->assertNull($this->form->getCurrentSession());
+ }
- public function testIncorrectSessionIdentifier() {
- $this->form->setCurrentSessionHash('sdfsdf3432325325sfsdfdf'); // made up!
+ public function testIncorrectSessionIdentifier()
+ {
+ $this->form->setCurrentSessionHash('sdfsdf3432325325sfsdfdf'); // made up!
- // A new session is generated, even though we made up the identifier
- $this->assertInstanceOf('MultiFormSession', $this->form->session);
- }
+ // A new session is generated, even though we made up the identifier
+ $this->assertInstanceOf('MultiFormSession', $this->form->session);
+ }
- function testCustomGetVar() {
- Config::nest();
- Config::inst()->update('MultiForm', 'get_var', 'SuperSessionID');
+ function testCustomGetVar()
+ {
+ Config::nest();
+ Config::inst()->update('MultiForm', 'get_var', 'SuperSessionID');
- $form = $this->controller->Form();
- $this->assertContains('SuperSessionID', $form::$ignored_fields, "GET var wasn't added to ignored fields");
- $this->assertContains('SuperSessionID', $form->FormAction(), "Form action doesn't contain correct session
+ $form = $this->controller->Form();
+ $this->assertContains('SuperSessionID', $form::$ignored_fields, "GET var wasn't added to ignored fields");
+ $this->assertContains('SuperSessionID', $form->FormAction(), "Form action doesn't contain correct session
ID parameter");
- $this->assertContains('SuperSessionID', $form->getCurrentStep()->Link(), "Form step doesn't contain correct
+ $this->assertContains('SuperSessionID', $form->getCurrentStep()->Link(), "Form step doesn't contain correct
session ID parameter");
- Config::unnest();
-}
-
+ Config::unnest();
+ }
}
/**
* @package multiform
* @subpackage tests
*/
-class MultiFormTest_Controller extends Controller implements TestOnly {
+class MultiFormTest_Controller extends Controller implements TestOnly
+{
- public function Link() {
- return 'MultiFormTest_Controller';
- }
+ public function Link()
+ {
+ return 'MultiFormTest_Controller';
+ }
- public function Form($request = null) {
- $form = new MultiFormTest_Form($this, 'Form');
- $form->setHTMLID('MultiFormTest_Form');
- return $form;
- }
+ public function Form($request = null)
+ {
+ $form = new MultiFormTest_Form($this, 'Form');
+ $form->setHTMLID('MultiFormTest_Form');
+ return $form;
+ }
}
/**
* @package multiform
* @subpackage tests
*/
-class MultiFormTest_Form extends MultiForm implements TestOnly {
+class MultiFormTest_Form extends MultiForm implements TestOnly
+{
- public static $start_step = 'MultiFormTest_StepOne';
-
- public function getStartStep() {
- return self::$start_step;
- }
+ public static $start_step = 'MultiFormTest_StepOne';
+ public function getStartStep()
+ {
+ return self::$start_step;
+ }
}
/**
* @package multiform
* @subpackage tests
*/
-class MultiFormTest_StepOne extends MultiFormStep implements TestOnly {
+class MultiFormTest_StepOne extends MultiFormStep implements TestOnly
+{
- public static $next_steps = 'MultiFormTest_StepTwo';
+ public static $next_steps = 'MultiFormTest_StepTwo';
- public function getFields() {
- $class = (class_exists('FieldList')) ? 'FieldList' : 'FieldSet';
- return new $class(
- new TextField('FirstName', 'First name'),
- new TextField('Surname', 'Surname'),
- new EmailField('Email', 'Email address')
- );
- }
+ public function getFields()
+ {
+ $class = (class_exists('FieldList')) ? 'FieldList' : 'FieldSet';
+ return new $class(
+ new TextField('FirstName', 'First name'),
+ new TextField('Surname', 'Surname'),
+ new EmailField('Email', 'Email address')
+ );
+ }
}
-
+
/**
* @package multiform
* @subpackage tests
*/
-class MultiFormTest_StepTwo extends MultiFormStep implements TestOnly {
+class MultiFormTest_StepTwo extends MultiFormStep implements TestOnly
+{
- public static $next_steps = 'MultiFormTest_StepThree';
+ public static $next_steps = 'MultiFormTest_StepThree';
- public function getFields() {
- $class = (class_exists('FieldList')) ? 'FieldList' : 'FieldSet';
- return new $class(
- new TextareaField('Comments', 'Tell us a bit about yourself...')
- );
- }
+ public function getFields()
+ {
+ $class = (class_exists('FieldList')) ? 'FieldList' : 'FieldSet';
+ return new $class(
+ new TextareaField('Comments', 'Tell us a bit about yourself...')
+ );
+ }
}
-
+
/**
* @package multiform
* @subpackage tests
*/
-class MultiFormTest_StepThree extends MultiFormStep implements TestOnly {
+class MultiFormTest_StepThree extends MultiFormStep implements TestOnly
+{
- public static $is_final_step = true;
-
- public function getFields() {
- $class = (class_exists('FieldList')) ? 'FieldList' : 'FieldSet';
- return new $class(
- new TextField('Test', 'Anything else you\'d like to tell us?')
- );
- }
+ public static $is_final_step = true;
+ public function getFields()
+ {
+ $class = (class_exists('FieldList')) ? 'FieldList' : 'FieldSet';
+ return new $class(
+ new TextField('Test', 'Anything else you\'d like to tell us?')
+ );
+ }
}