fRecordSetclass implements IteratorCountable (internal interface)v1.0.0b32
A lightweight, iterable set of fActiveRecord-based objects
| 1.0.0b32 | Fixed a column aliasing issue with SQLite 1/25/10 |
|---|---|
| 1.0.0b31 | Added the ability to compare columns in build() with the =:, !:, <:, <=:, >: and >=: operators 12/8/09 |
| 1.0.0b30 | Fixed a bug affecting where conditions with columns that are not null but have a default value 11/3/09 |
| 1.0.0b29 | Updated code for the new fORMDatabase and fORMSchema APIs 10/28/09 |
| 1.0.0b28 | Fixed prebuild() and precount() to work across all databases, changed SQL statements to use value placeholders, identifier escaping and schema support 10/22/09 |
| 1.0.0b27 | Changed fRecordSet::build() to fix bad $page numbers instead of throwing an fProgrammerException 10/5/09 |
| 1.0.0b26 | Updated the documentation for build() and filter() to reflect new functionality 9/21/09 |
| 1.0.0b25 | Fixed map() to work with string-style static method callbacks in PHP 5.1 9/18/09 |
| 1.0.0b24 | Backwards Compatibility Break - renamed buildFromRecords() to buildFromArray(). Added buildFromCall(), buildFromMap() and ::build{RelatedRecords}() 9/16/09 |
| 1.0.0b23 | Added an extra parameter to diff(), filter(), intersect(), slice() and unique() to save the number of records in the current set as the non-limited count for the new set 9/15/09 |
| 1.0.0b22 | Changed __construct() to accept any Iterator instead of just an fResult object 8/12/09 |
| 1.0.0b21 | Added performance tweaks to prebuild() and precreate() 7/31/09 |
| 1.0.0b20 | Changed the class to implement Countable, making the count() function work 7/29/09 |
| 1.0.0b19 | Fixed bugs with diff() and intersect() and empty record sets 7/29/09 |
| 1.0.0b18 | Added method chaining support to prebuild, precount and precreate methods 7/15/09 |
| 1.0.0b17 | Changed __call() to pass the parameters to the callback 7/14/09 |
| 1.0.0b16 | Updated documentation for the intersection operator >< 7/13/09 |
| 1.0.0b15 | Added the methods diff() and intersect() 7/13/09 |
| 1.0.0b14 | Added the methods contains() and unique() 7/9/09 |
| 1.0.0b13 | Added documentation to build() about the intersection operator >< 7/9/09 |
| 1.0.0b12 | Added documentation to build() about the AND LIKE operator &~ 7/9/09 |
| 1.0.0b11 | Added documentation to build() about the NOT LIKE operator !~ 7/8/09 |
| 1.0.0b10 | Moved the private method checkConditions() to fActiveRecord::checkConditions() 7/8/09 |
| 1.0.0b9 | Changed build() to only fall back to ordering by primary keys if one exists 6/26/09 |
| 1.0.0b8 | Updated merge() to accept arrays of fActiveRecords or a single fActiveRecord in addition to an fRecordSet 6/2/09 |
| 1.0.0b7 | Backwards Compatibility Break - Removed flagAssociate() and isFlaggedForAssociation(), callbacks registered via fORM::registerRecordSetMethod() no longer receive the $associate parameter 6/2/09 |
| 1.0.0b6 | Changed tossIfEmpty() to return the record set to allow for method chaining 5/18/09 |
| 1.0.0b5 | build() now allows NULL for $where_conditions and $order_bys, added a check to the SQL passed to buildFromSQL() 5/3/09 |
| 1.0.0b4 | __call() was changed to prevent exceptions coming from fGrammar when an unknown method is called 3/27/09 |
| 1.0.0b3 | sort() and sortByCallback() now return the record set to allow for method chaining 3/23/09 |
| 1.0.0b2 | Added support for != and <> to build() and filter() 12/4/08 |
| 1.0.0b | The initial implementation 8/4/07 |
Static Methods
::build() public
Creates an fRecordSet by specifying the class to create plus the where conditions and order by rules
The where conditions array can contain key => value entries in any of the following formats:
'column=' => VALUE, // column = VALUE
'column!' => VALUE // column <> VALUE
'column!=' => VALUE // column <> VALUE
'column<>' => VALUE // column <> VALUE
'column~' => VALUE // column LIKE '%VALUE%'
'column!~' => VALUE // column NOT LIKE '%VALUE%'
'column<' => VALUE // column < VALUE
'column<=' => VALUE // column <= VALUE
'column>' => VALUE // column > VALUE
'column>=' => VALUE // column >= VALUE
'column=:' => 'other_column' // column = other_column
'column!:' => 'other_column' // column <> other_column
'column!=:' => 'other_column' // column <> other_column
'column<>:' => 'other_column' // column <> other_column
'column<:' => 'other_column' // column < other_column
'column<=:' => 'other_column' // column <= other_column
'column>:' => 'other_column' // column > other_column
'column>=:' => 'other_column' // column >= other_column
'column=' => array(VALUE, VALUE2, ... ) // column IN (VALUE, VALUE2, ... )
'column!' => array(VALUE, VALUE2, ... ) // column NOT IN (VALUE, VALUE2, ... )
'column!=' => array(VALUE, VALUE2, ... ) // column NOT IN (VALUE, VALUE2, ... )
'column<>' => array(VALUE, VALUE2, ... ) // column NOT IN (VALUE, VALUE2, ... )
'column~' => array(VALUE, VALUE2, ... ) // (column LIKE '%VALUE%' OR column LIKE '%VALUE2%' OR column ... )
'column&~' => array(VALUE, VALUE2, ... ) // (column LIKE '%VALUE%' AND column LIKE '%VALUE2%' AND column ... )
'column!~' => array(VALUE, VALUE2, ... ) // (column NOT LIKE '%VALUE%' AND column NOT LIKE '%VALUE2%' AND column ... )
'column!|column2<|column3=' => array(VALUE, VALUE2, VALUE3) // (column <> '%VALUE%' OR column2 < '%VALUE2%' OR column3 = '%VALUE3%')
'column|column2><' => array(VALUE, VALUE2) // WHEN VALUE === NULL: ((column2 IS NULL AND column = VALUE) OR (column2 IS NOT NULL AND column <= VALUE AND column2 >= VALUE))
// WHEN VALUE !== NULL: ((column <= VALUE AND column2 >= VALUE) OR (column >= VALUE AND column <= VALUE2))
'column|column2|column3~' => VALUE // (column LIKE '%VALUE%' OR column2 LIKE '%VALUE%' OR column3 LIKE '%VALUE%')
'column|column2|column3~' => array(VALUE, VALUE2, ... ) // ((column LIKE '%VALUE%' OR column2 LIKE '%VALUE%' OR column3 LIKE '%VALUE%') AND (column LIKE '%VALUE2%' OR column2 LIKE '%VALUE2%' OR column3 LIKE '%VALUE2%') AND ... )When creating a condition in the form column|column2|column3~, if the value for the condition is a single string that contains spaces, the string will be parsed for search terms. The search term parsing will handle quoted phrases and normal words and will strip punctuation and stop words (such as "the" and "a").
The order bys array can contain key => value entries in any of the following formats:
'column' => 'asc' // 'first_name' => 'asc' 'column' => 'desc' // 'last_name' => 'desc' 'expression' => 'asc' // "CASE first_name WHEN 'smith' THEN 1 ELSE 2 END" => 'asc' 'expression' => 'desc' // "CASE first_name WHEN 'smith' THEN 1 ELSE 2 END" => 'desc'
The column in both the where conditions and order bys can be in any of the formats:
'column' // e.g. 'first_name'
'current_table.column' // e.g. 'users.first_name'
'related_table.column' // e.g. 'user_groups.name'
'related_table{route}.column' // e.g. 'user_groups{user_group_id}.name'
'related_table=>once_removed_related_table.column' // e.g. 'user_groups=>permissions.level'
'related_table{route}=>once_removed_related_table.column' // e.g. 'user_groups{user_group_id}=>permissions.level'
'related_table=>once_removed_related_table{route}.column' // e.g. 'user_groups=>permissions{read}.level'
'related_table{route}=>once_removed_related_table{route}.column' // e.g. 'user_groups{user_group_id}=>permissions{read}.level'
'column||other_column' // e.g. 'first_name||last_name' - this concatenates the column valuesIn addition to using plain column names for where conditions, it is also possible to pass an aggregate function wrapped around a column in place of a column name, but only for certain comparison types. Note that for column comparisons, the function may be placed on either column or both.
'function(column)=' => VALUE, // function(column) = VALUE 'function(column)!' => VALUE // function(column) <> VALUE 'function(column)!= => VALUE // function(column) <> VALUE 'function(column)<>' => VALUE // function(column) <> VALUE 'function(column)~' => VALUE // function(column) LIKE '%VALUE%' 'function(column)!~' => VALUE // function(column) NOT LIKE '%VALUE%' 'function(column)<' => VALUE // function(column) < VALUE 'function(column)<=' => VALUE // function(column) <= VALUE 'function(column)>' => VALUE // function(column) > VALUE 'function(column)>=' => VALUE // function(column) >= VALUE 'function(column)=:' => 'other_column' // function(column) = other_column 'function(column)!:' => 'other_column' // function(column) <> other_column 'function(column)!=:' => 'other_column' // function(column) <> other_column 'function(column)<>:' => 'other_column' // function(column) <> other_column 'function(column)<:' => 'other_column' // function(column) < other_column 'function(column)<=:' => 'other_column' // function(column) <= other_column 'function(column)>:' => 'other_column' // function(column) > other_column 'function(column)>=:' => 'other_column' // function(column) >= other_column 'function(column)=' => array(VALUE, VALUE2, ... ) // function(column) IN (VALUE, VALUE2, ... ) 'function(column)!' => array(VALUE, VALUE2, ... ) // function(column) NOT IN (VALUE, VALUE2, ... ) 'function(column)!=' => array(VALUE, VALUE2, ... ) // function(column) NOT IN (VALUE, VALUE2, ... ) 'function(column)<>' => array(VALUE, VALUE2, ... ) // function(column) NOT IN (VALUE, VALUE2, ... )
The aggregate functions AVG(), COUNT(), MAX(), MIN() and SUM() are supported across all database types.
Below is an example of using where conditions and order bys. Please note that values should not be escaped for the database, but should just be normal PHP values.
return fRecordSet::build( 'User', array( 'first_name=' => 'John', 'status!' => 'Inactive', 'groups.group_id=' => 2 ), array( 'last_name' => 'asc', 'date_joined' => 'desc' ) );
Signature
fRecordSet build( string $class, array $where_conditions=array(), array $order_bys=array(), integer $limit=NULL, integer $page=NULL )
Parameters
| string | $class | The class to create the fRecordSet of |
| array | $where_conditions | The column => value comparisons for the WHERE clause |
| array | $order_bys | The column => direction values to use for the ORDER BY clause |
| integer | $limit | The number of records to fetch |
| integer | $page | The page offset to use when limiting records |
Returns
A set of fActiveRecord objects
::buildFromArray() internal public
Please note: this method is public, however it is primarily intended for internal use by Flourish and will normally not be useful in site/application code
Creates an fRecordSet from an array of records
Signature
fRecordSet buildFromArray( string|array $class, array $records )
Parameters
| string|array | $class | The class or classes of the records |
| array | $records | The records to create the set from, the order of the record set will be the same as the order of the array. |
Returns
A set of fActiveRecord objects
::buildFromSQL() public
Creates an fRecordSet from an SQL statement
The SQL statement should select all columns from a single table with a * pattern since that is what an fActiveRecord models. If any columns are left out or added, strange error may happen when loading or saving records.
Here is an example of an appropriate SQL statement:
#!sql SELECT users.* FROM users INNER JOIN groups ON users.group_id = groups.group_id WHERE groups.name = 'Public'
Here is an example of a SQL statement that will cause errors:
#!sql SELECT users.*, groups.name FROM users INNER JOIN groups ON users.group_id = groups.group_id WHERE groups.group_id = 2
The $non_limited_count_sql should only be passed when the $sql contains a LIMIT clause and should contain a count of the records when a LIMIT is not imposed.
Here is an example of a $sql statement with a LIMIT clause and a corresponding $non_limited_count_sql:
fRecordSet::buildFromSQL('User', 'SELECT * FROM users LIMIT 5', 'SELECT count(*) FROM users');
The $non_limited_count_sql is used when count() is called with TRUE passed as the parameter.
Signature
fRecordSet buildFromSQL( string $class, string $sql, string $non_limited_count_sql=NULL )
Parameters
| string | $class | The class to create the fRecordSet of |
| string | $sql | The SQL to create the set from |
| string | $non_limited_count_sql | An SQL statement to get the total number of rows that would have been returned if a LIMIT clause had not been used. Should only be passed if a LIMIT clause is used. |
Returns
A set of fActiveRecord objects
::compose() protected
Composes text using fText if loaded
Signature
string compose( string $message, mixed $component )
Parameters
| string | $message | The message to compose |
| mixed | $component [, ... ] | A string or number to insert into the message |
Returns
The composed and possible translated message
Methods
->__construct() protected
Sets the contents of the set
Signature
fRecordSet __construct( string|array $class, Iterator|array $records=NULL, string|integer $non_limited_count=NULL )
Parameters
| string|array | $class | The type(s) of records the object will contain |
| Iterator|array | $records | The Iterator object of the records to create or an array of records |
| string|integer | $non_limited_count | An SQL statement to get the total number of records sans a LIMIT clause or a integer of the total number of records |
->__call() public
Allows for preloading various data related to the record set in single database queries, as opposed to one query per record
This method will handle methods in the format verbRelatedRecords() for the verbs build, prebuild, precount and precreate.
build calls create{RelatedClass}() on each record in the set and returns the result as a new record set. The relationship route can be passed as an optional parameter.
prebuild builds *-to-many record sets for all records in the record set. precount will count records in *-to-many record sets for every record in the record set. precreate will create a *-to-one record for every record in the record set.
Signature
void __call( string $method_name, string $parameters )
Parameters
| string | $method_name | The name of the method called |
| string | $parameters | The parameters passed |
->__get() internal public
Please note: this method is public, however it is primarily intended for internal use by Flourish and will normally not be useful in site/application code
All requests that hit this method should be requests for callbacks
Signature
callback __get( string $method )
Parameters
| string | $method | The method to create a callback for |
Returns
The callback for the method requested
->buildFromCall() public
Calls a specific method on each object, returning an fRecordSet of the results
Signature
fRecordSet buildFromCall( string $method, mixed $parameter )
Parameters
| string | $method | The method to call |
| mixed | $parameter [, ... ] | A parameter to pass for each call to the method |
Returns
A set of records that resulted from calling the method
->buildFromMap() public
Maps each record in the set to a callback function, returning an fRecordSet of the results
Signature
fRecordSet buildFromMap( callback $callback, mixed $parameter )
Parameters
| callback | $callback | The callback to pass the values to |
| mixed | $parameter [, ... ] | The parameter to pass to the callback - see method description for details |
Returns
A set of records that resulted from the mapping operation
->call() public
Calls a specific method on each object, returning an array of the results
Signature
array call( string $method, mixed $parameter )
Parameters
| string | $method | The method to call |
| mixed | $parameter [, ... ] | A parameter to pass for each call to the method |
Returns
An array the size of the record set with one result from each record/method
->contains() public
Checks if the record set contains the record specified
Signature
boolean contains( fActiveRecord $record )
Parameters
| fActiveRecord | $record | The record to check, must exist in the database |
Returns
If the record specified is in this record set
->count() public implements Countable
Returns the number of records in the set
Signature
integer count( boolean $ignore_limit=FALSE )
Parameters
| boolean | $ignore_limit | If set to TRUE, this method will return the number of records that would be in the set if there was no LIMIT clause |
Returns
The number of records in the set
->current() internal public implements Iterator
Please note: this method is public, however it is primarily intended for internal use by Flourish and will normally not be useful in site/application code
Returns the current record in the set (used for iteration)
Signature
fActiveRecord current( )
Returns
The current record
Throws
- fNoRemainingException
- When there are no remaining records in the set
->diff() public
Removes all passed records from the current record set
Signature
fRecordSet diff( fRecordSet|array|fActiveRecord $records, boolean $remember_original_count=FALSE )
Parameters
| fRecordSet|array|fActiveRecord | $records | The record set, array of records, or record to remove from the current record set, all instances will be removed |
| boolean | $remember_original_count | If the number of records in the current set should be saved as the non-limited count for the new set |
Returns
The records not present in the passed records
->fetchRecord() public
Returns the current record in the set and moves the pointer to the next
Signature
fActiveRecord fetchRecord( )
Returns
The current record
Throws
- fNoRemainingException
- When there are no remaining records in the set
->filter() public
Filters the records in the record set via a callback
The $callback parameter can be one of three different forms to filter the records in the set:
- A callback that accepts a single record and returns FALSE if it should be removed
- A psuedo-callback in the form '{record}::methodName' to filter out any records where the output of $record->methodName() is equivalent to FALSE
- A conditions array that will remove any records that don't meet all of the conditions
The conditions array can use one or more of the following key => value syntaxes to perform various comparisons. The array keys are method names followed by a comparison operator.
// The following forms work for any $value that is not an array 'methodName=' => $value // If the output is equal to $value 'methodName!' => $value // If the output is not equal to $value 'methodName!=' => $value // If the output is not equal to $value 'methodName<>' => $value // If the output is not equal to $value 'methodName<' => $value // If the output is less than $value 'methodName<=' => $value // If the output is less than or equal to $value 'methodName>' => $value // If the output is greater than $value 'methodName>=' => $value // If the output is greater than or equal to $value 'methodName~' => $value // If the output contains the $value (case insensitive) 'methodName!~' => $value // If the output does not contain the $value (case insensitive) 'methodName|methodName2|methodName3~' => $value // Parses $value as a search string and make sure each term is present in at least one output (case insensitive) // The following forms work for any $array that is an array 'methodName=' => $array // If the output is equal to at least one value in $array 'methodName!' => $array // If the output is not equal to any value in $array 'methodName!=' => $array // If the output is not equal to any value in $array 'methodName<>' => $array // If the output is not equal to any value in $array 'methodName~' => $array // If the output contains one of the strings in $array (case insensitive) 'methodName!~' => $array // If the output contains none of the strings in $array (case insensitive) 'methodName&~' => $array // If the output contains all of the strings in $array (case insensitive) 'methodName|methodName2|methodName3~' => $array // If each value in the array is present in the output of at least one method (case insensitive) // The following works for an equal number of methods and values in the array 'methodName!|methodName2<|methodName3=' => array($value, $value2, $value3) // An OR statement - one of the method to value comparisons must be TRUE // The following accepts exactly two methods and two values, although the second value may be NULL 'methodName|methodName2><' => array($value, $value2) // If the range of values from the methods intersects the range of $value and $value2 - should be dates, times, timestamps or numbers
Signature
fRecordSet filter( callback|string|array $procedure, boolean $remember_original_count=FALSE )
Parameters
| callback|string|array | $procedure | The way in which to filter the records - see method description for possible forms |
| boolean | $remember_original_count | If the number of records in the current set should be saved as the non-limited count for the new set |
Returns
A new fRecordSet with the filtered records
->getClass() public
Returns the class name of the record being stored
Signature
string|array getClass( )
Returns
The class name(s) of the records in the set
->getPrimaryKeys() public
Returns the primary keys for all of the records in the set
Signature
array getPrimaryKeys( )
Returns
The primary keys of all the records in the set
->getRecords() public
Returns all of the records in the set
Signature
array getRecords( )
Returns
The records in the set
->intersect() public
Returns all records in the current record set that are also present in the passed records
Signature
fRecordSet intersect( fRecordSet|array|fActiveRecord $records, boolean $remember_original_count=FALSE )
Parameters
| fRecordSet|array|fActiveRecord | $records | The record set, array of records, or record to create an intersection of with the current record set |
| boolean | $remember_original_count | If the number of records in the current set should be saved as the non-limited count for the new set |
Returns
The records present in the current record set that are also present in the passed records
->key() internal public implements Iterator
Please note: this method is public, however it is primarily intended for internal use by Flourish and will normally not be useful in site/application code
Returns the primary key for the current record (used for iteration)
Signature
mixed key( )
Returns
The primay key of the current record
->map() public
Performs an array_map() on the record in the set
The record will be passed to the callback as the first parameter unless it's position is specified by the placeholder string '{record}'.
Additional parameters can be passed to the callback in one of two different ways:
- Passing a non-array value will cause it to be passed to the callback
- Passing an array value will cause the array values to be passed to the callback with their corresponding record
If an array parameter is too long (more items than records in the set) it will be truncated. If an array parameter is too short (less items than records in the set) it will be padded with NULL values.
To allow passing the record as a specific parameter to the callback, a placeholder string '{record}' will be replaced with a the record. It is also possible to specify '{record}::methodName' to cause the output of a method from the record to be passed instead of the whole record.
It is also possible to pass the zero-based record index to the callback by passing a parameter that contains '{index}'.
Signature
array map( callback $callback, mixed $parameter )
Parameters
| callback | $callback | The callback to pass the values to |
| mixed | $parameter [, ... ] | The parameter to pass to the callback - see method description for details |
Returns
An array of the results from the callback
->merge() public
Merges the record set with more records
Signature
fRecordSet merge( fRecordSet|array|fActiveRecord $records )
Parameters
| fRecordSet|array|fActiveRecord | $records | The record set, array of records, or record to merge with the current record set, duplicates will not be removed |
Returns
The merged record sets
->next() internal public implements Iterator
Please note: this method is public, however it is primarily intended for internal use by Flourish and will normally not be useful in site/application code
Moves to the next record in the set (used for iteration)
Signature
void next( )
->reduce() public
Reduces the record set to a single value via a callback
The callback should take two parameters and return a single value:
- The initial value and the first record for the first call
- The result of the last call plus the next record for the second and subsequent calls
Signature
mixed reduce( callback $callback, mixed $inital_value=NULL )
Parameters
| callback | $callback | The callback to pass the records to - see method description for details |
| mixed | $inital_value | The initial value to seed reduce with |
Returns
The result of the reduce operation
->rewind() internal public implements Iterator
Please note: this method is public, however it is primarily intended for internal use by Flourish and will normally not be useful in site/application code
Rewinds the set to the first record (used for iteration)
Signature
void rewind( )
->slice() public
Slices a section of records from the set and returns a new set containing those
Signature
fRecordSet slice( integer $offset, integer $length=NULL, boolean $remember_original_count=FALSE )
Parameters
| integer | $offset | The index to start at, negative indexes will slice that many records from the end |
| integer | $length | The number of records to return, negative values will stop that many records before the end, NULL will return all records to the end of the set - if there are not enough records, less than $length will be returned |
| boolean | $remember_original_count | If the number of records in the current set should be saved as the non-limited count for the new set |
Returns
The new slice of records
->sort() public
Sorts the set by the return value of a method from the class created and rewind the interator
This methods uses fUTF8::inatcmp() to perform comparisons.
Signature
fRecordSet sort( string $method, string $direction )
Parameters
| string | $method | The method to call on each object to get the value to sort by |
| string | $direction | Either 'asc' or 'desc' |
Returns
The record set object, to allow for method chaining
->sortByCallback() public
Sorts the set by passing the callback to usort() and rewinds the interator
Signature
fRecordSet sortByCallback( mixed $callback )
Parameters
| mixed | $callback | The function/method to pass to usort() |
Returns
The record set object, to allow for method chaining
->tossIfEmpty() public
Throws an fEmptySetException if the record set is empty
Signature
fRecordSet tossIfEmpty( string $message=NULL )
Parameters
| string | $message | The message to use for the exception if there are no records in this set |
Returns
The record set object, to allow for method chaining
Throws
- fEmptySetException
- When there are no record in the set
->unique() public
Returns a new fRecordSet containing only unique records in the record set
Signature
fRecordSet unique( boolean $remember_original_count=FALSE )
Parameters
| boolean | $remember_original_count | If the number of records in the current set should be saved as the non-limited count for the new set |
Returns
The new record set with only unique records
->valid() internal public implements Iterator
Please note: this method is public, however it is primarily intended for internal use by Flourish and will normally not be useful in site/application code
Returns if the set has any records left (used for iteration)
Signature
boolean valid( )
Returns
If the iterator is still valid
