Question

Here below is the usual project layout of a Play application:

myProject
    + app
       + controllers
       + models
       + views

I think the content of controllers, models, and views is clear to most of us. Now let's suppose we need to implement a DAO service using the cake pattern:

DaoServiceComponent.scala:

trait DaoServiceComponent[A] {

  def daoService: DaoService

  trait DaoService {

    def insert(entity: A): Future[A]
    def find(id: Id): Future[Option[A]]
    ...
  }
}

trait DefaultDaoServiceComponent[A] extends DaoServiceComponent[A] {
  this: DaoComponent[A] =>

  def daoService = new DaoService {

    def insert(entity: A) = dao.insert(entity)
    def find(id: Id) = dao.find(id)
    ...
  }
}

DaoComponent.scala:

trait DaoComponent[A] {

  def dao: Dao

  trait Dao {

    def insert(entity: A): Future[A]
    def find(id: Id): Future[Option[A]]
    ...
  }
}

UserDaoComponent.scala:

trait UserDaoComponent extends DaoComponent[User] {

  protected val collection: JSONCollection

  def dao = new Dao {

    def insert(entity: User): Future[User] = {
      ...
    }

    def find(id: Id): Future[Option[User]] = {
      ...
    }
  }
}

And finally we wire everything up in our controller object as usual:

object Users extends Controller {

  private val userService: DaoServiceComponent[User]#DaoService =
    new DefaultDaoServiceComponent[User]
    with UserDaoComponent {
      val collection = db.collection[JSONCollection]("users")
    }.daoService

  def create = Action.async(parse.json) { implicit request =>
    request.body.validate[User].fold(
      valid = { user =>
        userService.insert()..
    ...
  }
}

Now going back to our project layout, where should we put DaoServiceComponent, DaoComponent, UserDaoComponent, and any other support class? Should these files go all together in the services directory?

myProject
    + app
       + controllers
       + models
       + services
            + DaoComponent.scala
            + DaoException.scala
            + DaoServiceComponent.scala
            + EmailServiceComponent.scala
            + RichEmailComponent.scala
            + ServiceException.scala
            + UserDaoComponent.scala
            + ...
       + views

No correct solution

OTHER TIPS

Our project is probably not an exemplary implementation of the Cake pattern because it was originally a Ruby app that didn't use any dependency injection, so take this with a grain of salt

Our DAOs are in the model layer / folder - User.scala contains a User case class and a Users Slick Table[User].

The traits in the Service layer / folder are tightly coupled to the model layer - we do not inject the DAOs.

The service traits are injected into the controllers using the Cake pattern. We have one Service per Controller, eg we have a StreamsController and a StreamsService.

We have about twelve Controllers / Services and about eighty DAOs (one per MySql table).

We have several utility classes, such as a Redis client pool and an HTML template renderer - these are in a Common folder below the model layer because a few are used in the DAOs. We have an Apps trait in the service layer that holds abstract vals to these classes, and all Services include Apps via self : Apps => . The controller layer then has the responsibility to implement and inject Apps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top