Na minha opinião, o fato de que os modelos são estaticamente digitados é realmente uma coisa boa : você garante que a chamada do seu modelo não falhará se for compilada.
No entanto, ele realmente adiciona alguns clichês nos sites de chamada. Mas você pode reduzi-lo (sem perder as vantagens da digitação estática).
No Scala, vejo duas maneiras de alcançá-lo: através da composição de ações ou usando parâmetros implícitos. Em Java, sugiro usar o Http.Context.args
mapa para armazenar valores úteis e recuperá-los dos modelos sem ter que passar explicitamente como parâmetros de modelos.
Usando parâmetros implícitos
Coloque o menus
parâmetro no final dos main.scala.html
parâmetros do seu modelo e marque-o como "implícito":
@(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>
Agora, se você tiver modelos chamando esse modelo principal, poderá menus
passar o parâmetro implicitamente para o main
modelo pelo compilador Scala, se ele também for declarado como parâmetro implícito nesses modelos:
@()(implicit menus: Seq[Menu])
@main("SubPage") {
...
}
Mas se você deseja que seja passado implicitamente do seu controlador, é necessário fornecê-lo como um valor implícito, disponível no escopo de onde você chama o modelo. Por exemplo, você pode declarar o seguinte método no seu controlador:
implicit val menu: Seq[Menu] = Menu.findAll
Em suas ações, você poderá escrever o seguinte:
def index = Action {
Ok(views.html.index())
}
def index2 = Action {
Ok(views.html.index2())
}
Você pode encontrar mais informações sobre essa abordagem nesta postagem do blog e neste exemplo de código .
Atualização : Um bom post de blog demonstrando esse padrão também foi escrito aqui .
Usando composição de ações
Na verdade, geralmente é útil passar o RequestHeader
valor para os modelos (veja, por exemplo, este exemplo ). Isso não adiciona muito clichê ao código do controlador, porque você pode escrever facilmente ações que recebem um valor implícito de solicitação:
def index = Action { implicit request =>
Ok(views.html.index()) // The `request` value is implicitly passed by the compiler
}
Portanto, como os modelos geralmente recebem pelo menos esse parâmetro implícito, você pode substituí-lo por um valor mais rico, contendo, por exemplo, seus menus. Você pode fazer isso usando o mecanismo de composição de ações do Play 2.
Para fazer isso, você precisa definir sua Context
classe, agrupando uma solicitação subjacente:
case class Context(menus: Seq[Menu], request: Request[AnyContent])
extends WrappedRequest(request)
Então você pode definir o seguinte ActionWithMenu
método:
def ActionWithMenu(f: Context => Result) = {
Action { request =>
f(Context(Menu.findAll, request))
}
}
Que pode ser usado assim:
def index = ActionWithMenu { implicit context =>
Ok(views.html.index())
}
E você pode considerar o contexto como um parâmetro implícito em seus modelos. Por exemplo, para 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>
O uso da composição de ações permite agregar todos os valores implícitos que seus modelos exigem em um único valor, mas por outro lado, você pode perder alguma flexibilidade…
Usando Http.Context (Java)
Como o Java não possui o mecanismo implícito do Scala ou similar, se você deseja evitar passar explicitamente os parâmetros dos modelos, uma maneira possível é armazená-los no Http.Context
objeto que vive apenas pela duração de uma solicitação. Este objecto contém um args
valor de tipo Map<String, Object>
.
Assim, você pode começar escrevendo um interceptador, conforme explicado na documentação :
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");
}
}
O método estático é apenas uma abreviação para recuperar os menus do contexto atual. Em seguida, anote seu controlador para ser misturado com o Menus
interceptor de ação:
@With(Menus.class)
public class Application extends Controller {
// …
}
Por fim, recupere o menus
valor dos seus modelos da seguinte maneira:
@(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>