如何为play2的表单定义StopOnFirstFail dsl?

时间:2012-03-18 15:46:53

标签: forms validation playframework-2.0

在这个问题:If a form field has multi validators, how to let play verify them one by one, not all?中,Julien给了我一个名为stopOnFirstFail的方法来解决我的问题:

def stopOnFirstFail[T](constraints: Constraint[T]*) = Constraint { field: T =>
  constraints.toList dropWhile (_(field) == Valid) match {
    case Nil => Valid
    case constraint :: _ => constraint(field)
  }
}

它的用法是:

val loginForm = Form(
  "name" -> (text verifying stopOnFirstFail( nonEmpty, minLength(4) ))
)

但我希望定义一个可以用作:

的dsl
val loginForm = Form(
  "name" -> (text verifying ( nonEmpty or minLength(4) ))
)

我尝试为play.api.data.validation.Constraint定义隐式方法:

import play.api.data.validation._

implicit def _Constraint[T](cons: Constraint[T]) = new {

  def or[T](other: Constraint[T]) = Constraint { field: T =>
    cons(field) match {              // (!)
      case Valid => other(field)
      case invalid => invlaid
    }
  }
}

但它无法编译,(!)行中的错误和消息是:

type mismatch; 
found: field.type (with underlying type T) required: T 
Note: implicit method _Constraint is not applicable here
      because it comes after the application point and it lacks an explicit result type

如何解决?

2 个答案:

答案 0 :(得分:3)

or方法不接受类型参数:

implicit def toLazyOr[T](cons: Constraint[T]) = new {
  def or(other: Constraint[T]) = Constraint { field: T =>
    cons(field) match {
      case Valid => other(field)
      case Invalid => Invalid
    }
  }
}

答案 1 :(得分:0)

  def stopOnFirstFail[T](constraints: Constraint[T]*) = Constraint { field: T =>
    var result: ValidationResult = null
    val loop = new Breaks
    loop.breakable(
      for (constrain <- constraints) {
        result = constrain(field)
        if (result != Valid) {
          loop.break()
        }
      }
    )
    if (result == null) Valid else result
  }

此实现只进行一次验证:)