• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Pagination Problems

#1
Question 
I have a (reasonably) 'standard' incarnation of the manual pagination working well, however, in an attempt to maximize MySQL's index use, whilst not generating an excessively burdensome load on MySQL to maintain indexes, I have my code pulling a 'general' query out of the database, which is then processed in the CI application (basically removing the (potentially diverse), but few specific unwanted records that have come back in the sizeable general query result).

This works great because I get to maximize the use of the database indexes, which are also kept small and easy for MySQL to maintain, and at the same time can filter on any field and have reasonably complex processing on the returned data before presenting it to the user... in what would seem a pretty much typical implementation of CI interfacing with a database.

This is all good, however, I've now come up against a bit of a headache with the way I've been handling pagination- which relies on all the filtering being done via builder selected queries (with chaining) in a Model and then returning $this.

I currently have the database interaction happening in a Model, and then the specific/detailed filtering (which is directly controlled by selections by the user) happening in a Controller (that, as expected, gets the user selections posted from a View generated by that particular Controller).

Once I have the filtered/processed results done to be paginated, they are now sitting in an array in the Controller... and it's seemingly very difficult/impossible to now get this result into the Pagination functionality.

Do I need to pass all of the user-spec'd parameters down to the Model to have the fine filtering/processing happen there (and would it work if it was there... it would still somehow have to be pushed in a sensible manner into $this to be returned (?))... or is there some other sensible way to get around this (like passing the final results array to a dummy Model (that would come with the standard builder functionality) that can then simply return what it has been past as $this)?... if that makes sense?

And pointers or advice would be greatly appreciated. Thanks.
Reply

#2
In the method that's doing your query do not tell it to return a result instead tell to return $this

Then you would paginate it like so:

PHP Code:
$data['query'] = $model->myQuery()->paginate(10); 

This allows you to chain your query with the pagination.
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply

#3
As @InsiteFX said:
Code:
$data['query'] = $model->myQuery()->paginate(10);

In your model, write a function myQuery()
Code:
function myQuery()
{
    $sql = "your query here";
    $this->db->query($sql);
    return $this;
}

I think so hehe

Learning CI4 from my works, from errors and how to fix bugs in the community

Love CI & Thanks CI Teams

Reply

#4
You do not return $query you return $this

$this allows you to chain the methods above together.
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply

#5
(09-29-2020, 05:36 PM)InsiteFX Wrote: You do not return $query you return $this

$this allows you to chain the methods above together.

As
Code:
function myQuery()
{
    $sql = "your query here";
    $this->db->query($sql);
    return $this;
}
Right? return $this;

Thanks @InsiteFX, now I understand, thank you very much.

Learning CI4 from my works, from errors and how to fix bugs in the community

Love CI & Thanks CI Teams

Reply

#6
Thanks... though this is how I have all of my (long-time already) operational Pagination working, and as mentioned, it works great.

The problem I have is that, to save on a stupid amount of mostly unused indices in the database, I want to do something like this (also the complex calculations would be difficult/impossible to do in a query):

Code:
function myQuery()
{   $sql = "your simple index-based query here";
    $this->db->query($sql);

    // apply user-defined filters that don't rely on an index
    // + custom complex calculations on the query results

    return the filtered/calculated results; // and have Pagination still work
}

Basically, I'd like to be able to have Pagination work with an array of processed data - either from inside a Model (which is where most of the Pagination appears to be embedded), or somehow from inside a Controller.

Update:

I was hopeful when I found the set() method in Model.php (which takes an array as an argument), however, on closer inspection I find it’s only used for 'input' and not for generating results/'output' in methods like paginate().

I see that the HTML Table Class works in a manner close to what I’m looking for, and does accept a user-defined array as an input… however, it doesn’t appear to support pagination.

There is also callback functionality… where one can set up a trigger to do something with the data that has been found…

Code:
$eventData = $this->trigger('afterFind', $eventData);

...though I’ve not come across any documentation detailing its use (to be fair, it’s probably pretty simple to work out without any documentation)... however, in my case, this still looks a bit of pain to implement and if there is a way to somehow get it done from my existing (processed) array, it would be a lot easier.
Reply

#7
Code:
$data['query'] = $model->myQuery()->paginate(10);

$data['result_process'] = $model->processResult($data['query']);

Write a function processResult in your model

Learning CI4 from my works, from errors and how to fix bugs in the community

Love CI & Thanks CI Teams

Reply

#8
(09-30-2020, 06:13 PM)nc03061981 Wrote:
Code:
$data['query'] = $model->myQuery()->paginate(10);

$data['result_process'] = $model->processResult($data['query']);

Write a function processResult in your model

Nope, that doesn't work very well... as noted by InsiteFX, one cannot return the result directly (it breaks the chaining that Pagination relies on to work).

I experimented a bit with the callback functionality... initially with $afterFind, but that also breaks the chaining, so then with $beforeFind... which worked without too much trouble, but relied on tricking the Model's findAll() method to bypass some of its functionality by setting the (undocumented) $eventData['returnData'] = TRUE (which, who knows, may change/be removed from the framework's code at some point, and I didn't feel comfortable relying on)...

I ended up writing my own pagination() and findAll() routines for pagination with array data that I simply invoke as an ArrayPagination model to replace the framework's base Model's default whenever I want to paginate with an array of processed data.

Still, I can't believe I'm the only person who wants to paginate with data from a custom array!?!... so perhaps I've ended up redesigning something that already exists somewhere in the framework that I'm too much of hacky beginner to know about Wink
Reply

#9
That's because if you look at the paginate method it is using findAll() to get the record set.

I use it like above to return my categories by id and it works fine no idea why it's not working
for you.


Model:

PHP Code:
    // -------------------------------------------------------------------

    /**
     * getAllPostsByCategory ()
     * -------------------------------------------------------------------
     *
     * $query = $builder->get(10, 20);
     * $query = $builder->get($limit, $offset);
     *
     * @param  int $categoryID
     * @return PostModel
     */
    
public function getAllPostsByCategory(int $categoryID 0) : PostModel
    
{
    
    $this->categoryID $categoryID;

        
$builder $this->builder();

        
$builder->where("category_id"$categoryID)
        
        ->where('status''published');

        return 
$this;
    } 

Controller:

PHP Code:
    /**
     * -------------------------------------------------------------------
     * category ()
     * -------------------------------------------------------------------
     *
     * @param int $id
     */
    
public function category(int $id 0)
    {
        
$pager Services::pager();

        
$posts      = new PostModel($this->request);
        
$categories = new CategoryModel();

        
$data = [
            
'posts'       => $posts->getAllPostsByCategory($id)->paginate(10'group1'),
            
'pager'       => $posts->pager,
            
'currentPage' => $posts->pager->getCurrentPage('group1'),
            
'totalPages'  => $posts->pager->getPageCount('group1'),
            
'category'    => $categories->getCategory($id),
            
'categories'  => $categories->getTopCategories(),
            
'titles'      => $categories->getCategoryTitles($id),
            
'title'       => 'Blog Categories',
            
'typography'  => Services::typography(),
        ];

        
$data['pageHeading'] = $data['titles']['title'];
        
$data['subHeading']  $data['titles']['sub_title'];

        
// Make all variables global to all views...
        
echo view('Insitefx\Blog\Views\view_data'$data);
        echo 
view('Insitefx\Blog\Views\posts\index');
    } 
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply

#10
In my opinion what InsiteFX wants to say is:

1. Only Model can point to paginate function.
2. Any function in your Model that returns 1 Model = $this can point to function paginate.
3. $this is the Model and it will hold the result of the last Query that the Model did, so maybe -> paginate for that result.

Thanks InsiteFX for more knowledge

Learning CI4 from my works, from errors and how to fix bugs in the community

Love CI & Thanks CI Teams

Reply


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2020 MyBB Group.