jueves, 19 de enero de 2012

My First RESTful Web Service with Symfony2 (Pagination) Part II

On the first part My First RESTful Web Service with Symfony2 Part I. I discussed how to create a simple restful web service using JSON. I mainly focused on how to create the Symfony2 project and make it respond to json call.

On this post I´ll discuss how to make the web service paginate and create a simple interface to display the results using jQuery.

1   Changing the MRoute Repository

On Part I we laid the ground for pagination on the repository but didn´t work out the details.

What we're going to do is make pagination work and add the getCount method that will return the count of MRoutes on the database.

  1. Open srcMyGISGISBundleEntityMRouteRepository.php.
  2. Replace the previous getMRoutes method with the following. The previous code had a bug on the order by lines.
    public function getMRoutes($order_by = array(), $offset = 0, $limit = 0) {
        //Create query builder for languages table
        $qb = $this->createQueryBuilder('m');
        //Show all if offset and limit not set, also show all when limit is 0
        if ((isset($offset)) && (isset($limit))) {
            if ($limit > 0) {
                $qb->setFirstResult($offset);
                $qb->setMaxResults($limit);
            }
            //else we want to display all items on one page
        }
        //Adding defined sorting parameters from variable into query
        if (isset($order_by)) {
            foreach ($order_by as $key => $value) {
                $qb->add('orderBy', 'm.' . $key . ' ' . $value);
            }
        }
        //Get our query
        $q = $qb->getQuery();
        //Return result
        return $q->getResult();
    }
    
  3. On the same class add the following method:
    public function getCount() {
        $query = $this->createQueryBuilder('m')
                ->select('COUNT(m.id)')
                ->getQuery();
        return  $query->getSingleScalarResult();
    }
    

2   Changing the MRoute Controller

There are four things we need to do to the contoller. Read the count of MRoutes from the repository, Order the MRoutes by id, calculate the offset and define the routes.

  1. Open srcMyGISGISBundleControllerMRouteController.php.
  2. Replace the previuos routingInfoAction method with the following code:
    /**
     * Gets paged MRoutes JSON objects.
     * @Route("/routing-info/info.json",
     *     defaults ={"page" = 1, "count" = 10},
     *     name="mroute_json_list2")
     * @Route("/routing-info/{page}/{count}/info.json",
     *     requirements = {"page" = "\d+", "count" = "\d+"},
     *     defaults ={"page" = 1, "count" = 10},
     *     name="mroute_json_list")
     * @Method("get")
     */
    public function routingInfoAction($page, $count) {
        $offset = ($page - 1) * $count;
    
        $em = $this->getDoctrine()->getEntityManager();
         $total = $em->getRepository('MyGISGISBundle:MRoute')->getCount();
    
        $mroutes = $em->getRepository('MyGISGISBundle:MRoute')->getMRoutes(array('id' => 'ASC'), $offset, $count);
        $r_array = $this->routes2Array($mroutes);
        $r = array('page' => $page, 'count' => $count, 'total' => $total,'routes' => $r_array);
        return new Response(json_encode($r));
    }
    

    Now the web service will respond to http://localhost/mroute-rest-service/web/app_dev.php/mroute/routing-info/info.json using route mroute_json_list2 and will respond to http://localhost/mroute-rest-service/web/app_dev.php/mroute/routing-info/2/10/info.json will respond to route mroute_json_list.

Now we´re ready to consume the service.

3   Consuming the Web Service

Since I'm a little green using Twig what I did was create a new Netbeans PHP project and add on the index.html the following code:

<html>
   <head>
       <title></title>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
       <script type="text/javascript" src="../js/jquery-1.6.4.min.js"></script>
        <link rel="stylesheet" type="text/css" href="../css/routing2.css" media="screen">
       <style>
           .page-link{
               margin: 0.2em;
               padding: 0.2em 0.5em;
               background-color: #1c94c4;
           }
           .page-link.selected{
               color: white;
               background-color: #005B81;

           }
           .page-link:hover{
               cursor: pointer;
           }
           .coordinates{
               height: 30px;
           }
       </style>
       <script type="text/javascript" >
           function roundNumber(rnum, rlength) { // Arguments: number to round, number of decimal places
               var newnumber = Math.round(rnum * Math.pow(10, rlength)) / Math.pow(10, rlength);
               if(rnum % 1)
                   return newnumber;
           }
           function showData(page, count){
               $('#routes').empty();
               $('#routes').html('<span class="loading">Loading ' + count + ' records for page ' + page +'...</span>');
               var baseUrl ='http://localhost/mroute-rest-service/web/app_dev.php/mroute/routing-info/'
                   + page + '/' + count +'/info.json' ;
               $.ajax({
                   url      : baseUrl,
                   dataType : 'json',
                   success  : function(data){
                        $('#routes').empty();
                       $.each(data.routes, function(i,route){
                           var li = $("<div/>").attr("id","route-" + route.id);
                           li.html(route.name);
                           $.each(route.points, function(i,point){
                               if(point.ptype == 'STOP'){
                                   var num = i +1;
                                   var className = 'stop-0' + num
                               }
                               var pointDiv   = $("<div/>").attr("id","point-" + point.id);
                               pointDiv.addClass('coordinates');
                               pointDiv.html('<span class="' + className + '" style= "float:left;"></span>' +point.x + ', ' + point.y);
                               li.append(pointDiv);
                           });
                           $('#routes').append(li);
                       });
                       var pagingDiv = $("<div/>").attr("id","paging-info");
                       pagingDiv.html('Page ' + data.page + ' count: ' + data.count+ ' total: ' + data.total + '<br/>');
                       var m = Math.ceil(data.total / data.count);
                       for(i =1; i <= m; i++){
                           var pageLink = $("<span/>").attr({"id" : "page-link-"+i, 'class' : 'page-link'}).html(i);
                           if(i == page){
                               pageLink.addClass('selected');
                           }
                           pageLink.bind('click',{'page': i}, onClickLink);

                           pageLink.appendTo(pagingDiv);
                       }
                       $('#routes').append(pagingDiv);
                   }});


           }
           function onClickLink(event){
               //alert(event.data.page);
               showData(event.data.page, 10);
           }

           $(document).ready(function(){
               showData(1,10);
           });

       </script>
   </head>
   <body>
       <div>
           <div id="routes"></div>
       </div>
   </body>
</html>

Now you´re able to consume the web service.

1 comentario:

  1. Hi ,

    You can see the important link : http://www.dev-skills.com/list-pagination-in-symfony2-without-bundles/

    ResponderEliminar