我观察到,当我向 Play Framework Form-class 添加超过 18 个参数时,我会收到一个很长(对我来说难以理解)的编译错误。
这是有记录的限制吗?我需要在表单帖子中接收多达 29 个参数。我不决定参数的设计和数量,因为我正在实现开放标准的协议。
我这样映射:
val registration = Form(mapping(
"client_type" -> nonEmptyText,
"client_id" -> optional(nonEmptyText),
... up to 29 args, all optional(nonEmptyText)
){ (clientType, clientId ...) => RegistrationRequest(clientType, clientId ...) }
{ req => None })
我的策略是以这种方式进行映射而不是应用/取消应用并创建案例类的层次结构。原因是为了解决 Case 类中 22 个参数的限制,这是我遇到的第一个看似任意的限制。最多 18 个参数映射有效,之后我收到一个很长的编译错误。
错误消息可以在这里找到(太长,无法包含):https://gist.github.com/2928297
我正在寻找有关如何克服此限制的建议。我知道在 Post 表单中发送 29 个参数是糟糕的设计,但它应该仍然是可能的。
黑客/解决方法/解决方案
好吧,这是我破解的解决方法(写这篇文章比实现花费的时间要长得多,我为此破解了约 30 分钟)
我编写了预处理请求参数并添加组前缀来对某些参数进行分组的函数。然后,我使用生成的 Map[String, String] 并继续处理表单类,照常进行验证等。这允许我在映射中使用嵌套案例类并低于 18 个参数限制。
当心:前面的代码很丑陋!我可能不应该展示这样的早期黑客代码,但我希望它能帮助其他想要解决方法的人。
def preprocessFormParams(prefix:String, replace:String)(implicit request:Request[AnyContent]):Map[String, String] = request.body.asFormUrlEncoded.map( _.filterKeys( _.startsWith(prefix)).map( m => m._1.patch(0, replace, prefix.length) -> m._2.head )).getOrElse(Map.empty)
def unprocessedFormParams(prefixes:Set[String])(implicit request:Request[AnyContent]):Map[String, String] = request.body.asFormUrlEncoded.map( _.filterKeys( !prefixes.contains(_) ).map( m => m._1 -> m._2.head )).getOrElse(Map.empty)
因此,这些函数可能应该用于理解或拆分,但这里是:
preprocessedFormParms 采用前缀并替换它:
val clientParams = preprocessFormParams("client_", "client.")
("client_id" -> "val1", "client_type" -> "val2") becomes ("client.id" -> "val1", "client.type" -> "val2")
当我有 group.key1, group.key2 形式的参数时,我可以像这样以这样的形式嵌套案例类
Form(mapping("client" -> mapping("type" -> nonEmptyText
"id" -> optional(nonEmptyText),
"secret" -> optional(nonEmptyText))
(RegisterClient.apply)(RegisterClient.unapply)
... more params ...)
(RegisterRequest.apply)(RegisterRequest.unapply)
在我的行动中,我继续过滤掉我的每个组
implicit request =>
val clientParams = preprocessFormParams("client_", "client.")
val applicationParams = preprocessFormParams("application_", "application.")
val unprocessedParams = unprocessedFormParams(Set("client_", "application_"))
val processedForm = clientParams ++ applicationParams ++ unprocessedParams
最后,我可以像平常一样应用我的表单,但现在我得到了嵌套结构 I,它减少了参数数量,并希望使案例类更易于管理。
clientRegistrationForm.bind(processedForm).fold( ... )
使用这种方法可以减少参数的数量。如果您的参数没有相同的前缀以便像我的问题一样轻松分组,那么您仍然可以使用相同的基本方法,但根据其他条件进行过滤。