From 5a32ee8938439012a3ab00ceb00bd511cbc5cf75 Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 19:06:45 +0100 Subject: [PATCH 01/12] Removes unnecessary variable. --- binding.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/binding.go b/binding.go index bd27cfd..5cfad06 100644 --- a/binding.go +++ b/binding.go @@ -236,10 +236,9 @@ func mapForm(formStruct reflect.Value, form map[string][]string, if formStruct.Kind() == reflect.Ptr { formStruct = formStruct.Elem() } - typ := formStruct.Type() - for i := 0; i < typ.NumField(); i++ { - typeField := typ.Field(i) + for i := 0; i < formStruct.Type().NumField(); i++ { + typeField := formStruct.Type().Field(i) structField := formStruct.Field(i) if typeField.Type.Kind() == reflect.Ptr && typeField.Anonymous { From 0ddf2279b5f27d1bbe361db726c0fd0c62cce562 Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 19:10:06 +0100 Subject: [PATCH 02/12] Proper variable usage. --- binding.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binding.go b/binding.go index 5cfad06..511ac03 100644 --- a/binding.go +++ b/binding.go @@ -263,7 +263,7 @@ func mapForm(formStruct reflect.Value, form map[string][]string, for i := 0; i < numElems; i++ { setWithProperType(sliceOf, inputValue[i], slice.Index(i), inputFieldName, errors) } - formStruct.Field(i).Set(slice) + structField.Set(slice) } else { setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) } From 6550649d30c60e311b05efabaa475b52f2febdfe Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 19:13:19 +0100 Subject: [PATCH 03/12] Refectors for clarity and to avoid variable shadowing. --- binding.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/binding.go b/binding.go index 511ac03..53021e2 100644 --- a/binding.go +++ b/binding.go @@ -260,8 +260,8 @@ func mapForm(formStruct reflect.Value, form map[string][]string, 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++ { - setWithProperType(sliceOf, inputValue[i], slice.Index(i), inputFieldName, errors) + for elemIdx := 0; elemIdx < numElems; elemIdx++ { + setWithProperType(sliceOf, inputValue[elemIdx], slice.Index(elemIdx), inputFieldName, errors) } structField.Set(slice) } else { @@ -278,8 +278,8 @@ func mapForm(formStruct reflect.Value, form map[string][]string, numElems := len(inputFile) if structField.Kind() == reflect.Slice && numElems > 0 && structField.Type().Elem() == fhType { slice := reflect.MakeSlice(structField.Type(), numElems, numElems) - for i := 0; i < numElems; i++ { - slice.Index(i).Set(reflect.ValueOf(inputFile[i])) + for elemIdx := 0; elemIdx < numElems; elemIdx++ { + slice.Index(elemIdx).Set(reflect.ValueOf(inputFile[elemIdx])) } structField.Set(slice) } else if structField.Type() == fhType { From 6c2e8718ee5a844ec74089a8c7b8bf7f99167b58 Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 19:16:07 +0100 Subject: [PATCH 04/12] Changes naming for clarity. --- binding.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/binding.go b/binding.go index 53021e2..a4a4a8e 100644 --- a/binding.go +++ b/binding.go @@ -237,9 +237,9 @@ func mapForm(formStruct reflect.Value, form map[string][]string, formStruct = formStruct.Elem() } - for i := 0; i < formStruct.Type().NumField(); i++ { - typeField := formStruct.Type().Field(i) - structField := formStruct.Field(i) + for fieldIdx := 0; fieldIdx < formStruct.Type().NumField(); fieldIdx++ { + typeField := formStruct.Type().Field(fieldIdx) + structField := formStruct.Field(fieldIdx) if typeField.Type.Kind() == reflect.Ptr && typeField.Anonymous { structField.Set(reflect.New(typeField.Type.Elem())) From 86b9c9e4b75809dc4e1e2e3867c1b90282f165f3 Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 19:24:33 +0100 Subject: [PATCH 05/12] Moves out mapForm main for loop logic into own function. --- binding.go | 80 +++++++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/binding.go b/binding.go index a4a4a8e..8d80f75 100644 --- a/binding.go +++ b/binding.go @@ -240,51 +240,57 @@ func mapForm(formStruct reflect.Value, form map[string][]string, for fieldIdx := 0; fieldIdx < formStruct.Type().NumField(); fieldIdx++ { typeField := formStruct.Type().Field(fieldIdx) structField := formStruct.Field(fieldIdx) + mapFormField(typeField, structField, form, formfile, errors) + } +} - if typeField.Type.Kind() == reflect.Ptr && typeField.Anonymous { - structField.Set(reflect.New(typeField.Type.Elem())) - mapForm(structField.Elem(), form, formfile, errors) - if reflect.DeepEqual(structField.Elem().Interface(), reflect.Zero(structField.Elem().Type()).Interface()) { - structField.Set(reflect.Zero(structField.Type())) - } - } else if typeField.Type.Kind() == reflect.Struct { - mapForm(structField, form, formfile, errors) - } else if inputFieldName := typeField.Tag.Get("form"); inputFieldName != "" { - if !structField.CanSet() { - continue - } +func mapFormField(typeField reflect.StructField, + structField reflect.Value, form map[string][]string, + formfile map[string][]*multipart.FileHeader, errors Errors) { - inputValue, exists := form[inputFieldName] - if exists { - numElems := len(inputValue) - if structField.Kind() == reflect.Slice && numElems > 0 { - sliceOf := structField.Type().Elem().Kind() - slice := reflect.MakeSlice(structField.Type(), numElems, numElems) - for elemIdx := 0; elemIdx < numElems; elemIdx++ { - setWithProperType(sliceOf, inputValue[elemIdx], slice.Index(elemIdx), inputFieldName, errors) - } - structField.Set(slice) - } else { - setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) - } - continue - } + if typeField.Type.Kind() == reflect.Ptr && typeField.Anonymous { + structField.Set(reflect.New(typeField.Type.Elem())) + mapForm(structField.Elem(), form, formfile, errors) + if reflect.DeepEqual(structField.Elem().Interface(), reflect.Zero(structField.Elem().Type()).Interface()) { + structField.Set(reflect.Zero(structField.Type())) + } + } else if typeField.Type.Kind() == reflect.Struct { + mapForm(structField, form, formfile, errors) + } else if inputFieldName := typeField.Tag.Get("form"); inputFieldName != "" { + if !structField.CanSet() { + return + } - inputFile, exists := formfile[inputFieldName] - if !exists { - continue - } - fhType := reflect.TypeOf((*multipart.FileHeader)(nil)) - numElems := len(inputFile) - if structField.Kind() == reflect.Slice && numElems > 0 && structField.Type().Elem() == fhType { + inputValue, exists := form[inputFieldName] + if exists { + numElems := len(inputValue) + if structField.Kind() == reflect.Slice && numElems > 0 { + sliceOf := structField.Type().Elem().Kind() slice := reflect.MakeSlice(structField.Type(), numElems, numElems) for elemIdx := 0; elemIdx < numElems; elemIdx++ { - slice.Index(elemIdx).Set(reflect.ValueOf(inputFile[elemIdx])) + setWithProperType(sliceOf, inputValue[elemIdx], slice.Index(elemIdx), inputFieldName, errors) } structField.Set(slice) - } else if structField.Type() == fhType { - structField.Set(reflect.ValueOf(inputFile[0])) + } else { + setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) + } + return + } + + inputFile, exists := formfile[inputFieldName] + if !exists { + return + } + fhType := reflect.TypeOf((*multipart.FileHeader)(nil)) + numElems := len(inputFile) + if structField.Kind() == reflect.Slice && numElems > 0 && structField.Type().Elem() == fhType { + slice := reflect.MakeSlice(structField.Type(), numElems, numElems) + for elemIdx := 0; elemIdx < numElems; elemIdx++ { + slice.Index(elemIdx).Set(reflect.ValueOf(inputFile[elemIdx])) } + structField.Set(slice) + } else if structField.Type() == fhType { + structField.Set(reflect.ValueOf(inputFile[0])) } } } From 796cc88d6e9d997b39ed1163defef16a901bf678 Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 19:45:16 +0100 Subject: [PATCH 06/12] Moves out mapping field value into own function mapFormFieldValue. --- binding.go | 63 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/binding.go b/binding.go index 8d80f75..f3aae11 100644 --- a/binding.go +++ b/binding.go @@ -257,41 +257,48 @@ func mapFormField(typeField reflect.StructField, } else if typeField.Type.Kind() == reflect.Struct { mapForm(structField, form, formfile, errors) } else if inputFieldName := typeField.Tag.Get("form"); inputFieldName != "" { - if !structField.CanSet() { - return - } + mapFormFieldValue(inputFieldName, typeField, structField, form, formfile, errors) + } +} - inputValue, exists := form[inputFieldName] - if exists { - numElems := len(inputValue) - if structField.Kind() == reflect.Slice && numElems > 0 { - sliceOf := structField.Type().Elem().Kind() - slice := reflect.MakeSlice(structField.Type(), numElems, numElems) - for elemIdx := 0; elemIdx < numElems; elemIdx++ { - setWithProperType(sliceOf, inputValue[elemIdx], slice.Index(elemIdx), inputFieldName, errors) - } - structField.Set(slice) - } else { - setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) - } - return - } +func mapFormFieldValue(inputFieldName string, typeField reflect.StructField, + structField reflect.Value, form map[string][]string, + formfile map[string][]*multipart.FileHeader, errors Errors) { - inputFile, exists := formfile[inputFieldName] - if !exists { - return - } - fhType := reflect.TypeOf((*multipart.FileHeader)(nil)) - numElems := len(inputFile) - if structField.Kind() == reflect.Slice && numElems > 0 && structField.Type().Elem() == fhType { + if !structField.CanSet() { + return + } + + inputValue, exists := form[inputFieldName] + if exists { + numElems := len(inputValue) + if structField.Kind() == reflect.Slice && numElems > 0 { + sliceOf := structField.Type().Elem().Kind() slice := reflect.MakeSlice(structField.Type(), numElems, numElems) for elemIdx := 0; elemIdx < numElems; elemIdx++ { - slice.Index(elemIdx).Set(reflect.ValueOf(inputFile[elemIdx])) + setWithProperType(sliceOf, inputValue[elemIdx], slice.Index(elemIdx), inputFieldName, errors) } structField.Set(slice) - } else if structField.Type() == fhType { - structField.Set(reflect.ValueOf(inputFile[0])) + } else { + setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) + } + return + } + + inputFile, exists := formfile[inputFieldName] + if !exists { + return + } + fhType := reflect.TypeOf((*multipart.FileHeader)(nil)) + numElems := len(inputFile) + if structField.Kind() == reflect.Slice && numElems > 0 && structField.Type().Elem() == fhType { + slice := reflect.MakeSlice(structField.Type(), numElems, numElems) + for elemIdx := 0; elemIdx < numElems; elemIdx++ { + slice.Index(elemIdx).Set(reflect.ValueOf(inputFile[elemIdx])) } + structField.Set(slice) + } else if structField.Type() == fhType { + structField.Set(reflect.ValueOf(inputFile[0])) } } From 7a5cd90c2c0bd8cfaf165b66086774d821097326 Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 19:49:12 +0100 Subject: [PATCH 07/12] Moves out mapping form multiparts into own function mapFormFieldMultipart. --- binding.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/binding.go b/binding.go index f3aae11..4b6cc24 100644 --- a/binding.go +++ b/binding.go @@ -285,6 +285,12 @@ func mapFormFieldValue(inputFieldName string, typeField reflect.StructField, return } + mapFormFieldMultipart(inputFieldName, structField, formfile, errors) +} + +func mapFormFieldMultipart(inputFieldName string, structField reflect.Value, + formfile map[string][]*multipart.FileHeader, errors Errors) { + inputFile, exists := formfile[inputFieldName] if !exists { return From 276d9ca7f110a2ea0587206a6d2f640189187bab Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 19:52:52 +0100 Subject: [PATCH 08/12] Refactors control flow for less nesting and clearer code. --- binding.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/binding.go b/binding.go index 4b6cc24..9e762de 100644 --- a/binding.go +++ b/binding.go @@ -270,22 +270,22 @@ func mapFormFieldValue(inputFieldName string, typeField reflect.StructField, } inputValue, exists := form[inputFieldName] - if exists { - numElems := len(inputValue) - if structField.Kind() == reflect.Slice && numElems > 0 { - sliceOf := structField.Type().Elem().Kind() - slice := reflect.MakeSlice(structField.Type(), numElems, numElems) - for elemIdx := 0; elemIdx < numElems; elemIdx++ { - setWithProperType(sliceOf, inputValue[elemIdx], slice.Index(elemIdx), inputFieldName, errors) - } - structField.Set(slice) - } else { - setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) - } + if !exists { + mapFormFieldMultipart(inputFieldName, structField, formfile, errors) return } - mapFormFieldMultipart(inputFieldName, structField, formfile, errors) + numElems := len(inputValue) + if structField.Kind() == reflect.Slice && numElems > 0 { + sliceOf := structField.Type().Elem().Kind() + slice := reflect.MakeSlice(structField.Type(), numElems, numElems) + for elemIdx := 0; elemIdx < numElems; elemIdx++ { + setWithProperType(sliceOf, inputValue[elemIdx], slice.Index(elemIdx), inputFieldName, errors) + } + structField.Set(slice) + } else { + setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) + } } func mapFormFieldMultipart(inputFieldName string, structField reflect.Value, From 74192f8c0252c011fb6a758572a551bb408d9272 Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 20:46:54 +0100 Subject: [PATCH 09/12] Cleans up the last else statement for mapping the form. --- binding.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/binding.go b/binding.go index 9e762de..86f1b08 100644 --- a/binding.go +++ b/binding.go @@ -256,15 +256,20 @@ func mapFormField(typeField reflect.StructField, } } else if typeField.Type.Kind() == reflect.Struct { mapForm(structField, form, formfile, errors) - } else if inputFieldName := typeField.Tag.Get("form"); inputFieldName != "" { - mapFormFieldValue(inputFieldName, typeField, structField, form, formfile, errors) + } else { + mapFormFieldValue(typeField, structField, form, formfile, errors) } } -func mapFormFieldValue(inputFieldName string, typeField reflect.StructField, +func mapFormFieldValue(typeField reflect.StructField, structField reflect.Value, form map[string][]string, formfile map[string][]*multipart.FileHeader, errors Errors) { + inputFieldName := typeField.Tag.Get("form") + if inputFieldName == "" { + return + } + if !structField.CanSet() { return } From 0fd5bd5c3a52090bde66f1a0d43b43d14e7442af Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 21:39:49 +0100 Subject: [PATCH 10/12] Refactors and splits up form mapping logic into smaller functions and separates out slice handling. --- binding.go | 60 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/binding.go b/binding.go index 86f1b08..d3f7c85 100644 --- a/binding.go +++ b/binding.go @@ -248,6 +248,10 @@ func mapFormField(typeField reflect.StructField, structField reflect.Value, form map[string][]string, formfile map[string][]*multipart.FileHeader, errors Errors) { + if !structField.CanSet() { + return + } + if typeField.Type.Kind() == reflect.Ptr && typeField.Anonymous { structField.Set(reflect.New(typeField.Type.Elem())) mapForm(structField.Elem(), form, formfile, errors) @@ -256,46 +260,82 @@ func mapFormField(typeField reflect.StructField, } } else if typeField.Type.Kind() == reflect.Struct { mapForm(structField, form, formfile, errors) + } else if typeField.Type.Kind() == reflect.Slice { + mapFormFieldSlice(typeField, structField, form, formfile, errors) } else { mapFormFieldValue(typeField, structField, form, formfile, errors) } } -func mapFormFieldValue(typeField reflect.StructField, +func mapFormFieldSlice(typeField reflect.StructField, structField reflect.Value, form map[string][]string, formfile map[string][]*multipart.FileHeader, errors Errors) { - inputFieldName := typeField.Tag.Get("form") - if inputFieldName == "" { - return + if reflect.TypeOf((*multipart.FileHeader)(nil)) == structField.Type().Elem() { + mapFormFieldMultipart(typeField, structField, formfile, errors) + } else if structField.Type().Elem().Kind() == reflect.Struct { + // TODO: element in slice is struct, iterate all and call mapForm + } else { + mapFormFieldSliceBuiltin(typeField, structField, form, errors) } +} - if !structField.CanSet() { +func mapFormFieldSliceBuiltin(typeField reflect.StructField, + structField reflect.Value, form map[string][]string, errors Errors) { + + inputFieldName := typeField.Tag.Get("form") + if inputFieldName == "" { return } inputValue, exists := form[inputFieldName] if !exists { - mapFormFieldMultipart(inputFieldName, structField, formfile, errors) return } numElems := len(inputValue) - if structField.Kind() == reflect.Slice && numElems > 0 { + if numElems > 0 { sliceOf := structField.Type().Elem().Kind() slice := reflect.MakeSlice(structField.Type(), numElems, numElems) for elemIdx := 0; elemIdx < numElems; elemIdx++ { setWithProperType(sliceOf, inputValue[elemIdx], slice.Index(elemIdx), inputFieldName, errors) } structField.Set(slice) - } else { - setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) } } -func mapFormFieldMultipart(inputFieldName string, structField reflect.Value, +func mapFormFieldValue(typeField reflect.StructField, + structField reflect.Value, form map[string][]string, formfile map[string][]*multipart.FileHeader, errors Errors) { + // handle multipart separately + if structField.Type() == reflect.TypeOf((*multipart.FileHeader)(nil)) { + mapFormFieldMultipart(typeField, structField, formfile, errors) + return + } + + inputFieldName := typeField.Tag.Get("form") + if inputFieldName == "" { + return + } + + inputValue, exists := form[inputFieldName] + if !exists { + return + } + + setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) +} + +func mapFormFieldMultipart(typeField reflect.StructField, + structField reflect.Value, + formfile map[string][]*multipart.FileHeader, errors Errors) { + + inputFieldName := typeField.Tag.Get("form") + if inputFieldName == "" { + return + } + inputFile, exists := formfile[inputFieldName] if !exists { return From 4727c481780a60250519fff6f22498b12dd0364a Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 21:44:51 +0100 Subject: [PATCH 11/12] Changes back to using i as index variable name. --- binding.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/binding.go b/binding.go index d3f7c85..4134a9d 100644 --- a/binding.go +++ b/binding.go @@ -237,9 +237,9 @@ func mapForm(formStruct reflect.Value, form map[string][]string, formStruct = formStruct.Elem() } - for fieldIdx := 0; fieldIdx < formStruct.Type().NumField(); fieldIdx++ { - typeField := formStruct.Type().Field(fieldIdx) - structField := formStruct.Field(fieldIdx) + for i := 0; i < formStruct.Type().NumField(); i++ { + typeField := formStruct.Type().Field(i) + structField := formStruct.Field(i) mapFormField(typeField, structField, form, formfile, errors) } } @@ -297,8 +297,8 @@ func mapFormFieldSliceBuiltin(typeField reflect.StructField, if numElems > 0 { sliceOf := structField.Type().Elem().Kind() slice := reflect.MakeSlice(structField.Type(), numElems, numElems) - for elemIdx := 0; elemIdx < numElems; elemIdx++ { - setWithProperType(sliceOf, inputValue[elemIdx], slice.Index(elemIdx), inputFieldName, errors) + for i := 0; i < numElems; i++ { + setWithProperType(sliceOf, inputValue[i], slice.Index(i), inputFieldName, errors) } structField.Set(slice) } @@ -344,8 +344,8 @@ func mapFormFieldMultipart(typeField reflect.StructField, numElems := len(inputFile) if structField.Kind() == reflect.Slice && numElems > 0 && structField.Type().Elem() == fhType { slice := reflect.MakeSlice(structField.Type(), numElems, numElems) - for elemIdx := 0; elemIdx < numElems; elemIdx++ { - slice.Index(elemIdx).Set(reflect.ValueOf(inputFile[elemIdx])) + for i := 0; i < numElems; i++ { + slice.Index(i).Set(reflect.ValueOf(inputFile[i])) } structField.Set(slice) } else if structField.Type() == fhType { From 5eb09733b689b2a21875c3e8fd4fe16b120bef37 Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Wed, 4 Mar 2015 21:53:48 +0100 Subject: [PATCH 12/12] Splits out form mapping into own file. --- binding.go | 125 ---------------------------------------------- form_mapping.go | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 125 deletions(-) create mode 100644 form_mapping.go diff --git a/binding.go b/binding.go index 4134a9d..159c5ac 100644 --- a/binding.go +++ b/binding.go @@ -6,7 +6,6 @@ package binding import ( "encoding/json" "io" - "mime/multipart" "net/http" "reflect" "strconv" @@ -229,130 +228,6 @@ func validateStruct(errors Errors, obj interface{}) Errors { return errors } -// Takes values from the form data and puts them into a struct -func mapForm(formStruct reflect.Value, form map[string][]string, - formfile map[string][]*multipart.FileHeader, errors Errors) { - - if formStruct.Kind() == reflect.Ptr { - formStruct = formStruct.Elem() - } - - for i := 0; i < formStruct.Type().NumField(); i++ { - typeField := formStruct.Type().Field(i) - structField := formStruct.Field(i) - mapFormField(typeField, structField, form, formfile, errors) - } -} - -func mapFormField(typeField reflect.StructField, - structField reflect.Value, form map[string][]string, - formfile map[string][]*multipart.FileHeader, errors Errors) { - - if !structField.CanSet() { - return - } - - if typeField.Type.Kind() == reflect.Ptr && typeField.Anonymous { - structField.Set(reflect.New(typeField.Type.Elem())) - mapForm(structField.Elem(), form, formfile, errors) - if reflect.DeepEqual(structField.Elem().Interface(), reflect.Zero(structField.Elem().Type()).Interface()) { - structField.Set(reflect.Zero(structField.Type())) - } - } else if typeField.Type.Kind() == reflect.Struct { - mapForm(structField, form, formfile, errors) - } else if typeField.Type.Kind() == reflect.Slice { - mapFormFieldSlice(typeField, structField, form, formfile, errors) - } else { - mapFormFieldValue(typeField, structField, form, formfile, errors) - } -} - -func mapFormFieldSlice(typeField reflect.StructField, - structField reflect.Value, form map[string][]string, - formfile map[string][]*multipart.FileHeader, errors Errors) { - - if reflect.TypeOf((*multipart.FileHeader)(nil)) == structField.Type().Elem() { - mapFormFieldMultipart(typeField, structField, formfile, errors) - } else if structField.Type().Elem().Kind() == reflect.Struct { - // TODO: element in slice is struct, iterate all and call mapForm - } else { - mapFormFieldSliceBuiltin(typeField, structField, form, errors) - } -} - -func mapFormFieldSliceBuiltin(typeField reflect.StructField, - structField reflect.Value, form map[string][]string, errors Errors) { - - inputFieldName := typeField.Tag.Get("form") - if inputFieldName == "" { - return - } - - inputValue, exists := form[inputFieldName] - if !exists { - return - } - - numElems := len(inputValue) - if numElems > 0 { - sliceOf := structField.Type().Elem().Kind() - slice := reflect.MakeSlice(structField.Type(), numElems, numElems) - for i := 0; i < numElems; i++ { - setWithProperType(sliceOf, inputValue[i], slice.Index(i), inputFieldName, errors) - } - structField.Set(slice) - } -} - -func mapFormFieldValue(typeField reflect.StructField, - structField reflect.Value, form map[string][]string, - formfile map[string][]*multipart.FileHeader, errors Errors) { - - // handle multipart separately - if structField.Type() == reflect.TypeOf((*multipart.FileHeader)(nil)) { - mapFormFieldMultipart(typeField, structField, formfile, errors) - return - } - - inputFieldName := typeField.Tag.Get("form") - if inputFieldName == "" { - return - } - - inputValue, exists := form[inputFieldName] - if !exists { - return - } - - setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) -} - -func mapFormFieldMultipart(typeField reflect.StructField, - structField reflect.Value, - formfile map[string][]*multipart.FileHeader, errors Errors) { - - inputFieldName := typeField.Tag.Get("form") - if inputFieldName == "" { - return - } - - inputFile, exists := formfile[inputFieldName] - if !exists { - return - } - fhType := reflect.TypeOf((*multipart.FileHeader)(nil)) - numElems := len(inputFile) - if structField.Kind() == reflect.Slice && numElems > 0 && structField.Type().Elem() == fhType { - slice := reflect.MakeSlice(structField.Type(), numElems, numElems) - for i := 0; i < numElems; i++ { - slice.Index(i).Set(reflect.ValueOf(inputFile[i])) - } - structField.Set(slice) - } else if structField.Type() == fhType { - structField.Set(reflect.ValueOf(inputFile[0])) - } -} - // ErrorHandler simply counts the number of errors in the // context and, if more than 0, writes a response with an // error code and a JSON payload describing the errors. diff --git a/form_mapping.go b/form_mapping.go new file mode 100644 index 0000000..f30ce07 --- /dev/null +++ b/form_mapping.go @@ -0,0 +1,130 @@ +package binding + +import( + "mime/multipart" + "reflect" +) + +// Takes values from the form data and puts them into a struct +func mapForm(formStruct reflect.Value, form map[string][]string, + formfile map[string][]*multipart.FileHeader, errors Errors) { + + if formStruct.Kind() == reflect.Ptr { + formStruct = formStruct.Elem() + } + + for i := 0; i < formStruct.Type().NumField(); i++ { + typeField := formStruct.Type().Field(i) + structField := formStruct.Field(i) + mapFormField(typeField, structField, form, formfile, errors) + } +} + +func mapFormField(typeField reflect.StructField, + structField reflect.Value, form map[string][]string, + formfile map[string][]*multipart.FileHeader, errors Errors) { + + if !structField.CanSet() { + return + } + + if typeField.Type.Kind() == reflect.Ptr && typeField.Anonymous { + structField.Set(reflect.New(typeField.Type.Elem())) + mapForm(structField.Elem(), form, formfile, errors) + if reflect.DeepEqual(structField.Elem().Interface(), reflect.Zero(structField.Elem().Type()).Interface()) { + structField.Set(reflect.Zero(structField.Type())) + } + } else if typeField.Type.Kind() == reflect.Struct { + mapForm(structField, form, formfile, errors) + } else if typeField.Type.Kind() == reflect.Slice { + mapFormFieldSlice(typeField, structField, form, formfile, errors) + } else { + mapFormFieldValue(typeField, structField, form, formfile, errors) + } +} + +func mapFormFieldSlice(typeField reflect.StructField, + structField reflect.Value, form map[string][]string, + formfile map[string][]*multipart.FileHeader, errors Errors) { + + if reflect.TypeOf((*multipart.FileHeader)(nil)) == structField.Type().Elem() { + mapFormFieldMultipart(typeField, structField, formfile, errors) + } else if structField.Type().Elem().Kind() == reflect.Struct { + // TODO: element in slice is struct, iterate all and call mapForm + } else { + mapFormFieldSliceBuiltin(typeField, structField, form, errors) + } +} + +func mapFormFieldSliceBuiltin(typeField reflect.StructField, + structField reflect.Value, form map[string][]string, errors Errors) { + + inputFieldName := typeField.Tag.Get("form") + if inputFieldName == "" { + return + } + + inputValue, exists := form[inputFieldName] + if !exists { + return + } + + numElems := len(inputValue) + if numElems > 0 { + sliceOf := structField.Type().Elem().Kind() + slice := reflect.MakeSlice(structField.Type(), numElems, numElems) + for i := 0; i < numElems; i++ { + setWithProperType(sliceOf, inputValue[i], slice.Index(i), inputFieldName, errors) + } + structField.Set(slice) + } +} + +func mapFormFieldValue(typeField reflect.StructField, + structField reflect.Value, form map[string][]string, + formfile map[string][]*multipart.FileHeader, errors Errors) { + + // handle multipart separately + if structField.Type() == reflect.TypeOf((*multipart.FileHeader)(nil)) { + mapFormFieldMultipart(typeField, structField, formfile, errors) + return + } + + inputFieldName := typeField.Tag.Get("form") + if inputFieldName == "" { + return + } + + inputValue, exists := form[inputFieldName] + if !exists { + return + } + + setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors) +} + +func mapFormFieldMultipart(typeField reflect.StructField, + structField reflect.Value, + formfile map[string][]*multipart.FileHeader, errors Errors) { + + inputFieldName := typeField.Tag.Get("form") + if inputFieldName == "" { + return + } + + inputFile, exists := formfile[inputFieldName] + if !exists { + return + } + fhType := reflect.TypeOf((*multipart.FileHeader)(nil)) + numElems := len(inputFile) + if structField.Kind() == reflect.Slice && numElems > 0 && structField.Type().Elem() == fhType { + slice := reflect.MakeSlice(structField.Type(), numElems, numElems) + for i := 0; i < numElems; i++ { + slice.Index(i).Set(reflect.ValueOf(inputFile[i])) + } + structField.Set(slice) + } else if structField.Type() == fhType { + structField.Set(reflect.ValueOf(inputFile[0])) + } +}