From 46695d3b4b871ddfc88ab7d7ffc83bf6d67edc0d Mon Sep 17 00:00:00 2001 From: Fred Condo Date: Tue, 18 Feb 2014 15:10:02 -0800 Subject: [PATCH] Combine form validation topic with forms topic - Proofread entire file (forms & form validation topics) - Re-wrap paragraphs to 80 columns - Correct/update links from other doc files --- docs/en/topics/datamodel.md | 2 +- docs/en/topics/form-validation.md | 159 ---------------- docs/en/topics/forms.md | 290 ++++++++++++++++++++++++------ docs/en/topics/index.md | 3 +- 4 files changed, 235 insertions(+), 219 deletions(-) delete mode 100644 docs/en/topics/form-validation.md diff --git a/docs/en/topics/datamodel.md b/docs/en/topics/datamodel.md index 7306ac2d3..6643b5656 100755 --- a/docs/en/topics/datamodel.md +++ b/docs/en/topics/datamodel.md @@ -720,7 +720,7 @@ an object, not for displaying the objects contained in the relation. ## Validation and Constraints Traditionally, validation in SilverStripe has been mostly handled on the -controller through [form validation](/topics/form-validation). +controller through [form validation](/topics/forms#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. diff --git a/docs/en/topics/form-validation.md b/docs/en/topics/form-validation.md deleted file mode 100644 index 94f7264bc..000000000 --- a/docs/en/topics/form-validation.md +++ /dev/null @@ -1,159 +0,0 @@ -# Form Validation - -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). - -## 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() { - $form = new Form($this, 'Form', - new FieldList( - new TextField('MyRequiredField'), - new TextField('MyOptionalField') - ), - new FieldList( - new FormAction('submit', 'Submit form') - ), - new RequiredFields(array('MyRequiredField')) - ); - // Optional: Add a CSS class for custom styling - $form->dataFieldByName('MyRequiredField')->addExtraClass('required'); - return $form; - } - -## 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 { - private static $allowed_actions = array('Form'); - 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 - TextField::create('MyText')->setAttribute('required', true); - - // Markup contains - 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 - DateField::create('MyDate')->setConfig('dateformat', 'dd.MM.yyyy'); - - // Limit extensions on upload (in PHP) - // Markup contains - $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. - -## Validation in the CMS - -Since you're not creating the forms for editing CMS records, -SilverStripe provides you with a `getCMSValidator()` method on your models -to return a `[api:Validator]` instance. - - :::php - class Page extends SiteTree { - private static $db = array('MyRequiredField' => 'Text'); - - public function getCMSValidator() { - return new RequiredFields(array('MyRequiredField')); - } - } - -## 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 - - * Model Validation with [api:DataObject->validate()] diff --git a/docs/en/topics/forms.md b/docs/en/topics/forms.md index 3de8c2fe2..41eeff251 100644 --- a/docs/en/topics/forms.md +++ b/docs/en/topics/forms.md @@ -1,6 +1,6 @@ # Forms -HTML forms are in practice the most used way to communicate with a browser. +HTML forms are in practice the most used way to interact with a user. SilverStripe provides classes to generate and handle the actions and data from a form. @@ -9,14 +9,14 @@ form. A fully implemented form in SilverStripe includes a couple of classes that individually have separate concerns. - * Controller - Takes care of assembling the form and receiving data from it. - * Form - Holds sets of fields, actions and validators. - * FormField - Fields that receive data or displays them, e.g input fields. - * FormActions - Often submit buttons that executes actions. - * Validators - Validate the whole form, see [Form validation](form-validation.md) topic for more information. +* Controller—Takes care of assembling the form and receiving data from it. +* Form—Holds sets of fields, actions and validators. +* FormField —Fields that receive data or displays them, e.g input fields. +* FormActions—Often submit buttons that executes actions. +* Validators—Validate the whole form. -Depending on your needs you can customize and override any of the above classes, -however the defaults are often sufficient. +Depending on your needs you can customize and override any of the above classes; +the defaults, however, are often sufficient. ## The Controller @@ -53,12 +53,13 @@ in a controller. The name of the form ("HelloForm") is passed into the `Form` constructor as a second argument. It needs to match the method name. -Since forms need a URL, the `HelloForm()` method needs to be handled like any -other controller action. In order to whitelist its access through URLs, we add -it to the `$allowed_actions` array. +Because forms need a URL, the `HelloForm()` method needs to be handled like any +other controller action. To grant it access through URLs, we add it to the +`$allowed_actions` array. -Form actions ("doSayHello") on the other hand should NOT be included here, these -are handled separately through `Form->httpSubmission()`. +Form actions ("doSayHello"), on the other hand, should _not_ be included in +`$allowed_actions`; these are handled separately through +`Form->httpSubmission()`. You can control access on form actions either by conditionally removing a `FormAction` from the form construction, or by defining `$allowed_actions` in @@ -68,19 +69,21 @@ your own `Form` class (more information in the **Page.ss** :::ss - + <%-- place where you would like the form to show up --%>
$HelloForm
-Be sure to add the Form name 'HelloForm' to the Controller::$allowed_actions() -to be sure that form submissions get through to the correct action. +Be sure to add the Form name 'HelloForm' to your controller's $allowed_actions +array to enable form submissions.
-You'll notice that we've used a new notation for creating form fields, using `create()` instead of the `new` operator. -These are functionally equivalent, but allows PHP to chain operations like `setTitle()` without assigning the field -instance to a temporary variable. For in-depth information on the create syntax, see the [Injector](/reference/injector) -documentation or the API documentation for `[api:Object]`::create(). +You'll notice that we've used a new notation for creating form fields, using +`create()` instead of the `new` operator. These are functionally equivalent, but +allows PHP to chain operations like `setTitle()` without assigning the field +instance to a temporary variable. For in-depth information on the create syntax, +see the [Injector](/reference/injector) documentation or the API documentation +for `[api:Object]`::create().
## The Form @@ -95,13 +98,18 @@ Creating a form is a matter of defining a method to represent that form. This method should return a form object. The constructor takes the following arguments: -* `$controller`: This must be an instance of the controller that contains the form, often `$this`. -* `$name`: This must be the name of the method on that controller that is called to return the form. The first two -fields allow the form object to be re-created after submission. **It's vital that they are properly set - if you ever -have problems with form action handler not working, check that these values are correct.** -* `$fields`: A `[api:FieldList]` containing `[api:FormField]` instances make up fields in the form. -* `$actions`: A `[api:FieldList]` containing the `[api:FormAction]` objects - the buttons at the bottom. -* `$validator`: An optional `[api:Validator]` for validation of the form. +* `$controller`: This must be an instance of the controller that contains the + form, often `$this`. +* `$name`: This must be the name of the method on that controller that is + called to return the form. The first two arguments allow the form object + to be re-created after submission. **It's vital that they be properly + set—if you ever have problems with a form action handler not working, + check that these values are correct.** +* `$fields`: A `[api:FieldList]` containing `[api:FormField]` instances make + up fields in the form. +* `$actions`: A `[api:FieldList]` containing the `[api:FormAction]` objects - + the buttons at the bottom. +* `$validator`: An optional `[api:Validator]` for validation of the form. Example: @@ -119,13 +127,14 @@ Example: ## Subclassing a form -It's the responsibility of your subclass' constructor to call +It's the responsibility of your subclass's constructor to call :::php parent::__construct() -with the right parameters. You may choose to take $fields and $actions as arguments if you wish, but $controller and -$name must be passed - their values depend on where the form is instantiated. +with the right parameters. You may choose to take $fields and $actions as +arguments if you wish, but $controller and $name must be passed—their values +depend on where the form is instantiated. :::php class MyForm extends Form { @@ -141,8 +150,9 @@ $name must be passed - their values depend on where the form is instantiated. } -The real difference, however, is that you can then define your controller methods within the form class itself. This -means that the form takes responsibilities from the controller and manage how to parse and use the form +The real difference, however, is that you can then define your controller +methods within the form class itself. This means that the form takes +responsibilities from the controller and manage how to parse and use the form data. **Page.php** @@ -211,10 +221,10 @@ form. ) ); -## Readonly +## Readonly You can turn a form or individual fields into a readonly version. This is handy -in the case of confirmation pages or when certain fields can be edited due to +in the case of confirmation pages or when certain fields cannot be edited due to permissions. Readonly on a Form @@ -241,10 +251,13 @@ Readonly on a FormField You can use a custom form template to render with, instead of *Form.ss* -It's recommended you only do this if you've got a lot of presentation text, graphics that surround the form fields. This -is better than defining those as *LiteralField* objects, as it doesn't clutter the data layer with presentation junk. +It's recommended you do this only if you have a lot of presentation text or +graphics that surround the form fields. This is better than defining those as +*LiteralField* objects, as it doesn't clutter the data layer with presentation +junk. -First of all, you need to create your form on it's own class, that way you can define a custom template using a `forTemplate()` method on your Form class. +First you need to create your own form class extending Form; that way you can +define a custom template using a `forTemplate()` method on your Form class. :::php class MyForm extends Form { @@ -305,14 +318,16 @@ your project. Here is an example of basic customization: <% end_if %> -`$Fields.dataFieldByName(FirstName)` will return the form control contents of `Field()` for the particular field object, -in this case `EmailField->Field()` or `PasswordField->Field()` which returns an `` element with specific markup -for the type of field. Pass in the name of the field as the first parameter, as done above, to render it into the -template. +`$Fields.dataFieldByName(FirstName)` will return the form control contents of +`Field()` for the particular field object, in this case `EmailField->Field()` or +`PasswordField->Field()` which returns an `` element with specific markup +for the type of field. Pass in the name of the field as the first parameter, as +done above, to render it into the template. -To find more methods, have a look at the `[api:Form]` class and `[api:FieldList]` class as there is a lot of different -methods of customising the form templates. An example is that you could use `<% loop $Fields %>` instead of specifying -each field manually, as we've done above. +To find more methods, have a look at the `[api:Form]` class and +`[api:FieldList]` class as there is a lot of different methods of customising +the form templates. An example is that you could use `<% loop $Fields %>` +instead of specifying each field manually, as we've done above. ### Custom form field templates @@ -333,19 +348,20 @@ Each form field is rendered into a form via the `
` as well as a `