Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

NEW Docs for form validation (incl. HTML5 types) and model validatoin

  • Loading branch information...
commit 0236a3c03a9bf3332a7fc3a8bdb54347de1db0e9 1 parent 3ef394c
Ingo Schommer chillu authored
Showing with 141 additions and 36 deletions.
  1. +39 −0 docs/en/topics/datamodel.md
  2. +102 −36 docs/en/topics/form-validation.md
39 docs/en/topics/datamodel.md
View
@@ -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
138 docs/en/topics/form-validation.md
View
@@ -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,49 +29,114 @@ class.
return $form;
}
-### Subclassing Validator
+## Form Field Validation
-To create your own validator, you need to subclass validator and define two methods:
+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).
- * **javascript()** Should output a snippet of JavaScript that will get called to perform javascript validation.
- * **php($data)** Should return true if the given data is valid, and call $this->validationError() if there were any
-errors.
+## Adding your own validation messages
-## JavaScript
+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.
-### Default validator.js implementation
+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.
-TODO Describe behaviour.js solution easily, how to disable it
+Example: Validate postcodes based on the selected country (on the controller).
-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.",
+ :::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...
+ }
}
- });
-### Other validation libraries
+## JavaScript Validation
-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)).
+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.
-Disable for all forms (in `mysite/_config.php`):
+### 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
- Validator::set_javascript_validation_handler('none');
+ // 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?://.+')
-Disable for a specific form:
+### 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
- $myForm->getValidator()->setJavascriptValidationHandler('none');
+ // 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:
+
+ * **javascript()** Should output a snippet of JavaScript that will get called to perform javascript validation.
+ * **php($data)** Should return true if the given data is valid, and call $this->validationError() if there were any
+errors.
## Related
Please sign in to comment.
Something went wrong with that request. Please try again.