2014-04-22 3 views
3

AJAX 요청에서 양식 제출을 처리하는 컨트롤러가 있습니다. 나는 나 자신을 반복하고 싶지 않아, 그래서 방법으로 폼 처리 코드를 삽입 :POST 대신 PUT을 사용하여 양식 제출

// Should process POST request 
public function create(Request $request) 
{ 
    return $this->processEdit($request); 
} 

// Should process PUT request 
public function update($id, Request $request) 
{ 
    $entity = $this->findEntity($id); // custom method 

    if (!$entity) 
     return $this->myCustomErrorResponse(); 

    return $this->processEdit($request, $entity); 
} 

private function processEdit(Request $request, Entity $entity = null) 
{ 
    $form = $this->createForm('my_entity', $entity); 

    $form->handleRequest($request); 

    if ($form->isValid()) { 
     // Do something 
    } else { 
     // Handle invalid form 
    } 

    return $response; 
} 

내가 가지고있는 다음과 같은 두 가지 경로 : 그러나

ajax_create: 
    pattern:/
    defaults: { _controller: 'MyBundle:Ajax:create' } 
    methods: [ POST ] 

ajax_update: 
    pattern: /{id} 
    defaults: { _controller: 'MyBundle:Ajax:update' } 
    methods: [ PUT ] 
    requirements: 
     id: \d+ 

, 나는 AJAX를 통해 양식을 제출할 때 , 그것은 양식 오류 메시지없이 PUT 요청 및 반환 양식을 사용할 수 없습니다 허용하지 않습니다. 내가 컨트롤러 코드 ABIT를 변경하는 경우,

$form = $this->createForm('my_entity', $entity, array(
    'method' => 'PUT', 
)); 

... 그것은 PUT 요청하지만 POST 요청을 처리합니다.

Symfony2의 어느 부분에서 HTTP 메소드가 양식을 검사하는지 궁금해하므로 소스 코드에서 답변을 찾으려고했지만 단서를 찾을 수 없습니다. 여러분 중 누구도 지식을 공유 할 수 있습니까?

또 다른 질문은 HTTP 메소드 검사를 건너 뛸 수있는 방법이 있습니까? 현재 $method을 위의 방법에 전달 중입니다.

대단히 감사합니다.


업데이트 :

내 질문에 명확하게하기 위해, 내 Symfony2 응용 프로그램 경로 요청 (POST 모두와 PUT) 올바른 제어 방법에 관한 것이다.

// Should process POST request 
public function create(Request $request) 
{ 
    return $this->processEdit($request); 
} 

// Should process PUT request 
public function update($id, Request $request) 
{ 
    $entity = $this->findEntity($id); // custom method 

    if (!$entity) 
     return $this->myCustomErrorResponse(); 

    return $this->processEdit($request, 'PUT', $entity); 
} 

private function processEdit(Request $request, $method = 'POST', Entity $entity = null) 
{ 
    $form = $this->createForm('my_entity', $entity, array(
     'method' => $method, 
    )); 

    $form->handleRequest($request); 

    if ($form->isValid()) { 
     // Do something 
    } else { 
     // Handle invalid form 
    } 

    return $response; 
} 

답변

3

:

것부터 먼저, 당신이 얻을 수를 제출 메서드를 요청 개체에서 별도로 전달할 필요가 없습니다.

getMethod()

둘째, 내가 찾던 코드 부분을 찾은 것 같습니다. 먼저 symfony Form 클래스에서 handleRequest 호출을 확인하면 config에있는 RequestHandler 클래스 (FormConfigInterface 클래스)에있는 handleRequest을 호출하는 것을 볼 수 있습니다. 나는 RequestHandlerInterface의 올바른 구현이 NativeRequestHandler이라고 추측합니다. 거기에있는 48 요청 방법의 평등에 대한 확인을 볼 수 있습니다.

이제는이를 처리하기 위해 양식의 FormConfigInterface를 사용자 정의 값으로 설정할 수 있습니다. 여기서 사용자 정의 구현에 대한 RequestHandler를 만들었습니다. NativeRequestHandler이 서비스로 정의 된 경우 운이 좋지 않습니다 (현재 서비스 목록에 액세스 할 수 없음). 자신의 구현을 가리 키도록 클래스를 전환하십시오.

이 모든 것을 이야기 했으므로 양식 유형 검사가 이유가 있다고 생각합니다. 이제는 양식 제출 유형을 별도로 처리해야합니다. 또한, 편집을 삽입하기 위해 POST를 사용하는 것은 좋은 해결책입니다. 새 버그를 도입 할 가능성이 낮을수록 간단 해집니다!

+0

안녕하세요. 어제 또 다른 비슷한 형식을 구현하고 있었는데 갑자기'Request :: getMethod()'를 사용할 수 있다는 것을 깨달았습니다! 어쨌든, 고마워. – pikachu0

3

[편집 2014-05-23] 그것은 "더러운 해킹"이었다 나는 완전히 내 첫 번째 대답을 수정 한 :

나는 여기있다, 위의 변경된 코드를 언급했다.

정확히 동일한 문제 (거의 동일한 코드)가 있습니다. 여기에 대한 답변을 읽었으며 내 자신의 코드에서 중요한 문제를 발견했습니다. 파일을 수정하여 기본 설정 인 HttpMethodParameterOverride 매개 변수를 수정하는 것을 잊었습니다. handleRequest() 기능을 사용하여 예상대로 (It's a change introduced in Symfony2.2)

지금 모든 작동합니다

  • 조치가 POST 쿼리를 사용하여 만들 수 있습니다.
  • 편집 작업은 PUT 쿼리를 사용합니다.
  • 삭제 작업은 DELETE 쿼리를 사용합니다.

허용 된 대답에서 제안한대로 RequestHandler 구성을 수정할 필요가 없습니다.

이제 코드는 다음과 같습니다

/** 
* Fruits CRUD service controller. 
* 
* @Route("/services/fruits") 
*/ 
class FruitsController extends Controller 
{ 
    // ... 

/** 
* Create a fruit. 
* 
* @param Request $request 
* 
* @Rest\Post("", name="backend_fruits_create") 
* 
* @return View|array 
*/ 
public function createAction(Request $request) 
{ 
    return $this->processForm($request, new Fruit()); 
} 

/** 
* Edit a fruit. 
* 
* @param Request $request 
* @param Fruit $fruit 
* 
* @Rest\Put("/{id}", name="backend_fruits_edit", requirements={"id" = "\d+"}) 
* @throws HttpException 
* 
* ## DEV FORM ## 
* @Rest\Get("/edit/{id}", name="backend_fruits_edit_dev", requirements={"id" = "\d+"}) 
* @Rest\View 
* ## DEV FORM ## 
* 
* @return View|array 
*/ 
public function editAction(Request $request, Fruit $fruit) 
{ 
    return $this->processForm($request, $fruit); 
} 

/** 
* Delete a fruit. 
* 
* @param Fruit $fruit 
* 
* @Rest\Delete("/{id}", name="backend_fruits_delete") 
* @throws HttpException 
* 
* @return View 
*/ 
public function deleteAction(Fruit $fruit) 
{ 
    $fruit->delete(); 

    return $this->responseHelper->createSuccessResponse(
     $fruit->getTree()->getFruits(), 
     Response::HTTP_ACCEPTED 
    ); 
} 

/** 
* Form handling. 
* 
* @param Request $request 
* @param Fruit $fruit 
* 
* @return View|array 
*/ 
protected function processForm(Request $request, Fruit $fruit) 
{ 
    list($statusCode, $httpMethod, $action) = $this->getActionParameters($fruit); 

    $form = $this->createForm(
     new FruitType(), $fruit, 
     array('action' => $action, 'method' => $httpMethod) 
    ); 

    if (in_array($request->getMethod(), array('POST', 'PUT'))) { 
     if (!$form->handleRequest($request)->isValid()) { 

      return $this->responseHelper->createErrorResponse($form); 
     } 
     $form->getData()->save(); 

     return $this->responseHelper->createSuccessResponse($form->getData(), $statusCode); 
    } 

    return compact('form'); 
} 

/** 
* Set the form and action parameters depending on the REST action. 
* 
* @param Fruit $fruit 
* 
* @return array 
*/ 
protected function getActionParameters(Fruit $fruit) 
{ 
    if ($fruit->isNew()) { 
     $statusCode = Response::HTTP_CREATED; 
     $httpMethod = 'POST'; 
     $action = $this->generateUrl('backend_fruits_create'); 
    } else { 
     $statusCode = Response::HTTP_OK; 
     $httpMethod = 'PUT'; 
     $action = $this->generateUrl('backend_fruits_edit', array('id' => $fruit->getId())); 
    } 

    return array($statusCode, $httpMethod, $action); 
} 

: 양식 유형은 모델 개체에 바인딩됩니다.

참고 2 : 알다시피, 나는 추가 경로를 얻었습니다. 내 브라우저에서 양식을 디버깅 할 때 개발할 때 유용합니다. 이 서비스 관리자로서, 필자가 관련 코드를 삭제할 것입니다. 경로 및 processForm 함수에서 메서드를 테스트하고 더 이상 폼을 반환 할 필요가 없습니다.

/** 
* Form handling. 
* 
* @param Request $request 
* @param Fruit $fruit 
* 
* @return mixed 
*/ 
protected function processForm(Request $request, Fruit $fruit) 
{ 
    list($statusCode, $httpMethod, $action) = $this->getActionParameters($fruit); 

    $form = $this->createForm(
     new FruitType(), $fruit, 
     array('action' => $action, 'method' => $httpMethod) 
    ); 

    if (!$form->handleRequest($request)->isValid()) { 
     return $this->responseHelper->createErrorResponse($form); 
    } 
    $form->getData()->save(); 

    return $this->responseHelper->createSuccessResponse($form->getData(), $statusCode); 
} 

주 3 : 응답 도우미 그냥 FOSRestBundle와 사용자 정의 View 응답 개체를 만듭니다.

REST 및 Symfony2에 대한 자세한 :

+0

너무 늦게 답변 해 주셔서 죄송합니다. 프로젝트는 다음 단계로 이동했으며 이전 코드를 리팩토링 할 시간이되면 솔루션을 테스트 할 것입니다. 갑자기 그것을하려고 노력할 것이다! 고맙습니다. – pikachu0

+0

안녕하세요, 귀하의 답변은 좋아 보이지만 이것을 처리하는 더 좋은 방법을 발견했습니다. 표시된 대답을 참조하십시오. 고맙습니다. – pikachu0

관련 문제