Symfony action ajax calls

This post is about how to handle http or ajax calls to Symfony actions and serve up appropriate content. I’ve implemented it on noodleDig.com.

One my projects, noodleDig, is built using Symfony. A lot of the functionality is standard make a request, get a response type stuff. However, for some pages, like the memory walls, I wanted to make certain features more dynamic (i.e. dynamic ajax CRUD).  In particular, if user generated content is added or edited, I wanted ajax to handle that if javascript was available, or fall back to standard functionality if not.

Adding user generated content

Determining from a Symfony action whether the request was ajax or not turns out to be quite simple. A symfony action is called, with the posted form data. If the form data is valid, the data is persisted to the db. A check is then made to see whether the request was made using ajax. If it was, a JsonResponse is created, the relevant content is prepared and passed back to the calling javascript function. If not, a standard view is returned. Here’s the addUGCAction action…

public function addUGCAction($mwid, $slug, Request $request = null){

  //..

  $mwugc = new MemoryWallUGC(array(
      'mw'    =>  $mw,
  ));
  $form = $this->createForm(new MemoryWallUGCType(), $mwugc); 
  $form->handleRequest($request);
  if($request->getMethod() == 'POST'){
    $response = new JsonResponse();
    $content = array();
    if($form->isValid()){
      $mwugc = $form->getData();
      $mw->addMemoryWallUGC($mwugc);
      $this->em->flush();                
      $session->getFlashBag()->add('notice', 'memoryWall.ugc.add.flash.success');

      //if come from ajax request return json, otherwise redirect to show wall
      if($request->isXmlHttpRequest()){
        $flash = $this->trans($session->getFlashBag()->get('notice'));
        $content = $this->render('SkNdUserBundle:MemoryWallContent:ugcStrategyPartial.html.twig', array(
               'mwc' => $mwugc,
               'wallBelongsToCurrentUser' => $this->mwAccessManager->memoryWallBelongsToUser($mw),
         ))->getContent();
         $response->setData(array(
           'status'    => 'success',
           'content'   => $content,
           'flash'     => $flash,
         ));
         return $response;
       } else {
         return $this->redirect($this->generateUrl('memoryWallShow', array(
      'id'    => $mw->getId(),
      'slug'  => $mw->getSlug(),
       )));
       }
     } else {
       $session->getFlashBag()->add('notice', 'memoryWall.ugc.add.flash.fail');
       if($request->isXmlHttpRequest()){
         //get errors
       }
    }
    $response->setData(array(
      'status'    =>  'fail',
      'content'   =>  $content,
      'flash'     =>  $flash,
    ));
    return $response;
  }
}           

}

  return $this->render('SkNdUserBundle:MemoryWallContent:addUGCPartial.html.twig', array(
            'mwid'   => $mwid,
            'slug'   => $slug,
            'form'   => $form->createView(),
        ));
}

Here, if the form is valid, its processed. If its not valid and is not an ajax request, it just returns the form with errors showing. If its not valid but was an ajax request, it returns those errors to the calling javascript function using a JsonResponse.

If it was valid and was an ajax request, the resulting view is dynamically rendered and stored to the $content variable, which is then passed back to the javascript function to be dynamically displayed. If it wasn’t an ajax request, the user is redirected to the show wall action, which just reloads the entire wall.

By using this method, any non-javascript users can still add content, and error-processing is still carried out. For those using javascript, the experience is just a little slicker. How’s that for unobtrusive javascript!

In another post, I’m going to discuss getting this unit tested using BDD.

Leave a Reply