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: cakePHP, models, php, while loop