Adds FORM bindings
This commit is contained in:
		| @ -6,6 +6,7 @@ import ( | ||||
| 	"errors" | ||||
| 	"net/http" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| @ -49,9 +50,107 @@ func (_ xmlBinding) Bind(req *http.Request, obj interface{}) error { | ||||
| } | ||||
|  | ||||
| func (_ formBinding) Bind(req *http.Request, obj interface{}) error { | ||||
| 	if err := req.ParseForm(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := mapForm(obj, req.Form); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return Validate(obj) | ||||
| } | ||||
|  | ||||
| func mapForm(ptr interface{}, form map[string][]string) error { | ||||
| 	typ := reflect.TypeOf(ptr).Elem() | ||||
| 	formStruct := reflect.ValueOf(ptr).Elem() | ||||
| 	for i := 0; i < typ.NumField(); i++ { | ||||
| 		typeField := typ.Field(i) | ||||
| 		if inputFieldName := typeField.Tag.Get("form"); inputFieldName != "" { | ||||
| 			structField := formStruct.Field(i) | ||||
| 			if !structField.CanSet() { | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			inputValue, exists := form[inputFieldName] | ||||
| 			if !exists { | ||||
| 				continue | ||||
| 			} | ||||
| 			numElems := len(inputValue) | ||||
| 			if structField.Kind() == reflect.Slice && numElems > 0 { | ||||
| 				sliceOf := structField.Type().Elem().Kind() | ||||
| 				slice := reflect.MakeSlice(structField.Type(), numElems, numElems) | ||||
| 				for i := 0; i < numElems; i++ { | ||||
| 					if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				formStruct.Elem().Field(i).Set(slice) | ||||
| 			} else { | ||||
| 				if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error { | ||||
| 	switch valueKind { | ||||
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 		if val == "" { | ||||
| 			val = "0" | ||||
| 		} | ||||
| 		intVal, err := strconv.Atoi(val) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} else { | ||||
| 			structField.SetInt(int64(intVal)) | ||||
| 		} | ||||
| 	case reflect.Bool: | ||||
| 		if val == "" { | ||||
| 			val = "false" | ||||
| 		} | ||||
| 		boolVal, err := strconv.ParseBool(val) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} else { | ||||
| 			structField.SetBool(boolVal) | ||||
| 		} | ||||
| 	case reflect.Float32: | ||||
| 		if val == "" { | ||||
| 			val = "0.0" | ||||
| 		} | ||||
| 		floatVal, err := strconv.ParseFloat(val, 32) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} else { | ||||
| 			structField.SetFloat(floatVal) | ||||
| 		} | ||||
| 	case reflect.Float64: | ||||
| 		if val == "" { | ||||
| 			val = "0.0" | ||||
| 		} | ||||
| 		floatVal, err := strconv.ParseFloat(val, 64) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} else { | ||||
| 			structField.SetFloat(floatVal) | ||||
| 		} | ||||
| 	case reflect.String: | ||||
| 		structField.SetString(val) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Don't pass in pointers to bind to. Can lead to bugs. See: | ||||
| // https://github.com/codegangsta/martini-contrib/issues/40 | ||||
| // https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659 | ||||
| func ensureNotPointer(obj interface{}) { | ||||
| 	if reflect.TypeOf(obj).Kind() == reflect.Ptr { | ||||
| 		panic("Pointers are not accepted as binding models") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Validate(obj interface{}) error { | ||||
|  | ||||
| 	typ := reflect.TypeOf(obj) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user