Using a CakePHP model to loop over database records

By cbotman

I was quite pleased to get this working so easily CakePHP 1.2.

Problem: I needed to iterate over records in a table, but there’s potentially too much data to fetch every record at once with findAll().

This isn’t a case of premature optimisation–using a CakePHP model to fetch records with complex associations can cause your script to be killed for using too much memory (the default allowance is 32MB, I think).

I only need a single record at a time, so rather than increase the memory limit (which won’t scale that well) I’d like to change how data is fetched.

Solution: Use a while loop with the “Model->find( ‘first’ )” method and a page variable, like so:

$page = 1;
while ( $record = $this->Model->find( 'first', array( 'page' => $page++ ) ) ) {
  print_r( $record );
}

And that’s all there is to it. We can now work with each record, having only one record in memory at a time. Eventually find() will return false when it has passed the last record, cleaning up the $record variable.

This is a similar approach to querying the database with SQL directly, then using a method such as mysql_fetch_array() to parse the results.

The only difference is the addition of the $page variable, which acts as a pointer and is incremented so it returns the next record each time. Otherwise we would get the first record returned over and over, creating an infinite loop. mysql_fetch_array() uses a pointer like this too (as far as I know), but it’s hidden inside the method.

You could easily do the same in CakePHP to create a findNext() function on your CakePHP model that then calls find(), along with any other conditions passed in. It would be used like so:

while ( $record = $this->Model->findNext( $conditions ) ) {
  print_r( $record );
}

But I haven’t tested that yet. :)

Tags: , , ,

Leave a Reply