Skip to content

Commit

Permalink
feat(form): rework code to work a more use cases
Browse files Browse the repository at this point in the history
  • Loading branch information
rande committed Oct 11, 2023
1 parent 2205576 commit 31dd3b2
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 117 deletions.
12 changes: 8 additions & 4 deletions core/form/form_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,26 @@ func yes(value string) bool {
return value == "checked" || value == "true" || value == "1" || value == "on" || value == "yes"
}

func no(value string) bool {
return value == "false" || value == "0" || value == "off" || value == "no"
}

func BoolToStr(v interface{}) (string, bool) {
if v, ok := v.(bool); ok {
if v {
return "yes", true
return "true", true
} else {
return "no", true
return "false", true
}
}

return "", false
}

func StrToBool(value interface{}) (bool, bool) {
if value == "yes" {
if yes(value.(string)) {
return true, true
} else if value == "no" {
} else if no(value.(string)) {
return false, true
}

Expand Down
223 changes: 149 additions & 74 deletions core/form/form_marshaller.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,38 @@ func iterateFields(form *Form, fields []*FormField) {
}
}

func configure(field *FormField, form *Form) {
var rv reflect.Value
func marshal(field *FormField, form *Form) {
field.Marshaller(field, form)
}

if form.Data != nil && field.InitialValue == nil {
field.reflectField = form.reflect.FieldByName(field.Name)
rv = field.reflectField
} else if field.InitialValue != nil {
field.reflectValue = reflect.ValueOf(field.InitialValue)
rv = field.reflectValue
} else {
panic(fmt.Sprintf("Unable to find the field type: %s, %v", field.Name, field.InitialValue))
}
func unmarshal(field *FormField, form *Form, values url.Values) {
field.Errors = []string{}

if rv.Kind() != reflect.Invalid {
field.InitialValue = rv.Interface()
if values.Has(field.Input.Name) {
field.Input.Value = values.Get(field.Input.Name)
}

var marshaller Marshaller = defaultMarshal
var unmarshaller Unmarshaller = defaultUnmarshal
kind := "text"
field.Unmarshaller(field, form, values)

field.HasErrors = len(field.Errors) > 0
}

type MarshallerResult struct {
Marshaller Marshaller
Unmarshaller Unmarshaller
Type string
}

func findMarshaller(rv reflect.Value) *MarshallerResult {
if rv.Kind() == reflect.String {
marshaller = defaultMarshal
unmarshaller = defaultUnmarshal
kind = "text"
} else if rv.Kind() == reflect.Int ||
return &MarshallerResult{
Marshaller: defaultMarshal,
Unmarshaller: defaultUnmarshal,
Type: "text",
}
}

if rv.Kind() == reflect.Int ||
rv.Kind() == reflect.Int8 ||
rv.Kind() == reflect.Int16 ||
rv.Kind() == reflect.Int32 ||
Expand All @@ -63,59 +69,85 @@ func configure(field *FormField, form *Form) {
rv.Kind() == reflect.Uint64 ||
rv.Kind() == reflect.Float32 ||
rv.Kind() == reflect.Float64 {
marshaller = numberMarshal
unmarshaller = numberUnmarshal
kind = "number"
} else if rv.Kind() == reflect.Bool {
marshaller = booleanMarshal
unmarshaller = booleanUnmarshal
kind = "boolean"

} else if rv.Kind() == reflect.Struct {

return &MarshallerResult{
Marshaller: numberMarshal,
Unmarshaller: numberUnmarshal,
Type: "number",
}
}

if rv.Kind() == reflect.Bool {
return &MarshallerResult{
Marshaller: booleanMarshal,
Unmarshaller: booleanUnmarshal,
Type: "boolean",
}
}

if rv.Kind() == reflect.Struct {
if rv.Type() == reflect.TypeOf(time.Time{}) {
marshaller = dateMarshal
unmarshaller = dateUnmarshal
kind = "date"
return &MarshallerResult{
Marshaller: dateMarshal,
Unmarshaller: dateUnmarshal,
Type: "date",
}
}
} else if rv.Kind() == reflect.Ptr {
}

if rv.Kind() == reflect.Ptr {
if rv.Type() == reflect.TypeOf(&Form{}) {
marshaller = formMarshal
unmarshaller = formUnmarshal
kind = "form"
} else if rv.Type() == reflect.TypeOf(&FieldCollectionOptions{}) {
marshaller = collectionMarshal
unmarshaller = collectionUnmarshal
kind = "collection"
return &MarshallerResult{
Marshaller: formMarshal,
Unmarshaller: formUnmarshal,
Type: "form",
}
}

if rv.Type() == reflect.TypeOf(&FieldCollectionOptions{}) {
return &MarshallerResult{
Marshaller: collectionMarshal,
Unmarshaller: collectionUnmarshal,
Type: "collection",
}
}
}

if field.Input.Type == "" {
field.Input.Type = kind
return &MarshallerResult{
Marshaller: defaultMarshal,
Unmarshaller: defaultUnmarshal,
Type: "text",
}
}

if field.Marshaller == nil {
field.Marshaller = marshaller
func configure(field *FormField, form *Form) {

if form.Data != nil && field.InitialValue == nil {
field.reflect = form.reflect.FieldByName(field.Name)
}

if field.Unmarshaller == nil {
field.Unmarshaller = unmarshaller
if field.reflect.Kind() == reflect.Invalid && field.InitialValue != nil {

field.reflect = reflect.ValueOf(field.InitialValue)
}
}

func marshal(field *FormField, form *Form) {
field.Marshaller(field, form)
}
if field.reflect.Kind() != reflect.Invalid {
field.InitialValue = field.reflect.Interface()
}

func unmarshal(field *FormField, form *Form, values url.Values) {
field.Errors = []string{}
result := findMarshaller(field.reflect)

if values.Has(field.Input.Name) {
field.Input.Value = values.Get(field.Input.Name)
if field.Input.Type == "" {
field.Input.Type = result.Type
}

field.Unmarshaller(field, form, values)
if field.Marshaller == nil {
field.Marshaller = result.Marshaller
}

field.HasErrors = len(field.Errors) > 0
if field.Unmarshaller == nil {
field.Unmarshaller = result.Unmarshaller
}
}

func defaultMarshal(field *FormField, form *Form) error {
Expand Down Expand Up @@ -144,7 +176,9 @@ func defaultUnmarshal(field *FormField, form *Form, values url.Values) error {
}

func booleanMarshal(field *FormField, form *Form) error {
defaultMarshal(field, form)
if err := defaultMarshal(field, form); err != nil {
return err
}

if v, ok := BoolToStr(field.InitialValue); ok && !field.HasErrors {
field.Input.Value = v
Expand All @@ -154,7 +188,9 @@ func booleanMarshal(field *FormField, form *Form) error {
}

func booleanUnmarshal(field *FormField, form *Form, values url.Values) error {
defaultUnmarshal(field, form, values)
if err := defaultUnmarshal(field, form, values); err != nil {
return err
}

if v, ok := StrToBool(field.SubmittedValue); ok && !field.HasErrors {
field.SubmittedValue = v
Expand All @@ -164,7 +200,9 @@ func booleanUnmarshal(field *FormField, form *Form, values url.Values) error {
}

func numberMarshal(field *FormField, form *Form) error {
defaultMarshal(field, form)
if err := defaultMarshal(field, form); err != nil {
return err
}

if field.InitialValue != nil {
v, _ := NumberToStr(field.InitialValue)
Expand All @@ -177,28 +215,23 @@ func numberMarshal(field *FormField, form *Form) error {
}

func numberUnmarshal(field *FormField, form *Form, values url.Values) error {
defaultUnmarshal(field, form, values)
if err := defaultUnmarshal(field, form, values); err != nil {
return err
}

if field.HasErrors {
return nil
}

var rv reflect.Value
var v string
var ok bool

if field.reflectValue.IsValid() {
rv = field.reflectValue
} else {
rv = field.reflectField
}

if v, ok = field.SubmittedValue.(string); !ok {
field.Errors = append(field.Errors, ErrInvalidType.Error())
return nil
}

if value, ok := StrToNumber(v, rv.Kind()); ok {
if value, ok := StrToNumber(v, field.reflect.Kind()); ok {
field.SubmittedValue = value
} else {
field.Errors = append(field.Errors, ErrInvalidType.Error())
Expand All @@ -212,7 +245,9 @@ func numberUnmarshal(field *FormField, form *Form, values url.Values) error {
// but the parsed value is always formatted yyyy-mm-dd.
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date
func dateMarshal(field *FormField, form *Form) error {
defaultMarshal(field, form)
if err := defaultMarshal(field, form); err != nil {
return err
}

if v, ok := field.InitialValue.(time.Time); ok {
field.Input.Value = v.Format("2006-01-02")
Expand All @@ -224,7 +259,9 @@ func dateMarshal(field *FormField, form *Form) error {
}

func dateUnmarshal(field *FormField, form *Form, values url.Values) error {
defaultUnmarshal(field, form, values)
if err := defaultUnmarshal(field, form, values); err != nil {
return err
}

if v, ok := field.SubmittedValue.(string); ok {
if t, err := time.ParseInLocation("2006-01-02", v, time.UTC); err != nil {
Expand Down Expand Up @@ -264,7 +301,7 @@ func formUnmarshal(field *FormField, form *Form, values url.Values) error {
}

func collectionMarshal(field *FormField, form *Form) error {
options := field.InitialValue.(*FieldCollectionOptions)
options := field.Options.(*FieldCollectionOptions)

field.Input.Name = fmt.Sprintf("%s%s", field.Prefix, field.Name)
field.Input.Id = replacers.Replace(field.Input.Name)
Expand All @@ -274,6 +311,7 @@ func collectionMarshal(field *FormField, form *Form) error {

subField := create(value.Key, "form", subForm)
subField.Input.Name = fmt.Sprintf("%s[%s]", field.Input.Name, value.Key)

subField.Input.Id = replacers.Replace(subField.Input.Name)
subField.Prefix = field.Input.Name + "."

Expand All @@ -287,7 +325,7 @@ func collectionMarshal(field *FormField, form *Form) error {
}

func collectionUnmarshal(field *FormField, form *Form, values url.Values) error {
options := field.InitialValue.(*FieldCollectionOptions)
options := field.Options.(*FieldCollectionOptions)

for _, value := range options.Items {
subField := field.Get(value.Key)
Expand All @@ -302,7 +340,7 @@ func checkboxMarshal(field *FormField, form *Form) error {
field.Input.Name = fmt.Sprintf("%s%s", field.Prefix, field.Name)
field.Input.Id = replacers.Replace(field.Input.Name)

for i, option := range field.InitialValue.(FieldOptions) {
for i, option := range field.Options.(FieldOptions) {
// find a nice way to generate the name
subField := CreateFormField()
subField.Name = fmt.Sprintf("%d", i)
Expand All @@ -321,7 +359,7 @@ func checkboxMarshal(field *FormField, form *Form) error {
func checkboxUnmarshal(field *FormField, form *Form, values url.Values) error {
// we need to check for extra values!
submitedValues := FieldOptions{}
for i, option := range field.InitialValue.(FieldOptions) {
for i, option := range field.Options.(FieldOptions) {
name := fmt.Sprintf("%d", i)
value, err := getValue(field.Get(name), values)

Expand All @@ -345,3 +383,40 @@ func checkboxUnmarshal(field *FormField, form *Form, values url.Values) error {

return nil
}

func selectMarshal(field *FormField, form *Form) error {
field.Input.Name = fmt.Sprintf("%s%s", field.Prefix, field.Name)
field.Input.Id = replacers.Replace(field.Input.Name)

for i, option := range field.Options.(FieldOptions) {
marshallers := findMarshaller(reflect.ValueOf(option.Value))

// find a nice way to generate the name
subField := CreateFormField()
subField.Name = fmt.Sprintf("%d", i)
subField.Input.Name = fmt.Sprintf("%s[%s]", field.Input.Name, subField.Name)
subField.Input.Id = replacers.Replace(subField.Input.Name)
subField.Label.Value = option.Label
subField.Input.Type = "option"
subField.Marshaller = marshallers.Marshaller
subField.Unmarshaller = marshallers.Unmarshaller

marshal(subField, form)

field.Children = append(field.Children, subField)
}

return nil
}

func selectUnmarshal(field *FormField, form *Form, values url.Values) error {

if len(field.Children) == 0 {
field.Errors = append(field.Errors, "Unable to find any options")
field.HasErrors = true
}

field.Children[0].Unmarshaller(field, form, values)

return nil
}
Loading

0 comments on commit 31dd3b2

Please sign in to comment.