1
0
mirror of https://github.com/astaxie/beego.git synced 2024-11-29 23:11:29 +00:00
Beego/validation/util.go

199 lines
3.9 KiB
Go
Raw Normal View History

2013-07-23 06:42:14 +00:00
package validation
import (
"fmt"
"reflect"
2013-07-23 17:20:24 +00:00
"regexp"
"strconv"
2013-07-23 06:42:14 +00:00
"strings"
)
const (
VALIDTAG = "valid"
)
var (
// key: function name
// value: the number of parameters
2013-07-23 17:20:24 +00:00
funcs = make(Funcs)
2013-07-23 06:42:14 +00:00
// doesn't belong to validation functions
unFuncs = map[string]bool{
"Clear": true,
"HasErrors": true,
"ErrorMap": true,
"Error": true,
"apply": true,
"Check": true,
"Valid": true,
}
)
func init() {
v := &Validation{}
t := reflect.TypeOf(v)
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
if !unFuncs[m.Name] {
2013-07-23 17:20:24 +00:00
funcs[m.Name] = m.Func
2013-07-23 06:42:14 +00:00
}
}
}
type ValidFunc struct {
Name string
Params []interface{}
}
2013-07-23 17:20:24 +00:00
type Funcs map[string]reflect.Value
func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) {
2013-07-24 04:20:42 +00:00
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
2013-07-23 17:20:24 +00:00
if _, ok := f[name]; !ok {
err = fmt.Errorf("%s does not exist", name)
return
}
if len(params) != f[name].Type().NumIn() {
err = fmt.Errorf("The number of params is not adapted")
return
}
in := make([]reflect.Value, len(params))
for k, param := range params {
in[k] = reflect.ValueOf(param)
}
result = f[name].Call(in)
return
}
2013-07-23 06:42:14 +00:00
func isStruct(t reflect.Type) bool {
return t.Kind() == reflect.Struct
}
func isStructPtr(t reflect.Type) bool {
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
}
func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) {
tag := f.Tag.Get(VALIDTAG)
if len(tag) == 0 {
return
}
fs := strings.Split(tag, ";")
for _, vfunc := range fs {
var vf ValidFunc
vf, err = parseFunc(vfunc)
if err != nil {
return
}
vfs = append(vfs, vf)
}
return
}
func parseFunc(vfunc string) (v ValidFunc, err error) {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
vfunc = strings.TrimSpace(vfunc)
start := strings.Index(vfunc, "(")
var num int
// doesn't need parameter valid function
if start == -1 {
if num, err = numIn(vfunc); err != nil {
return
}
if num != 0 {
err = fmt.Errorf("%s require %d parameters", vfunc, num)
return
}
2013-07-24 04:20:42 +00:00
v = ValidFunc{vfunc, []interface{}{vfunc}}
2013-07-23 06:42:14 +00:00
return
}
end := strings.Index(vfunc, ")")
if end == -1 {
err = fmt.Errorf("invalid valid function")
return
}
name := strings.TrimSpace(vfunc[:start])
if num, err = numIn(name); err != nil {
return
}
params := strings.Split(vfunc[start+1:end], ",")
// the num of param must be equal
if num != len(params) {
err = fmt.Errorf("%s require %d parameters", name, num)
return
}
2013-07-23 17:20:24 +00:00
tParams, err := trim(name, params)
if err != nil {
return
}
v = ValidFunc{name, tParams}
2013-07-23 06:42:14 +00:00
return
}
func numIn(name string) (num int, err error) {
2013-07-23 17:20:24 +00:00
fn, ok := funcs[name]
2013-07-23 06:42:14 +00:00
if !ok {
err = fmt.Errorf("doesn't exsits %s valid function", name)
2013-07-23 17:20:24 +00:00
return
2013-07-23 06:42:14 +00:00
}
2013-07-24 04:20:42 +00:00
// sub *Validation obj and key
2013-07-23 17:20:24 +00:00
num = fn.Type().NumIn() - 3
2013-07-23 06:42:14 +00:00
return
}
2013-07-23 17:20:24 +00:00
func trim(name string, s []string) (ts []interface{}, err error) {
2013-07-24 04:20:42 +00:00
ts = make([]interface{}, len(s), len(s)+1)
2013-07-23 17:20:24 +00:00
fn, ok := funcs[name]
if !ok {
err = fmt.Errorf("doesn't exsits %s valid function", name)
return
}
2013-07-23 06:42:14 +00:00
for i := 0; i < len(s); i++ {
2013-07-23 17:20:24 +00:00
var param interface{}
2013-07-24 04:20:42 +00:00
// skip *Validation and obj params
2013-07-23 17:20:24 +00:00
if param, err = magic(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil {
return
}
ts[i] = param
}
2013-07-24 04:20:42 +00:00
ts = append(ts, name)
2013-07-23 17:20:24 +00:00
return
}
2013-07-24 04:20:42 +00:00
// modify the parameters's type to adapt the function input parameters' type
2013-07-23 17:20:24 +00:00
func magic(t reflect.Type, s string) (i interface{}, err error) {
switch t.Kind() {
case reflect.Int:
i, err = strconv.Atoi(s)
case reflect.String:
i = s
case reflect.Ptr:
if t.Elem().String() != "regexp.Regexp" {
2013-07-24 04:20:42 +00:00
err = fmt.Errorf("does not support %s", t.Elem().String())
2013-07-23 17:20:24 +00:00
return
}
i, err = regexp.Compile(s)
2013-07-24 04:20:42 +00:00
default:
err = fmt.Errorf("does not support %s", t.Kind().String())
2013-07-23 06:42:14 +00:00
}
2013-07-23 17:20:24 +00:00
return
2013-07-23 06:42:14 +00:00
}
2013-07-24 04:20:42 +00:00
func mergeParam(v *Validation, obj interface{}, params []interface{}) []interface{} {
return append([]interface{}{v, obj}, params...)
}