6

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( ... )

このアプローチを使用すると、パラメーターの数を抑えることができます。私の問題のように簡単にグループ化するためにパラメーターに同じプレフィックスがない場合でも、同じ基本的なアプローチを使用できますが、他の基準でフィルター処理できます。

4

3 に答える 3

4

使用するメソッドは単一のmappingメソッドではありませんが、オーバーロードされています。1 つのパラメーターの場合、2 つの型パラメーターがあり、1 つは結果の型用で、もう 1 つは使用している要素用です。を構築しObjectMapping1ます。2 つのパラメーターの場合、3 つの型パラメーターがあり、ObjectMapping2.

お気づきのように、これらのObjectMappingXクラスは まで定義されています。ObjectMapping18次の Play のソース コードで見つけることができます。 play/api/data/Forms.scala

推奨される解決策は、このサイズのネストされていないフォームを避けることです。それが避けられない場合は、組み込みの Play とは異なるライブラリを使用するか、不足しているObjectMappingXオブジェクトと対応するメソッドを定義して自分で構築することができます。

于 2012-06-14T06:50:38.270 に答える
3

数週間前にこの問題についてチケットをオープンしました。

投票すると、おそらく Play 開発者から注目されるでしょう。

それが彼らの優先リストの上位にあるとは思えません (19、20、21、および 22 のマッピング [T] に追加するのは多かれ少なかれ単なるコピペであることを考えると残念です)。

絶望的な場合は、Play をフォークできます。それ以外の場合は、ネストされたフォームを利用するか、22 個を超えるフィールド モデルを個別のフォームに分割するなどの回避策を考えてください。

于 2012-06-14T06:48:17.803 に答える