util.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // Copyright 2014 beego Author. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package validation
  15. import (
  16. "fmt"
  17. "reflect"
  18. "regexp"
  19. "strconv"
  20. "strings"
  21. )
  22. const (
  23. // ValidTag struct tag
  24. ValidTag = "valid"
  25. )
  26. var (
  27. // key: function name
  28. // value: the number of parameters
  29. funcs = make(Funcs)
  30. // doesn't belong to validation functions
  31. unFuncs = map[string]bool{
  32. "Clear": true,
  33. "HasErrors": true,
  34. "ErrorMap": true,
  35. "Error": true,
  36. "apply": true,
  37. "Check": true,
  38. "Valid": true,
  39. "NoMatch": true,
  40. }
  41. )
  42. func init() {
  43. v := &Validation{}
  44. t := reflect.TypeOf(v)
  45. for i := 0; i < t.NumMethod(); i++ {
  46. m := t.Method(i)
  47. if !unFuncs[m.Name] {
  48. funcs[m.Name] = m.Func
  49. }
  50. }
  51. }
  52. // CustomFunc is for custom validate function
  53. type CustomFunc func(v *Validation, obj interface{}, key string)
  54. // AddCustomFunc Add a custom function to validation
  55. // The name can not be:
  56. // Clear
  57. // HasErrors
  58. // ErrorMap
  59. // Error
  60. // Check
  61. // Valid
  62. // NoMatch
  63. // If the name is same with exists function, it will replace the origin valid function
  64. func AddCustomFunc(name string, f CustomFunc) error {
  65. if unFuncs[name] {
  66. return fmt.Errorf("invalid function name: %s", name)
  67. }
  68. funcs[name] = reflect.ValueOf(f)
  69. return nil
  70. }
  71. // ValidFunc Valid function type
  72. type ValidFunc struct {
  73. Name string
  74. Params []interface{}
  75. }
  76. // Funcs Validate function map
  77. type Funcs map[string]reflect.Value
  78. // Call validate values with named type string
  79. func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) {
  80. defer func() {
  81. if r := recover(); r != nil {
  82. err = fmt.Errorf("%v", r)
  83. }
  84. }()
  85. if _, ok := f[name]; !ok {
  86. err = fmt.Errorf("%s does not exist", name)
  87. return
  88. }
  89. if len(params) != f[name].Type().NumIn() {
  90. err = fmt.Errorf("The number of params is not adapted")
  91. return
  92. }
  93. in := make([]reflect.Value, len(params))
  94. for k, param := range params {
  95. in[k] = reflect.ValueOf(param)
  96. }
  97. result = f[name].Call(in)
  98. return
  99. }
  100. func isStruct(t reflect.Type) bool {
  101. return t.Kind() == reflect.Struct
  102. }
  103. func isStructPtr(t reflect.Type) bool {
  104. return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
  105. }
  106. func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) {
  107. tag := f.Tag.Get(ValidTag)
  108. if len(tag) == 0 {
  109. return
  110. }
  111. if vfs, tag, err = getRegFuncs(tag, f.Name); err != nil {
  112. return
  113. }
  114. fs := strings.Split(tag, ";")
  115. for _, vfunc := range fs {
  116. var vf ValidFunc
  117. if len(vfunc) == 0 {
  118. continue
  119. }
  120. vf, err = parseFunc(vfunc, f.Name)
  121. if err != nil {
  122. return
  123. }
  124. vfs = append(vfs, vf)
  125. }
  126. return
  127. }
  128. // Get Match function
  129. // May be get NoMatch function in the future
  130. func getRegFuncs(tag, key string) (vfs []ValidFunc, str string, err error) {
  131. tag = strings.TrimSpace(tag)
  132. index := strings.Index(tag, "Match(/")
  133. if index == -1 {
  134. str = tag
  135. return
  136. }
  137. end := strings.LastIndex(tag, "/)")
  138. if end < index {
  139. err = fmt.Errorf("invalid Match function")
  140. return
  141. }
  142. reg, err := regexp.Compile(tag[index+len("Match(/") : end])
  143. if err != nil {
  144. return
  145. }
  146. vfs = []ValidFunc{{"Match", []interface{}{reg, key + ".Match"}}}
  147. str = strings.TrimSpace(tag[:index]) + strings.TrimSpace(tag[end+len("/)"):])
  148. return
  149. }
  150. func parseFunc(vfunc, key string) (v ValidFunc, err error) {
  151. defer func() {
  152. if r := recover(); r != nil {
  153. err = fmt.Errorf("%v", r)
  154. }
  155. }()
  156. vfunc = strings.TrimSpace(vfunc)
  157. start := strings.Index(vfunc, "(")
  158. var num int
  159. // doesn't need parameter valid function
  160. if start == -1 {
  161. if num, err = numIn(vfunc); err != nil {
  162. return
  163. }
  164. if num != 0 {
  165. err = fmt.Errorf("%s require %d parameters", vfunc, num)
  166. return
  167. }
  168. v = ValidFunc{vfunc, []interface{}{key + "." + vfunc}}
  169. return
  170. }
  171. end := strings.Index(vfunc, ")")
  172. if end == -1 {
  173. err = fmt.Errorf("invalid valid function")
  174. return
  175. }
  176. name := strings.TrimSpace(vfunc[:start])
  177. if num, err = numIn(name); err != nil {
  178. return
  179. }
  180. params := strings.Split(vfunc[start+1:end], ",")
  181. // the num of param must be equal
  182. if num != len(params) {
  183. err = fmt.Errorf("%s require %d parameters", name, num)
  184. return
  185. }
  186. tParams, err := trim(name, key+"."+name, params)
  187. if err != nil {
  188. return
  189. }
  190. v = ValidFunc{name, tParams}
  191. return
  192. }
  193. func numIn(name string) (num int, err error) {
  194. fn, ok := funcs[name]
  195. if !ok {
  196. err = fmt.Errorf("doesn't exsits %s valid function", name)
  197. return
  198. }
  199. // sub *Validation obj and key
  200. num = fn.Type().NumIn() - 3
  201. return
  202. }
  203. func trim(name, key string, s []string) (ts []interface{}, err error) {
  204. ts = make([]interface{}, len(s), len(s)+1)
  205. fn, ok := funcs[name]
  206. if !ok {
  207. err = fmt.Errorf("doesn't exsits %s valid function", name)
  208. return
  209. }
  210. for i := 0; i < len(s); i++ {
  211. var param interface{}
  212. // skip *Validation and obj params
  213. if param, err = parseParam(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil {
  214. return
  215. }
  216. ts[i] = param
  217. }
  218. ts = append(ts, key)
  219. return
  220. }
  221. // modify the parameters's type to adapt the function input parameters' type
  222. func parseParam(t reflect.Type, s string) (i interface{}, err error) {
  223. switch t.Kind() {
  224. case reflect.Int:
  225. i, err = strconv.Atoi(s)
  226. case reflect.String:
  227. i = s
  228. case reflect.Ptr:
  229. if t.Elem().String() != "regexp.Regexp" {
  230. err = fmt.Errorf("does not support %s", t.Elem().String())
  231. return
  232. }
  233. i, err = regexp.Compile(s)
  234. default:
  235. err = fmt.Errorf("does not support %s", t.Kind().String())
  236. }
  237. return
  238. }
  239. func mergeParam(v *Validation, obj interface{}, params []interface{}) []interface{} {
  240. return append([]interface{}{v, obj}, params...)
  241. }