mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 17:05:42 +02: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
|
||||
$step = EditableFormStep::create();
|
||||
$step->Title = _t('EditableFormStep.TITLE_FIRST', 'First Step');
|
||||
$step->Title = _t('EditableFormStep.TITLE_FIRST', 'First Page');
|
||||
$step->Sort = 1;
|
||||
$step->write();
|
||||
$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');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate formfields
|
||||
*/
|
||||
public function getCMSValidator() {
|
||||
return new UserFormValidator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,6 +5,10 @@
|
||||
*/
|
||||
class EditableFieldGroup extends EditableFormField {
|
||||
|
||||
private static $has_one = array(
|
||||
'End' => 'EditableFieldGroupEnd'
|
||||
);
|
||||
|
||||
/**
|
||||
* Disable selection of group class
|
||||
*
|
||||
@ -19,13 +23,20 @@ class EditableFieldGroup extends EditableFormField {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function getInlineClassnameField($column, $fieldClasses) {
|
||||
return new LabelField(
|
||||
$column,
|
||||
_t('EditableFieldGroup.FIELD_GROUP_START', 'Field Group (start)')
|
||||
public function getCMSTitle() {
|
||||
return _t(
|
||||
'EditableFieldGroupEnd.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() {
|
||||
return false;
|
||||
}
|
||||
@ -49,5 +60,21 @@ class EditableFieldGroup extends EditableFormField {
|
||||
$field->addExtraClass($field->ExtraClass);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
private static $belongs_to = array(
|
||||
'Group' => 'EditableFieldGroup'
|
||||
);
|
||||
|
||||
/**
|
||||
* Disable selection of group class
|
||||
*
|
||||
@ -13,6 +17,17 @@ class EditableFieldGroupEnd extends EditableFormField {
|
||||
*/
|
||||
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() {
|
||||
$fields = parent::getCMSFields();
|
||||
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'DisplayRules'));
|
||||
@ -20,10 +35,7 @@ class EditableFieldGroupEnd extends EditableFormField {
|
||||
}
|
||||
|
||||
public function getInlineClassnameField($column, $fieldClasses) {
|
||||
return new LabelField(
|
||||
$column,
|
||||
_t('EditableFieldGroupEnd.FIELD_GROUP_END', 'Field Group (end)')
|
||||
);
|
||||
return new LabelField($column, $this->CMSTitle);
|
||||
}
|
||||
|
||||
public function getInlineTitleField($column) {
|
||||
@ -38,8 +50,37 @@ class EditableFieldGroupEnd extends EditableFormField {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canEdit($member = null) {
|
||||
return false;
|
||||
public function onAfterWrite() {
|
||||
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);
|
||||
}
|
||||
|
||||
public function getCMSTitle() {
|
||||
return $this->i18n_singular_name() . ' (' . $this->Title . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since version 4.0
|
||||
*/
|
||||
|
@ -6,6 +6,10 @@
|
||||
*/
|
||||
class EditableFormStep extends EditableFormField {
|
||||
|
||||
private static $singular_name = 'Page Break';
|
||||
|
||||
private static $plural_name = 'Page Breaks';
|
||||
|
||||
/**
|
||||
* Disable selection of step class
|
||||
*
|
||||
@ -14,18 +18,6 @@ class EditableFormStep extends EditableFormField {
|
||||
*/
|
||||
private static $hidden = true;
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var string
|
||||
*/
|
||||
private static $singular_name = 'Step';
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var string
|
||||
*/
|
||||
private static $plural_name = 'Steps';
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
@ -64,7 +56,15 @@ class EditableFormStep extends EditableFormField {
|
||||
public function getInlineClassnameField($column, $fieldClasses) {
|
||||
return new LabelField(
|
||||
$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…
Reference in New Issue
Block a user