-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathform.go
164 lines (142 loc) · 3.55 KB
/
form.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package gforms
import (
"mime/multipart"
"net/url"
"reflect"
)
//------------------------------------------------------------------------------
func init() {
Register((*StringField)(nil), func() interface{} {
return NewStringField()
})
Register((*TextareaStringField)(nil), func() interface{} {
return NewTextareaStringField()
})
Register((*StringChoiceField)(nil), func() interface{} {
return NewSelectStringField()
})
Register((*Int64Field)(nil), func() interface{} {
return NewInt64Field()
})
Register((*Int64ChoiceField)(nil), func() interface{} {
return NewSelectInt64Field()
})
Register((*BoolField)(nil), func() interface{} {
return NewBoolField()
})
Register((*MultiStringChoiceField)(nil), func() interface{} {
return NewMultiSelectStringField()
})
Register((*MultiInt64ChoiceField)(nil), func() interface{} {
return NewMultiSelectInt64Field()
})
}
//------------------------------------------------------------------------------
type Form interface {
SetFields(map[string]Field)
Fields() map[string]Field
SetErrors(map[string]error)
Errors() map[string]error
}
func InitForm(form Form) error {
formv := reflect.ValueOf(form).Elem()
formt := formv.Type()
tinfo := tinfoMap.TypeInfo(formt)
fields := make(map[string]Field, len(tinfo.fields))
for _, finfo := range tinfo.fields {
fv := formv.FieldByIndex(finfo.idx)
isNil := fv.IsNil()
if isNil {
fv.Set(reflect.ValueOf(finfo.constr()))
}
f := fv.Interface().(Field)
if !f.HasName() {
f.SetName(finfo.name)
}
if !f.HasLabel() {
f.SetLabel(finfo.label)
}
if isNil {
f.SetIsRequired(finfo.flags&fReq != 0)
}
fields[f.Name()] = f
}
form.SetFields(fields)
return nil
}
type valueGetterFunc func(Field) interface{}
func IsValid(f Form, getValue valueGetterFunc) bool {
formv := reflect.ValueOf(f).Elem()
formt := formv.Type()
tinfo := tinfoMap.TypeInfo(formt)
errs := make(map[string]error, 0)
for _, finfo := range tinfo.fields {
fv := formv.FieldByIndex(finfo.idx)
if fv.IsNil() {
continue
}
f := fv.Interface().(Field)
if !IsFieldValid(f, getValue(f)) {
errs[f.Name()] = f.ValidationError()
}
}
f.SetErrors(errs)
return len(f.Errors()) == 0
}
func IsFormValid(form Form, formValues url.Values) bool {
getValue := func(f Field) interface{} {
if f.IsMultipart() {
panic("IsFormValid() is called on multipart form (use IsMultipartFormValid())")
} else {
if f.IsMulti() {
return formValues[f.Name()]
} else {
if values, ok := formValues[f.Name()]; ok {
return values[0]
}
}
}
return nil
}
return IsValid(form, getValue)
}
func IsMultipartFormValid(form Form, multipartForm *multipart.Form) bool {
getValue := func(f Field) interface{} {
if f.IsMultipart() {
if f.IsMulti() {
return multipartForm.File[f.Name()]
} else {
if _, ok := multipartForm.File[f.Name()]; ok {
return multipartForm.File[f.Name()][0]
}
}
} else {
if f.IsMulti() {
return multipartForm.Value[f.Name()]
} else {
if values, ok := multipartForm.Value[f.Name()]; ok {
return values[0]
}
}
}
return nil
}
return IsValid(form, getValue)
}
//------------------------------------------------------------------------------
type BaseForm struct {
fields map[string]Field
errors map[string]error
}
func (f *BaseForm) SetFields(fields map[string]Field) {
f.fields = fields
}
func (f *BaseForm) Fields() map[string]Field {
return f.fields
}
func (f *BaseForm) SetErrors(errors map[string]error) {
f.errors = errors
}
func (f *BaseForm) Errors() map[string]error {
return f.errors
}