From b9c4929fd50b47a14cb5b1d93b53b11a72b291fe Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Thu, 7 Sep 2017 08:42:03 +1200 Subject: [PATCH 01/16] FIX renamed code/ to src/ --- {code => src}/extensions/MultiFormObjectDecorator.php | 0 {code => src}/model/MultiForm.php | 0 {code => src}/model/MultiFormSession.php | 0 {code => src}/model/MultiFormStep.php | 0 {code => src}/tasks/MultiFormPurgeTask.php | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename {code => src}/extensions/MultiFormObjectDecorator.php (100%) rename {code => src}/model/MultiForm.php (100%) rename {code => src}/model/MultiFormSession.php (100%) rename {code => src}/model/MultiFormStep.php (100%) rename {code => src}/tasks/MultiFormPurgeTask.php (100%) diff --git a/code/extensions/MultiFormObjectDecorator.php b/src/extensions/MultiFormObjectDecorator.php similarity index 100% rename from code/extensions/MultiFormObjectDecorator.php rename to src/extensions/MultiFormObjectDecorator.php diff --git a/code/model/MultiForm.php b/src/model/MultiForm.php similarity index 100% rename from code/model/MultiForm.php rename to src/model/MultiForm.php diff --git a/code/model/MultiFormSession.php b/src/model/MultiFormSession.php similarity index 100% rename from code/model/MultiFormSession.php rename to src/model/MultiFormSession.php diff --git a/code/model/MultiFormStep.php b/src/model/MultiFormStep.php similarity index 100% rename from code/model/MultiFormStep.php rename to src/model/MultiFormStep.php diff --git a/code/tasks/MultiFormPurgeTask.php b/src/tasks/MultiFormPurgeTask.php similarity index 100% rename from code/tasks/MultiFormPurgeTask.php rename to src/tasks/MultiFormPurgeTask.php From 43cc780627c5a55d78e01cbd58e3946a20a235e0 Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Thu, 7 Sep 2017 08:47:35 +1200 Subject: [PATCH 02/16] FIX ran linter and removed php tags from README --- README.md | 477 +++---- _config.php | 1 - lang/ar_SA.php | 8 +- lang/bg_BG.php | 8 +- lang/bs_BA.php | 8 +- lang/cs_CZ.php | 8 +- lang/da_DK.php | 8 +- lang/de_DE.php | 8 +- lang/en_US.php | 26 +- lang/eo_XX.php | 8 +- lang/es_419.php | 9 +- lang/es_AR.php | 8 +- lang/es_MX.php | 8 +- lang/et_EE.php | 8 +- lang/fr_FR.php | 8 +- lang/id_ID.php | 8 +- lang/is_IS.php | 8 +- lang/it_IT.php | 8 +- lang/ja_JP.php | 8 +- lang/ms_MY.php | 8 +- lang/nb_NO.php | 8 +- lang/nl_NL.php | 8 +- lang/pl_PL.php | 8 +- lang/pt_PT.php | 8 +- lang/sr_RS.php | 8 +- lang/sv_SE.php | 8 +- lang/tr_TR.php | 8 +- lang/zh_CN.php | 8 +- src/extensions/MultiFormObjectDecorator.php | 94 +- src/model/MultiForm.php | 1399 ++++++++++--------- src/model/MultiFormSession.php | 101 +- src/model/MultiFormStep.php | 908 ++++++------ src/tasks/MultiFormPurgeTask.php | 78 +- tests/MultiFormObjectDecoratorTest.php | 65 +- tests/MultiFormTest.php | 219 +-- 35 files changed, 1797 insertions(+), 1772 deletions(-) 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?') + ); + } } From a3a9725d60cda19f7fcbd3b1be1c9c01629e52ea Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Thu, 7 Sep 2017 11:17:54 +1200 Subject: [PATCH 03/16] FIX ran SS4 upgrader --- lang/ar_SA.php | 29 ------------------- lang/bg_BG.php | 25 ---------------- lang/bs_BA.php | 26 ----------------- lang/cs_CZ.php | 29 ------------------- lang/da_DK.php | 26 ----------------- lang/de_DE.php | 29 ------------------- lang/en_US.php | 27 ----------------- lang/eo_XX.php | 29 ------------------- lang/es_419.php | 17 ----------- lang/es_AR.php | 29 ------------------- lang/es_MX.php | 29 ------------------- lang/et_EE.php | 29 ------------------- lang/fr_FR.php | 29 ------------------- lang/id_ID.php | 28 ------------------ lang/is_IS.php | 23 --------------- lang/it_IT.php | 29 ------------------- lang/ja_JP.php | 23 --------------- lang/ms_MY.php | 26 ----------------- lang/nb_NO.php | 29 ------------------- lang/nl_NL.php | 29 ------------------- lang/pl_PL.php | 29 ------------------- lang/pt_PT.php | 25 ---------------- lang/sr_RS.php | 24 --------------- lang/sv_SE.php | 26 ----------------- lang/tr_TR.php | 29 ------------------- lang/zh_CN.php | 29 ------------------- .../MultiFormObjectDecorator_DataObject.php | 8 +++++ tests/Stubs/MultiFormStepOne.php | 8 +++++ tests/Stubs/MultiFormTestForm.php | 8 +++++ tests/Stubs/MultiFormTestStepThree.php | 8 +++++ tests/Stubs/MultiFormTestStepTwo.php | 0 tests/Stubs/MultiFormTest_Controller.php | 8 +++++ 32 files changed, 40 insertions(+), 702 deletions(-) delete mode 100644 lang/ar_SA.php delete mode 100644 lang/bg_BG.php delete mode 100644 lang/bs_BA.php delete mode 100644 lang/cs_CZ.php delete mode 100644 lang/da_DK.php delete mode 100644 lang/de_DE.php delete mode 100644 lang/en_US.php delete mode 100644 lang/eo_XX.php delete mode 100644 lang/es_419.php delete mode 100644 lang/es_AR.php delete mode 100644 lang/es_MX.php delete mode 100644 lang/et_EE.php delete mode 100644 lang/fr_FR.php delete mode 100644 lang/id_ID.php delete mode 100644 lang/is_IS.php delete mode 100644 lang/it_IT.php delete mode 100644 lang/ja_JP.php delete mode 100644 lang/ms_MY.php delete mode 100644 lang/nb_NO.php delete mode 100644 lang/nl_NL.php delete mode 100644 lang/pl_PL.php delete mode 100644 lang/pt_PT.php delete mode 100644 lang/sr_RS.php delete mode 100644 lang/sv_SE.php delete mode 100644 lang/tr_TR.php delete mode 100644 lang/zh_CN.php create mode 100644 tests/Stubs/MultiFormObjectDecorator_DataObject.php create mode 100644 tests/Stubs/MultiFormStepOne.php create mode 100644 tests/Stubs/MultiFormTestForm.php create mode 100644 tests/Stubs/MultiFormTestStepThree.php create mode 100644 tests/Stubs/MultiFormTestStepTwo.php create mode 100644 tests/Stubs/MultiFormTest_Controller.php diff --git a/lang/ar_SA.php b/lang/ar_SA.php deleted file mode 100644 index 4d1d3b8..0000000 --- a/lang/ar_SA.php +++ /dev/null @@ -1,29 +0,0 @@ - Date: Thu, 7 Sep 2017 11:32:55 +1200 Subject: [PATCH 04/16] Namespace changes and some more linting fixes --- .upgrade.yml | 14 ++ _config/config.yml | 3 + _config/legacy.yml | 6 + codecov.yml | 1 + license.md | 2 +- src/{model => Models}/MultiForm.php | 94 ++++++----- src/{model => Models}/MultiFormSession.php | 24 ++- src/{model => Models}/MultiFormStep.php | 66 +++++--- src/extensions/MultiFormObjectDecorator.php | 20 ++- src/tasks/MultiFormPurgeTask.php | 11 +- templates/Includes/MultiFormProgressList.ss | 24 ++- .../Includes/MultiFormProgressPercent.ss | 2 +- tests/MultiFormObjectDecoratorTest.php | 32 ++-- tests/MultiFormObjectDecoratorTest.yml | 2 +- tests/MultiFormTest.php | 154 +++++------------- tests/MultiFormTest.yml | 2 +- .../MultiFormObjectDecoratorDataObject.php | 13 ++ .../MultiFormObjectDecorator_DataObject.php | 8 - tests/Stubs/MultiFormStepOne.php | 23 ++- tests/Stubs/MultiFormTestController.php | 25 +++ tests/Stubs/MultiFormTestForm.php | 16 +- tests/Stubs/MultiFormTestStepThree.php | 20 ++- tests/Stubs/MultiFormTestStepTwo.php | 23 +++ tests/Stubs/MultiFormTest_Controller.php | 8 - 24 files changed, 352 insertions(+), 241 deletions(-) create mode 100644 .upgrade.yml create mode 100644 _config/config.yml create mode 100644 _config/legacy.yml create mode 100644 codecov.yml rename src/{model => Models}/MultiForm.php (89%) rename src/{model => Models}/MultiFormSession.php (81%) rename src/{model => Models}/MultiFormStep.php (90%) create mode 100644 tests/Stubs/MultiFormObjectDecoratorDataObject.php delete mode 100644 tests/Stubs/MultiFormObjectDecorator_DataObject.php create mode 100644 tests/Stubs/MultiFormTestController.php delete mode 100644 tests/Stubs/MultiFormTest_Controller.php diff --git a/.upgrade.yml b/.upgrade.yml new file mode 100644 index 0000000..8104798 --- /dev/null +++ b/.upgrade.yml @@ -0,0 +1,14 @@ +mappings: + MultiFormObjectDecorator: SilverStripe\MultiForm\MultiFormObjectDecorator + MultiForm: SilverStripe\MultiForm\MultiForm + MultiFormSession: SilverStripe\MultiForm\MultiFormSession + MultiFormStep: SilverStripe\MultiForm\MultiFormStep + MultiFormPurgeTask: SilverStripe\MultiForm\MultiFormPurgeTask + MultiFormObjectDecoratorTest: SilverStripe\MultiForm\MultiFormObjectDecoratorTest + MultiFormObjectDecorator_DataObject: SilverStripe\MultiForm\MultiFormObjectDecorator_DataObject + MultiFormTest: SilverStripe\MultiForm\MultiFormTest + MultiFormTest_Controller: SilverStripe\MultiForm\MultiFormTest_Controller + MultiFormTest_Form: SilverStripe\MultiForm\MultiFormTest_Form + MultiFormTest_StepOne: SilverStripe\MultiForm\MultiFormTest_StepOne + MultiFormTest_StepTwo: SilverStripe\MultiForm\MultiFormTest_StepTwo + MultiFormTest_StepThree: SilverStripe\MultiForm\MultiFormTest_StepThree diff --git a/_config/config.yml b/_config/config.yml new file mode 100644 index 0000000..775b48a --- /dev/null +++ b/_config/config.yml @@ -0,0 +1,3 @@ +--- +Name: multisiteconfig +--- diff --git a/_config/legacy.yml b/_config/legacy.yml new file mode 100644 index 0000000..2eaf6f9 --- /dev/null +++ b/_config/legacy.yml @@ -0,0 +1,6 @@ +--- +Name: multisitelegacy +--- +SilverStripe\ORM\DatabaseAdmin: + classname_value_remapping: + MultiFormSession: SilverStripe\MultiForm\Model\MultiFormSession diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..69cb760 --- /dev/null +++ b/codecov.yml @@ -0,0 +1 @@ +comment: false diff --git a/license.md b/license.md index 9445c8e..8794670 100644 --- a/license.md +++ b/license.md @@ -1,4 +1,4 @@ -Copyright (c) 2016, SilverStripe Limited +Copyright (c) 2017, SilverStripe Limited All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/model/MultiForm.php b/src/Models/MultiForm.php similarity index 89% rename from src/model/MultiForm.php rename to src/Models/MultiForm.php index 547fdd7..1f42c90 100644 --- a/src/model/MultiForm.php +++ b/src/Models/MultiForm.php @@ -1,5 +1,21 @@ 'Int', 'TotalStepCount' => 'Int', 'CompletedPercent' => 'Float' - ); + ]; /** * @var string @@ -63,11 +78,11 @@ abstract class MultiForm extends Form * * @var array */ - public static $ignored_fields = array( + public static $ignored_fields = [ 'url', 'executeForm', 'SecurityID' - ); + ]; /** * Any of the actions defined in this variable are exempt from @@ -79,9 +94,9 @@ abstract class MultiForm extends Form * * @var array */ - public static $actions_exempt_from_validation = array( + public static $actions_exempt_from_validation = [ 'action_prev' - ); + ]; /** * @var string @@ -98,7 +113,7 @@ abstract class MultiForm extends Form /** * Start the MultiForm instance. * - * @param Controller instance $controller Controller this form is created on + * @param Controller $controller Controller instance this form is created on * @param string $name The form name, typically the same as the method name */ public function __construct($controller, $name) @@ -155,7 +170,7 @@ abstract class MultiForm extends Form $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)); + $this->fields->push(HiddenField::create($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!) @@ -213,14 +228,14 @@ abstract class MultiForm extends Form // Determine whether we use the current step, or create one if it doesn't exist $currentStep = null; - $StepID = $this->controller->request->getVar('StepID'); + $StepID = $this->controller->getRequest()->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(); @@ -228,7 +243,7 @@ abstract class MultiForm extends Form // 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 = Injector::inst()->create($startStepClass); $currentStep->SessionID = $this->session->ID; $currentStep->write(); $this->session->CurrentStepID = $currentStep->ID; @@ -314,17 +329,17 @@ abstract class MultiForm extends Form public function getCurrentSession() { if (!$this->currentSessionHash) { - $this->currentSessionHash = $this->controller->request->getVar($this->config()->get_var); + $this->currentSessionHash = $this->controller->getRequest()->getVar($this->config()->get_var); if (!$this->currentSessionHash) { return false; } } - $this->session = MultiFormSession::get()->filter(array( + $this->session = MultiFormSession::get()->filter([ "Hash" => $this->currentSessionHash, "IsComplete" => 0 - ))->first(); + ])->first(); return $this->session; } @@ -336,7 +351,7 @@ abstract class MultiForm extends Form * to the database, use {@link getAllStepsLinear()}. * * @param string $filter SQL WHERE statement - * @return DataObjectSet|boolean A set of MultiFormStep subclasses + * @return DataList|boolean A set of MultiFormStep subclasses */ public function getSavedSteps($filter = null) { @@ -351,7 +366,7 @@ abstract class MultiForm extends Form * in your chain with the same classname. * * @param string $className Classname of a {@link MultiFormStep} subclass - * @return MultiFormStep + * @return DataObject */ public function getSavedStepByClass($className) { @@ -381,30 +396,30 @@ abstract class MultiForm extends Form * 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 + * @param MultiFormStep $step 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(); + $actions = FieldList::create(); // 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())); + $actions->push(FormAction::create('finish', $step->getSubmitText())); } else { - $actions->push(new FormAction('next', $step->getNextText())); + $actions->push(FormAction::create('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'); + $actions->insertBefore($prev = FormAction::create('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'); + $actions->insertBefore($prev = FormAction::create('prev', $step->getPrevText()), 'action_finish'); } //remove browser validation from prev action $prev->setAttribute("formnovalidate", "formnovalidate"); @@ -427,13 +442,13 @@ abstract class MultiForm extends Form */ public function forTemplate() { - $return = $this->renderWith(array( + $return = $this->renderWith([ $this->getCurrentStep()->class, 'MultiFormStep', $this->class, 'MultiForm', 'Form' - )); + ]); $this->clearMessage(); @@ -447,7 +462,8 @@ abstract class MultiForm extends Form * 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 + * @param Form $form The form that the action was called on + * @return bool */ public function finish($data, $form) { @@ -460,7 +476,7 @@ abstract class MultiForm extends Form } if (!$this->getCurrentStep()->validateStep($data, $form)) { - Session::set("FormInfo.{$form->FormName()}.data", $form->getData()); + Injector::inst()->get(Session::class)->set("FormInfo.{$form->FormName()}.data", $form->getData()); $this->controller->redirectBack(); return false; } @@ -475,7 +491,8 @@ abstract class MultiForm extends Form * 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 + * @param Form $form The form that the action was called on + * @return bool */ public function next($data, $form) { @@ -494,17 +511,17 @@ abstract class MultiForm extends Form // 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()); + Injector::inst()->get(Session::class)->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(); + $this->clearFormState(); // 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 = Injector::inst()->create($nextStepClass); $nextStep->SessionID = $this->session->ID; $nextStep->write(); } @@ -524,7 +541,8 @@ abstract class MultiForm extends Form * 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 + * @param Form $form The form that the action was called on + * @return bool|HTTPResponse */ public function prev($data, $form) { @@ -546,7 +564,7 @@ abstract class MultiForm extends Form $this->setCurrentStep($prevStep); // Redirect to the previous step - $this->controller->redirect($prevStep->Link()); + return $this->controller->redirect($prevStep->Link()); } /** @@ -620,11 +638,11 @@ abstract class MultiForm extends Form * first step. We run {@link getAllStepsRecursive} passing the steps found * by reference to get a listing of the steps. * - * @return DataObjectSet of MultiFormStep instances + * @return ArrayList of MultiFormStep instances */ public function getAllStepsLinear() { - $stepsFound = (class_exists('ArrayList')) ? new ArrayList() : new DataObjectSet(); + $stepsFound = ArrayList::create(); $firstStep = DataObject::get_one(static::$start_step, "\"SessionID\" = {$this->session->ID}"); $firstStep->LinkingMode = ($firstStep->ID == $this->getCurrentStep()->ID) ? 'current' : 'link'; @@ -651,9 +669,9 @@ abstract class MultiForm extends Form * 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 MultiFormStep $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 + * @return DataList of MultiFormStep instances */ protected function getAllStepsRecursive($step, &$stepsFound) { diff --git a/src/model/MultiFormSession.php b/src/Models/MultiFormSession.php similarity index 81% rename from src/model/MultiFormSession.php rename to src/Models/MultiFormSession.php index dbd3cf7..431a693 100644 --- a/src/model/MultiFormSession.php +++ b/src/Models/MultiFormSession.php @@ -1,5 +1,10 @@ 'Varchar(40)', // cryptographic hash identification to this session 'IsComplete' => 'Boolean' // flag to determine if this session is marked completed - ); + ]; - private static $has_one = array( + private static $has_one = [ 'Submitter' => 'Member', 'CurrentStep' => 'MultiFormStep' - ); + ]; - private static $has_many = array( + private static $has_many = [ 'FormSteps' => 'MultiFormStep' - ); + ]; + + private static $table_name = 'MultiFormSession'; /** * Mark this session as completed. @@ -45,8 +51,8 @@ class MultiFormSession extends DataObject public function onBeforeWrite() { // save submitter if a Member is logged in - $currentMember = Member::currentUser(); - if (!$this->SubmitterID && $currentMember) { + $currentMember = Security::getCurrentUser(); + if (!$this->SubmitterID && $currentMember->ID) { $this->SubmitterID = $currentMember->ID; } diff --git a/src/model/MultiFormStep.php b/src/Models/MultiFormStep.php similarity index 90% rename from src/model/MultiFormStep.php rename to src/Models/MultiFormStep.php index f08adf7..1e03b21 100644 --- a/src/model/MultiFormStep.php +++ b/src/Models/MultiFormStep.php @@ -1,5 +1,13 @@ 'Text' // stores serialized maps with all session information - ); + ]; - private static $has_one = array( + private static $has_one = [ 'Session' => 'MultiFormSession' - ); + ]; + + private static $table_name = 'MultiFormStep'; /** * Centerpiece of the flow control for the form. @@ -78,14 +87,14 @@ class MultiFormStep extends DataObject * * @var array $extraClasses */ - protected $extraClasses = array(); + protected $extraClasses = []; /** * Temporary cache to increase the performance for repeated look ups. * * @var array $cache */ - protected $step_data_cache = array(); + protected $step_data_cache = []; /** * Form fields to be rendered with this step. @@ -112,14 +121,14 @@ class MultiFormStep extends DataObject */ public function getExtraActions() { - return (class_exists('FieldList')) ? new FieldList() : new FieldSet(); + return FieldList::create(); } /** * Get a validator specific to this form. * The form is automatically validated in {@link Form->httpSubmission()}. * - * @return Validator + * @return bool|Validator */ public function getValidator() { @@ -147,7 +156,10 @@ class MultiFormStep extends DataObject public function Link() { $form = $this->form; - return Controller::join_links($form->getDisplayLink(), "?{$form->config()->get_var}={$this->Session()->Hash}"); + return Controller::join_links( + $form->getDisplayLink(), + "?{$form->config()->get_var}={$this->getSession()->Hash}" + ); } /** @@ -164,7 +176,7 @@ class MultiFormStep extends DataObject */ public function loadData() { - return ($this->Data && is_string($this->Data)) ? unserialize($this->Data) : array(); + return ($this->Data && is_string($this->Data)) ? unserialize($this->Data) : []; } /** @@ -191,14 +203,15 @@ class MultiFormStep extends DataObject * as a simple value outside of the original FormField context. * * @param DataObject $obj + * @return DataObject */ public function saveInto($obj) { - $form = new Form( + $form = Form::create( Controller::curr(), 'Form', $this->getFields(), - ((class_exists('FieldList')) ? new FieldList() : new FieldSet()) + FieldList::create() ); $form->loadDataFrom($this->loadData()); $form->saveInto($obj); @@ -235,7 +248,11 @@ class MultiFormStep extends DataObject // 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); + user_error( + 'MultiFormStep->getNextStep(): Please define at least one $next_steps on ' + . $this->class, + E_USER_ERROR + ); } } @@ -326,7 +343,7 @@ class MultiFormStep extends DataObject */ public function getPrevText() { - return _t('MultiForm.BACK', 'Back'); + return _t(__CLASS__ . '.BACK', 'Back'); } /** @@ -335,7 +352,7 @@ class MultiFormStep extends DataObject */ public function getNextText() { - return _t('MultiForm.NEXT', 'Next'); + return _t(__CLASS__ . '.NEXT', 'Next'); } /** @@ -344,13 +361,13 @@ class MultiFormStep extends DataObject */ public function getSubmitText() { - return _t('MultiForm.SUBMIT', 'Submit'); + return _t(__CLASS__ . '.SUBMIT', 'Submit'); } /** * Sets the form that this step is directly related to. * - * @param MultiForm subclass $form + * @param MultiForm $form subclass */ public function setForm($form) { @@ -401,7 +418,7 @@ class MultiFormStep extends DataObject */ public function isCurrentStep() { - return ($this->class == $this->Session()->CurrentStep()->class) ? true : false; + return ($this->class == $this->getSession()->CurrentStep()->class) ? true : false; } /** @@ -458,7 +475,7 @@ class MultiFormStep extends DataObject { // 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); + $steps = self::get()->filter('SessionID', $this->form->session->ID); if ($steps) { foreach ($steps as $step) { @@ -494,4 +511,13 @@ class MultiFormStep extends DataObject $fields->fieldByName($fieldNameTarget)->setValue($this->getValueFromOtherStep($formStep, $fieldName)); } + + /** + * Gets the linked MultiFormSession + * @return MultiFormSession + */ + public function getSession() + { + return $this->Session(); + } } diff --git a/src/extensions/MultiFormObjectDecorator.php b/src/extensions/MultiFormObjectDecorator.php index 3423a65..73beb63 100644 --- a/src/extensions/MultiFormObjectDecorator.php +++ b/src/extensions/MultiFormObjectDecorator.php @@ -1,5 +1,11 @@ 'Boolean', - ); + ]; - private static $has_one = array( + private static $has_one = [ 'MultiFormSession' => 'MultiFormSession', - ); + ]; /** * Augment any queries to MultiFormObjectDecorator and only * return anything that isn't considered temporary. + * @param SQLSelect $query + * @param DataQuery|null $dataQuery */ - public function augmentSQL(SQLQuery &$query) + public function augmentSQL(SQLSelect $query, DataQuery $dataQuery = null) { $where = $query->getWhere(); if (!$where && !$this->wantsTemporary($query)) { @@ -53,7 +61,7 @@ class MultiFormObjectDecorator extends DataExtension * to be exempt from the automatic filtering out * of temporary records. * - * @param SQLQuery $query + * @param SQLSelect $query * @return boolean */ protected function wantsTemporary($query) diff --git a/src/tasks/MultiFormPurgeTask.php b/src/tasks/MultiFormPurgeTask.php index c761e98..0aa56fe 100644 --- a/src/tasks/MultiFormPurgeTask.php +++ b/src/tasks/MultiFormPurgeTask.php @@ -1,5 +1,11 @@ " . self::$session_expiry_days ); } diff --git a/templates/Includes/MultiFormProgressList.ss b/templates/Includes/MultiFormProgressList.ss index 59a420d..af77977 100644 --- a/templates/Includes/MultiFormProgressList.ss +++ b/templates/Includes/MultiFormProgressList.ss @@ -1,9 +1,19 @@ diff --git a/templates/Includes/MultiFormProgressPercent.ss b/templates/Includes/MultiFormProgressPercent.ss index f2b064a..a1d919b 100644 --- a/templates/Includes/MultiFormProgressPercent.ss +++ b/templates/Includes/MultiFormProgressPercent.ss @@ -1 +1 @@ -

You've completed {$CompletedPercent.Nice}% ($CompletedStepCount/$TotalStepCount)

\ No newline at end of file +

<%t MULTIFORM.ProgressPercent "You've completed {percent}% ({completedSteps}/{totalSteps})" percent=$CompletedPercent.Nice completedSteps=$CompletedStepCount totalSteps$TotalStepCount %>

diff --git a/tests/MultiFormObjectDecoratorTest.php b/tests/MultiFormObjectDecoratorTest.php index 15f9b8a..f825b2a 100644 --- a/tests/MultiFormObjectDecoratorTest.php +++ b/tests/MultiFormObjectDecoratorTest.php @@ -1,20 +1,24 @@ array('MultiFormObjectDecorator') - ); + protected $requiredExtensions = [ + 'MultiFormObjectDecoratorDataObject' => ['MultiFormObjectDecorator'] + ]; - protected $extraDataObjects = array( - 'MultiFormObjectDecorator_DataObject' - ); + protected $extraDataObjects = [ + 'MultiFormObjectDecoratorDataObject' + ]; public function testTemporaryDataFilteredQuery() { - $records = MultiFormObjectDecorator_DataObject::get() + $records = MultiFormObjectDecoratorDataObject::get() ->map('Name') ->toArray(); @@ -25,8 +29,8 @@ class MultiFormObjectDecoratorTest extends SapphireTest public function testTemporaryDataQuery() { - $records = MultiFormObjectDecorator_DataObject::get() - ->filter(array('MultiFormIsTemporary' => 1)) + $records = MultiFormObjectDecoratorDataObject::get() + ->filter(['MultiFormIsTemporary' => 1]) ->map('Name') ->toArray(); @@ -35,11 +39,3 @@ class MultiFormObjectDecoratorTest extends SapphireTest $this->assertContains('Test 3', $records); } } - -class MultiFormObjectDecorator_DataObject extends DataObject -{ - - private static $db = array( - 'Name' => 'Varchar' - ); -} diff --git a/tests/MultiFormObjectDecoratorTest.yml b/tests/MultiFormObjectDecoratorTest.yml index 99bee26..1b4fca3 100644 --- a/tests/MultiFormObjectDecoratorTest.yml +++ b/tests/MultiFormObjectDecoratorTest.yml @@ -1,4 +1,4 @@ -MultiFormObjectDecorator_DataObject: +SilverStripe\MultiForm\Tests\MultiFormObjectDecoratorDataObject: test-data-1: Name: Test 1 MultiFormIsTemporary: 0 diff --git a/tests/MultiFormTest.php b/tests/MultiFormTest.php index 589a485..4430046 100644 --- a/tests/MultiFormTest.php +++ b/tests/MultiFormTest.php @@ -1,16 +1,22 @@ controller = new MultiFormTest_Controller(); + $this->controller = new MultiFormTestController(); $this->form = $this->controller->Form(); } @@ -36,22 +47,22 @@ class MultiFormTest extends FunctionalTest { $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()); + $this->assertEquals(MultiFormTestStepOne::class, $this->form->getStartStep()); } public function testSessionGeneration() { - $this->assertTrue($this->form->session->ID > 0); + $this->assertTrue($this->form->getSession()->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); - $session = $this->form->session; + $userId = $this->logInWithPermission('ADMIN'); + + $session = $this->form->getSession(); $session->write(); $this->assertEquals($userId, $session->SubmitterID); @@ -59,7 +70,7 @@ class MultiFormTest extends FunctionalTest public function testSecondStep() { - $this->assertEquals('MultiFormTest_StepTwo', $this->form->getCurrentStep()->getNextStep()); + $this->assertEquals(MultiFormTestStepTwo::class, $this->form->getCurrentStep()->getNextStep()); } public function testParentForm() @@ -75,9 +86,9 @@ class MultiFormTest extends FunctionalTest public function testCompletedSession() { - $this->form->setCurrentSessionHash($this->form->session->Hash); + $this->form->setCurrentSessionHash($this->form->getSession()->Hash); $this->assertInstanceOf('MultiFormSession', $this->form->getCurrentSession()); - $this->form->session->markCompleted(); + $this->form->getSession()->markCompleted(); $this->assertNull($this->form->getCurrentSession()); } @@ -86,112 +97,27 @@ class MultiFormTest extends FunctionalTest $this->form->setCurrentSessionHash('sdfsdf3432325325sfsdfdf'); // made up! // A new session is generated, even though we made up the identifier - $this->assertInstanceOf('MultiFormSession', $this->form->session); + $this->assertInstanceOf('MultiFormSession', $this->form->getSession()); } - function testCustomGetVar() + public function testCustomGetVar() { Config::nest(); - Config::inst()->update('MultiForm', 'get_var', 'SuperSessionID'); + Config::modify()->set('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 - ID parameter"); - $this->assertContains('SuperSessionID', $form->getCurrentStep()->Link(), "Form step doesn't contain correct - session ID parameter"); + $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 session ID parameter" + ); Config::unnest(); } } - -/** - * @package multiform - * @subpackage tests - */ -class MultiFormTest_Controller extends Controller implements TestOnly -{ - - public function Link() - { - return 'MultiFormTest_Controller'; - } - - 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 -{ - - public static $start_step = 'MultiFormTest_StepOne'; - - public function getStartStep() - { - return self::$start_step; - } -} - -/** - * @package multiform - * @subpackage tests - */ -class MultiFormTest_StepOne extends MultiFormStep implements TestOnly -{ - - 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') - ); - } -} - -/** - * @package multiform - * @subpackage tests - */ -class MultiFormTest_StepTwo extends MultiFormStep implements TestOnly -{ - - 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...') - ); - } -} - -/** - * @package multiform - * @subpackage tests - */ -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?') - ); - } -} diff --git a/tests/MultiFormTest.yml b/tests/MultiFormTest.yml index b11eb72..e4a5ae0 100644 --- a/tests/MultiFormTest.yml +++ b/tests/MultiFormTest.yml @@ -1,4 +1,4 @@ -Member: +SilverStripe\Security\Member: admin: FirstName: Admin Surname: Admin diff --git a/tests/Stubs/MultiFormObjectDecoratorDataObject.php b/tests/Stubs/MultiFormObjectDecoratorDataObject.php new file mode 100644 index 0000000..f2d3d0f --- /dev/null +++ b/tests/Stubs/MultiFormObjectDecoratorDataObject.php @@ -0,0 +1,13 @@ + 'Varchar' + ]; +} diff --git a/tests/Stubs/MultiFormObjectDecorator_DataObject.php b/tests/Stubs/MultiFormObjectDecorator_DataObject.php deleted file mode 100644 index 88e83ad..0000000 --- a/tests/Stubs/MultiFormObjectDecorator_DataObject.php +++ /dev/null @@ -1,8 +0,0 @@ -setHTMLID(self::class); + return $form; + } +} diff --git a/tests/Stubs/MultiFormTestForm.php b/tests/Stubs/MultiFormTestForm.php index 6ab1dee..aeb5ab5 100644 --- a/tests/Stubs/MultiFormTestForm.php +++ b/tests/Stubs/MultiFormTestForm.php @@ -1,8 +1,20 @@ Date: Fri, 8 Sep 2017 17:09:16 +1200 Subject: [PATCH 05/16] Resolved composer config --- .travis.yml | 43 ++++++++++++++++---------------- README.md | 2 +- _config/legacy.yml | 3 ++- composer.json | 19 +++++++++----- phpunit.xml.dist | 13 ++++++++++ src/tasks/MultiFormPurgeTask.php | 3 ++- 6 files changed, 53 insertions(+), 30 deletions(-) create mode 100644 phpunit.xml.dist diff --git a/.travis.yml b/.travis.yml index 44a7095..5a002b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,34 +1,35 @@ -# See https://github.com/silverstripe-labs/silverstripe-travis-support for setup details - -sudo: false - language: php -php: - - 5.3 - - 5.4 - - 5.5 - - 5.6 - - 7.0 +dist: trusty env: - - DB=MYSQL CORE_RELEASE=3.2 + global: + - COMPOSER_ROOT_VERSION=4.0.x-dev matrix: include: - php: 5.6 - env: DB=MYSQL CORE_RELEASE=3 - - php: 5.6 - env: DB=PGSQL CORE_RELEASE=3.2 - allow_failures: + env: DB=MYSQL PHPCS_TEST=1 PHPUNIT_TEST=1 - php: 7.0 + env: DB=PGSQL PHPUNIT_TEST=1 + - php: 7.1 + env: DB=MYSQL PHPUNIT_COVERAGE_TEST=1 before_script: - - composer self-update || true - - git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support - - php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss - - cd ~/builds/ss - - composer install + # Init PHP + - phpenv rehash + - phpenv config-rm xdebug.ini + + # Install composer dependencies + - composer install --prefer-dist + - composer require --prefer-dist --no-update silverstripe/recipe-framework:1.0.x-dev + - if [[ $DB == PGSQL ]]; then composer require --prefer-dist --no-update silverstripe/postgresql:2.0.x-dev; fi + - composer update script: - - vendor/bin/phpunit multiform/tests + - if [[ $PHPUNIT_TEST ]]; then vendor/bin/phpunit; fi + - if [[ $PHPUNIT_COVERAGE_TEST ]]; then phpdbg -qrr vendor/bin/phpunit --coverage-clover=coverage.xml; fi + - if [[ $PHPCS_TEST ]]; then vendor/bin/phpcs --standard=framework/phpcs.xml.dist src/ tests/; fi + +after_success: + - if [[ $PHPUNIT_COVERAGE_TEST ]]; then bash <(curl -s https://codecov.io/bash) -f coverage.xml; fi diff --git a/README.md b/README.md index e4ca932..ac552e8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MultiForm Module -[![Build Status](https://api.travis-ci.org/silverstripe/silverstripe-multiform.svg?branch=master)](https://travis-ci.org/silverstripe/silverstripe-multiform) +[![Build Status](https://travis-ci.org/silverstripe/silverstripe-multiform.svg?branch=master)](https://travis-ci.org/silverstripe/silverstripe-multiform) [![Latest Stable Version](https://poser.pugx.org/silverstripe/multiform/version.svg)](https://github.com/silverstripe/silverstripe-multiform/releases) [![Latest Unstable Version](https://poser.pugx.org/silverstripe/multiform/v/unstable.svg)](https://packagist.org/packages/silverstripe/multiform) [![Total Downloads](https://poser.pugx.org/silverstripe/multiform/downloads.svg)](https://packagist.org/packages/silverstripe/multiform) diff --git a/_config/legacy.yml b/_config/legacy.yml index 2eaf6f9..32b046c 100644 --- a/_config/legacy.yml +++ b/_config/legacy.yml @@ -3,4 +3,5 @@ Name: multisitelegacy --- SilverStripe\ORM\DatabaseAdmin: classname_value_remapping: - MultiFormSession: SilverStripe\MultiForm\Model\MultiFormSession + MultiFormSession: SilverStripe\MultiForm\Models\MultiFormSession + MultiFormStep: SilverStripe\MultiForm\Models\MultiFormStep diff --git a/composer.json b/composer.json index 0d71251..e3ca26c 100644 --- a/composer.json +++ b/composer.json @@ -13,10 +13,17 @@ "require": { "silverstripe/framework": "~3.2" }, - "license": "BSD-3-Clause", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - } + "require": { + "silverstripe/framework": "^4@dev" + }, + "require-dev": { + "phpunit/phpunit": "^5.7", + "squizlabs/php_codesniffer": "^3.0" + }, + "license": "BSD-3-Clause", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..50e5f66 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,13 @@ + + + tests/ + + + + src/ + + tests/ + + + + diff --git a/src/tasks/MultiFormPurgeTask.php b/src/tasks/MultiFormPurgeTask.php index 0aa56fe..cdcb49a 100644 --- a/src/tasks/MultiFormPurgeTask.php +++ b/src/tasks/MultiFormPurgeTask.php @@ -1,8 +1,9 @@ Date: Fri, 8 Sep 2017 17:09:39 +1200 Subject: [PATCH 06/16] Resolved composer config --- composer.json | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index e3ca26c..9996f3b 100644 --- a/composer.json +++ b/composer.json @@ -1,18 +1,21 @@ { - "name": "silverstripe/multiform", - "description": "SilverStripe forms with multiple steps, flow control and state persistence", - "type": "silverstripe-module", - "keywords": ["silverstripe", "forms"], - "authors": [{ - "name": "Ingo Schommer", - "email": "ingo@silverstripe.com" - }, { - "name": "Sean Harvey", - "email": "sean@silverstripe.com" - }], - "require": { - "silverstripe/framework": "~3.2" - }, + "name": "silverstripe/multiform", + "description": "SilverStripe forms with multiple steps, flow control and state persistence", + "type": "silverstripe-module", + "keywords": [ + "silverstripe", + "forms" + ], + "authors": [ + { + "name": "Ingo Schommer", + "email": "ingo@silverstripe.com" + }, + { + "name": "Sean Harvey", + "email": "sean@silverstripe.com" + } + ], "require": { "silverstripe/framework": "^4@dev" }, From 2c3ed600399b1de7010739b80be33048d3f820e0 Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Thu, 7 Sep 2017 13:44:31 +1200 Subject: [PATCH 07/16] Updated travis config, added legacy.yml and composer.json updated --- tests/MultiFormObjectDecoratorTest.php | 7 ++++--- tests/Stubs/MultiFormObjectDecoratorDataObject.php | 2 ++ tests/Stubs/MultiFormTestController.php | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/MultiFormObjectDecoratorTest.php b/tests/MultiFormObjectDecoratorTest.php index f825b2a..9683f95 100644 --- a/tests/MultiFormObjectDecoratorTest.php +++ b/tests/MultiFormObjectDecoratorTest.php @@ -3,17 +3,18 @@ namespace SilverStripe\MultiForm\Tests; use SilverStripe\Dev\SapphireTest; +use SilverStripe\MultiForm\Extensions\MultiFormObjectDecorator; class MultiFormObjectDecoratorTest extends SapphireTest { protected static $fixture_file = 'MultiFormObjectDecoratorTest.yml'; - protected $requiredExtensions = [ - 'MultiFormObjectDecoratorDataObject' => ['MultiFormObjectDecorator'] + protected static $required_extensions = [ + MultiFormObjectDecoratorDataObject::class => [MultiFormObjectDecorator::class] ]; protected $extraDataObjects = [ - 'MultiFormObjectDecoratorDataObject' + MultiFormObjectDecoratorDataObject::class ]; public function testTemporaryDataFilteredQuery() diff --git a/tests/Stubs/MultiFormObjectDecoratorDataObject.php b/tests/Stubs/MultiFormObjectDecoratorDataObject.php index f2d3d0f..7b05c4d 100644 --- a/tests/Stubs/MultiFormObjectDecoratorDataObject.php +++ b/tests/Stubs/MultiFormObjectDecoratorDataObject.php @@ -10,4 +10,6 @@ class MultiFormObjectDecoratorDataObject extends DataObject implements TestOnly private static $db = [ 'Name' => 'Varchar' ]; + + private static $table_name = 'MultiFormObjectDecoratorDataObject'; } diff --git a/tests/Stubs/MultiFormTestController.php b/tests/Stubs/MultiFormTestController.php index b7b6a2f..ee0a86b 100644 --- a/tests/Stubs/MultiFormTestController.php +++ b/tests/Stubs/MultiFormTestController.php @@ -11,7 +11,7 @@ use SilverStripe\Dev\TestOnly; */ class MultiFormTestController extends Controller implements TestOnly { - public function Link() + public function Link($action = null) { return self::class; } From a633f81b966388385c6b033cff109b9c07f0a44a Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Fri, 8 Sep 2017 13:57:33 +1200 Subject: [PATCH 08/16] FIX fixed failing tests --- README.md | 14 ++++---- src/Models/MultiForm.php | 33 +++++++++-------- src/Models/MultiFormSession.php | 9 ++--- src/Models/MultiFormStep.php | 6 ++-- src/extensions/MultiFormObjectDecorator.php | 8 ++--- tests/MultiFormObjectDecoratorTest.php | 2 +- tests/MultiFormTest.php | 40 +++++++++++++-------- tests/Stubs/MultiFormTestController.php | 13 +++---- 8 files changed, 69 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index ac552e8..67ab59f 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ a *FieldSet* with some form field objects. These are the fields that the form will render for the given step. Keep in mind that our multi-form also requires an end point. This step is the -final, and needs to have another variable set to let the multi-form system know +final one, and needs to have another variable set to let the multi-form system know this is the final step. So, if we assume that the last step in our process is @@ -220,7 +220,7 @@ class Page_Controller extends ContentController { } ``` -The `SurveyForm()` function will create a new instance our subclass of +The `SurveyForm()` function will create a new instance of our subclass of MultiForm, which in this example, is *SurveyForm*. This in turn will then set up all the form fields, actions, and validation available to each step, as well as the session. @@ -384,7 +384,7 @@ class SurveyForm extends MultiForm { parent::finish($data, $form); $steps = DataObject::get( - 'MultiFormStep', + MultiFormStep::class, "SessionID = {$this->session->ID}" ); @@ -480,21 +480,21 @@ MultiForm class: More than likely, you'll want the first one to be available when the form renders. To that effect, you can start placing templates in the -*templates/Includes* directory for your project. You need to call them the same +*templates/Includes* directory for your project. You need to name them the same as the class name for each step. For example, if you want *MembershipForm*, a subclass of *MultiFormStep* to have it's own template, you would put *MembershipForm.ss* into that directory, and run *?flush=1*. If you'd like a pre-existing template on how to customise the form step, have a -look at Form.ss that's found within the sapphire module. Use that template, as +look at Form.ss that's found within the framework module. Use that template, as a base for your new MembershipForm.ss template in your project templates. For more information on this, please [look at the Form documentation](http://doc.silverstripe.org/framework/en/topics/forms#custom-form-templates). ### getNextStep() -If you are wanting to override the next step (so, if you want the next step to -be something different based on a user's choice of input during the step, you +If you are wanting to override the next step (for example if you want the next step to +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: diff --git a/src/Models/MultiForm.php b/src/Models/MultiForm.php index 1f42c90..7a7f44b 100644 --- a/src/Models/MultiForm.php +++ b/src/Models/MultiForm.php @@ -150,7 +150,7 @@ abstract class MultiForm extends Form if ($actionNames) { foreach ($actionNames as $exemptAction) { - if (!empty($_REQUEST[$exemptAction])) { + if (!empty($this->getRequest()->requestVar($exemptAction))) { $applyValidation = false; break; } @@ -160,14 +160,14 @@ abstract class MultiForm extends Form // Apply validation if the current step requires validation (is not exempt) if ($applyValidation) { if ($currentStep->getValidator()) { - $validator = $currentStep->getValidator(); + $this->setValidator($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); + parent::__construct($controller, $name, $fields, $actions); - $getVar = $this->config()->get_var; + $getVar = $this->getGetVar(); // Set a hidden field in our form with an encrypted hash to identify this session. $this->fields->push(HiddenField::create($getVar, false, $this->session->Hash)); @@ -201,7 +201,7 @@ abstract class MultiForm extends Form */ public function getGetVar() { - return $this->config()->get_var; + return $this->config()->get('get_var'); } /** @@ -231,7 +231,7 @@ abstract class MultiForm extends Form $StepID = $this->controller->getRequest()->getVar('StepID'); if (isset($StepID)) { $currentStep = DataObject::get_one( - 'MultiFormStep', + MultiFormStep::class, [ 'SessionID' => $this->session->ID, 'ID' => $StepID @@ -277,8 +277,11 @@ abstract class MultiForm extends Form * * @return MultiFormSession */ - public function getSession() + public function getMultiFormSession() { + if (!$this->session) { + $this->setSession(); + } return $this->session; } @@ -300,7 +303,7 @@ abstract class MultiForm extends Form // If there was no session found, create a new one instead if (!$this->session) { - $this->session = new MultiFormSession(); + $this->session = MultiFormSession::create(); } // Create encrypted identification to the session instance if it doesn't exist @@ -329,7 +332,7 @@ abstract class MultiForm extends Form public function getCurrentSession() { if (!$this->currentSessionHash) { - $this->currentSessionHash = $this->controller->getRequest()->getVar($this->config()->get_var); + $this->currentSessionHash = $this->controller->getRequest()->getVar($this->getGetVar()); if (!$this->currentSessionHash) { return false; @@ -357,7 +360,7 @@ abstract class MultiForm extends Form { $filter .= ($filter) ? ' AND ' : ''; $filter .= sprintf("\"SessionID\" = '%s'", $this->session->ID); - return DataObject::get('MultiFormStep', $filter); + return DataObject::get(MultiFormStep::class, $filter); } /** @@ -371,7 +374,7 @@ abstract class MultiForm extends Form public function getSavedStepByClass($className) { return DataObject::get_one( - 'MultiFormStep', + MultiFormStep::class, sprintf( "\"SessionID\" = '%s' AND \"ClassName\" = '%s'", $this->session->ID, @@ -476,7 +479,7 @@ abstract class MultiForm extends Form } if (!$this->getCurrentStep()->validateStep($data, $form)) { - Injector::inst()->get(Session::class)->set("FormInfo.{$form->FormName()}.data", $form->getData()); + $this->getRequest()->getSession()->set("FormInfo.{$form->FormName()}.data", $form->getData()); $this->controller->redirectBack(); return false; } @@ -511,7 +514,7 @@ abstract class MultiForm extends Form // built-in functionality). The data needs to be manually saved on error // so the form is re-populated. if (!$this->getCurrentStep()->validateStep($data, $form)) { - Injector::inst()->get(Session::class)->set("FormInfo.{$form->FormName()}.data", $form->getData()); + $this->getRequest()->getSession()->set("FormInfo.{$form->FormName()}.data", $form->getData()); $this->controller->redirectBack(); return false; } @@ -603,7 +606,7 @@ abstract class MultiForm extends Form { $action = parent::FormAction(); $action .= (strpos($action, '?')) ? '&' : '?'; - $action .= "{$this->config()->get_var}={$this->session->Hash}"; + $action .= "{$this->getGetVar()}={$this->session->Hash}"; return $action; } @@ -723,7 +726,7 @@ abstract class MultiForm extends Form */ public function getCompletedStepCount() { - $steps = DataObject::get('MultiFormStep', "\"SessionID\" = {$this->session->ID} && \"Data\" IS NOT NULL"); + $steps = DataObject::get(MultiFormStep::class, "\"SessionID\" = {$this->session->ID} && \"Data\" IS NOT NULL"); return $steps ? $steps->Count() : 0; } diff --git a/src/Models/MultiFormSession.php b/src/Models/MultiFormSession.php index 431a693..39ecb45 100644 --- a/src/Models/MultiFormSession.php +++ b/src/Models/MultiFormSession.php @@ -3,6 +3,7 @@ namespace SilverStripe\MultiForm\Models; use SilverStripe\ORM\DataObject; +use SilverStripe\Security\Member; use SilverStripe\Security\Security; /** @@ -23,12 +24,12 @@ class MultiFormSession extends DataObject ]; private static $has_one = [ - 'Submitter' => 'Member', - 'CurrentStep' => 'MultiFormStep' + 'Submitter' => Member::class, + 'CurrentStep' => MultiFormStep::class ]; private static $has_many = [ - 'FormSteps' => 'MultiFormStep' + 'FormSteps' => MultiFormStep::class ]; private static $table_name = 'MultiFormSession'; @@ -52,7 +53,7 @@ class MultiFormSession extends DataObject { // save submitter if a Member is logged in $currentMember = Security::getCurrentUser(); - if (!$this->SubmitterID && $currentMember->ID) { + if (!$this->SubmitterID && $currentMember) { $this->SubmitterID = $currentMember->ID; } diff --git a/src/Models/MultiFormStep.php b/src/Models/MultiFormStep.php index 1e03b21..ac52501 100644 --- a/src/Models/MultiFormStep.php +++ b/src/Models/MultiFormStep.php @@ -24,7 +24,7 @@ class MultiFormStep extends DataObject ]; private static $has_one = [ - 'Session' => 'MultiFormSession' + 'Session' => MultiFormSession::class ]; private static $table_name = 'MultiFormStep'; @@ -158,7 +158,7 @@ class MultiFormStep extends DataObject $form = $this->form; return Controller::join_links( $form->getDisplayLink(), - "?{$form->config()->get_var}={$this->getSession()->Hash}" + "?{$form->getGetVar()}={$this->getSession()->Hash}" ); } @@ -309,7 +309,7 @@ class MultiFormStep extends DataObject */ public function getPreviousStep() { - $steps = DataObject::get('MultiFormStep', "\"SessionID\" = {$this->SessionID}", '"LastEdited" DESC'); + $steps = DataObject::get(MultiFormStep::class, "\"SessionID\" = {$this->SessionID}", '"LastEdited" DESC'); if ($steps) { foreach ($steps as $step) { $step->setForm($this->form); diff --git a/src/extensions/MultiFormObjectDecorator.php b/src/extensions/MultiFormObjectDecorator.php index 73beb63..5ae6720 100644 --- a/src/extensions/MultiFormObjectDecorator.php +++ b/src/extensions/MultiFormObjectDecorator.php @@ -45,10 +45,10 @@ class MultiFormObjectDecorator extends DataExtension $query->addWhere("{$from[0]}.\"MultiFormIsTemporary\" = '0'"); return; } - - if (strpos($where[0], ".`ID` = ") === false - && strpos($where[0], ".ID = ") === false - && strpos($where[0], "ID = ") !== 0 + $filterKey = key($where[0]); + if (strpos($filterKey, ".`ID` = ") === false + && strpos($filterKey, ".ID = ") === false + && strpos($filterKey, "ID = ") !== 0 && !$this->wantsTemporary($query) ) { $from = array_values($query->getFrom()); diff --git a/tests/MultiFormObjectDecoratorTest.php b/tests/MultiFormObjectDecoratorTest.php index 9683f95..f0da517 100644 --- a/tests/MultiFormObjectDecoratorTest.php +++ b/tests/MultiFormObjectDecoratorTest.php @@ -13,7 +13,7 @@ class MultiFormObjectDecoratorTest extends SapphireTest MultiFormObjectDecoratorDataObject::class => [MultiFormObjectDecorator::class] ]; - protected $extraDataObjects = [ + protected static $extra_dataobjects = [ MultiFormObjectDecoratorDataObject::class ]; diff --git a/tests/MultiFormTest.php b/tests/MultiFormTest.php index 4430046..d0e9169 100644 --- a/tests/MultiFormTest.php +++ b/tests/MultiFormTest.php @@ -2,8 +2,13 @@ namespace SilverStripe\MultiForm\Tests; +use SilverStripe\Control\HTTPRequest; +use SilverStripe\Control\Session; use SilverStripe\Core\Config\Config; +use SilverStripe\Core\Injector\Injector; use SilverStripe\Dev\FunctionalTest; +use SilverStripe\MultiForm\Models\MultiForm; +use SilverStripe\MultiForm\Models\MultiFormSession; /** * MultiFormTest @@ -25,9 +30,11 @@ use SilverStripe\Dev\FunctionalTest; */ class MultiFormTest extends FunctionalTest { - public static $fixture_file = 'MultiFormTest.yml'; + /** + * @var MultiFormTestController + */ protected $controller; /** @@ -35,24 +42,32 @@ class MultiFormTest extends FunctionalTest */ protected $form; - public function setUp() + protected function setUp() { parent::setUp(); $this->controller = new MultiFormTestController(); - $this->form = $this->controller->Form(); + $this->controller->setRequest(new HTTPRequest('GET', '/')); + $this->controller->getRequest()->setSession(new Session([])); + $this->controller->pushCurrent(); + $form = $this->form = $this->controller->Form(); + Injector::inst()->registerService($form, MultiForm::class); + $this->form = $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->assertTrue( + is_numeric($this->form->getMultiFormSession()->ID) + && ($this->form->getMultiFormSession()->ID > 0) + ); $this->assertEquals(MultiFormTestStepOne::class, $this->form->getStartStep()); } public function testSessionGeneration() { - $this->assertTrue($this->form->getSession()->ID > 0); + $this->assertTrue($this->form->getMultiFormSession()->ID > 0); } public function testMemberLogging() @@ -62,7 +77,7 @@ class MultiFormTest extends FunctionalTest $userId = $this->logInWithPermission('ADMIN'); - $session = $this->form->getSession(); + $session = $this->form->getMultiFormSession(); $session->write(); $this->assertEquals($userId, $session->SubmitterID); @@ -86,9 +101,9 @@ class MultiFormTest extends FunctionalTest public function testCompletedSession() { - $this->form->setCurrentSessionHash($this->form->getSession()->Hash); - $this->assertInstanceOf('MultiFormSession', $this->form->getCurrentSession()); - $this->form->getSession()->markCompleted(); + $this->form->setCurrentSessionHash($this->form->getMultiFormSession()->Hash); + $this->assertInstanceOf(MultiFormSession::class, $this->form->getCurrentSession()); + $this->form->getMultiFormSession()->markCompleted(); $this->assertNull($this->form->getCurrentSession()); } @@ -97,13 +112,12 @@ class MultiFormTest extends FunctionalTest $this->form->setCurrentSessionHash('sdfsdf3432325325sfsdfdf'); // made up! // A new session is generated, even though we made up the identifier - $this->assertInstanceOf('MultiFormSession', $this->form->getSession()); + $this->assertInstanceOf(MultiFormSession::class, $this->form->getMultiFormSession()); } public function testCustomGetVar() { - Config::nest(); - Config::modify()->set('MultiForm', 'get_var', 'SuperSessionID'); + Config::modify()->set(MultiForm::class, 'get_var', 'SuperSessionID'); $form = $this->controller->Form(); $this->assertContains('SuperSessionID', $form::$ignored_fields, "GET var wasn't added to ignored fields"); @@ -117,7 +131,5 @@ class MultiFormTest extends FunctionalTest $form->getCurrentStep()->Link(), "Form step doesn't contain correct session ID parameter" ); - - Config::unnest(); } } diff --git a/tests/Stubs/MultiFormTestController.php b/tests/Stubs/MultiFormTestController.php index ee0a86b..651366e 100644 --- a/tests/Stubs/MultiFormTestController.php +++ b/tests/Stubs/MultiFormTestController.php @@ -3,6 +3,7 @@ namespace SilverStripe\MultiForm\Tests; use SilverStripe\Control\Controller; +use SilverStripe\Core\Injector\Injector; use SilverStripe\Dev\TestOnly; /** @@ -11,15 +12,11 @@ use SilverStripe\Dev\TestOnly; */ class MultiFormTestController extends Controller implements TestOnly { - public function Link($action = null) - { - return self::class; - } + private static $url_segment = 'MultiFormTestController'; - public function Form($request = null) + public function Form() { - $form = new MultiFormTestForm($this, 'Form'); - $form->setHTMLID(self::class); - return $form; + return Injector::inst()->get(MultiFormTestForm::class, false, [$this, 'Form']) + ->setHTMLID(MultiFormTestForm::class); } } From bc05f327d3fe35746f31ef69f98388afa1cb5bf9 Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Fri, 8 Sep 2017 14:24:28 +1200 Subject: [PATCH 09/16] FIX removed static:: and self:: calls --- README.md | 14 +++++++------- src/Models/MultiForm.php | 16 ++++++++-------- src/Models/MultiFormStep.php | 14 +++++++------- src/tasks/MultiFormPurgeTask.php | 6 +++--- tests/MultiFormObjectDecoratorTest.php | 1 - tests/MultiFormTest.php | 8 ++++++-- tests/Stubs/MultiFormStepOne.php | 2 +- tests/Stubs/MultiFormTestForm.php | 4 ++-- tests/Stubs/MultiFormTestStepThree.php | 2 +- tests/Stubs/MultiFormTestStepTwo.php | 2 +- 10 files changed, 36 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 67ab59f..46d295e 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ is the first step. ```php class SurveyForm extends MultiForm { - public static $start_step = 'SurveyFormPersonalDetailsStep'; + private static $start_step = 'SurveyFormPersonalDetailsStep'; } ``` @@ -141,7 +141,7 @@ the `$start_step` variable *SurveyForm*, but we call it `$next_steps`. ```php class SurveyFormPersonalDetailsStep extends MultiFormStep { - public static $next_steps = 'SurveyFormOrganisationDetailsStep'; + private static $next_steps = 'SurveyFormOrganisationDetailsStep'; public function getFields() { return new FieldList( @@ -167,7 +167,7 @@ SurveyFormOrganisationDetailsStep, then we can do something like this: ```php class SurveyFormOrganisationDetailsStep extends MultiFormStep { - public static $is_final_step = true; + private static $is_final_step = true; } ``` @@ -334,7 +334,7 @@ Here is an example of how to populate the email address from step 1 in step2 : ```php class Step1 extends MultiFormStep { - public static $next_steps = 'Step2'; + private static $next_steps = 'Step2'; public function getFields() { return new FieldList( @@ -345,7 +345,7 @@ class Step1 extends MultiFormStep class Step2 extends MultiFormStep { - public static $next_steps = 'Step3'; + private static $next_steps = 'Step3'; public function getFields() { $fields = new FieldList( @@ -378,7 +378,7 @@ Here is an example of what we could do here: ```php class SurveyForm extends MultiForm { - public static $start_step = 'SurveyFormPersonalDetailsStep'; + private static $start_step = 'SurveyFormPersonalDetailsStep'; public function finish($data, $form) { parent::finish($data, $form); @@ -557,7 +557,7 @@ For example: ```php class SurveyForm extends MultiForm { - public static $start_step = 'SurveyFormPersonalDetailsStep'; + private static $start_step = 'SurveyFormPersonalDetailsStep'; public function finish($data, $form) { parent::finish($data, $form); diff --git a/src/Models/MultiForm.php b/src/Models/MultiForm.php index 7a7f44b..2d9a81c 100644 --- a/src/Models/MultiForm.php +++ b/src/Models/MultiForm.php @@ -53,7 +53,7 @@ abstract class MultiForm extends Form * * @var string Classname of a {@link MultiFormStep} subclass */ - public static $start_step; + private static $start_step; /** * Set the casting for these fields. @@ -78,7 +78,7 @@ abstract class MultiForm extends Form * * @var array */ - public static $ignored_fields = [ + private static $ignored_fields = [ 'url', 'executeForm', 'SecurityID' @@ -94,7 +94,7 @@ abstract class MultiForm extends Form * * @var array */ - public static $actions_exempt_from_validation = [ + private static $actions_exempt_from_validation = [ 'action_prev' ]; @@ -146,7 +146,7 @@ abstract class MultiForm extends Form $validator = null; $applyValidation = true; - $actionNames = static::$actions_exempt_from_validation; + $actionNames = $this->config()->get('actions_exempt_from_validation'); if ($actionNames) { foreach ($actionNames as $exemptAction) { @@ -181,7 +181,7 @@ abstract class MultiForm extends Form // Disable security token - we tie a form to a session ID instead $this->disableSecurityToken(); - self::$ignored_fields[] = $getVar; + $this->config()->merge('ignored_fields', $getVar); } /** @@ -216,7 +216,7 @@ abstract class MultiForm extends Form */ public function getCurrentStep() { - $startStepClass = static::$start_step; + $startStepClass = $this->config()->get('start_step'); // Check if there was a start step defined on the subclass of MultiForm if (!isset($startStepClass)) { @@ -584,7 +584,7 @@ abstract class MultiForm extends Form $currentStep = $this->getCurrentStep(); if (is_array($data)) { foreach ($data as $field => $value) { - if (in_array($field, static::$ignored_fields)) { + if (in_array($field, $this->config()->get('ignored_fields'))) { unset($data[$field]); } } @@ -647,7 +647,7 @@ abstract class MultiForm extends Form { $stepsFound = ArrayList::create(); - $firstStep = DataObject::get_one(static::$start_step, "\"SessionID\" = {$this->session->ID}"); + $firstStep = DataObject::get_one($this->config()->get('start_step'), "\"SessionID\" = {$this->session->ID}"); $firstStep->LinkingMode = ($firstStep->ID == $this->getCurrentStep()->ID) ? 'current' : 'link'; $firstStep->setForm($this); $stepsFound->push($firstStep); diff --git a/src/Models/MultiFormStep.php b/src/Models/MultiFormStep.php index ac52501..5962e20 100644 --- a/src/Models/MultiFormStep.php +++ b/src/Models/MultiFormStep.php @@ -40,7 +40,7 @@ class MultiFormStep extends DataObject * * @var array|string */ - public static $next_steps; + private static $next_steps; /** * Each {@link MultiForm} subclass needs at least @@ -50,7 +50,7 @@ class MultiFormStep extends DataObject * * @var boolean */ - public static $is_final_step = false; + private static $is_final_step = false; /** * This variable determines whether a user can use @@ -243,7 +243,7 @@ class MultiFormStep extends DataObject */ public function getNextStep() { - $nextSteps = static::$next_steps; + $nextSteps = $this->config()->get('next_steps'); // Check if next_steps have been implemented properly if not the final step if (!$this->isFinalStep()) { @@ -277,7 +277,7 @@ class MultiFormStep extends DataObject public function getNextStepFromDatabase() { if ($this->SessionID && is_numeric($this->SessionID)) { - $nextSteps = static::$next_steps; + $nextSteps = $this->config()->get('next_steps'); if (is_string($nextSteps)) { return DataObject::get_one($nextSteps, "\"SessionID\" = {$this->SessionID}"); @@ -296,7 +296,7 @@ class MultiFormStep extends DataObject */ public function getNextSteps() { - return static::$next_steps; + return $this->config()->get('next_steps'); } /** @@ -394,7 +394,7 @@ class MultiFormStep extends DataObject */ public function canGoBack() { - return static::$can_go_back; + return $this->config()->get('can_go_back'); } /** @@ -405,7 +405,7 @@ class MultiFormStep extends DataObject */ public function isFinalStep() { - return static::$is_final_step; + return $this->config()->get('is_final_step'); } /** diff --git a/src/tasks/MultiFormPurgeTask.php b/src/tasks/MultiFormPurgeTask.php index cdcb49a..2765a05 100644 --- a/src/tasks/MultiFormPurgeTask.php +++ b/src/tasks/MultiFormPurgeTask.php @@ -27,7 +27,7 @@ class MultiFormPurgeTask extends BuildTask * * @var int */ - public static $session_expiry_days = 7; + private static $session_expiry_days = 7; /** * Run this cron task. @@ -46,7 +46,7 @@ class MultiFormPurgeTask extends BuildTask $delCount++; } } - echo $delCount . ' session records deleted that were older than ' . self::$session_expiry_days . ' days.'; + echo $delCount . ' session records deleted that were older than ' . $this->config()->get('session_expiry_days') . ' days.'; } /** @@ -59,7 +59,7 @@ class MultiFormPurgeTask extends BuildTask { return DataObject::get( MultiFormSession::class, - "DATEDIFF(NOW(), \"MultiFormSession\".\"Created\") > " . self::$session_expiry_days + "DATEDIFF(NOW(), \"MultiFormSession\".\"Created\") > " . $this->config()->get('session_expiry_days') ); } } diff --git a/tests/MultiFormObjectDecoratorTest.php b/tests/MultiFormObjectDecoratorTest.php index f0da517..bbcbc28 100644 --- a/tests/MultiFormObjectDecoratorTest.php +++ b/tests/MultiFormObjectDecoratorTest.php @@ -34,7 +34,6 @@ class MultiFormObjectDecoratorTest extends SapphireTest ->filter(['MultiFormIsTemporary' => 1]) ->map('Name') ->toArray(); - $this->assertNotContains('Test 1', $records); $this->assertNotContains('Test 2', $records); $this->assertContains('Test 3', $records); diff --git a/tests/MultiFormTest.php b/tests/MultiFormTest.php index d0e9169..50b2476 100644 --- a/tests/MultiFormTest.php +++ b/tests/MultiFormTest.php @@ -30,7 +30,7 @@ use SilverStripe\MultiForm\Models\MultiFormSession; */ class MultiFormTest extends FunctionalTest { - public static $fixture_file = 'MultiFormTest.yml'; + protected static $fixture_file = 'MultiFormTest.yml'; /** * @var MultiFormTestController @@ -120,7 +120,11 @@ class MultiFormTest extends FunctionalTest Config::modify()->set(MultiForm::class, '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->config()->get('ignored_fields'), + 'GET var wasn\'t added to ignored fields' + ); $this->assertContains( 'SuperSessionID', $form->FormAction(), diff --git a/tests/Stubs/MultiFormStepOne.php b/tests/Stubs/MultiFormStepOne.php index fdc87b8..1511ce1 100644 --- a/tests/Stubs/MultiFormStepOne.php +++ b/tests/Stubs/MultiFormStepOne.php @@ -14,7 +14,7 @@ use SilverStripe\MultiForm\Models\MultiFormStep; */ class MultiFormTestStepOne extends MultiFormStep implements TestOnly { - public static $next_steps = MultiFormTestStepTwo::class; + private static $next_steps = MultiFormTestStepTwo::class; public function getFields() { diff --git a/tests/Stubs/MultiFormTestForm.php b/tests/Stubs/MultiFormTestForm.php index aeb5ab5..ca569e2 100644 --- a/tests/Stubs/MultiFormTestForm.php +++ b/tests/Stubs/MultiFormTestForm.php @@ -11,10 +11,10 @@ use SilverStripe\MultiForm\Models\MultiForm; */ class MultiFormTestForm extends MultiForm implements TestOnly { - public static $start_step = MultiFormTestStepOne::class; + private static $start_step = MultiFormTestStepOne::class; public function getStartStep() { - return self::$start_step; + return $this->config()->get('start_step'); } } diff --git a/tests/Stubs/MultiFormTestStepThree.php b/tests/Stubs/MultiFormTestStepThree.php index a677c14..1644456 100644 --- a/tests/Stubs/MultiFormTestStepThree.php +++ b/tests/Stubs/MultiFormTestStepThree.php @@ -13,7 +13,7 @@ use SilverStripe\MultiForm\Models\MultiFormStep; */ class MultiFormTestStepThree extends MultiFormStep implements TestOnly { - public static $is_final_step = true; + private static $is_final_step = true; public function getFields() { diff --git a/tests/Stubs/MultiFormTestStepTwo.php b/tests/Stubs/MultiFormTestStepTwo.php index 2ad20d5..e1abf6a 100644 --- a/tests/Stubs/MultiFormTestStepTwo.php +++ b/tests/Stubs/MultiFormTestStepTwo.php @@ -12,7 +12,7 @@ use SilverStripe\MultiForm\Models\MultiFormStep; */ class MultiFormTestStepTwo extends MultiFormStep implements TestOnly { - public static $next_steps = MultiFormTestStepThree::class; + private static $next_steps = MultiFormTestStepThree::class; public function getFields() { From 8c8071460570f8a31e0321606b2f248263b258d0 Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Fri, 8 Sep 2017 14:35:42 +1200 Subject: [PATCH 10/16] FIX replaced class literal with ::class reference --- src/extensions/MultiFormObjectDecorator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extensions/MultiFormObjectDecorator.php b/src/extensions/MultiFormObjectDecorator.php index 5ae6720..6997204 100644 --- a/src/extensions/MultiFormObjectDecorator.php +++ b/src/extensions/MultiFormObjectDecorator.php @@ -2,6 +2,7 @@ namespace SilverStripe\MultiForm\Extensions; +use SilverStripe\MultiForm\Models\MultiFormSession; use SilverStripe\ORM\DataExtension; use SilverStripe\ORM\DataQuery; use SilverStripe\ORM\Queries\SQLSelect; @@ -22,13 +23,12 @@ use SilverStripe\ORM\Queries\SQLSelect; */ class MultiFormObjectDecorator extends DataExtension { - private static $db = [ 'MultiFormIsTemporary' => 'Boolean', ]; private static $has_one = [ - 'MultiFormSession' => 'MultiFormSession', + 'MultiFormSession' => MultiFormSession::class, ]; /** From 49cecd7777c92ae79726cdbc520fd004e9977841 Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Fri, 8 Sep 2017 14:38:27 +1200 Subject: [PATCH 11/16] Fixed PSR4 namespaces in composer.json --- composer.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/composer.json b/composer.json index 9996f3b..1e3a2ed 100644 --- a/composer.json +++ b/composer.json @@ -28,5 +28,11 @@ "branch-alias": { "dev-master": "2.x-dev" } + }, + "autoload": { + "psr-4": { + "SilverStripe\\MultiForm\\": "src/", + "SilverStripe\\MultiForm\\Tests\\": "tests/" + } } } From 8bd277d9f12487d6f8dbac43295a978f4e81ad86 Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Fri, 8 Sep 2017 15:05:49 +1200 Subject: [PATCH 12/16] FIX updated wantsTemporary query --- src/extensions/MultiFormObjectDecorator.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/extensions/MultiFormObjectDecorator.php b/src/extensions/MultiFormObjectDecorator.php index 6997204..594a73b 100644 --- a/src/extensions/MultiFormObjectDecorator.php +++ b/src/extensions/MultiFormObjectDecorator.php @@ -69,7 +69,8 @@ class MultiFormObjectDecorator extends DataExtension 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'") { + $key = key($whereClause); + if ($key == "{$from[0]}.\"MultiFormIsTemporary\" = ?" && current($whereClause[$key]) == 1) { return true; } } From 7a3cc2e2ab1bba19e192e4bad5f33f288db29f5a Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Fri, 8 Sep 2017 15:06:47 +1200 Subject: [PATCH 13/16] Updated travis config to use recipe-core --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5a002b4..51c2ef3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ before_script: # Install composer dependencies - composer install --prefer-dist - - composer require --prefer-dist --no-update silverstripe/recipe-framework:1.0.x-dev + - composer require --prefer-dist --no-update silverstripe/recipe-core:1.0.x-dev - if [[ $DB == PGSQL ]]; then composer require --prefer-dist --no-update silverstripe/postgresql:2.0.x-dev; fi - composer update From 1331a60fd7a1f0dbd71755cdf7ddfd20983da032 Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Fri, 8 Sep 2017 15:59:53 +1200 Subject: [PATCH 14/16] FIX PR review fixes * removed @package references * included stubs in the test namespaces * updated various return types * updated composr psr4 autoload classes * doc update --- README.md | 2 +- composer.json | 6 ++++-- lang/en.yml | 6 +++--- src/Models/MultiForm.php | 1 - src/Models/MultiFormSession.php | 1 - src/Models/MultiFormStep.php | 7 +++---- src/extensions/MultiFormObjectDecorator.php | 1 - src/tasks/MultiFormPurgeTask.php | 6 ++++-- templates/Includes/MultiFormProgressPercent.ss | 2 +- tests/MultiFormObjectDecoratorTest.php | 1 + tests/MultiFormObjectDecoratorTest.yml | 2 +- tests/MultiFormTest.php | 6 ++++-- tests/Stubs/MultiFormObjectDecoratorDataObject.php | 2 +- tests/Stubs/MultiFormStepOne.php | 6 +----- tests/Stubs/MultiFormTestController.php | 6 +----- tests/Stubs/MultiFormTestForm.php | 6 +----- tests/Stubs/MultiFormTestStepThree.php | 6 +----- tests/Stubs/MultiFormTestStepTwo.php | 6 +----- 18 files changed, 28 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 46d295e..c46e0d2 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 diff --git a/composer.json b/composer.json index 1e3a2ed..0b145df 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,6 @@ "phpunit/phpunit": "^5.7", "squizlabs/php_codesniffer": "^3.0" }, - "license": "BSD-3-Clause", "extra": { "branch-alias": { "dev-master": "2.x-dev" @@ -34,5 +33,8 @@ "SilverStripe\\MultiForm\\": "src/", "SilverStripe\\MultiForm\\Tests\\": "tests/" } - } + }, + "license": "BSD-3-Clause", + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/lang/en.yml b/lang/en.yml index 5d8ffa9..a50a0d9 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -1,11 +1,11 @@ en: - MultiForm: + SilverStripe\MultiForm\MultiForm: BACK: Back NEXT: Next SUBMIT: Submit - MultiFormSession: + SilverStripe\MultiForm\MultiFormSession: PLURALNAME: 'Multi Form Sessions' SINGULARNAME: 'Multi Form Session' - MultiFormStep: + SilverStripe\MultiForm\MultiFormStep: PLURALNAME: 'Multi Form Steps' SINGULARNAME: 'Multi Form Step' diff --git a/src/Models/MultiForm.php b/src/Models/MultiForm.php index 2d9a81c..5882d25 100644 --- a/src/Models/MultiForm.php +++ b/src/Models/MultiForm.php @@ -28,7 +28,6 @@ use SilverStripe\View\SSViewer; * private static $allowed_actions = array('next','prev'); * * - * @package multiform */ abstract class MultiForm extends Form { diff --git a/src/Models/MultiFormSession.php b/src/Models/MultiFormSession.php index 39ecb45..7b92259 100644 --- a/src/Models/MultiFormSession.php +++ b/src/Models/MultiFormSession.php @@ -14,7 +14,6 @@ use SilverStripe\Security\Security; * the {@link MultiForm} and {@link MultiFormStep} classes * know what the current step is. * - * @package multiform */ class MultiFormSession extends DataObject { diff --git a/src/Models/MultiFormStep.php b/src/Models/MultiFormStep.php index 5962e20..493b3a0 100644 --- a/src/Models/MultiFormStep.php +++ b/src/Models/MultiFormStep.php @@ -15,7 +15,6 @@ use SilverStripe\ORM\DataObject; * in the process by knowing what it's next step is, and if applicable, it's previous * step. * - * @package multiform */ class MultiFormStep extends DataObject { @@ -142,7 +141,7 @@ class MultiFormStep extends DataObject */ public function getTitle() { - return $this->title ? $this->title : $this->class; + return $this->title ? $this->title : get_class($this); } /** @@ -272,7 +271,7 @@ class MultiFormStep extends DataObject * 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 + * @return MultiFormStep|boolean|void */ public function getNextStepFromDatabase() { @@ -305,7 +304,7 @@ class MultiFormStep extends DataObject * 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 + * @return string|void Classname of a {@link MultiFormStep} subclass */ public function getPreviousStep() { diff --git a/src/extensions/MultiFormObjectDecorator.php b/src/extensions/MultiFormObjectDecorator.php index 594a73b..ff9975f 100644 --- a/src/extensions/MultiFormObjectDecorator.php +++ b/src/extensions/MultiFormObjectDecorator.php @@ -19,7 +19,6 @@ use SilverStripe\ORM\Queries\SQLSelect; * in your WHERE clause: * ``.`MultiFormIsTemporary` = 1 * - * @package multiform */ class MultiFormObjectDecorator extends DataExtension { diff --git a/src/tasks/MultiFormPurgeTask.php b/src/tasks/MultiFormPurgeTask.php index 2765a05..6b2b359 100644 --- a/src/tasks/MultiFormPurgeTask.php +++ b/src/tasks/MultiFormPurgeTask.php @@ -17,7 +17,6 @@ use SilverStripe\ORM\DataObject; * or * `framework/sake MultiFormPurgeTask` * - * @package multiform */ class MultiFormPurgeTask extends BuildTask { @@ -29,6 +28,8 @@ class MultiFormPurgeTask extends BuildTask */ private static $session_expiry_days = 7; + private static $segment = 'MultiFormPurgeTask'; + /** * Run this cron task. * @@ -46,7 +47,8 @@ class MultiFormPurgeTask extends BuildTask $delCount++; } } - echo $delCount . ' session records deleted that were older than ' . $this->config()->get('session_expiry_days') . ' days.'; + echo $delCount . ' session records deleted that were older than ' + . $this->config()->get('session_expiry_days') . ' days.'. PHP_EOL; } /** diff --git a/templates/Includes/MultiFormProgressPercent.ss b/templates/Includes/MultiFormProgressPercent.ss index a1d919b..d47b1de 100644 --- a/templates/Includes/MultiFormProgressPercent.ss +++ b/templates/Includes/MultiFormProgressPercent.ss @@ -1 +1 @@ -

<%t MULTIFORM.ProgressPercent "You've completed {percent}% ({completedSteps}/{totalSteps})" percent=$CompletedPercent.Nice completedSteps=$CompletedStepCount totalSteps$TotalStepCount %>

+

<%t SilverStripe\\MultiForm\\MultiForm.ProgressPercent "You've completed {percent}% ({completedSteps}/{totalSteps})" percent=$CompletedPercent.Nice completedSteps=$CompletedStepCount totalSteps$TotalStepCount %>

diff --git a/tests/MultiFormObjectDecoratorTest.php b/tests/MultiFormObjectDecoratorTest.php index bbcbc28..9ef0137 100644 --- a/tests/MultiFormObjectDecoratorTest.php +++ b/tests/MultiFormObjectDecoratorTest.php @@ -4,6 +4,7 @@ namespace SilverStripe\MultiForm\Tests; use SilverStripe\Dev\SapphireTest; use SilverStripe\MultiForm\Extensions\MultiFormObjectDecorator; +use SilverStripe\MultiForm\Tests\Stubs\MultiFormObjectDecoratorDataObject; class MultiFormObjectDecoratorTest extends SapphireTest { diff --git a/tests/MultiFormObjectDecoratorTest.yml b/tests/MultiFormObjectDecoratorTest.yml index 1b4fca3..2ce3b5e 100644 --- a/tests/MultiFormObjectDecoratorTest.yml +++ b/tests/MultiFormObjectDecoratorTest.yml @@ -1,4 +1,4 @@ -SilverStripe\MultiForm\Tests\MultiFormObjectDecoratorDataObject: +SilverStripe\MultiForm\Tests\Stubs\MultiFormObjectDecoratorDataObject: test-data-1: Name: Test 1 MultiFormIsTemporary: 0 diff --git a/tests/MultiFormTest.php b/tests/MultiFormTest.php index 50b2476..d09d73e 100644 --- a/tests/MultiFormTest.php +++ b/tests/MultiFormTest.php @@ -9,6 +9,10 @@ use SilverStripe\Core\Injector\Injector; use SilverStripe\Dev\FunctionalTest; use SilverStripe\MultiForm\Models\MultiForm; use SilverStripe\MultiForm\Models\MultiFormSession; +use SilverStripe\MultiForm\Tests\Stubs\MultiFormTestController; +use SilverStripe\MultiForm\Tests\Stubs\MultiFormTestForm; +use SilverStripe\MultiForm\Tests\Stubs\MultiFormTestStepOne; +use SilverStripe\MultiForm\Tests\Stubs\MultiFormTestStepTwo; /** * MultiFormTest @@ -25,8 +29,6 @@ use SilverStripe\MultiForm\Models\MultiFormSession; * is a simulation of a page where MultiFormTest_Form is a simple * multi-step contact form it belongs to. * - * @package multiform - * @subpackage tests */ class MultiFormTest extends FunctionalTest { diff --git a/tests/Stubs/MultiFormObjectDecoratorDataObject.php b/tests/Stubs/MultiFormObjectDecoratorDataObject.php index 7b05c4d..45be595 100644 --- a/tests/Stubs/MultiFormObjectDecoratorDataObject.php +++ b/tests/Stubs/MultiFormObjectDecoratorDataObject.php @@ -1,6 +1,6 @@ Date: Fri, 8 Sep 2017 16:11:33 +1200 Subject: [PATCH 15/16] FIX updated upgrade.yml --- .upgrade.yml | 26 +++++++++++++------------- README.md | 4 +++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.upgrade.yml b/.upgrade.yml index 8104798..63633ab 100644 --- a/.upgrade.yml +++ b/.upgrade.yml @@ -1,14 +1,14 @@ mappings: - MultiFormObjectDecorator: SilverStripe\MultiForm\MultiFormObjectDecorator - MultiForm: SilverStripe\MultiForm\MultiForm - MultiFormSession: SilverStripe\MultiForm\MultiFormSession - MultiFormStep: SilverStripe\MultiForm\MultiFormStep - MultiFormPurgeTask: SilverStripe\MultiForm\MultiFormPurgeTask - MultiFormObjectDecoratorTest: SilverStripe\MultiForm\MultiFormObjectDecoratorTest - MultiFormObjectDecorator_DataObject: SilverStripe\MultiForm\MultiFormObjectDecorator_DataObject - MultiFormTest: SilverStripe\MultiForm\MultiFormTest - MultiFormTest_Controller: SilverStripe\MultiForm\MultiFormTest_Controller - MultiFormTest_Form: SilverStripe\MultiForm\MultiFormTest_Form - MultiFormTest_StepOne: SilverStripe\MultiForm\MultiFormTest_StepOne - MultiFormTest_StepTwo: SilverStripe\MultiForm\MultiFormTest_StepTwo - MultiFormTest_StepThree: SilverStripe\MultiForm\MultiFormTest_StepThree + MultiFormObjectDecorator: SilverStripe\MultiForm\Extensions\MultiFormObjectDecorator + MultiForm: SilverStripe\MultiForm\Models\MultiForm + MultiFormSession: SilverStripe\MultiForm\Models\MultiFormSession + MultiFormStep: SilverStripe\MultiForm\Models\MultiFormStep + MultiFormPurgeTask: SilverStripe\MultiForm\Tasks\MultiFormPurgeTask + MultiFormObjectDecoratorTest: SilverStripe\MultiForm\Tests\MultiFormObjectDecoratorTest + MultiFormObjectDecoratorDataObject: SilverStripe\MultiForm\Tests\Stubs\MultiFormObjectDecoratorDataObject + MultiFormTest: SilverStripe\MultiForm\Tests\MultiFormTest + MultiFormTestController: SilverStripe\MultiForm\Tests\Stubs\MultiFormTestController + MultiFormTestForm: SilverStripe\MultiForm\Tests\Stubs\MultiFormTestForm + MultiFormTestStepOne: SilverStripe\MultiForm\Tests\Stubs\MultiFormTestStepOne + MultiFormTestStepTwo: SilverStripe\MultiForm\Tests\Stubs\MultiFormTestStepTwo + MultiFormTestStepThree: SilverStripe\MultiForm\Tests\Stubs\MultiFormTestStepThree diff --git a/README.md b/README.md index c46e0d2..0bb61dc 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,9 @@ 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 From f2e37e4b02d8e82661d1015bc5881e5254126cde Mon Sep 17 00:00:00 2001 From: Franco Springveldt Date: Fri, 8 Sep 2017 16:22:12 +1200 Subject: [PATCH 16/16] FIX added versioned to dev requirements --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0b145df..52f0695 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,8 @@ }, "require-dev": { "phpunit/phpunit": "^5.7", - "squizlabs/php_codesniffer": "^3.0" + "squizlabs/php_codesniffer": "^3.0", + "silverstripe/versioned": "^1@dev" }, "extra": { "branch-alias": {