Play Framework 2.4 use injected variable in Scala template - scala

I would like to show some data from the database in the menubar of my web page. To get the data, I have a data-access-object (DAO) which is usually created with Guice injection.
How can I use such an (injected) object in my Scala templates?
I could pass it as a parameter to the template, but I had to do this on every single page (because it should be displayed in the menubar). I'm looking for another solution where I don't have to pass it everywhere. Currently I'm creating a new object inside the template, whenever it is rendered (which gets me a cleaner code but a worse performance).

You can kinda-sorta fake this without too much effort.
First, create a Scala object that provides access to your DAO (this can contain as many things as you want, just repeat the pattern within the top-level object and the Implicits object).
package com.example.stuff
object ViewAccessPoint {
private[stuff] val myDaoCache = Application.instanceCache[MyDao]
object Implicits {
implicit def myDao(implicit application: Application): MyDao = myDaoCache(application)
}
}
In your view, you can then import the Implicits object into your template and get hold of the DAO created by Guice.
#import com.example.stuff.ViewAccessPoint.Implicits._
#import play.api.Play.current
myDao.whatever()
This works for both Java and Scala projects.
You can see this in practice here:
Access point
Template
On a side note, I would consider if you really want to be doing data access in your template layer.

Related

how init a val out the object in scala?

A redis cluster client should should be shared in many place,am I right? with the google, so I use a RedisCli object:
object RedisCli {
val jedisClusterNodes = new java.util.HashSet[HostAndPort]()
jedisClusterNodes.add(new HostAndPort("192.168.1.100", 6379))
lazy val jedisCluster = new JedisCluster(jedisClusterNodes)
//...method with jedisCluster
}
the problem is how can I init the jedisCluster out the object--I want init the HostAndPort in the main method of other object, get the ip from properties file the file passed by command line. should I just use class RedisCli in my circumstance?
I think I am totally lost in class and object.
In Scala all members of a singleton objects should be defined. While you are allowed to modify var members from the outside, take a step back and ask yourself what is the point of having a singleton object in your case if each client can modify its members? You will only end up with spaghetti code.
I would highly recommend using a dependency injection framework (Spring for example) where you can create beans in a specific place then inject them where you need them.
In a nutshell singleton objects should be used when you want to define methods and values (never seen a case where a var is used) that are not specific to each instance of a class (think Java static). In your case, you seem to want different instances (otherwise why should they be set from client code) but want a certain instance to be shared across different clients and this is exactly what dependency injection allows you to do.
If you don't want to use a DI framework and are okay with having clients modify your instances as they please, then simply use a class as opposed to an object. When you use the class keyword, different instances can be instantiated.
class RedisCli(val ip: String, val port: Int) {
val hostAndPort: HostAndPort = new HostAndPort(ip, port)
etc...
}
Hope this helps.

Using dependency injection in a Game of Life to inject new rules

I have a course project that is a refactor of Game of Life in Scala. It's a
simple pure Scala + SBT project. One of my tasks is to extract the game logic
from GameEngine class and make easier to add new rules, as Conway, Highlife or
anything like that. I turned GameEngine into an abstract class and made all
classes that inherit from it implement methods to decide when cells should die or
reborn. When my game is starting, I have this code:
def addGameMode(gameMode:GameEngine) {
modes += gameMode
}
addGameMode(ConwayEngine)
addGameMode(EasyMode)
addGameMode(HighLife)
addGameMode(Seeds)
And my classes that depends on the GameEngine rule receives it as a
construct parameter. When I need to change the game rule, I use an setter method, like
the code below:
class GameView( var gameEngine: GameEngine, modes: MutableList[GameEngine] ) extends JFXApp {
...
def setGameEngine(g: GameEngine) {
gameEngine = g
}
...
}
I don't know if this approach is correct but, from what I learned, the dependency
injection is correct. But, for my teacher, it isn't. And there my problems began.
According to him, the dependency should be declared in a .xml file and treated by
an external lib. He recommended Spring but I don't know how I should implement
the dependency injection in simple Scala + SBT project using a web framework.
Hopefully, I can ignore this recommendation to use Spring and use another lib.
I found MacWire but I don't know how to use it
to solve this problem. Can someone help me?

Using object SomeController extends Controller in Play framework 2.5 instead

We're in the progress of upgrading to play 2.5.5 from play 2.4.x. We have a
pretty large amount of controllers that are objects, like so:
object TranslationsController extends Controller { ... }
However, since switching to 2.5, we now get hundreds of errors like this
(it's a pretty huge project):
type TranslationsController is not a member of package controllers
Is there a way to still allow some/most our Controllers to be object and
not class? I realize this has everything to do with dependency injection.
But a pretty large percentage of the controllers, has no dependencies.
Of course, we could rewrite it like so just to make it compile:
class TranslationsController #Inject () extends Controller { ... }
but that's really pointless?? An immutable class/object that takes no
parameters, should be an object. It's like case class None() vs case
object None. Of course the latter should be the preferred one in every case.
The big deal here is that we can't just string replace object->class
either, because we have a lot (~1000) of tests that assumes these
controllers to be objects. To make it work with class, we would have to
rewrite all those tests to first do a val controller =
new TranslationsController, first, which is a lot of work (and tons of
boilerplate).
I would really appreciate if there was some way to still use object. Is
there some syntax for it in the .routes files, or is there an easy
workaround? I mean, once there are dependencies to these controllers, we'll
make them classes, but to do that to 100 controllers in one go without any
benefit is pretty painful.
You should be able to keep those controllers if you tell Play to use the old routes generator. In your build.sbt put:
routesGenerator := StaticRoutesGenerator
and reload your project

How do I give global access to an object in Scala without making it a singleton or passing it to everything?

I have a Logger class that logs events in my application. While I only need one instance of the logger in this application, I want this class to be reusable, so I don't want to make it a singleton and couple it with my specific needs for this application.
I want to be able to access this Logger instance from anywhere in the application without having to create a new one every time or pass it around to every class that might need to log something. What I currently do is have an ApplicationUtils singleton that I use as the point of access for the application's Logger:
object ApplicationUtils {
lazy val log : Logger = new Logger()
}
Then I have a Loggable trait that I add to classes that need the Logger:
trait Loggable {
protected[this] lazy val log = ApplicationUtils.log
}
Is this a valid approach for what I am trying to accomplish? It feels a little hack-y. Is there a better approach I could be using? I'm pretty new to Scala.
Be careful when putting functionality in objects. That functionality is easily testable, but if you need to test clients of that code to make sure they interact with it correctly (via mocks and spies), you're stuck 'cause objects compile to final classes and thus cannot be mocked.
Instead, use this pattern:
trait T { /* code goes here */ }
object T extends T /* pass this to client code from main sources */
Now you can create Mockito mocks / spies for trait T in your test code, pass that in and confirm that the interactions of the code under test with the trait T code are what they should be.
If you have code that's a client of T and whose interactions with it don't require testing, you can directly reference object T.
To address what you're trying to do (rather than what you're asking), take a look at TypeSafe's scalalogging package. It provides a Logging trait that you can use like so:
class MyClass extends Logging {
logger.debug("This is very convenient ;-)")
}
It's a macro-based wrapper for SLF4J, so something like logger.debug(...) gets compiled as if (logger.isDebugEnabled) logger.debug(...).

PlayFramework instantiate object in current request scope?

I am currently active PlayFramework learner who came from world of PHP.
For example I have a Head block object in my app, which should hold title, charset encoding, meta information, etc. Something similar to Magento blocks, but without XML declaration
package blocks.Page
object Head {
var title: String = "";
}
In Application.index() method I have
blocks.Page.Head.title
Ok(views.html.application.index());
And finally in html template
#import blocks.Page.Head
<title>#Head.title</title>
However, blocks.Page.Head object is defined for entire application scope, not for single request. This object is the same for each request.
What is the right way to do, what I am trying to do? I can create container with all blocks and instantiate it with each request, then just pass to all templates. But I have a feeling that this is wrong way.
Just use usual class instead of object and pass instance to template as parameter.
Like this:
package blocks.Page
case class Head(title: String = "")
Controller:
val head = Head("Blah")
Ok(views.html.application.index(head))
And template will looks like:
#(head: blocks.Page.Head)
...
<title>#head.title</title>
I know the feeling when coming from a request-oriented language like PHP :). However, consider application-wide access as a gift of a VM (in PHP we need to go the extra mile of using some bytecode and data caching tool like APC or eAccellerator).
I would probably create a blockManager class which gives you static access to blocks by name/tag/id from the template: Block.get("MyBlock"). Then you can define and later modify your caching / storing strategy (holding in memory vs. loading from storage) without affecting your templates.