forms

package
Version: v0.0.0-...-c971602 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 6, 2014 License: BSD-2-Clause Imports: 6 Imported by: 0

Documentation

Overview

Package forms provides tools for validating data found in gadget.Request.Params. Its structure is inspired by Django's forms library and is intended to be both declarative and highly independent of your application's model layer. Forms are struct types that embed *DefaultForm and declare as their fields pointers to any number of Field types. They look something like this:

type InvoiceForm struct {
	*DefaultForm
	Client, Notes *StringField
	Date          *TimeField
	Number        *IntField
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Copy

func Copy(f Form, target interface{}) error

Copy transfers data from a validated Form to another struct for further processing (presumably persistance). The target struct must have a field of the appropriate type and the same name for every FormField in the Form.

Copy will return an error if the Form has not passed validation, if it cannot find a corresponding field on the target struct for a FormField, or if it cannot set the FormField's value on the target field.

Example
package main

import (
	"fmt"

	"github.com/redneckbeard/gadget/forms"
)

func main() {
	type Invoice struct {
		Client, Notes string
		Paid          bool
		Number        int
	}

	type InvoiceForm struct {
		*forms.DefaultForm
		Client, Notes *forms.StringField
		Paid          *forms.BoolField
		Number        *forms.IntField
	}

	form := &InvoiceForm{}
	forms.Init(form, nil)
	forms.Populate(form, map[string]interface{}{
		"Client": "M.A.D.",
		"Notes":  "Some day, Gadget, some day...",
		"Paid":   "1",
		"Number": 23,
	})
	fmt.Println(forms.IsValid(form))

	invoice := &Invoice{}
	forms.Copy(form, invoice)
	fmt.Println(invoice.Client)
	fmt.Println(invoice.Notes)
	fmt.Println(invoice.Paid)
	fmt.Println(invoice.Number)
}
Output:

true
M.A.D.
Some day, Gadget, some day...
true
23

func Init

func Init(form Form, initializer func(Form))

Init correctly initializes all FormFields and the embedded DefaultForm on a struct. Its first argument a Form, and its second an optional func that will receive the form as its only argument after initialization is complete. This callback enables you to do additional setup on FormFields included in your Form.

Example
package main

import (
	"fmt"

	"github.com/redneckbeard/gadget/forms"
)

func main() {
	type ArticleForm struct {
		*forms.DefaultForm
		Title, Body *forms.StringField
		AuthorId    *forms.IntField
	}
	form := &ArticleForm{}
	forms.Init(form, func(f forms.Form) {
		form := f.(*ArticleForm)
		form.AuthorId.Required = false
	})
	forms.Populate(form, map[string]interface{}{
		"Title": "Mission: Stop Dr. Claw",
	})
	fmt.Println(forms.IsValid(form))
	fmt.Println(form.AuthorId.Error())
	fmt.Println(form.Body.Error())
}
Output:

false
<nil>
This field is required

func IsValid

func IsValid(f Form) bool

IsValid calls the Clean method on all of a Form's FormFields. As a result, if IsValid returns true, the Value fields of all required FormFields will be non-nil. If false, error messages may be retrieved by the Error method of an individual field or by retrieving the error for a field by name from the Form's Errors map.

If validation is needed beyond what a FormField type provides by default, Forms may define special methods to perform more robust checks on the value of the Data field. These methods are named "Clean<Fieldname>" and receive the field being validated as their argument. An example is provided below.

Example
package main

import (
	"fmt"
	"regexp"

	"github.com/redneckbeard/gadget/forms"
)

type UserForm struct {
	*forms.DefaultForm
	Username, Email *forms.StringField
}

func (form *UserForm) CleanEmail(f forms.FormField) {
	field := f.(*forms.StringField)
	naiveEmailPattern := regexp.MustCompile(`[\w.-]+@[\w.-]\.(com|net|org)`)
	if !naiveEmailPattern.MatchString(field.Value) {
		field.SetError("Email must be an email")
	}
}

func main() {
	/*
	 *type UserForm struct {
	 *        *forms.DefaultForm
	 *        Username, Email *forms.StringField
	 *}
	 *
	 *func (form *UserForm) CleanEmail(f forms.FormField) {
	 *        field := f.(*forms.StringField)
	 *        naiveEmailPattern := regexp.MustCompile(`[\w.-]+@[\w.-]\.(com|net|org)`)
	 *        if !naiveEmailPattern.MatchString(field.Value) {
	 *                field.SetError("Email must be an email")
	 *        }
	 *}
	 */

	form := &UserForm{}
	forms.Init(form, nil)
	forms.Populate(form, map[string]interface{}{
		"Username": "penny",
		"Email":    "clearly not an email address",
	})
	fmt.Println(forms.IsValid(form))
	fmt.Println(form.Email.Error())
}
Output:

false
Email must be an email

func Populate

func Populate(form Form, payload map[string]interface{}) error

Populate copies data from a map[string]interface{} value into the Data members of the corresponding FormFields of the Form. The keys of the map must be a case-sensitive exact match of exported names of FormFields on the struct. Populate will return an error if Init has not yet been called on the Form.

Note that the type of the second argument is not map[string][]string. This is meant to provide ease of use with gadget.Request.Params over http.Request.Form.

Types

type BaseField

type BaseField struct {
	Data        interface{}
	Messages    map[string]string
	Required    bool
	Placeholder bool
	// contains filtered or unexported fields
}

func (*BaseField) DefaultMessages

func (field *BaseField) DefaultMessages()

func (*BaseField) Error

func (field *BaseField) Error() error

func (*BaseField) GetMessage

func (field *BaseField) GetMessage(msgName string) string

func (*BaseField) Set

func (field *BaseField) Set(data interface{})

func (*BaseField) SetError

func (field *BaseField) SetError(msg string)

func (*BaseField) SetMessage

func (field *BaseField) SetMessage(msgName string, msgValue string)

type BoolField

type BoolField struct {
	*BaseField
	Value bool
}

func (*BoolField) Clean

func (field *BoolField) Clean()

Boolfield validates the presence of a boolean value. If the Data on the FormField is an int, 0 is taken for false and 1 for true. If it is a string, it is parsed by strconv.ParseBool.

func (*BoolField) Copy

func (field *BoolField) Copy(v reflect.Value)

func (*BoolField) DefaultMessages

func (field *BoolField) DefaultMessages()

type DefaultForm

type DefaultForm struct {
	Fields map[string]FormField
	Errors map[string]error
}

DefaultForm provides a complete implementation of the Form interface for you to embed in your form struct.

func (*DefaultForm) HasErrors

func (f *DefaultForm) HasErrors() bool

HasErrors returns true if the Error method of any of a Form's FormField members returns non-nil.

type Float64Field

type Float64Field struct {
	*BaseField
	Value float64
}

Float64Field validates the presence of a float64 value. If the Data on the FormField is a string, the Clean method will attempt to parse it. If it is an int, it will cast it to a float64.

func (*Float64Field) Clean

func (field *Float64Field) Clean()

func (*Float64Field) Copy

func (field *Float64Field) Copy(v reflect.Value)

func (*Float64Field) DefaultMessages

func (field *Float64Field) DefaultMessages()

type Form

type Form interface {
	HasErrors() bool
	// contains filtered or unexported methods
}

Form is the interface that wraps the validation functionality provided by this package. To implement the Form interface, struct types must embed a pointer to DefaultForm, since the interface includes unexported fields that DefaultForm provides. DefaultForm implements all the methods necessary to satisfy the interface.

type FormField

type FormField interface {
	Clean()
	Copy(reflect.Value)

	DefaultMessages()
	Error() error
	GetMessage(string) string
	Set(interface{})

	SetError(string)
	SetMessage(string, string)
	// contains filtered or unexported methods
}

FormField is the interface that encapsulates field-level form operations. All types implementing FormField should be struct types that embed BaseField, which provides all methods except Clean and Copy. Individual field types must implement those methods appropriatly for the types of data they are intended to validate.

By virtue of their embedded BaseField, all FormFields have a Data field of type interface{}. The FormFields themselves conventionally have a Value field of the type that they purport to validate. All FormFields are required unless their Required field is set to false in the form's SetOptions method.

The forms package ships with FormField types for string, int, bool, float64, and time.Time values. Users can easily define additional fields. Refer to the source for the builtin FormField types for details of how to define new ones.

type IntField

type IntField struct {
	*BaseField
	Value int64
}

IntField validates the presence of an int value. If the Data on the FormField is string, its Clean method will attempt to parse it.

func (*IntField) Clean

func (field *IntField) Clean()

func (*IntField) Copy

func (field *IntField) Copy(v reflect.Value)

func (*IntField) DefaultMessages

func (field *IntField) DefaultMessages()

type IntSliceField

type IntSliceField struct {
	*BaseField
	Value []int64
}

func (*IntSliceField) Clean

func (field *IntSliceField) Clean()

func (*IntSliceField) Copy

func (field *IntSliceField) Copy(v reflect.Value)

func (*IntSliceField) DefaultMessages

func (field *IntSliceField) DefaultMessages()

type StringField

type StringField struct {
	*BaseField
	Value string
}

StringField validates the presences of a string value.

func (*StringField) Clean

func (field *StringField) Clean()

func (*StringField) Copy

func (field *StringField) Copy(v reflect.Value)

func (*StringField) DefaultMessages

func (field *StringField) DefaultMessages()

type TimeField

type TimeField struct {
	*BaseField
	Value  time.Time
	Format string
}

TimeField validates the presence of a Time value. If the value is an int64, it is parsed as seconds since the epoch. If it is a string, TimeField will attempt to parse it with the value of its Format field as the layout. The default time format is RFC 33339.

func (*TimeField) Clean

func (field *TimeField) Clean()

func (*TimeField) Copy

func (field *TimeField) Copy(v reflect.Value)

func (*TimeField) DefaultMessages

func (field *TimeField) DefaultMessages()

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL