Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ErrorHandler 不接受指针类型 #5

Open
cgyy opened this issue Oct 26, 2015 · 9 comments
Open

ErrorHandler 不接受指针类型 #5

cgyy opened this issue Oct 26, 2015 · 9 comments

Comments

@cgyy
Copy link

cgyy commented Oct 26, 2015

Validate 和Error 对指针的处理方式不统一, 前者接受指针类型而后者不接受

// 这样的方法不被识别
func (form *VariantForm) Error(ctx *macaron.Context, errs binding.Errors) {}

// macaron 识别这样的方法
func (form *VariantForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {}

@unknwon
Copy link
Contributor

unknwon commented Oct 26, 2015

func (form *VariantForm) Error(ctx *macaron.Context, errs binding.Errors) {}

不是很懂你这个方法是怎么来的。。

@cgyy
Copy link
Author

cgyy commented Oct 26, 2015

你好,是这样的
比如我要自定义form的验证方法,可以这样写:

func (form *MyForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
///
}

也可以这样写

func (form MyForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
///
}

而自定义错误处理,只能写成这样:

func (cf ContactForm) Error(ctx *macaron.Context, errs binding.Errors) {
    // 自定义错误处理过程
}

写成下面这样不起作用

func (cf *ContactForm) Error(ctx *macaron.Context, errs binding.Errors) {
    // �自定义错误处理过程不起作用,
}

@unknwon
Copy link
Contributor

unknwon commented Oct 26, 2015

能否发一下你绑定某个 form(不起作用的) 是怎么写的?

@cgyy
Copy link
Author

cgyy commented Oct 26, 2015

// 商品型号
type VariantForm struct {
    OptionValues []int
    Price        float32 `binding:"Required"`
    Sku          string
}

// 验证选项值需要全部大于0
func (form *VariantForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
    if len(errs) > 0 {
        return errs
    }
    for _, v := range form.OptionValues {
        if v == 0 {
            errs.Add([]string{"OptionValues"}, "RequiredError", "Required")
            break
        }

    }
    return errs
}

func (form *VariantForm) Error(ctx *macaron.Context, errs binding.Errors) {
    if len(errs) > 0 {
        flash := ctx.GetVal(reflect.TypeOf(&session.Flash{})).Interface().(*session.Flash)
        errMsg := fmt.Sprintf("%s: %s", strings.Join(errs[0].FieldNames, ","), errs[0].Message)
        flash.Error(errMsg)
        ctx.Redirect(fmt.Sprintf("/variants/%d/edit", 30))
    }
}

自定义错误处理写成下面可以运行:

func (form VariantForm) Error(ctx *macaron.Context, errs binding.Errors) {
    if len(errs) > 0 {
        flash := ctx.GetVal(reflect.TypeOf(&session.Flash{})).Interface().(*session.Flash)
        errMsg := fmt.Sprintf("%s: %s", strings.Join(errs[0].FieldNames, ","), errs[0].Message)
        flash.Error(errMsg)
        ctx.Redirect(fmt.Sprintf("/variants/%d/edit", 30))
    }
}

@unknwon
Copy link
Contributor

unknwon commented Oct 26, 2015

额。。其实我想说的是,注册路由部分的代码。。

@cgyy
Copy link
Author

cgyy commented Oct 27, 2015

好的,代码是这样的:

type VariantsController struct {
    *macaron.Context
}

func MapVariants(ctx *macaron.Context) {
    ctx.Map(&VariantsController{ctx})
}

    m.Group("/variants", func() {
        m.Get("/:id/edit", (*VariantsController).Edit)
        m.Put("/:id", binding.Bind(VariantForm{}), (*VariantsController).Update)

    }, MapVariants)

@unknwon
Copy link
Contributor

unknwon commented Oct 28, 2015

额。。看起来没问题。。我看了代码,判断 Validate 和 Error 的用法是一样的。。暂时不知道为什么。。0 0

@cgyy
Copy link
Author

cgyy commented Oct 28, 2015

似乎是Bind 方法里面没有判断指针类型的原因
binding.go 104行

func Bind(obj interface{}, ifacePtr ...interface{}) macaron.Handler {
    return func(ctx *macaron.Context) {
        bind(ctx, obj, ifacePtr...)
        if handler, ok := obj.(ErrorHandler); ok {
            ctx.Invoke(handler.Error)
        } else {
            ctx.Invoke(errorHandler)
        }
    }
}

第210行

func Validate(obj interface{}) macaron.Handler {
    return func(ctx *macaron.Context) {
        var errors Errors
        v := reflect.ValueOf(obj)
        k := v.Kind()
        if k == reflect.Interface || k == reflect.Ptr {
            v = v.Elem()
            k = v.Kind()
        }
        if k == reflect.Slice || k == reflect.Array {
            for i := 0; i < v.Len(); i++ {
                e := v.Index(i).Interface()
                errors = validateStruct(errors, e)
                if validator, ok := e.(Validator); ok {
                    errors = validator.Validate(ctx, errors)
                }
            }
        } else {
            errors = validateStruct(errors, obj)
            if validator, ok := obj.(Validator); ok {
                errors = validator.Validate(ctx, errors)
            }
        }
        ctx.Map(errors)
    }
}

@unknwon
Copy link
Contributor

unknwon commented Oct 29, 2015

噢。。那这个目前我还没想到什么好的办法,因为 Bind 是禁止你传指针的,否则会出现大量数据竞争破坏内存出现奇怪的错误

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants