2015-01-21 5 views
1

저는 프레임 워크 2.3의 ActionBuilder와 동작을 동적으로 작성할 수있는 andThen 메소드를 정말 좋아합니다. 당신이 추측 수 있듯이Play framework 2.3 ActionBuilder composition issue

def showHomepage = RedirectingAction andThen 
    AuthenticatedAction andThen NotificationAction async { request => 
     Future { 
     Ok(views.html.homepage.render(request.user, request.notifications)) 
    } 
} 

이 NotificationAction이 AuthenticatedAction에 따라, 따라서 사용자 개체를 포함 AuthenticatedRequest이 필요합니다 :

는 여기에 액션 구성을 사용하는 방법의 조각입니다.

코드가 뿌려 :

object NotificationAction extends ActionBuilder[NotificationAuthRequest] { 
    def invokeBlock[A](request: AuthenticatedRequest[A], block: (NotificationAuthRequest[A]) => Future[Result]) = { ... 

오류이다 객체 생성 불가능한 입력의 특성에 ActionFunction 방법 invokeBlock 때문에 [A] (요청 : play.api.mvc.Request [A] 블록 : controllers.v3.ScalaHomepageController.NotificationAuthRequest [A] => scala.concurrent.Future [play.api.mvc.Result] scala.concurrent.Future [play.api.mvc.Result]가 정의되지 않았습니다.

분명히 허용되는 것 :

def invokeBlock[A](request: Request[A], block: ... 

하지만 누군가가이 빛을 던질 수 있다면

def invokeBlock[A](request: AuthenticatedRequest[A], block: ... 

난 정말 감사하겠습니다. 어쩌면 내 접근 방식이 잘못되었을 수도 있지만 나중에 혼합 할 수있는 작업이 더 많아지기 때문에 미리 작성된 액션 (ActionFunction 사용)과 같은 아이디어가 마음에 들지 않습니다. 난 당신이 ActionRefiners 및 ActionTransformers이 필요합니다 생각하는 문서를 읽기

case class AuthenticatedRequest[A](val user: Option[User], request: Request[A]) extends WrappedRequest(request) 

case class NotificationAuthRequest[A](val user: Option[User], val notifications: Option[List[UserNotificationData]], request: Request[A]) extends WrappedRequest(request) 


    object RedirectingAction extends ActionBuilder[Request] { 

     def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = { 
      Future { 
      Redirect(REDIRECT_URL + request.uri + paramString) 
      } 
     } 
    } 

    object AuthenticatedAction extends ActionBuilder[AuthenticatedRequest] { 

    def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) => Future[Result]) = { 
     request.cookies.get("uid") map { 
     cookie => 
      val user = userClient.getUserById(userId(cookie)).get 
      block(AuthenticatedRequest[A](user, request)) 
     } getOrElse { 
     block(AuthenticatedRequest[A](userClient.getUserById(uid).get, request)) 
     } 
    } 


    def userId(cookie: Cookie) = { 
     if(AppUtil.isProd) cookie.value else IMPERSONATE_ID.getOrElse(cookie.value) 
    } 
    } 

    object NotificationAction extends ActionBuilder[NotificationAuthRequest] { 
    def invokeBlock[A](request: AuthenticatedRequest[A], block: (NotificationAuthRequest[A]) => Future[Result]) = { 
     request.user.map { 
     user => block(NotificationAuthRequest[A](Some(user), userClient.getNotifications(user.getId).get.map(_.toList), request)) 
     }.getOrElse { 
     block(NotificationAuthRequest[A](None, None, request)) 
     } 
    } 
    } 

답변

6

:

여기에 코드입니다.

package controllers 

import play.api.mvc._ 

import scala.concurrent.Future 

case class User(id: Long) 

case class UserNotificationData(text: String) 

case class AuthRequest[A](user: Option[User], request: Request[A]) extends WrappedRequest(request) 

case class AuthNotificationRequest[A](user: Option[User], notifications: Option[List[UserNotificationData]], request: Request[A]) extends WrappedRequest(request) 

object RedirectingAction extends ActionBuilder[Request] { 

    def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = { 
    block(request) 
    } 
} 

object AuthenticatedAction extends ActionBuilder[AuthRequest] with ActionTransformer[Request, AuthRequest] { 

    def transform[A](request: Request[A]) = Future.successful { 
    request.cookies.get("uid") map { 
     cookie => 
     val user = Some(User(1)) 
     AuthRequest[A](user, request) 
    } getOrElse { 
     AuthRequest[A](Some(User(1)), request) 
    } 
    } 
} 

object WithNotifications extends ActionTransformer[AuthRequest, AuthNotificationRequest] { 
    def transform[A](request: AuthRequest[A]) = Future.successful { 
    request.user.map { user => AuthNotificationRequest[A](Some(user), Some(List(UserNotificationData("Notification"))), request)} getOrElse { 
     AuthNotificationRequest[A](None, None, request) 
    } 
    } 
} 

object Application extends Controller { 

    def index = (RedirectingAction andThen AuthenticatedAction andThen WithNotifications) { request: AuthNotificationRequest[AnyContent] => 
    Ok(views.html.index("Your new application is ready.")) 
    } 

} 
+0

감사 :

이 내가 생각 해낸 것입니다! 이것은 정말로 좋아 보인다. 나는 이것을 오늘 시험해보고, 그것이 작동하는지에 관해 당신에게 알릴 것이다 :) –

+0

나는 거의 거기에있다! ActionRefiner 문제가 반환 유형이므로 (scala.concurrent.Future [scala.Either [play.api.mvc.Result, P [A]]]) 더 많은 작업을해야합니다. 결과를 반환하고 싶지 않습니다. 다음과 같이 반환하고 싶습니다. 두 경우 모두 NotificationAuthRequest [A] (없음, 없음, 요청). –

+0

대신'ActionTransformer'를 사용할 수 있어야합니다. 시도해 봤어? – bjoernhaeuser