An iterator is a convenient way of combining the power of active record objects with the performance of a gateway. The iterator simply takes a query and an active record object and then allows you to loop over the query and load each record into the same active record object instead of creating an array of individual records. This improves performance considerably since only the one active record object is in memory throughout the loop.
In the example below, imagine that the active record object represents a table containing the columns FIRSTNAME and LASTNAME and the function getFullName() returns the person's name in the format "LASTNAME, FIRSTNAME". Now the potential exists that at some later time you may want to change the way names are formatted -- perhaps the internal logic to determine how to format names may vary based on some other variables at run-time to suppot international clients. Keeping the functionality for getting full name in the active record may not eliminate the need to rewrite code, however, it may still reduce the amount of code you need to rewrite since it allows the formatting to be reused.
<cfset ds = request.DataFaucet.getDatasource() /> <cfset gateway = ds.getGateway(className="my.peopleGateway").init() /> <cfset ar = ds.getActiveRecord(className="my.personRecord").init() /> <cfset iterator = CreateObject("component","datafaucet.system.iterator") /> <cfset iterator.init(gateway.search(form.search),ar) /> <cfoutput> <table> <thead> <tr> <th>Name</th> <th>Email</th> <th>Phone</th> </tr> </thead> <tbody> <cfloop condition="iterator.next()"> <tr> <td>#htmleditformat(ar.getFullName())#</td> <td>#htmleditformat(ar.getEmail())#</td> <td>#htmleditformat(ar.getPhoneNumber())#</td> </tr> </cfloop> </tbody> </table> </cfoutput>
The methods of the iterator object should be pretty self-explanatory. The public methods allow you to retrieve the query, the record or the current index via the getQuery(), getRecord() and getIndex() methods, however most of the work you do with an iterator won't focus on these methods. Instead you'll mostly use iterator.next() to move to the next record. The additional method iterator.back() will allow you to traverse the query in reverse, or iterator.moveTo() will allow you to move to a specific record, while iterator.first() and iterator.last() will move to the first or last record respectively. Iterator.length() will return the size of the loaded query and iterator.more() will tell you if there are more records.