玩框架形式只有18个PARAMS(Play Framework Form only 18 param

2019-06-25 11:32发布

我观察到,当我增加超过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个ARGS测绘工作,在那之后我得到很长的编译错误。

可以在这里找到该错误消息(太长包括): https://gist.github.com/2928297

我在寻找的建议我如何能解决此限制得到。 我知道这是不好的设计在29个参数发送的形式发布,但应该还是可以的。


哈克/变通方法/解决方案

好吧,这里是我砍死在一起的解决方法(写这篇文章花了更长的时间比实现,我砍死了〜30分钟就这一点)

我写了预处理的请求参数,并增加了一组前缀组一定PARAMS功能。 然后我使用生成的地图[字符串,字符串]并继续处理与表单类,做验证等如常。 这让我在映射使用嵌套case类,并得到低于18个PARAMS限制。

当心:丑陋的代码迈进! 我可能不应该表现出早期哈克这样的代码,但我希望它会帮助别人谁想要一个解决方法。

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

最后我能将我的形式,像正常的,但现在我得到的嵌套结构我减少参数的个数,希望使类的情况下更易于管理。

clientRegistrationForm.bind(processedForm).fold( ... )

使用这种方法,你可以保持参数的数量下降。 如果你的参数没有可以方便地将像我的问题相同的前缀,那么你仍然可以使用相同的基本方法,但在其他指标分析筛选。

Answer 1:

我打开一票几个星期前在这个问题上。

如果你选它,也许它会得到游戏开发者一起来看看。

怀疑它的高它们的优先级列表上(不幸给定它的更多或更少的只是一个复制粘贴到钉在19,20,21,和22映射[T])

如果你是绝望的,你可以叉游戏; 否则,想出了一个解决方法,例如,利用嵌套的形式或分裂> 22场模型成单独的形式。



Answer 2:

mapping使用方法不是单一的方法,但它是超载。 对于一个参数,它有两个类型参数,一个是结果类型,一个用于你消耗的元素。 它构建一个ObjectMapping1 。 对于两个参数,它有三种类型的参数,它构造一个ObjectMapping2

这些ObjectMappingX类定义多达ObjectMapping18 ,因为你已经注意到了。 您可以在游戏的源代码中找到它play/api/data/Forms.scala

推荐的解决方案是避免这种尺寸的非嵌套的形式。 如果这是不可避免的,你可以使用一个不同的库比内置的播放,或者你可以定义缺少的ObjectMappingX对象和相应的方法对自己构建它们。



Answer 3:

我不得不解决此限制的一天并没有发现这个SO发布,并与做事情的一种不同的方法,似乎它虽然看着有点靠不住的工作上来。

我们的表单组件

import play.api.data.Form
import play.api.data.Forms._

case class P1_18(f1: String,f2: String,f3: String,f4: String,f5: String,f6: String,f7: String,f8: String,f9: String,f10: String,f11: String,f12: String,f13: String,f14: String,f15: String,f16: String,f17: String,f18: String)

case class P2_18(f1: String,f2: String,f3: String,f4: String,f5: String,f6: String,f7: String,f8: String,f9: String,f10: String,f11: String,f12: String,f13: String,f14: String,f15: String,f16: String,f17: String,f18: String)

case class P36(f1: String,f2: String,f3: String,f4: String,f5: String,f6: String,f7: String,f8: String,f9: String,f10: String,f11: String,f12: String,f13: String,f14: String,f15: String,f16: String,f17: String,f18: String,f19: String,f20: String,f21: String,f22: String,f23: String,f24: String,f25: String,f26: String,f27: String,f28: String,f29: String,f30: String,f31: String,f32: String,f33: String,f34: String,f35: String,f36: String)

P36是你真正想要的对象,P1 / P2只是使用该框架的约束范围内建立起来的类,我在实际应用中取得这些私有的包装形式的对象。

然后,我们有我们的表单定义,这就是魔法发生:

val f = Form(
    mapping(
    "" -> mapping(
        "f1" -> text,
        "f2" -> text,
        "f3" -> text,
        "f4" -> text,
        "f5" -> text,
        "f6" -> text,
        "f7" -> text,
        "f8" -> text,
        "f9" -> text,
        "f10" -> text,
        "f11" -> text,
        "f12" -> text,
        "f13" -> text,
        "f14" -> text,
        "f15" -> text,
        "f16" -> text,
        "f17" -> text,
        "f18" -> text
    )(P1_18.apply)(P1_18.unapply),
    "" -> mapping(
        "f19" -> text,
        "f20" -> text,
        "f21" -> text,
        "f22" -> text,
        "f23" -> text,
        "f24" -> text,
        "f25" -> text,
        "f26" -> text,
        "f27" -> text,
        "f28" -> text,
        "f29" -> text,
        "f30" -> text,
        "f31" -> text,
        "f32" -> text,
        "f33" -> text,
        "f34" -> text,
        "f35" -> text,
        "f36" -> text
    )(P2_18.apply)(P2_18.unapply)
    )(
    (p1, p2) =>
        P36(
            f1 = p1.f1,
            f2 = p1.f2,
            f3 = p1.f3,
            f4 = p1.f4,
            f5 = p1.f5,
            f6 = p1.f6,
            f7 = p1.f7,
            f8 = p1.f8,
            f9 = p1.f9,
            f10 = p1.f10,
            f11 = p1.f11,
            f12 = p1.f12,
            f13 = p1.f13,
            f14 = p1.f14,
            f15 = p1.f15,
            f16 = p1.f16,
            f17 = p1.f17,
            f18 = p1.f18,
            f19 = p2.f1,
            f20 = p2.f2,
            f21 = p2.f3,
            f22 = p2.f4,
            f23 = p2.f5,
            f24 = p2.f6,
            f25 = p2.f7,
            f26 = p2.f8,
            f27 = p2.f9,
            f28 = p2.f10,
            f29 = p2.f11,
            f30 = p2.f12,
            f31 = p2.f13,
            f32 = p2.f14,
            f33 = p2.f15,
            f34 = p2.f16,
            f35 = p2.f17,
            f36 = p2.f18
        )
    )(
        p => {
            val p1 = P1_18(p.f1,p.f2,p.f3,p.f4,p.f5,p.f6,p.f7,p.f8,p.f9,p.f10,p.f11,p.f12,p.f13,p.f14,p.f15,p.f16,p.f17,p.f18)
            val p2 = P2_18(p.f19,p.f20,p.f21,p.f22,p.f23,p.f24,p.f25,p.f26,p.f27,p.f28,p.f29,p.f30,p.f31,p.f32,p.f33,p.f34,p.f35,p.f36)
            Option(
                (p1,p2)
            )
        }
    )
)

你可能会说:呵呵。 呃,对不起,你有一个绑定两次空键。 怎么可能可能工作呢? 我说:

val dataSeq = for(i <- 1 to 36) yield s"f${i}" -> s"text no. #${i}"
val filledFormFromMap = f.bind(dataSeq.toMap)

filledFormFromMap.value

// res9: Option[P36] = Some(P36(text no. #1,text no. #2,text no. #3,text no. #4,text no. #5,text no. #6,text no. #7,text no. #8,text no. #9,text no. #10,text no. #11,text no. #12,text no. #13,text no. #14,text no. #15,text no. #16,text no. #17,text no. #18,text no. #19,text no. #20,text no. #21,text no. #22,text no. #23,text no. #24,text no. #25,text no. #26,text no. #27,text no. #28,text no. #29,text no. #30,text no. #31,text no. #32,text no. #33,text no. #34,text no. #35,text no. #36))

也就是说,它实际是工作无故障。 与18-对象映射极限的问题不是形式不能支持多于18个字段内部但该结合可以不支持它。 然而,当我正看着ObjectMapping源我注意到,默认情况下, key的ObjectMapping的是一个空字符串。 然后还与所述前缀,该场结合必将给定的前缀和:

val field1 = f1._2.withPrefix(f1._1).withPrefix(key)

这让我认识到形式的“顶部”只是一个空的关键。 对于除了猖獗的好奇没有理由我尝试过了两个空的钥匙,因为你可以看到在ObjectMapping 2是空的关键是在这两个领域中:

  val field1 = f1._2.withPrefix(f1._1).withPrefix(key)

  val field2 = f2._2.withPrefix(f2._1).withPrefix(key)

由于mappings领域Mapping仅仅是一个Seq[Mapping]我想,下面的这一切,我们没有使用地图,其中键会冲突的深层合并方法和诸如此类的东西,但这样的组合在非-destructive时尚,因为他们都有这个顶级关键是如何玩(我相信)生成您的field.nested.thing根据您如何嵌套的映射自身的映射。 所以,这一切的一切,这意味着你可以有多个绑定到相同的密钥(或至少是为空字符串),因此可以通过分解成更小的组件,然后提供手动构建任何超过18场大型applyunapply方法结合起来的东西(如反对尝试使用P36.apply和P36.unapply因为这些不会因为元组限制,我相信工作)



文章来源: Play Framework Form only 18 params