is there a way to use the required fields for form validation after submission in order to give a proper error message via setSessionMessage()? If I understand it right, the required fields are preventing the form submission if they are not set and the page is just reloaded - so the submit function is not called. So my question is, do I have to check in the submit function manually for the required fields just to have custom error messages? Thx, Florian
2 回答
SilverStripe forms are more complex than one would believe at first glance.
you are right, the validator is checked before submitting, and only if the validator returns true the form action will be called. (also note that the form action is never exposed as URL, the URL is always the form it self, which then calls the form action.)
on validation error, errors are set (into session) and the form redirects back. then the errors are fetched from the session.
silverstripe forms are built with custom validation in mind. There is a class called Validator, everything that extends this class can be used to validate a form. (RequiredFields is a subclass of Validator). so you can built your own validator this way. But if you are looking for common validation cases the awesome NetefxValidator module might be what you are looking for: https://github.com/lx-berlin/NetefxValidator
it provides many rules to validate your form, for example:
- less then
- greater than
- text equals
- text contains
- regex
- ...
it can also combine rules with and
, or
and xor
(full list at https://github.com/lx-berlin/NetefxValidator/tree/master/code/rules)
it even lets you specify a custom php function to validate, like so:
# SilverStripe 3.x (but with some slight modifications it should also work in 2.x)
$fields = FieldList::create(array(
TextField::create('myField', 'some label')
));
$actions = FieldList::create(array(
FormAction::create('doSend', 'submit'),
));
$myValidationFunction = function ($data, $args) {
if ($data['myField'] == 'zauberfisch is awesome' && $args['someOtherThing'] == 'yay') {
// only allow this form to pass if the user acknowledges that zauberfisch is awesome
return true;
} else {
return false;
}
};
$additionalArguments = array('something' => 'ohai', 'someOtherThing' => 'yay');
$rule = NetefxValidatorRuleFUNCTION::create(
$fieldName = 'myField',
$errorMessage = 'to bad, you did not fill this field correctly',
null,
array($myValidationFunction, $additionalArguments)
);
$validator = NetefxValidator::create(array($rule));
$form = Form::create($this, $fields, $actions, $validator);
NOTE: Form::create()
is basicly the same as new Form()
about the idea that you want to set an error message in the form action: BAD idea, you will run into countless troubles trying to do this. the validator class exists for a reason, don't try to abuse something else to do what the validator should do
EDIT: to answer your question more clearly:
no, it is no possible to set your own error message, you need to use a custom validator for this.
Although it's possible I'm Doing It Wrong™, here's how I'm doing what I think you want.
<?php
class Thing_Controller extends Page_Controller {
/**
* Controller action for the page with the form on it
*/
public function page() {
$this->ThingForm = $this->page_form();
// Render using custom template templates/Layout/ThingFormPage.ss
// which contains $ThingForm to output
return $this->renderWith(array('ThingFormPage','Page'));
}
/**
* Return form definition
* Used both to display it and for validation
*/
public function page_form() {
$fields = new FieldList(
new TextboxField('MyFormInput', 'Input Your Kerjiggers')
);
$actions = new FieldList($this->forwardButton());
$required_fields = new RequiredFields(array('MyFormInput'));
$form = new Form($this, 'Thing_Form', $fields, $actions, $required_fields);
$form->setTemplate("Thing_Form");
$form->setFormAction("Thing/page_save");
$this->setFormMessageIfErrors($form);
return $form;
}
/**
* Validation, save and redirect
*/
public function page_save() {
$data = $this->request->postVars();
$form = $this->page_form();
$form->loadDataFrom($data);
if ($form->validator->validate() === NULL) {
// All good, proceed
$this->redirect('another_action');
} else {
$errors = $form->validator->validate();
foreach ($errors as $e) {
$form->addErrorMessage($e['fieldName'], $e['message'], $e['messageType']);
}
$this->redirectBack();
}
}
/**
* If there are any errors on any RequiredFields, also set a form-level message at the top
* so people know to scroll down and look for the specific errors.
*/
protected function setFormMessageIfErrors($form) {
$s = $this->getSession()->get_all();
if (@$s['FormInfo']['Thing_Form']['errors']) {
$form->setMessage("Please see the messages about your information below", 'info');
}
}
}