我正在define a form尝试使用以下属性和约束play! 2.0.4:
表单处理重复值(可以方便地假设这些值的类型为number
)。所以这将使我们得到这样的东西:
"numbers" -> list(number)
每个数字必须是唯一的,即它对于提交的所有其他数字必须是唯一的,并且它必须对数据库中已存在的数字是唯一的(这可以通过某个函数{{ 1}})。
表单错误应该特定于数字,这不是唯一的。我不希望一般表单错误说“有重复的数字”。
最好的方法是什么?
答案 0 :(得分:3)
这里的诀窍是定义一个类似example的自定义Constraint
。然后,可以在Constraint
上使用自定义Mapping[T]
,以使用verifying
方法验证表单中的字段。
自定义Constraint
包含返回ValidationResult
或Valid
Invalid
的逻辑。可以将错误消息传递给Invalid
结果,您可以在该结果中指定数据库中存在重复或存在的内容。
有关自定义验证的部分,请参阅Play for Scala。
//Make this lazy to prevent java.lang.ExceptionInInitializerError at runtime.
lazy val uniqueNumbersConstraint = Constraint[String](Some("Unique numbers constraint"), "")(checkNumbers)
//"Business Logic".
//Important part here is that the function returns a ValidationResult and complies with the signature for Constraint. i.e. f: (T) => ValidationResult
//Return Valid if n in numbers is not in database and there are no duplicates.
//Otherwise return Invalid and an error message showing what numbers are in the database or duplicated.
def checkNumbers(numbers: String):ValidationResult = {
val splitNums = numbers.split(" ").toList.map(_.toInt)
val dbnums = splitNums.partition(database.contains(_))
if(dbnums._1.isEmpty && uniquesAndDuplicates(splitNums)._2.isEmpty){
Valid
}else{
val duplicates = uniquesAndDuplicates(dbnums._2)._2
val error = "Database contains: " + dbnums._1 + ", duplicated values: " + duplicates
Invalid(error)
}
}
val helloForm = Form(
tuple(
"numbers" -> nonEmptyText.verifying(uniqueNumbersConstraint)
))
//Return unique values on left side and duplicate values on right side
def uniquesAndDuplicates(numbers: List[Int]):Tuple2[List[Int], List[Int]] = {
numbers.partition(i => numbers.indexOf (i) == numbers.lastIndexOf(i))
}
def checkNum(num: Int) = {
database.contains(num)
}
val database = List(5,6,7)
注意我在表单中将numbers
定义为String
。当我将其定义为list(number)
时,它会继续评估为List()
。我认为这是一个具有约束力的问题。如果使用List(1,2,3)
有效,则使用"1 2 3"
而不是list(number)
进行相当简单的更改。
答案 1 :(得分:2)
如下:
def validateUnique(input: List[Int]): ValidationResult = {
// Assuming check return true if the input num doesn't exist yet
def check(num: Int): Boolean = num % 2 == 0
val unique = input.toSet
val dbDuplicates = unique.filterNot(check)
val formDuplicates = input.diff(unique.toSeq)
val duplicates = (dbDuplicates ++ formDuplicates).toList
duplicates match {
case List() => Valid
case _ => Invalid("Duplicates: " + duplicates.mkString(", "))
}
}
val uniqueConstraint = Constraint[List[Int]](validateUnique(_))
然后您可以使用新约束:
mapping(
...,
"ints" -> list(number).verifying(uniqueConstraint)
...