TIP: Use Markdown or, <pre> for multi line code blocks / <code> for inline code.
Forums are in read-only mode while we transition to new software.
Paginiation in your Model
  • Just wondering how people deal with pagination within their model classes?

  • Pagination should be dealt with in the controller. Once you get SQL_limit and SQL_offset, you pass them in your model data retrieval method.

  • Pagination belongs in the View ;)

  • Actually. Pagination happens in your controller, your model and your view.

    On the URL you pass e.g. ?page=2. The controller picks this up and calls the model to run whatever query but keeping in mind to apply a LIMIT and an OFFSET to the query. If you e.g. have specified that there is 15 items per page you need to calculate the right LIMIT and OFFSET based on that. Anyway, your model returns the result back to the controller which passes it on to the view. In the view you determine how to display your pagination.

    Have a look at the pagination module that came with Kohana 3.0.x. This module only does view stuff but it's worth dissecting.

  • Haha 3 different answers.

    @xenakis, I also need to know the count.

    @Zeelot3k, what about the setup? ;p

    @pan69, Agreed but I'm trying to work out the separation and data that needs to flow to and from the model. For example, the model needs to know limit and offset from the pagination but the pagination also needs to know the record count from the model. How do you deal with the data exchange?

    Also must the query always run twice, once for the count and once for the record retrieval?

  • If you have e.g. a Model_User that is supposed to return a list of users you can do something like this:

    class Model_User {
    
       static public function get_users( $page = -1, $items_per_page = 15 )
       {
          if( $page < 0 )
          {
             // return all users
          }
          else
          {
             // calculate LIMIT & OFFSET and run query
          }
    
          return $users
       }
    
    }
    

    Not passing anything to this method returns all users. If the controller found a $page=? on the URL it can pass that value.

  • @pan69 Your controller passes the filters (page and limit) to the View, the view uses the model to find all results, applying filters, and displays it. :)

    This is off topic anyway, sorry for the flame bait! The model method looks like a good example but I would change the name of the $page variable to $offset simply because models should know nothing about 'pages'.

  • Maybe I missed this, but @Zeelot3k is talking about a View class (like for Mustache), not a view template. Right?

    So does this make sense:

    // Controller
    class Controller_Blog extends Controller {
    
        public function action_index()
        {
            $page    = (int) $_GET['page'];
            $perpage = (int) $_GET['perpage'];
    
            $view = new View_Blog_Index;
    
            $view->page    = $page;
            $view->perpage = $perpage;
    
            $this->response->body($view->render());
        }
    
    }
    
    // View Class
    class View_Blog_Index extends Kostache {
    
        protected $page = 1;
    
        protected $perpage = 10;
    
        public function posts()
        {
            return Model_Post::get_list($page, $perpage)->as_array();
        }
    
    }
    
    // Model
    class Model_Post extends Model {
    
        public static function get_list($offset, $limit)
        {
            $offset = ($offset - 1) * $limit;
    
            return DB::select()
                ->offset($offset)
                ->limit($limit)
                ->execute();
        }
    
    }
    
    // Template
    <div id="posts">
        {{#posts}}
            <div class="post">
                <h2>{{title}}</h2>
                {{content}}
            </div>
        {{/posts}}
    </div>
    
  • @corey yes, generally. But after working with Kostache, I would treat regular Kohana Views similarly now, with some php logic at the top of the file, and the rest of the html/php at the bottom. In a perfect world, I will never have to go back to the old PHP Views though :)

  • What! Blasphemy! Hahaha. The whole point (well, not the whoooole point) of MVC I thought was to avoid mixing PHP and HTML (more than just <?php echo $var ?>). I'd rather load a Model and query posts in the controller than a view.

  • But that puts view logic in your controller! O_O HOW COULD YOU!?

  • You can't do any MVC right without view models ;)

  • But after working with Kostache, I would treat regular Kohana Views similarly now, with some php logic at the top of the file, and the rest of the html/php at the bottom

    Why would you do this instead of using Kostache and doing it the right way?

  • Nobody has mentioned count and that's the reason I started this thread, as this needs to be retrieved from the model. Doesn't anybody use total_items in pagination?

    I guess the issue is how to make it DRY and is there any way to avoid running two queries every time (one for count and one for record retrieval)?

  • @Eclipse: this is roughly what I'm doing re pagination.

    Controller gets the model to do the query to establish the total rows.

    Controller decides what kind of result we have (expected, unexpected, error, whatever).

    If good result, Controller sets up the pagination options, does the query again with the required limit and offset, and hands the whole page off to the view.

    The queue to tell me I'm wrong will form shortly. ;-)

  • I do it like Martin.

    I can't think of a way not to make two queries.

    If your query doesn't have search parameters, and you are just retrieving everything from the table, then you could save the current table count so that it's faster to retrieve. If you do have search parameters, then you could either save a current count for common searches, or cache queries based on certain searches so they would be faster to retrieve.

    Another way to avoid two queries which would be less than optional would be to retrieve everything in the first query, then filter that result based on the pagination arguments you receive. However, this seems ridiculous and wouldn't scale at all. Could be useful in cases where you know you will never have many entries, but I can't think of such cases at the moment.

  • @Eclipse, the answer is to make the 2 queries.

  • Actually that's how I've been doing it previously but I'm trying to move the query building out of the controller and into the model so I end up with something like this:

    $biology_students = Model_Course::get_students('biology');
    

    Now I need to work out the best way to add pagination to it. (And yes looks like there's no avoiding the 2 repeated queries).

  • You can't do pagination without two queries.

  • Yes zombor I know, it's been said already. (Though technically you can! ;)

  • There's one other solution that hasn't been mentioned here yet (though this only applies to MySQL): SQL_CALC_FOUND_ROWS. If you use SELECT SQL_CALC_FOUND_ROWS * FROM ... ;, you can run SELECT FOUND_ROWS() immediately after the query and it will return the total row count matched, regardless of your LIMIT options. You're essentially still running two queries, but this can be easier to implement/manage in some cases.

  • It's been demonstrated to be faster to do two queries than to use SQL_CALC_FOUND_ROWS.

  • @zombor; performance varies depending on the situation. I think it's worth evaluating both. Here's one user's fairly comprehensive test that concludes that SQL_CALC_FOUND_ROWS is faster, at least in their situation: http://cafuego.net/2010/05/26/fast-paging-real-world

    Mileage may vary. :)

  • You can't do pagination without two queries.

    Actually you CAN do it if you don't need to know the total number of pages (If your pagination consists only of two links - next page and previous page, for example)

  • OK, now I'm paranoid again...
    I'm doing something similar to @Martin Hall (call model to get the count from my controller, create pagination in the controller, pass offset and limit to the model).
    But @Zeelot3k and @zombor are two very respected developers to me, and they are suggesting to call the model from our view?
    In desktop applications we have "events" and the view can listen an event from the model, and therefore get the data directly from the model.
    But in PHP I thought the right way was always getting the data from our controller, and passing it to our view, the view never access to the model directly.
    Is this wrong? when do you think is a best practice to access the model from our view?

  • There is no good reason to do view logic in the controller... it just makes your views harder to reuse. In desktop applications classes have to listen for changes because you are building stateful applications. In Kohana, the view just cares about display something right now. It has no interest in anything that might happen to a model 5 seconds from now. If a view is built to display the last 5 news articles on a page, what downside is there to letting the view ask the model for the last 5 items instead of depending on the controller to pass it in? If you use the same view in multiple locations, do you pass the 5 items from all those controllers? Seems silly to me! The controller uses models to alter your application (delete something, edit something, disable an account, etc). Let the view worry about displaying the data. Yes, completely.

    Edit: haven't slept so I hope I make sense :)

    P.S. the most annoying thing I see when looking at older Kohana code is when the controller tells the view the title of the page... GAH!

  • I have a little problem, all the options seems valid to me :D
    I found this question in SO:
    http://stackoverflow.com/questions/1463791/general-on-mvc-should-controller-pass-data-to-view-or-view-should-grab-it-dire

    Options:

    1. controller pass appropriate model object to view and view should pull out all the data from model when needed
    2.
    controller grab data from model and pass it to view, possibly wrapping it all into single wrapper object that view will access and grab data from there
    3.
    view simply instantiate appropriate model when needed and pull out data directly from model object

    Arguments for option number #2 (most voted option):

    The view shouldn't care about the model. The view shouldn't have any processing at all for that matter. It should do what it's supposed to do, format data.
    Controller should be responsible for everything that's happening between View and Model. If it's not, then why would they call it 'Controller'?

    Arguments for option #3 (accepted answer):

    The view shouldn't care about the controller. The view shouldn't have any dependency on the controller for that matter. It should do what it's supposed to do, show a view of the model.
    As an extension, user input can be consider part of the model, and both the controller and the view may read from it. The key point to take away is that Controller and View should have no dependency on each other. That's why the pattern is called MVC.
    Option number 2 is not MVC. It's MVP, wherein the Presenter is a mediator.
    A Controller has Write-Access to a Model; a View has only Read access.

    Finally a user commented:

    I think this is just a generic argue about what is better "push" or "pull" model. There is no "absolutely" best solution.

    And maybe it's right, but we have to choice one option, and for that we need to know the pros and cons of each option.

    For example, @Zeelot3k said that views accesing models is easier to reuse.
    But what happens with errror handling for example?
    Right now I'm checking everything with try catch in my controller, and if an error is thrown then I'm changing my view, or creating some messages, or even redirecting.
    How can I do that if I call the model from my view?

    Also, when are you passing vars to the view, if the view can read the model I don't see the needing of doing that.

  • @Zeelot3k, yes that makes perfect sense. I started this thread because I was rewriting my MVCs to something like you've just described, and yes I know what you mean about setting the page title in the controller, something I was reluctantly doing until I was able to properly separate each part into it's proper place.

  • @enridp, my understanding is that it can be both. Sometimes the controller will access the model and pass data to the view (e.g. controller calls model to delete a record and passes the result to the view) and other times the controller will just instantiate a view which will call the model directly (e.g. display a list of records).

  • People have been brainwashed into thinking that "View == no logic" because no web mvc frameworks (besides asp.net) has the concept of a "view model". When you don't have a view model, you are forced to put view logic (let's be straight here, view logic DOES exist) in the controller. View do have to do logic, and that stuff doesn't belong in the controller.

    I'm not sure I would go as far as what Zeelot suggested, but then again, I would never use class-less views ever again.

    The #3 response above is absolutely correct.

  • After searching a lot and reading about this, I think it's not a trivial problem, and maybe Kohana should maybe not force but at least guide in the right direction.
    Let's see if we can get a good conclusion:

    **Pull data or Push data? **

    Views accesing Model
    PROS:
    - One problem that I always have is that I need to read the view everytime I write a controller, because I need to see which vars are used by the view (because I need to pass it from my controller).
    - If our view is responsible of getting it's own data, then we don't have this problem.

    CONS:
    - The problem is with error handling, and info from results. I can't see how to decouple this.

    Maybe creating a new model for saving that data?, something like Model_Status, and we read the status of the application from our view (usually to show some notification).

    • Working in Teams. For instance if you use models in your views, this implies the design team has to know about models. It may also hamper porting the views later on to another framework or swapping templates.

    • If you need the same data from differents views you need to repeat yourself.

    Controllers pushing all the data inside view:
    PROS:
    - (see above cons)

    CONS:
    - (see above PROS)
    - and also, I think this is not MVC, is more like MVP with Passive View.

    I found a third alternative:
    MVVM (Model–View-ViewModel)

    equals to Presentation Model in this case I think

    The idea is to create a new class "ViewModel_xxx", that it is a flattened/altered version of the model for the view

    PROS:
    - You get the data from the view, but the view is not messed with a lot of logic, that is encapsulated in ViewModel.
    - We can decouple the view from the controller and also the view from the model.
    - We can reuse the ViewModel in other views.
    - The design team doesn't need to know about models.
    - Your Controller doesn't care exactly what specific data your View needs or especially what format your View needs that data in
    - Your View doesn't depend on the implementation details of your Model

    CONS:
    - Error handling inside ViewModel? is this correct?
    - Controller pass notifications to ViewModel so we can access them from our view?
    - performance?*
    from here:
    http://stackoverflow.com/questions/1371119/mvc-pass-model-model-data-to-a-view-from-a-controller

    Putting in so much code just for the sake of printing some paragraphs out as HTML is just making unnecessary maintenance nightmares later.

  • @enridp as far as error handling, you should mostly be dealing with handling for generic exceptions at the application level (with an execption_handler) rather than try catch in all your controllers. If you need to deal with recoverable errors or do specific things in specific circumstances then you can still try catch in the controller round explicitly initialising and rendering the view.

  • @andrewc: yes, I have a generic exception handler, but sometimes I want to show specific messages or redirects in some controllers.
    I think the best solution is to use the View-Model pattern, and put all the code related with views (that I have in my controller right now) inside a new ViewModel class.
    Controllers checks auth, redirect if necessary, gets input data, save/update the model, chooses the view, and pass notifications (related with auth, user input, or saving model) and user input data to the View (actually the View_Model).
    View creates the proper View_Model. View_Model get data from Models.
    So, our controller only need to know the view to show (notifications and user input is passed to View_Model always in the same way).
    Maybe something like this:

    //CONTROLLER
    action_index()
    {
       // before checks auth, and redirect if necessary
       $input = parse($_POST);
       ...
      try {
         $result = $model->update($input);
         if ( $result )
         {
             $notificator->set_success( 'success ' . $result );
         }
         else 
         {
             $notificator->set_warning( 'warning ' . $result );
         }
      }
      catch (Custom_Exception $e) {
         $notificator->set_error( 'Custom: ' . $e );
      }
      catch (Database_Exception $e) {
         $notificator->set_error( 'Database: ' . $e );
      }
      catch (Validation_Exception $e) {
        $notificator->set_error( 'Validation: ' . $e );
      }
      catch (Exception $e) {
        $notificator->set_error( 'Error: ' . $e );
      }
      $view = View::factory('theview');
      $view->notificator = $notificator;
      $view->input = $input;
      $this->template->content = $view;
    
    }
    

    And each view is responsible of getting the data from the models, but through it's "view_model":

    $view_model = new Custom_View_Model($input, $notificator);
    
    
    
    
    <?php $products = $view_model->getProducts(); 
    foreach ($products  as $product):
     ?>
    
    <?php echo $product; ?>
    
    <?php endforeach;?>
    
    
    
    
    

    What do you think?

    Here is a good tutorial about ViewModel in PHP:
    http://techportal.ibuildings.com/2010/11/02/creative-mvc-meet-the-viewmodel-pattern/

    And I found a module created by @zombor called "view-model":
    https://github.com/zombor/View-Model

    But I don't understand it well and I think it's abandoned (maybe it was replaced by his Kostache).

    PS: why HTML tags are not shown inside the code block??

  • But I don't understand it well and I think it's abandoned (maybe it was replaced by his Kostache).

    It was for people who wanted to use php syntax but take advantage of view models. It's better to use Kostache

  • It's not abandoned.

  • @zombor, I was reading this thread:
    http://forum.kohanaframework.org/discussion/comment/58517 and you said:

    will you still going to be actively developing View-Model

    No. It only exists for people who refuse to use mustache so they can use View Models.

    and also:

    I'd highly, highly, highly discourage using View_Model though.

    can you explain why?

  • can you explain why?

    I can lead to bad development practices like putting logic in your controller, the thing that mustache is designed to prevent. Another reason might have been because it used to use eval() to process the template, I'm not sure when I said that and when I switched it to use stream inputs instead.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion