7

I have method getListQuery() in my model, which return query. As we know, Joomla automically set limit and offset to query when we use JPagination. I have problem, that I want to use JPagination and fetch all rows in getListQuery(). As far as, I wrote code like

protected function getListQuery(){

    // here is created my $query object with query

    // I'm fetching all rows
    $rows = $db->loadObjectList();
    $this->rows = $rows;

    return $query;

}

It means, query is executing 2 times: one by me in this method and one by Joomla core. I'm not so happy with this solution, because it causes page loads 2x longer. Query has about 10 joins... With milions of rows it's really problem. Do you see any right solution?

2 Answers 2

7

I found a solution (I think). I've overwritten JModelList methods.

class MyComponentModel extends JModelList{

    protected $_items = array();

    public function getItems() {
        // Get a storage key.
        $store = $this->getStoreId();

        // Try to load the data from internal storage.
        if (isset($this->cache[$store])) {
            return $this->cache[$store];
        }
        $query = $this->getQuery();
        $this->query = $query;
        $db = JFactory::getDbo();
        $db->setQuery($query);
        $rows = $db->loadObjectList();
        $this->cache[$store] = $rows;
        $this->_items = $rows;
        return array_slice($rows, $this->getStart(), $this->getState('list.limit'));
    }

    public function getPagination() {
        // Get a storage key.
        $store = $this->getStoreId('getPagination');

        // Try to load the data from internal storage.
        if (isset($this->cache[$store])) {
            return $this->cache[$store];
        }

        // Create the pagination object.
        jimport('joomla.html.pagination');
        $limit = (int) $this->getState('list.limit') - (int) $this->getState('list.links');
        $page = new JPagination($this->getTotal(), $this->getStart(), $limit);

        // Add the object to the internal cache.
        $this->cache[$store] = $page;

        return $this->cache[$store];
    }

    function getTotal() {
        return count($this->_items);
    }

    public function getQuery() {
        // query
        return $query;
    }

}

view.html.php

$this->model = $this->getModel();
$this->items = $this->model->getItems();
$this->pagination = $this->model->getPagination();

page loads much faster. Is it good solution?

5
  • Why do you need all the rows? What are you doing with $this->_items in this case? Commented Aug 30, 2014 at 15:08
  • I have google maps with selected location as markers, so I wanted to fetch all rows to get coordinations from database and use pagination to display some rows
    – turson
    Commented Sep 1, 2014 at 8:12
  • I'm fairly certain that this still loads all the results each page load. The cache does not store the variable between page loads. I feel like joomla's default method would work fine. (Which probably means I'm missing something...) Commented Sep 1, 2014 at 14:41
  • Yes, it loads all results each page load, but in my opinion site loads faster then earlier when I've been executing query twice and pagination works fine
    – turson
    Commented Sep 2, 2014 at 7:00
  • Don't load all the rows if you need only say 20. Load data with: $db = $this->getDbo(); $db->setQuery($query, $start, $limit); Get count with: $this->_getListCount($query);
    – ed22
    Commented Feb 1, 2020 at 11:15
4

Joomla should be using getItems to run the query. So your best bet is to alter the state of the model to make sure that it loads all the results.

Within the model you can do this by using setState like so:

$this->setState('list.limit', 0);

Run that before the model calls getItems and it will load all the items for you.


A few caveats with this.

  1. You can also do this outside the model, so if for instance you were in your view. You could do the following:

    $model = $this->getModel(); $model->setState('list.limit', 0);

  2. Sometimes you can do this too early, before the model's state has been populated, which will cause the model to get rebuilt from the user state after you have set the limit, basically overriding the limit.

To fix this, you can force the model to populate its state first:

$model = $this->getModel();
$model->getState();
$model->setState('list.limit', 0);

The actual populateState method is protected, so outside the model you can't call it directly, but any call to getState will make sure that the populateState is called before returning the current settings in the state.

5
  • Thanks for reply. Unfortunately I didn't reach my aim yet. My view.html.php: $this->model = $this->getModel(); $this->model->getState(); $this->model->setState('list.limit', 0); $this->pagination = $this->get('Pagination'); $this->items = $this->get('Items'); $this->state = $this->get('State'); it causes query loads all rows at one page
    – turson
    Commented Aug 29, 2014 at 6:57
  • Hmm... I misunderstood. I thought you wanted ALL the rows. You actually want all the rows available but still just want to display some of the rows? Commented Aug 30, 2014 at 15:08
  • I wanted to fetch all rows (and store them in a variable) and use pagination at the same time
    – turson
    Commented Sep 1, 2014 at 8:10
  • But what are you doing with all the rows? What are you storing them for? Commented Sep 11, 2014 at 2:40
  • I need all rows to get coordinations and set markers on google map. On map have to be all markers.
    – turson
    Commented Sep 11, 2014 at 7:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.