mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 15:05:42 +00:00
Merge pull request #21 from tractorcow/pulls/field-groups
API Formfield validation for nested groups and pages
This commit is contained in:
commit
e839d7eead
@ -115,7 +115,7 @@ class UserFormFieldEditorExtension extends DataExtension {
|
|||||||
|
|
||||||
// Add step
|
// Add step
|
||||||
$step = EditableFormStep::create();
|
$step = EditableFormStep::create();
|
||||||
$step->Title = _t('EditableFormStep.TITLE_FIRST', 'First Step');
|
$step->Title = _t('EditableFormStep.TITLE_FIRST', 'First Page');
|
||||||
$step->Sort = 1;
|
$step->Sort = 1;
|
||||||
$step->write();
|
$step->write();
|
||||||
$fields->add($step);
|
$fields->add($step);
|
||||||
|
108
code/extensions/UserFormValidator.php
Normal file
108
code/extensions/UserFormValidator.php
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
class UserFormValidator extends RequiredFields {
|
||||||
|
public function php($data) {
|
||||||
|
if(!parent::php($data)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip unsaved records
|
||||||
|
if(empty($data['ID']) || !is_numeric($data['ID'])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields = EditableFormField::get()->filter('ParentID', $data['ID'])->sort('"Sort" ASC');
|
||||||
|
|
||||||
|
// Current nesting
|
||||||
|
$stack = array();
|
||||||
|
foreach($fields as $field) {
|
||||||
|
if($field instanceof EditableFormStep) {
|
||||||
|
// Page at top level, or after another page is ok
|
||||||
|
if(empty($stack) || (count($stack) === 1 && $stack[0] instanceof EditableFormStep)) {
|
||||||
|
$stack = array($field);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->validationError(
|
||||||
|
'FormFields',
|
||||||
|
_t(
|
||||||
|
"UserFormValidator.UNEXPECTED_BREAK",
|
||||||
|
"Unexpected page break '{name}' inside nested field '{group}'",
|
||||||
|
array(
|
||||||
|
'name' => $field->CMSTitle,
|
||||||
|
'group' => end($stack)->CMSTitle
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate no pages
|
||||||
|
if(empty($stack)) {
|
||||||
|
$this->validationError(
|
||||||
|
'FormFields',
|
||||||
|
_t(
|
||||||
|
"UserFormValidator.NO_PAGE",
|
||||||
|
"Field '{name}' found before any pages",
|
||||||
|
array(
|
||||||
|
'name' => $field->CMSTitle
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nest field group
|
||||||
|
if($field instanceof EditableFieldGroup) {
|
||||||
|
$stack[] = $field;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unnest field group
|
||||||
|
if($field instanceof EditableFieldGroupEnd) {
|
||||||
|
$top = end($stack);
|
||||||
|
|
||||||
|
// Check that the top is a group at all
|
||||||
|
if(!$top instanceof EditableFieldGroup) {
|
||||||
|
$this->validationError(
|
||||||
|
'FormFields',
|
||||||
|
_t(
|
||||||
|
"UserFormValidator.UNEXPECTED_GROUP_END",
|
||||||
|
"'{name}' found without a matching group",
|
||||||
|
array(
|
||||||
|
'name' => $field->CMSTitle
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the top is the right group
|
||||||
|
if($top->EndID != $field->ID) {
|
||||||
|
$this->validationError(
|
||||||
|
'FormFields',
|
||||||
|
_t(
|
||||||
|
"UserFormValidator.WRONG_GROUP_END",
|
||||||
|
"'{name}' found closes the wrong group '{group}'",
|
||||||
|
array(
|
||||||
|
'name' => $field->CMSTitle,
|
||||||
|
'group' => $top->CMSTitle
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unnest group
|
||||||
|
array_pop($stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -286,6 +286,14 @@ SQL;
|
|||||||
|
|
||||||
DB::alteration_message('Migrated userforms', 'changed');
|
DB::alteration_message('Migrated userforms', 'changed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate formfields
|
||||||
|
*/
|
||||||
|
public function getCMSValidator() {
|
||||||
|
return new UserFormValidator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
class EditableFieldGroup extends EditableFormField {
|
class EditableFieldGroup extends EditableFormField {
|
||||||
|
|
||||||
|
private static $has_one = array(
|
||||||
|
'End' => 'EditableFieldGroupEnd'
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable selection of group class
|
* Disable selection of group class
|
||||||
*
|
*
|
||||||
@ -19,13 +23,20 @@ class EditableFieldGroup extends EditableFormField {
|
|||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getInlineClassnameField($column, $fieldClasses) {
|
public function getCMSTitle() {
|
||||||
return new LabelField(
|
return _t(
|
||||||
$column,
|
'EditableFieldGroupEnd.FIELD_GROUP_START',
|
||||||
_t('EditableFieldGroup.FIELD_GROUP_START', 'Field Group (start)')
|
'Start of {group}',
|
||||||
|
array(
|
||||||
|
'group' => $this->Title ?: 'group'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getInlineClassnameField($column, $fieldClasses) {
|
||||||
|
return new LabelField($column, $this->CMSTitle);
|
||||||
|
}
|
||||||
|
|
||||||
public function showInReports() {
|
public function showInReports() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -50,4 +61,20 @@ class EditableFieldGroup extends EditableFormField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function onBeforeDelete() {
|
||||||
|
parent::onBeforeDelete();
|
||||||
|
|
||||||
|
// Ensures EndID is lazy-loaded for onAfterDelete
|
||||||
|
$this->EndID;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function onAfterDelete() {
|
||||||
|
parent::onAfterDelete();
|
||||||
|
|
||||||
|
// Delete end
|
||||||
|
if(($end = $this->End()) && $end->exists()) {
|
||||||
|
$end->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
class EditableFieldGroupEnd extends EditableFormField {
|
class EditableFieldGroupEnd extends EditableFormField {
|
||||||
|
|
||||||
|
private static $belongs_to = array(
|
||||||
|
'Group' => 'EditableFieldGroup'
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable selection of group class
|
* Disable selection of group class
|
||||||
*
|
*
|
||||||
@ -13,6 +17,17 @@ class EditableFieldGroupEnd extends EditableFormField {
|
|||||||
*/
|
*/
|
||||||
private static $hidden = true;
|
private static $hidden = true;
|
||||||
|
|
||||||
|
public function getCMSTitle() {
|
||||||
|
$group = $this->Group();
|
||||||
|
return _t(
|
||||||
|
'EditableFieldGroupEnd.FIELD_GROUP_END',
|
||||||
|
'End of {group}',
|
||||||
|
array(
|
||||||
|
'group' => ($group && $group->exists() && $group->Title) ? $group->Title : 'group'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function getCMSFields() {
|
public function getCMSFields() {
|
||||||
$fields = parent::getCMSFields();
|
$fields = parent::getCMSFields();
|
||||||
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'DisplayRules'));
|
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'DisplayRules'));
|
||||||
@ -20,10 +35,7 @@ class EditableFieldGroupEnd extends EditableFormField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getInlineClassnameField($column, $fieldClasses) {
|
public function getInlineClassnameField($column, $fieldClasses) {
|
||||||
return new LabelField(
|
return new LabelField($column, $this->CMSTitle);
|
||||||
$column,
|
|
||||||
_t('EditableFieldGroupEnd.FIELD_GROUP_END', 'Field Group (end)')
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getInlineTitleField($column) {
|
public function getInlineTitleField($column) {
|
||||||
@ -38,8 +50,37 @@ class EditableFieldGroupEnd extends EditableFormField {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canEdit($member = null) {
|
public function onAfterWrite() {
|
||||||
return false;
|
parent::onAfterWrite();
|
||||||
|
|
||||||
|
// If this is not attached to a group, find the first group prior to this
|
||||||
|
// with no end attached
|
||||||
|
$group = $this->Group();
|
||||||
|
if(!($group && $group->exists()) && $this->ParentID) {
|
||||||
|
$group = EditableFieldGroup::get()
|
||||||
|
->filter(array(
|
||||||
|
'ParentID' => $this->ParentID,
|
||||||
|
'Sort:LessThanOrEqual' => $this->Sort
|
||||||
|
))
|
||||||
|
->where('"EditableFieldGroup"."EndID" IS NULL OR "EditableFieldGroup"."EndID" = 0')
|
||||||
|
->sort('"Sort" DESC')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// When a group is found, attach it to this end
|
||||||
|
if($group) {
|
||||||
|
$group->EndID = $this->ID;
|
||||||
|
$group->write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function onAfterDelete() {
|
||||||
|
parent::onAfterDelete();
|
||||||
|
|
||||||
|
// Delete group
|
||||||
|
if(($group = $this->Group()) && $group->exists()) {
|
||||||
|
$group->delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -450,6 +450,10 @@ class EditableFormField extends DataObject {
|
|||||||
return Convert::raw2xml($this->Title);
|
return Convert::raw2xml($this->Title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCMSTitle() {
|
||||||
|
return $this->i18n_singular_name() . ' (' . $this->Title . ')';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated since version 4.0
|
* @deprecated since version 4.0
|
||||||
*/
|
*/
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
*/
|
*/
|
||||||
class EditableFormStep extends EditableFormField {
|
class EditableFormStep extends EditableFormField {
|
||||||
|
|
||||||
|
private static $singular_name = 'Page Break';
|
||||||
|
|
||||||
|
private static $plural_name = 'Page Breaks';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable selection of step class
|
* Disable selection of step class
|
||||||
*
|
*
|
||||||
@ -14,18 +18,6 @@ class EditableFormStep extends EditableFormField {
|
|||||||
*/
|
*/
|
||||||
private static $hidden = true;
|
private static $hidden = true;
|
||||||
|
|
||||||
/**
|
|
||||||
* @config
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private static $singular_name = 'Step';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @config
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private static $plural_name = 'Steps';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return FieldList
|
* @return FieldList
|
||||||
*/
|
*/
|
||||||
@ -64,7 +56,15 @@ class EditableFormStep extends EditableFormField {
|
|||||||
public function getInlineClassnameField($column, $fieldClasses) {
|
public function getInlineClassnameField($column, $fieldClasses) {
|
||||||
return new LabelField(
|
return new LabelField(
|
||||||
$column,
|
$column,
|
||||||
_t('EditableFieldGroupEnd.PAGE_BREAK', 'Page Break')
|
$this->CMSTitle
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCMSTitle() {
|
||||||
|
$title = $this->i18n_singular_name();
|
||||||
|
if($this->Title) {
|
||||||
|
$title .= ' (' . $this->Title . ')';
|
||||||
|
}
|
||||||
|
return $title;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user