mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
NEW Docs for form validation (incl. HTML5 types) and model validatoin
This commit is contained in:
parent
3ef394c448
commit
0236a3c03a
@ -569,6 +569,45 @@ the described relations).
|
||||
}
|
||||
}
|
||||
|
||||
## Validation and Constraints
|
||||
|
||||
Traditionally, validation in SilverStripe has been mostly handled on the controller
|
||||
through [form validation](/topics/form-validation).
|
||||
While this is a useful approach, it can lead to data inconsistencies if the
|
||||
record is modified outside of the controller and form context.
|
||||
Most validation constraints are actually data constraints which belong on the model.
|
||||
SilverStripe provides the `[api:DataObject->validate()]` method for this purpose.
|
||||
|
||||
By default, there is no validation - objects are always valid!
|
||||
However, you can overload this method in your
|
||||
DataObject sub-classes to specify custom validation,
|
||||
or use the hook through `[api:DataExtension]`.
|
||||
|
||||
Invalid objects won't be able to be written - a [api:ValidationException]`
|
||||
will be thrown and no write will occur.
|
||||
It is expected that you call validate() in your own application to test that an object
|
||||
is valid before attempting a write, and respond appropriately if it isn't.
|
||||
|
||||
The return value of `validate()` is a `[api:ValidationResult]` object.
|
||||
You can append your own errors in there.
|
||||
|
||||
Example: Validate postcodes based on the selected country
|
||||
|
||||
:::php
|
||||
class MyObject extends DataObject {
|
||||
static $db = array(
|
||||
'Country' => 'Varchar',
|
||||
'Postcode' => 'Varchar'
|
||||
);
|
||||
public function validate() {
|
||||
$result = parent::validate();
|
||||
if($this->Country == 'DE' && $this->Postcode && strlen($this->Postcode) != 5) {
|
||||
$result->error('Need five digits for German postcodes');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
## Maps
|
||||
|
||||
A map is an array where the array indexes contain data as well as the values. You can build a map
|
||||
|
@ -1,15 +1,16 @@
|
||||
# Form Validation
|
||||
|
||||
Form validation is a combination of PHP and JavaScript
|
||||
SilverStripe provides PHP form validation out of the box,
|
||||
but doesn't come with any built-in JavaScript validation
|
||||
(the previously used `Validator.js` approach has been deprecated).
|
||||
|
||||
## PHP
|
||||
|
||||
### Introduction
|
||||
|
||||
Validators are implemented as an argument to the `[api:Form]` constructor. You create a required fields validator like
|
||||
so. In this case, we're creating a `[api:RequiredFields]` validator - the `[api:Validator]` class itself is an abstract
|
||||
class.
|
||||
## Required Fields
|
||||
|
||||
Validators are implemented as an argument to the `[api:Form]` constructor,
|
||||
and are subclasses of the abstract `[api:Validator]` base class.
|
||||
The only implementation which comes with SilverStripe is
|
||||
the `[api:RequiredFields]` class, which ensures fields are filled out
|
||||
when the form is submitted.
|
||||
|
||||
:::php
|
||||
public function Form() {
|
||||
@ -19,7 +20,7 @@ class.
|
||||
new TextField('MyOptionalField')
|
||||
),
|
||||
new FieldList(
|
||||
new FormAction('submit', 'Submit')
|
||||
new FormAction('submit', 'Submit form')
|
||||
),
|
||||
new RequiredFields(array('MyRequiredField'))
|
||||
);
|
||||
@ -28,7 +29,108 @@ class.
|
||||
return $form;
|
||||
}
|
||||
|
||||
### Subclassing Validator
|
||||
## Form Field Validation
|
||||
|
||||
Form fields are responsible for validating the data they process,
|
||||
through the `[api:FormField->validate()] method. There are many fields
|
||||
for different purposes (see ["form field types"](/reference/form-field-types) for a full list).
|
||||
|
||||
## Adding your own validation messages
|
||||
|
||||
In many cases, you want to add PHP validation which is more complex than
|
||||
validating the format or existence of a single form field input.
|
||||
For example, you might want to have dependent validation on
|
||||
a postcode which depends on the country you've selected in a different field.
|
||||
|
||||
There's two ways to go about this: Either you can attach a custom error message
|
||||
to a specific field, or a generic message for the whole form.
|
||||
|
||||
Example: Validate postcodes based on the selected country (on the controller).
|
||||
|
||||
:::php
|
||||
class MyController extends Controller {
|
||||
public function Form() {
|
||||
return Form::create($this, 'Form',
|
||||
new FieldList(
|
||||
new NumericField('Postcode'),
|
||||
new CountryDropdownField('Country')
|
||||
),
|
||||
new FieldList(
|
||||
new FormAction('submit', 'Submit form')
|
||||
),
|
||||
new RequiredFields(array('Country'))
|
||||
);
|
||||
}
|
||||
public function submit($data, $form) {
|
||||
// At this point, RequiredFields->validate() will have been called already,
|
||||
// so we can assume that the values exist.
|
||||
|
||||
// German postcodes need to be five digits
|
||||
if($data['Country'] == 'de' && isset($data['Postcode']) && strlen($data['Postcode']) != 5) {
|
||||
$form->addErrorMessage('Postcode', 'Need five digits for German postcodes', 'bad');
|
||||
return $this->redirectBack();
|
||||
}
|
||||
|
||||
// Global validation error (not specific to form field)
|
||||
if($data['Country'] == 'IR' && isset($data['Postcode']) && $data['Postcode']) {
|
||||
$form->sessionMessage("Ireland doesn't have postcodes!", 'bad');
|
||||
return $this->redirectBack();
|
||||
}
|
||||
|
||||
// continue normal processing...
|
||||
}
|
||||
}
|
||||
|
||||
## JavaScript Validation
|
||||
|
||||
While there are no built-in JavaScript validation handlers in SilverStripe,
|
||||
the `FormField` API is flexible enough to provide the information required
|
||||
in order to plug in custom libraries.
|
||||
|
||||
### HTML5 attributes
|
||||
|
||||
HTML5 specifies some built-in form validations ([source](http://www.w3.org/wiki/HTML5_form_additions)),
|
||||
which are evaluated by modern browsers without any need for JavaScript.
|
||||
SilverStripe supports this by allowing to set custom attributes on fields.
|
||||
|
||||
:::php
|
||||
// Markup contains <input type="text" required />
|
||||
TextField::create('MyText')->setAttribute('required', true);
|
||||
|
||||
// Markup contains <input type="url" pattern="https?://.+" />
|
||||
TextField::create('MyText')
|
||||
->setAttribute('type', 'url')
|
||||
->setAttribute('pattern', 'https?://.+')
|
||||
|
||||
### HTML5 metadata
|
||||
|
||||
In addition, HTML5 elements can contain custom data attributes with the `data-` prefix.
|
||||
These are general purpose attributes, but can be used to hook in your own validation.
|
||||
|
||||
:::php
|
||||
// Validate a specific date format (in PHP)
|
||||
// Markup contains <input type="text" data-dateformat="dd.MM.yyyy" />
|
||||
DateField::create('MyDate')->setConfig('dateformat', 'dd.MM.yyyy');
|
||||
|
||||
// Limit extensions on upload (in PHP)
|
||||
// Markup contains <input type="file" data-allowed-extensions="jpg,jpeg,gif" />
|
||||
$exts = array('jpg', 'jpeg', 'gif');
|
||||
$validator = new Upload_Validator();
|
||||
$validator->setAllowedExtensions($exts);
|
||||
$upload = Upload::create()->setValidator($validator);
|
||||
$fileField = FileField::create('MyFile')->setUpload(new);
|
||||
$fileField->setAttribute('data-allowed-extensions', implode(',', $exts));
|
||||
|
||||
Note that these examples don't have any effect on the client as such,
|
||||
but are just a starting point for custom validation with JavaScript.
|
||||
|
||||
## Model Validation
|
||||
|
||||
An alternative (or additional) approach to validation is to place it directly
|
||||
on the model. SilverStripe provides a `[api:DataObject->validate()]` method for this purpose.
|
||||
Refer to the ["datamodel" topic](/topics/datamodel#validation-and-constraints) for more information.
|
||||
|
||||
## Subclassing Validator
|
||||
|
||||
To create your own validator, you need to subclass validator and define two methods:
|
||||
|
||||
@ -36,42 +138,6 @@ To create your own validator, you need to subclass validator and define two meth
|
||||
* **php($data)** Should return true if the given data is valid, and call $this->validationError() if there were any
|
||||
errors.
|
||||
|
||||
## JavaScript
|
||||
|
||||
### Default validator.js implementation
|
||||
|
||||
TODO Describe behaviour.js solution easily, how to disable it
|
||||
|
||||
Setting fieldEl.requiredErrorMsg or formEl.requiredErrorMsg will override the default error message. Both can include
|
||||
the string '$FieldLabel', which will be replaced with the field's label. Otherwise, the message is "Please fill out
|
||||
"$FieldLabel", it is required".
|
||||
|
||||
You can use Behaviour to load in the appropriate value:
|
||||
|
||||
:::js
|
||||
Behaviour.register({
|
||||
'#Form_Form' : {
|
||||
requiredErrorMsg: "Please complete this question before moving on.",
|
||||
}
|
||||
});
|
||||
|
||||
### Other validation libraries
|
||||
|
||||
By default, SilverStripe forms with an attached Validator instance use the custom Validator.js clientside logic. It is
|
||||
quite hard to customize, and might not be appropriate for all use-cases. You can disable integrated clientside
|
||||
validation, and use your own (e.g. [jquery.validate](http://docs.jquery.com/Plugins/Validation)).
|
||||
|
||||
Disable for all forms (in `mysite/_config.php`):
|
||||
|
||||
:::php
|
||||
Validator::set_javascript_validation_handler('none');
|
||||
|
||||
Disable for a specific form:
|
||||
|
||||
:::php
|
||||
$myForm->getValidator()->setJavascriptValidationHandler('none');
|
||||
|
||||
|
||||
## Related
|
||||
|
||||
* Model Validation with [api:DataObject->validate()]
|
Loading…
Reference in New Issue
Block a user