Skip to content
This repository
Browse code

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

  • Loading branch information...
commit 0236a3c03a9bf3332a7fc3a8bdb54347de1db0e9 1 parent 3ef394c
Ingo Schommer authored June 28, 2012
39  docs/en/topics/datamodel.md
Source Rendered
@@ -569,6 +569,45 @@ the described relations).
569 569
 	  }
570 570
 	}
571 571
 
  572
+## Validation and Constraints
  573
+
  574
+Traditionally, validation in SilverStripe has been mostly handled on the controller
  575
+through [form validation](/topics/form-validation).
  576
+While this is a useful approach, it can lead to data inconsistencies if the
  577
+record is modified outside of the controller and form context.
  578
+Most validation constraints are actually data constraints which belong on the model.
  579
+SilverStripe provides the `[api:DataObject->validate()]` method for this purpose.
  580
+
  581
+By default, there is no validation - objects are always valid!  
  582
+However, you can overload this method in your
  583
+DataObject sub-classes to specify custom validation, 
  584
+or use the hook through `[api:DataExtension]`.
  585
+
  586
+Invalid objects won't be able to be written - a [api:ValidationException]` 
  587
+will be thrown and no write will occur.
  588
+It is expected that you call validate() in your own application to test that an object 
  589
+is valid before attempting a write, and respond appropriately if it isn't.
  590
+
  591
+The return value of `validate()` is a `[api:ValidationResult]` object.
  592
+You can append your own errors in there.
  593
+
  594
+Example: Validate postcodes based on the selected country
  595
+
  596
+	:::php
  597
+	class MyObject extends DataObject {
  598
+		static $db = array(
  599
+			'Country' => 'Varchar',
  600
+			'Postcode' => 'Varchar'
  601
+		);
  602
+		public function validate() {
  603
+			$result = parent::validate();
  604
+			if($this->Country == 'DE' && $this->Postcode && strlen($this->Postcode) != 5) {
  605
+				$result->error('Need five digits for German postcodes');
  606
+			}
  607
+			return $result;
  608
+		}
  609
+	}
  610
+
572 611
 ## Maps
573 612
 
574 613
 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
Source Rendered
... ...
@@ -1,15 +1,16 @@
1 1
 # Form Validation
2 2
 
3  
-Form validation is a combination of PHP and JavaScript
  3
+SilverStripe provides PHP form validation out of the box,
  4
+but doesn't come with any built-in JavaScript validation
  5
+(the previously used `Validator.js` approach has been deprecated).
4 6
 
5  
-## PHP
6  
-
7  
-### Introduction
8  
-
9  
-Validators are implemented as an argument to the `[api:Form]` constructor.  You create a required fields validator like
10  
-so.  In this case, we're creating a `[api:RequiredFields]` validator - the `[api:Validator]` class itself is an abstract
11  
-class.
  7
+## Required Fields
12 8
 
  9
+Validators are implemented as an argument to the `[api:Form]` constructor,
  10
+and are subclasses of the abstract `[api:Validator]` base class.
  11
+The only implementation which comes with SilverStripe is
  12
+the `[api:RequiredFields]` class, which ensures fields are filled out
  13
+when the form is submitted.
13 14
 
14 15
 	:::php
15 16
 	public function Form() {
@@ -19,7 +20,7 @@ class.
19 20
 				new TextField('MyOptionalField')
20 21
 			),
21 22
 			new FieldList(
22  
-				new FormAction('submit', 'Submit')
  23
+				new FormAction('submit', 'Submit form')
23 24
 			),
24 25
 			new RequiredFields(array('MyRequiredField'))
25 26
 		);
@@ -28,49 +29,114 @@ class.
28 29
 		return $form;
29 30
 	}
30 31
 
31  
-### Subclassing Validator
  32
+## Form Field Validation
32 33
 
33  
-To create your own validator, you need to subclass validator and define two methods:
  34
+Form fields are responsible for validating the data they process,
  35
+through the `[api:FormField->validate()] method. There are many fields
  36
+for different purposes (see ["form field types"](/reference/form-field-types) for a full list).
34 37
 
35  
- *  **javascript()** Should output a snippet of JavaScript that will get called to perform javascript validation.
36  
- *  **php($data)** Should return true if the given data is valid, and call $this->validationError() if there were any
37  
-errors.
  38
+## Adding your own validation messages
38 39
 
39  
-## JavaScript
  40
+In many cases, you want to add PHP validation which is more complex than
  41
+validating the format or existence of a single form field input.
  42
+For example, you might want to have dependent validation on
  43
+a postcode which depends on the country you've selected in a different field.
40 44
 
41  
-### Default validator.js implementation
  45
+There's two ways to go about this: Either you can attach a custom error message
  46
+to a specific field, or a generic message for the whole form.
42 47
 
43  
-TODO Describe behaviour.js solution easily, how to disable it
  48
+Example: Validate postcodes based on the selected country (on the controller).
44 49
 
45  
-Setting fieldEl.requiredErrorMsg or formEl.requiredErrorMsg will override the default error message.  Both can include
46  
-the string '$FieldLabel', which will be replaced with the field's label. Otherwise, the message is "Please fill out
47  
-"$FieldLabel", it is required".
48  
-
49  
-You can use Behaviour to load in the appropriate value:
50  
-
51  
-	:::js
52  
-	Behaviour.register({
53  
-	'#Form_Form' : {
54  
-	   requiredErrorMsg: "Please complete this question before moving on.",
  50
+	:::php
  51
+	class MyController extends Controller {
  52
+		public function Form() {
  53
+			return Form::create($this, 'Form',
  54
+				new FieldList(
  55
+					new NumericField('Postcode'),
  56
+					new CountryDropdownField('Country')
  57
+				),
  58
+				new FieldList(
  59
+					new FormAction('submit', 'Submit form')
  60
+				),
  61
+				new RequiredFields(array('Country'))
  62
+			);
  63
+		}
  64
+		public function submit($data, $form) {
  65
+			// At this point, RequiredFields->validate() will have been called already,
  66
+			// so we can assume that the values exist.
  67
+
  68
+			// German postcodes need to be five digits
  69
+			if($data['Country'] == 'de' && isset($data['Postcode']) && strlen($data['Postcode']) != 5) {
  70
+				$form->addErrorMessage('Postcode', 'Need five digits for German postcodes', 'bad');
  71
+				return $this->redirectBack();
  72
+			}
  73
+
  74
+			// Global validation error (not specific to form field)
  75
+			if($data['Country'] == 'IR' && isset($data['Postcode']) && $data['Postcode']) {
  76
+				$form->sessionMessage("Ireland doesn't have postcodes!", 'bad');
  77
+				return $this->redirectBack();
  78
+			}
  79
+			
  80
+			// continue normal processing...
  81
+		}
55 82
 	}
56  
-	});
57 83
 
58  
-### Other validation libraries
  84
+## JavaScript Validation
59 85
 
60  
-By default, SilverStripe forms with an attached Validator instance use the custom Validator.js clientside logic. It is
61  
-quite hard to customize, and might not be appropriate for all use-cases. You can disable integrated clientside
62  
-validation, and use your own (e.g. [jquery.validate](http://docs.jquery.com/Plugins/Validation)).
  86
+While there are no built-in JavaScript validation handlers in SilverStripe,
  87
+the `FormField` API is flexible enough to provide the information required
  88
+in order to plug in custom libraries.
63 89
 
64  
-Disable for all forms (in `mysite/_config.php`):
  90
+### HTML5 attributes
  91
+
  92
+HTML5 specifies some built-in form validations ([source](http://www.w3.org/wiki/HTML5_form_additions)),
  93
+which are evaluated by modern browsers without any need for JavaScript.
  94
+SilverStripe supports this by allowing to set custom attributes on fields.
65 95
 
66 96
 	:::php
67  
-	Validator::set_javascript_validation_handler('none');
  97
+	// Markup contains <input type="text" required />
  98
+	TextField::create('MyText')->setAttribute('required', true);
  99
+
  100
+	// Markup contains <input type="url" pattern="https?://.+" />
  101
+	TextField::create('MyText')
  102
+		->setAttribute('type', 'url')
  103
+		->setAttribute('pattern', 'https?://.+')
68 104
 
69  
-Disable for a specific form:
  105
+### HTML5 metadata
  106
+
  107
+In addition, HTML5 elements can contain custom data attributes with the `data-` prefix.
  108
+These are general purpose attributes, but can be used to hook in your own validation.
70 109
 
71 110
 	:::php
72  
-	$myForm->getValidator()->setJavascriptValidationHandler('none');
  111
+	// Validate a specific date format (in PHP)
  112
+	// Markup contains <input type="text" data-dateformat="dd.MM.yyyy" />
  113
+	DateField::create('MyDate')->setConfig('dateformat', 'dd.MM.yyyy');
  114
+
  115
+	// Limit extensions on upload (in PHP)
  116
+	// Markup contains <input type="file" data-allowed-extensions="jpg,jpeg,gif" />
  117
+	$exts = array('jpg', 'jpeg', 'gif');
  118
+	$validator = new Upload_Validator();
  119
+	$validator->setAllowedExtensions($exts);
  120
+	$upload = Upload::create()->setValidator($validator);
  121
+	$fileField = FileField::create('MyFile')->setUpload(new);
  122
+	$fileField->setAttribute('data-allowed-extensions', implode(',', $exts));
  123
+
  124
+Note that these examples don't have any effect on the client as such,
  125
+but are just a starting point for custom validation with JavaScript.
  126
+
  127
+## Model Validation
  128
+
  129
+An alternative (or additional) approach to validation is to place it directly
  130
+on the model. SilverStripe provides a `[api:DataObject->validate()]` method for this purpose.
  131
+Refer to the ["datamodel" topic](/topics/datamodel#validation-and-constraints) for more information.
  132
+
  133
+## Subclassing Validator
73 134
 
  135
+To create your own validator, you need to subclass validator and define two methods:
  136
+
  137
+ *  **javascript()** Should output a snippet of JavaScript that will get called to perform javascript validation.
  138
+ *  **php($data)** Should return true if the given data is valid, and call $this->validationError() if there were any
  139
+errors.
74 140
 
75 141
 ## Related
76 142
 

0 notes on commit 0236a3c

Please sign in to comment.
Something went wrong with that request. Please try again.