Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add support for form multiple values for xxx[] keys (don't need to sp…

…ecify all indexes anymore)
  • Loading branch information...
commit d18711588dd2263d64a76459aceb852ece4aa138 1 parent 815d829
@guillaumebort guillaumebort authored
View
11 framework/src/play/src/main/java/play/data/DynamicForm.java
@@ -43,7 +43,16 @@ public String get(String key) {
* @return a copy of this form filled with the new data
*/
public DynamicForm bindFromRequest() {
- return bind(requestData());
+ return bind(requestData(play.mvc.Controller.request()));
+ }
+
+ /**
+ * Binds request data to this form - that is, handles form submission.
+ *
+ * @return a copy of this form filled with the new data
+ */
+ public DynamicForm bindFromRequest(play.mvc.Http.Request request) {
+ return bind(requestData(request));
}
/**
View
70 framework/src/play/src/main/java/play/data/Form.java
@@ -92,58 +92,79 @@ public Form(String rootName, Class<T> clazz, Map<String,String> data, Map<String
this.groups = groups;
}
- protected Map<String,String> requestData() {
+ protected Map<String,String> requestData(Http.Request request) {
Map<String,String[]> urlFormEncoded = new HashMap<String,String[]>();
- if(play.mvc.Controller.request().body().asFormUrlEncoded() != null) {
- urlFormEncoded = play.mvc.Controller.request().body().asFormUrlEncoded();
+ if(request.body().asFormUrlEncoded() != null) {
+ urlFormEncoded = request.body().asFormUrlEncoded();
}
Map<String,String[]> multipartFormData = new HashMap<String,String[]>();
- if(play.mvc.Controller.request().body().asMultipartFormData() != null) {
- multipartFormData = play.mvc.Controller.request().body().asMultipartFormData().asFormUrlEncoded();
+ if(request.body().asMultipartFormData() != null) {
+ multipartFormData = request.body().asMultipartFormData().asFormUrlEncoded();
}
Map<String,String> jsonData = new HashMap<String,String>();
- if(play.mvc.Controller.request().body().asJson() != null) {
+ if(request.body().asJson() != null) {
jsonData = play.libs.Scala.asJava(
play.api.data.FormUtils.fromJson("",
play.api.libs.json.Json.parse(
- play.libs.Json.stringify(play.mvc.Controller.request().body().asJson())
+ play.libs.Json.stringify(request.body().asJson())
)
)
);
}
- Map<String,String[]> queryString = play.mvc.Controller.request().queryString();
+ Map<String,String[]> queryString = request.queryString();
Map<String,String> data = new HashMap<String,String>();
for(String key: urlFormEncoded.keySet()) {
- String[] value = urlFormEncoded.get(key);
- if(value.length > 0) {
- data.put(key, value[0]);
+ String[] values = urlFormEncoded.get(key);
+ if(key.endsWith("[]")) {
+ String k = key.substring(0, key.length() - 2);
+ for(int i=0; i<values.length; i++) {
+ data.put(k + "[" + i + "]", values[i]);
+ }
+ } else {
+ if(values.length > 0) {
+ data.put(key, values[0]);
+ }
}
}
for(String key: multipartFormData.keySet()) {
- String[] value = multipartFormData.get(key);
- if(value.length > 0) {
- data.put(key, value[0]);
+ String[] values = multipartFormData.get(key);
+ if(key.endsWith("[]")) {
+ String k = key.substring(0, key.length() - 2);
+ for(int i=0; i<values.length; i++) {
+ data.put(k + "[" + i + "]", values[i]);
+ }
+ } else {
+ if(values.length > 0) {
+ data.put(key, values[0]);
+ }
}
}
-
+
for(String key: jsonData.keySet()) {
data.put(key, jsonData.get(key));
}
for(String key: queryString.keySet()) {
- String[] value = queryString.get(key);
- if(value.length > 0) {
- data.put(key, value[0]);
+ String[] values = queryString.get(key);
+ if(key.endsWith("[]")) {
+ String k = key.substring(0, key.length() - 2);
+ for(int i=0; i<values.length; i++) {
+ data.put(k + "[" + i + "]", values[i]);
+ }
+ } else {
+ if(values.length > 0) {
+ data.put(key, values[0]);
+ }
}
}
-
+
return data;
}
@@ -153,7 +174,16 @@ public Form(String rootName, Class<T> clazz, Map<String,String> data, Map<String
* @return a copy of this form filled with the new data
*/
public Form<T> bindFromRequest(String... allowedFields) {
- return bind(requestData(), allowedFields);
+ return bind(requestData(play.mvc.Controller.request()), allowedFields);
+ }
+
+ /**
+ * Binds request data to this form - that is, handles form submission.
+ *
+ * @return a copy of this form filled with the new data
+ */
+ public Form<T> bindFromRequest(Http.Request request, String... allowedFields) {
+ return bind(requestData(request), allowedFields);
}
/**
View
30 framework/src/play/src/main/scala/play/api/data/Form.scala
@@ -68,16 +68,26 @@ case class Form[T](mapping: Mapping[T], data: Map[String, String], errors: Seq[F
* @return a copy of this form filled with the new data
*/
def bindFromRequest()(implicit request: play.api.mvc.Request[_]): Form[T] = {
- val data = (request.body match {
- case body: play.api.mvc.AnyContent if body.asFormUrlEncoded.isDefined => body.asFormUrlEncoded.get
- case body: play.api.mvc.AnyContent if body.asMultipartFormData.isDefined => body.asMultipartFormData.get.asFormUrlEncoded
- case body: play.api.mvc.AnyContent if body.asJson.isDefined => FormUtils.fromJson(js = body.asJson.get).mapValues(Seq(_))
- case body: Map[_, _] => body.asInstanceOf[Map[String, Seq[String]]]
- case body: play.api.mvc.MultipartFormData[_] => body.asFormUrlEncoded
- case body: play.api.libs.json.JsValue => FormUtils.fromJson(js = body).mapValues(Seq(_))
- case _ => Map.empty[String, Seq[String]]
- }) ++ request.queryString
- bind(data.mapValues(_.headOption.getOrElse("")))
+ bindFromRequest {
+ (request.body match {
+ case body: play.api.mvc.AnyContent if body.asFormUrlEncoded.isDefined => body.asFormUrlEncoded.get
+ case body: play.api.mvc.AnyContent if body.asMultipartFormData.isDefined => body.asMultipartFormData.get.asFormUrlEncoded
+ case body: play.api.mvc.AnyContent if body.asJson.isDefined => FormUtils.fromJson(js = body.asJson.get).mapValues(Seq(_))
+ case body: Map[_, _] => body.asInstanceOf[Map[String, Seq[String]]]
+ case body: play.api.mvc.MultipartFormData[_] => body.asFormUrlEncoded
+ case body: play.api.libs.json.JsValue => FormUtils.fromJson(js = body).mapValues(Seq(_))
+ case _ => Map.empty[String, Seq[String]]
+ }) ++ request.queryString
+ }
+ }
+
+ def bindFromRequest(data: Map[String, Seq[String]]): Form[T] = {
+ bind {
+ data.foldLeft(Map.empty[String,String]) {
+ case (s, (key, values)) if key.endsWith("[]")=> s ++ values.zipWithIndex.map { case (v,i) => (key.dropRight(2) + "[" + i + "]") -> v }
+ case (s, (key, values)) => s + (key -> values.headOption.getOrElse(""))
+ }
+ }
}
/**
View
22 framework/src/play/src/test/scala/play/data/AnotherUser.java
@@ -0,0 +1,22 @@
+package play.data;
+
+import java.util.*;
+
+public class AnotherUser {
+
+ private String name;
+ private List<String> emails = new ArrayList<String>();
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public List<String> getEmails() {
+ return emails;
+ }
+
+}
View
50 framework/src/play/src/test/scala/play/data/FormSpec.scala
@@ -47,8 +47,9 @@ object ScalaForms {
val loginForm = Form(
tuple(
"email" -> of[String],
- "password" -> of[Int])
+ "password" -> of[Int]
)
+ )
val helloForm = Form(
tuple(
@@ -73,11 +74,19 @@ object ScalaForms {
)
)
+ val repeatedForm = Form(
+ tuple(
+ "name" -> nonEmptyText,
+ "emails" -> list(nonEmptyText)
+ )
+ )
+
val form = Form(
"foo" -> Forms.text.verifying("first.digit", s => (s.headOption map {_ == '3'}) getOrElse false)
.transform[Int](Integer.parseInt _, _.toString).verifying("number.42", _ < 42)
- )
+ )
}
+
object FormSpec extends Specification {
"A form" should {
@@ -114,8 +123,6 @@ object FormSpec extends Specification {
"apply constraints on wrapped mappings" in {
-
-
"when it binds data" in {
val f1 = ScalaForms.form.bind(Map("foo"->"0"))
f1.errors.size must equalTo (1)
@@ -154,13 +161,44 @@ object FormSpec extends Specification {
}
"render form using field[Type] syntax" in {
-
val anyData = Map("email" -> "bob@gmail.com", "password" -> "123")
ScalaForms.loginForm.bind(anyData).get.toString must equalTo("(bob@gmail.com,123)")
}
+ "support repeated values" in {
+ ScalaForms.repeatedForm.bindFromRequest( Map("name" -> Seq("Kiki")) ).get must equalTo(("Kiki", Seq()))
+ ScalaForms.repeatedForm.bindFromRequest( Map("name" -> Seq("Kiki"), "emails[0]" -> Seq("kiki@gmail.com")) ).get must equalTo(("Kiki", Seq("kiki@gmail.com")))
+ ScalaForms.repeatedForm.bindFromRequest( Map("name" -> Seq("Kiki"), "emails[0]" -> Seq("kiki@gmail.com"), "emails[1]" -> Seq("kiki@zen.com")) ).get must equalTo(("Kiki", Seq("kiki@gmail.com", "kiki@zen.com")))
+ ScalaForms.repeatedForm.bindFromRequest( Map("name" -> Seq("Kiki"), "emails[0]" -> Seq(), "emails[1]" -> Seq("kiki@zen.com")) ).hasErrors must equalTo(true)
+ ScalaForms.repeatedForm.bindFromRequest( Map("name" -> Seq("Kiki"), "emails[]" -> Seq("kiki@gmail.com")) ).get must equalTo(("Kiki", Seq("kiki@gmail.com")))
+ ScalaForms.repeatedForm.bindFromRequest( Map("name" -> Seq("Kiki"), "emails[]" -> Seq("kiki@gmail.com", "kiki@zen.com")) ).get must equalTo(("Kiki", Seq("kiki@gmail.com", "kiki@zen.com")))
+ }
+
+ "support repeated values for Java binding" in {
+
+ val user1 = Controller.form(classOf[play.data.AnotherUser]).bindFromRequest(new DummyRequest(Map("name" -> Array("Kiki")))).get
+ user1.getName must beEqualTo("Kiki")
+ user1.getEmails.size must beEqualTo(0)
+
+ val user2 = Controller.form(classOf[play.data.AnotherUser]).bindFromRequest(new DummyRequest(Map("name" -> Array("Kiki"), "emails[0]" -> Array("kiki@gmail.com")) )).get
+ user2.getName must beEqualTo("Kiki")
+ user2.getEmails.size must beEqualTo(1)
+
+ val user3 = Controller.form(classOf[play.data.AnotherUser]).bindFromRequest(new DummyRequest(Map("name" -> Array("Kiki"), "emails[0]" -> Array("kiki@gmail.com"), "emails[1]" -> Array("kiki@zen.com")) )).get
+ user3.getName must beEqualTo("Kiki")
+ user3.getEmails.size must beEqualTo(2)
+
+ val user4 = Controller.form(classOf[play.data.AnotherUser]).bindFromRequest(new DummyRequest(Map("name" -> Array("Kiki"), "emails[]" -> Array("kiki@gmail.com")) )).get
+ user4.getName must beEqualTo("Kiki")
+ user4.getEmails.size must beEqualTo(1)
+
+ val user5 = Controller.form(classOf[play.data.AnotherUser]).bindFromRequest(new DummyRequest(Map("name" -> Array("Kiki"), "emails[]" -> Array("kiki@gmail.com", "kiki@zen.com")) )).get
+ user5.getName must beEqualTo("Kiki")
+ user5.getEmails.size must beEqualTo(2)
+
+ }
+
"render a form with max 18 fields" in {
-
ScalaForms.helloForm.bind(Map("name" -> "foo", "repeat" -> "1")).get.toString must equalTo("(foo,1,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None)")
}
View
4 framework/src/play/src/test/scala/play/iteratee/ConcurrentSpec.scala
@@ -11,7 +11,7 @@ object ConcurrentSpec extends Specification {
"not slow down the enumerator if the iteratee is slow" in {
Promise.timeout((),1)
- val slowIteratee = Iteratee.foldM(List[Long]()){ (s,e:Long) => Promise.timeout(s :+ e,100) }
+ val slowIteratee = Iteratee.foldM(List[Long]()){ (s,e:Long) => Promise.timeout(s :+ e, 100) }
val fastEnumerator = Enumerator[Long](1,2,3,4,5,6,7,8,9,10)
val result =
fastEnumerator &>
@@ -20,7 +20,7 @@ object ConcurrentSpec extends Specification {
Concurrent.buffer(20) |>>>
slowIteratee
- result.value.get.max must beLessThan(100L)
+ result.value.get.max must beLessThan(1000L)
}
"throw an exception when buffer is full" in {
Please sign in to comment.
Something went wrong with that request. Please try again.