2011-02-17 8 views
0

MVC로 변환 할 PHP 응용 프로그램이 있습니다. 목표는 애플리케이션을 URL과 HTML 측면에서 동일하게 유지하는 것입니다 (SEO 등 + PHP 사이트는 아직 작업중입니다). 우리는 3 개의 뷰로 구성된 예약 프로세스를 가지고 있으며, 현재의 PHP 사이트에서는 모든 뷰가 동일한 URL에 다시 게시되고 예약 프로세스의 어느 페이지/단계가 되돌려 보내 졌는지를 구분하기 위해 숨겨진 필드를 보냅니다 (페이지 간 데이터 저장 됨). 상태가 쿼리가 작성 될 때).POST 매개 변수를 기반으로하는 MVC 경로

MVC에서이를 복제하려면 게시자가 어떤 페이지에서 게시되었는지에 따라 모델의 일부만 채우는 단일 바인더를 사용하여 모든 3 페이지가 게시되는 단일 액션 메소드를 사용할 수 있습니다. 모델을 선택하고 예약 과정에서 다음 스테이지를 결정합니다. 또는 이것이 가능하다면 (그리고 이것은 내 질문이다), POST 매개 변수를 읽을 수있는 경로를 설정하고 POST 매개 변수의 값을 기반으로 다른 동작 방법으로 연결합니다.

내가 아는 한 MVC 라우팅에서이 기능을 지원하지 않는다. (그러나 나는 이것에 대해서 잘못하고 싶다.) 그래서 이것을 지원하기 위해 MVC를 확장 할 필요가 있는가? (나는 여러 가지 동작 방법이 어떻게 든 더 깨끗하다고 ​​생각한다).

귀하의 도움을 많이 주시면 감사하겠습니다.

답변

1

저는 두 가지 해결책을 생각해 냈습니다. 하나는 내가 일하는 사람이 고안 한 것이고, 다른 하나는 더 우아한 해결책입니다.

첫번째 해결책은 지정된 경로에 대해 MVcRouteHandler을 확장하는 클래스를 지정하는 것이 었습니다. 이 경로 처리기는 HttpContext의 양식에서 경로를 검사하고 양식 데이터를 읽고 RequestContext에서 RouteData을 업데이트 할 수 있습니다.

MapRoute(routes, 
      "Book", 
      "{locale}/book", 
      new { controller = "Reservation", action = "Index" }).RouteHandler = new ReservationRouteHandler(); 

은 ReservationRouteHandler은 다음과 같습니다

public class ReservationRouteHandler: MvcRouteHandler 
{ 
    protected override IHttpHandler GetHttpHandler(RequestContext requestContext) 
    { 
     var request = requestContext.HttpContext.Request; 

     // First attempt to match one of the posted tab types 
     var action = ReservationNavigationHandler.GetActionFromPostData(request); 

     requestContext.RouteData.Values["action"] = action.ActionName; 
     requestContext.RouteData.Values["viewStage"] = action.ViewStage; 

     return base.GetHttpHandler(requestContext); 
    }   

NavigationHandler 실제로 양식 데이터를 찾고의 일을하지만 당신은 아이디어를 얻을.

이 솔루션은 효과가 있지만 컨트롤러 클래스를 보면 결코 알 수 없지만 en-gb/book이 다른 방법을 가리키는 이유는 알 수 없습니다. 이것은 실제로 재사용이 가능하다고 느끼지 않습니다.

더 나은 솔루션은 컨트롤러에 오버로드 된 메서드가있는 것입니다. 즉,이 메서드는 모두이 경우 book이라고하며 사용자 지정의 ActionMethodSelectorAttribute를 정의합니다. 이것은 HttpPost 속성이 파생 된 것입니다.

public class FormPostFilterAttribute : ActionMethodSelectorAttribute 
{ 
    private readonly string _elementId; 
    private readonly string _requiredValue; 

    public FormPostFilterAttribute(string elementId, string requiredValue) 
    { 
     _elementId = elementId; 
     _requiredValue = requiredValue; 
    } 

    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo) 
    { 
     if (string.IsNullOrEmpty(controllerContext.HttpContext.Request.Form[_elementId])) 
     { 
      return false; 
     } 

     if (controllerContext.HttpContext.Request.Form[_elementId] != _requiredValue) 
     { 
      return false; 
     } 

     return true; 
    } 
} 

MVC는 주어진 컨트롤러에서 올바른 작업 방법을 해결하려고 할 때이 클래스를 호출합니다. 다음과 같이 우리는 다음 작업 방법을 선언

public ActionResult Book(HotelSummaryPostData hotelSummary) 
    { 
     return View("CustomerDetails"); 
    } 

    [FormFieldFilter("stepID", "1")] 
    public ActionResult Book(YourDetailsPostData yourDetails, RequestedViewPostData requestedView) 
    { 
     return View(requestedView.RequestedView); 
    } 

    [FormFieldFilter("stepID", "2")] 
    public ActionResult Book(RoomDetailsPostData roomDetails, RequestedViewPostData requestedView) 
    { 
     return View(requestedView.RequestedView); 
    } 

    [HttpGet] 
    public ActionResult Book() 
    { 
     return View(); 
    } 

우리는 SelectorAttributes가 제대로되는 행동 방식을 결정하는이 페이지의 형태가 일반적인 URL에 다시 게시 할 때 있도록 숨겨진 필드가 다른 페이지에 stepID 정의해야 호출. 동일한 속성의 메소드가 존재하지 않고 속성 세트가 존재할 때 액션 메소드를 올바르게 선택한다는 사실에 놀라움을 금치 못했다.

이러한 메서드 선택기를 스택 할 수 있는지 여부를 살펴 보지 않았습니다. MVC에서이 기능을 매우 멋진 기능으로 만들 수 있다고 생각합니다.

나는이 답변이 나 이외의 다른 누군가에게 유용하기를 바랍니다. :)

관련 문제