À mon avis, le fait que les modèles soient typés de manière statique est en fait une bon une chose : vous avez la garantie que l'appel de votre modèle n'échouera pas s'il compile.
Cependant, cela ajoute effectivement un peu de "boilerplate" sur les sites appelants. Mais vous pouvez le réduire (sans perdre les avantages du typage statique).
En Scala, je vois deux façons d'y parvenir : par la composition d'actions ou par l'utilisation de paramètres implicites. En Java, je suggère d'utiliser la méthode Http.Context.args
map pour stocker des valeurs utiles et les récupérer dans les modèles sans avoir à passer explicitement les paramètres des modèles.
Utilisation de paramètres implicites
Placez le menus
à la fin de votre main.scala.html
paramètres du modèle et le marquer comme "implicite" :
@(title: String)(content: Html)(implicit menus: Seq[Menu])
<html>
<head><title>@title</title></head>
<body>
<div>
@for(menu<-menus) {
<a href="#">@menu.name</a>
}
</div>
@content
</body>
</html>
Maintenant, si vous avez des modèles qui appellent ce modèle principal, vous pouvez avoir l'attribut menus
passé implicitement pour vous à la main
par le compilateur Scala s'il est également déclaré comme paramètre implicite dans ces modèles :
@()(implicit menus: Seq[Menu])
@main("SubPage") {
...
}
Mais si vous voulez qu'elle soit implicitement transmise par votre contrôleur, vous devez la fournir comme une valeur implicite, disponible dans la portée d'où vous appelez le modèle. Par exemple, vous pouvez déclarer la méthode suivante dans votre contrôleur :
implicit val menu: Seq[Menu] = Menu.findAll
Ensuite, dans vos actions, vous pourrez simplement écrire ce qui suit :
def index = Action {
Ok(views.html.index())
}
def index2 = Action {
Ok(views.html.index2())
}
Vous pouvez trouver plus d'informations sur cette approche dans cet article de blog et en cet exemple de code .
Mise à jour : Un bon article de blog démontrant ce modèle a également été écrit. aquí .
Utilisation de la composition des actions
En fait, il est souvent utile de passer l'option RequestHeader
aux modèles (voir par exemple cet échantillon ). Cela n'ajoute pas beaucoup de texte passe-partout au code de votre contrôleur, car vous pouvez facilement écrire des actions recevant une valeur de demande implicite :
def index = Action { implicit request =>
Ok(views.html.index()) // The `request` value is implicitly passed by the compiler
}
Ainsi, puisque les modèles reçoivent souvent au moins ce paramètre implicite, vous pouvez le remplacer par une valeur plus riche contenant par exemple vos menus. Vous pouvez le faire en utilisant l'option composition des actions mécanisme de jeu 2.
Pour ce faire, vous devez définir votre Context
qui englobe une requête sous-jacente :
case class Context(menus: Seq[Menu], request: Request[AnyContent])
extends WrappedRequest(request)
Vous pouvez ensuite définir les éléments suivants ActionWithMenu
méthode :
def ActionWithMenu(f: Context => Result) = {
Action { request =>
f(Context(Menu.findAll, request))
}
}
Qui peut être utilisé comme ceci :
def index = ActionWithMenu { implicit context =>
Ok(views.html.index())
}
Et vous pouvez prendre le contexte comme un paramètre implicite dans vos modèles. Par exemple, pour main.scala.html
:
@(title: String)(content: Html)(implicit context: Context)
<html><head><title>@title</title></head>
<body>
<div>
@for(menu <- context.menus) {
<a href="#">@menu.name</a>
}
</div>
@content
</body>
</html>
L'utilisation de la composition d'actions vous permet d'agréger toutes les valeurs implicites que vos modèles requièrent en une seule valeur, mais d'un autre côté vous pouvez perdre une certaine flexibilité
Utilisation de Http.Context (Java)
Étant donné que Java ne dispose pas du mécanisme d'implicites de Scala ou d'un mécanisme similaire, si vous souhaitez éviter de passer explicitement les paramètres des modèles, une solution possible consiste à les stocker dans le fichier Http.Context
qui ne vit que le temps d'une requête. Cet objet contient un args
valeur de type Map<String, Object>
.
Ainsi, vous pouvez commencer par écrire un intercepteur, comme expliqué dans la rubrique la documentation :
public class Menus extends Action.Simple {
public Result call(Http.Context ctx) throws Throwable {
ctx.args.put("menus", Menu.find.all());
return delegate.call(ctx);
}
public static List<Menu> current() {
return (List<Menu>)Http.Context.current().args.get("menus");
}
}
La méthode statique est juste un raccourci pour récupérer les menus du contexte actuel. Ensuite, annotez votre contrôleur pour qu'il soit mélangé avec la méthode Menus
intercepteur d'action :
@With(Menus.class)
public class Application extends Controller {
// …
}
Enfin, récupérez le menus
de vos modèles comme suit :
@(title: String)(content: Html)
<html>
<head><title>@title</title></head>
<body>
<div>
@for(menu <- Menus.current()) {
<a href="#">@menu.name</a>
}
</div>
@content
</body>
</html>
0 votes
Peut-être que play2 devrait ajouter quelque chose comme les snippets de lift.