Skip to content

Commit 9738dd4

Browse files
Merge pull request #1650 from maenolis/SCALA-229
SCALA-229
2 parents 380a60a + 1f1b982 commit 9738dd4

File tree

10 files changed

+407
-1
lines changed

10 files changed

+407
-1
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package controllers
2+
3+
import com.google.inject.Inject
4+
import models.{
5+
ComplexFormCustomField,
6+
InputFormWithConstraints,
7+
MultipleFieldsForm,
8+
SimpleForm
9+
}
10+
import play.api.i18n.I18nSupport
11+
import play.api.libs.json.Json
12+
import play.api.mvc.{
13+
AbstractController,
14+
Action,
15+
AnyContent,
16+
ControllerComponents
17+
}
18+
19+
class FormController @Inject() (cc: ControllerComponents)
20+
extends AbstractController(cc)
21+
with I18nSupport {
22+
23+
def simpleForm: Action[AnyContent] = Action { implicit request =>
24+
Ok(views.html.Baeldung.FormTemplate(SimpleForm.form))
25+
}
26+
27+
def formPost(): Action[AnyContent] = Action { implicit request =>
28+
val form = SimpleForm.form.bindFromRequest().get
29+
Ok(form.toString)
30+
}
31+
32+
def multipleFieldsForm: Action[AnyContent] = Action { implicit request =>
33+
Ok(views.html.Baeldung.MultipleFieldsFormTemplate(MultipleFieldsForm.form))
34+
}
35+
36+
def multipleFieldsFormPost(): Action[AnyContent] = Action {
37+
implicit request =>
38+
val form = MultipleFieldsForm.form.bindFromRequest().get
39+
Ok(form.toString)
40+
}
41+
42+
def formWithConstraints: Action[AnyContent] = Action { implicit request =>
43+
Ok(
44+
views.html.Baeldung.FormTemplateWithConstraints(
45+
InputFormWithConstraints.form
46+
)
47+
)
48+
}
49+
50+
def formWithConstraintsPost(): Action[AnyContent] = Action {
51+
implicit request =>
52+
InputFormWithConstraints.form
53+
.bindFromRequest()
54+
.fold(
55+
{ formWithError =>
56+
BadRequest(
57+
views.html.Baeldung.FormTemplateWithConstraints(formWithError)
58+
)
59+
},
60+
{ data => Ok(Json.toJson(data)) }
61+
)
62+
}
63+
64+
def simpleFormPostWithErrors(): Action[AnyContent] = Action {
65+
implicit request =>
66+
SimpleForm.form
67+
.bindFromRequest()
68+
.fold(
69+
{ formWithError =>
70+
BadRequest(
71+
views.html.Baeldung.FormTemplateWithErrors(formWithError)
72+
)
73+
},
74+
{ data => Ok(Json.toJson(data)) }
75+
)
76+
}
77+
78+
def complexForm: Action[AnyContent] = Action { implicit request =>
79+
Ok(views.html.Baeldung.ComplexFormTemplate(ComplexFormCustomField.form))
80+
}
81+
82+
def complexFormPostWithErrors(): Action[AnyContent] = Action {
83+
implicit request =>
84+
ComplexFormCustomField.form
85+
.bindFromRequest()
86+
.fold(
87+
{ formWithError =>
88+
BadRequest(views.html.Baeldung.ComplexFormTemplate(formWithError))
89+
},
90+
{ data => Ok(Json.toJson(data)) }
91+
)
92+
}
93+
94+
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
package models
2+
3+
import models.Measure.UnitMeasurement
4+
import play.api.data.Form
5+
import play.api.data.Forms._
6+
import play.api.data.validation.Constraints.minLength
7+
import play.api.libs.json.{Json, Writes}
8+
9+
import java.time.Instant
10+
import java.time.temporal.ChronoUnit
11+
import java.util.{Date, UUID}
12+
13+
case class SimpleForm(i: Int, active: Boolean, msg: String)
14+
15+
object SimpleForm {
16+
17+
implicit val simpleFormWrites: Writes[SimpleForm] = Json.writes[SimpleForm]
18+
val form: Form[SimpleForm] = Form(
19+
mapping(
20+
"i" -> number,
21+
"active" -> boolean,
22+
"msg" -> text
23+
)(SimpleForm.apply)(SimpleForm.unapply)
24+
)
25+
26+
def unapply(simpleForm: SimpleForm): Option[(Int, Boolean, String)] = {
27+
Some((simpleForm.i, simpleForm.active, simpleForm.msg))
28+
}
29+
30+
}
31+
32+
case class MultipleFieldsForm(
33+
i: Int,
34+
pwd: String,
35+
active: Boolean,
36+
msg: String,
37+
date: Date,
38+
uuid: UUID,
39+
favMovie: String,
40+
favDrink: String
41+
)
42+
43+
object MultipleFieldsForm {
44+
45+
implicit val multipleFieldsFormWrites: Writes[MultipleFieldsForm] =
46+
Json.writes[MultipleFieldsForm]
47+
val form: Form[MultipleFieldsForm] = Form(
48+
mapping(
49+
"i" -> number,
50+
"pwd" -> text,
51+
"active" -> boolean,
52+
"msg" -> text,
53+
"date" -> date,
54+
"uuid" -> uuid,
55+
"favMovie" -> text,
56+
"favDrink" -> text
57+
)(MultipleFieldsForm.apply)(MultipleFieldsForm.unapply)
58+
)
59+
60+
def unapply(
61+
multipleFieldsForm: MultipleFieldsForm
62+
): Option[(Int, String, Boolean, String, Date, UUID, String, String)] = {
63+
Some(
64+
(
65+
multipleFieldsForm.i,
66+
multipleFieldsForm.pwd,
67+
multipleFieldsForm.active,
68+
multipleFieldsForm.msg,
69+
multipleFieldsForm.date,
70+
multipleFieldsForm.uuid,
71+
multipleFieldsForm.favMovie,
72+
multipleFieldsForm.favDrink
73+
)
74+
)
75+
}
76+
77+
object Movies {
78+
val list = List(
79+
"pulpFiction" -> "Pulp Fiction",
80+
"inception" -> "Inception",
81+
"theMatrix" -> "The Matrix",
82+
"titanic" -> "Titanic"
83+
)
84+
}
85+
86+
object Drinks {
87+
val list = List(
88+
"vodka" -> "Vodka",
89+
"tequila" -> "Tequila",
90+
"whisky" -> "Whisky",
91+
"wine" -> "Wine",
92+
"beer" -> "Beer"
93+
)
94+
}
95+
96+
}
97+
98+
case class ComplexFormCustomField(
99+
i: Int,
100+
active: Boolean,
101+
msg: String,
102+
measurement: UnitMeasurement
103+
)
104+
object ComplexFormCustomField {
105+
106+
implicit val complexFormWrites: Writes[ComplexFormCustomField] =
107+
Json.writes[ComplexFormCustomField]
108+
val form: Form[ComplexFormCustomField] = Form(
109+
mapping(
110+
"i" -> number,
111+
"active" -> boolean,
112+
"msg" -> text,
113+
"measurement" -> Measure.unitMeasurementMapping
114+
)(ComplexFormCustomField.apply)(ComplexFormCustomField.unapply)
115+
)
116+
117+
def unapply(
118+
complexForm: ComplexFormCustomField
119+
): Option[(Int, Boolean, String, UnitMeasurement)] = {
120+
Some(
121+
(
122+
complexForm.i,
123+
complexForm.active,
124+
complexForm.msg,
125+
complexForm.measurement
126+
)
127+
)
128+
}
129+
}
130+
131+
case class InputFormWithConstraints(
132+
i: Int,
133+
msg: String,
134+
msgOpt: Option[String],
135+
email: String,
136+
birthday: Date
137+
)
138+
object InputFormWithConstraints {
139+
140+
implicit val inputFormWrites: Writes[InputFormWithConstraints] =
141+
Json.writes[InputFormWithConstraints]
142+
val form: Form[InputFormWithConstraints] = Form(
143+
mapping(
144+
"i" -> number(min = 10, max = 20),
145+
"msg" -> text(minLength = 3, maxLength = 12),
146+
"msgOpt" -> optional(text),
147+
"email" -> email,
148+
"birthday" -> date
149+
)(InputFormWithConstraints.apply)(InputFormWithConstraints.unapply)
150+
)
151+
152+
def unapply(
153+
inputForm: InputFormWithConstraints
154+
): Option[(Int, String, Option[String], String, Date)] = {
155+
Some(
156+
(
157+
inputForm.i,
158+
inputForm.msg,
159+
inputForm.msgOpt,
160+
inputForm.email,
161+
inputForm.birthday
162+
)
163+
)
164+
}
165+
}
166+
167+
case class InputFormWithCustomConstraints(email: String, birthday: Date)
168+
object InputFormWithCustomConstraints {
169+
170+
implicit val inputFormWrites: Writes[InputFormWithCustomConstraints] =
171+
Json.writes[InputFormWithCustomConstraints]
172+
val form: Form[InputFormWithCustomConstraints] = Form(
173+
mapping(
174+
"email" -> email.verifying(minLength(15)),
175+
"birthday" -> date.verifying(
176+
"Not 18 years old",
177+
d => d.toInstant.isBefore(Instant.now().minus(18, ChronoUnit.YEARS))
178+
)
179+
)(InputFormWithCustomConstraints.apply)(
180+
InputFormWithCustomConstraints.unapply
181+
)
182+
)
183+
184+
def unapply(
185+
inputForm: InputFormWithCustomConstraints
186+
): Option[(String, Date)] = {
187+
Some((inputForm.email, inputForm.birthday))
188+
}
189+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package models
2+
3+
import play.api.data.format.{Formats, Formatter}
4+
import play.api.data.{FormError, Forms, Mapping}
5+
import play.api.libs.json.{Json, Writes}
6+
7+
object Measure {
8+
9+
def unitMeasurementMapping: Mapping[UnitMeasurement] =
10+
Forms.of[UnitMeasurement]
11+
12+
case class UnitMeasurement(quantity: Int, unit: String)
13+
14+
implicit def binder: Formatter[UnitMeasurement] =
15+
new Formatter[UnitMeasurement] {
16+
override def bind(
17+
key: String,
18+
data: Map[String, String]
19+
): Either[Seq[FormError], UnitMeasurement] = Formats.parsing(
20+
d => UnitMeasurement.fromString(d),
21+
"The format is (\\d*)(\\s)(\\D*)- example: \"1 pound\"",
22+
Nil
23+
)(key, data)
24+
25+
override def unbind(
26+
key: String,
27+
value: UnitMeasurement
28+
): Map[String, String] = Map(key -> s"${value.quantity} ${value.unit}")
29+
}
30+
31+
object UnitMeasurement {
32+
33+
implicit val unitMeasurementFormWrites: Writes[UnitMeasurement] =
34+
Json.writes[UnitMeasurement]
35+
36+
private val pattern = "(\\d*)(\\s)(\\D*)".r
37+
38+
def fromString(str: String): UnitMeasurement = {
39+
val matches = pattern.findAllIn(str)
40+
if (matches.hasNext) {
41+
val List(number, space, quantity) = matches.subgroups
42+
UnitMeasurement(number.toInt, quantity)
43+
} else {
44+
throw new RuntimeException(s"Incorrect data: $str")
45+
}
46+
}
47+
}
48+
49+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@import helper._
2+
3+
@(complexFormCustomField: Form[ComplexFormCustomField])(implicit messages: Messages)
4+
5+
6+
@form(action = routes.FormController.complexFormPostWithErrors()) {
7+
@inputText(complexFormCustomField("i"))
8+
@inputText(complexFormCustomField("active"))
9+
@inputText(complexFormCustomField("msg"))
10+
@inputText(complexFormCustomField("measurement"))
11+
<input type="submit" value="Submit">
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@import helper._
2+
3+
@(simpleForm: Form[SimpleForm])(implicit messages: Messages)
4+
5+
@form(action = routes.FormController.formPost()) {
6+
@inputText(simpleForm("i"))
7+
@inputText(simpleForm("active"))
8+
@inputText(simpleForm("msg"))
9+
<input type="submit" value="Submit">
10+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@import helper._
2+
3+
@(formWithConstraints: Form[InputFormWithConstraints])(implicit messages: Messages)
4+
5+
6+
@form(action = routes.FormController.formWithConstraintsPost()) {
7+
@inputText(formWithConstraints("i"))
8+
@inputText(formWithConstraints("msg"))
9+
@inputText(formWithConstraints("msgOpt"))
10+
@inputText(formWithConstraints("email"))
11+
@inputDate(formWithConstraints("birthday"))
12+
<input type="submit" value="Submit">
13+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@import helper._
2+
3+
@(simpleForm: Form[SimpleForm])(implicit messages: Messages)
4+
5+
6+
@form(action = routes.FormController.formPost()) {
7+
@inputText(simpleForm("i"))
8+
@inputText(simpleForm("active"))
9+
@inputText(simpleForm("msg"))
10+
<input type="submit" value="Submit">
11+
}

0 commit comments

Comments
 (0)