Flourish PHP Unframework

fActiveRecord

abstract class, v1.0.0b81

An active record pattern base class

This class uses fORMSchema to inspect your database and provides an OO interface to a single database table. The class dynamically handles method calls for getting, setting and other operations on columns. It also dynamically handles retrieving and storing related records.

Changes:
1.0.0b81Fixed a bug with updating a record that contains only an auto-incrementing primary key 9/6/11
1.0.0b80Added support to checkCondition() for the ^~ and $~ operators 6/20/11
1.0.0b79Fixed some bugs in handling relationships between PHP 5.3 namespaced classes 5/26/11
1.0.0b78Backwards Compatibility Break - reflect() now returns an associative array instead of a string 5/10/11
1.0.0b77Fixed inspect() to not throw an fProgrammerException when a valid element has a NULL value 5/10/11
1.0.0b76Added clearIdentityMap() 5/9/11
1.0.0b75Fixed a bug where child records of a record with a non-auto-incrementing primary key would not be saved properly for a new record 12/6/10
1.0.0b74Updated populate() to use the binary type for fRequest::get() 11/30/10
1.0.0b73Backwards Compatibility Break - changed column set methods to treat strings of all whitespace the same as empty string and convert them to NULL 11/29/10
1.0.0b72Added the new comment element to the reflection signature for inspect methods 11/28/10
1.0.0b71Updated class to use fORM::getRelatedClass() 11/24/10
1.0.0b70Added support for PHP 5.3 namespaced fActiveRecord classes 11/11/10
1.0.0b69Backwards Compatibility Break - changed validate() to return a nested array of validation messages when there are validation errors on child records 10/3/10
1.0.0b68Added hooks to replicate() 9/7/10
1.0.0b67Updated code to work with the new fORM API 8/6/10
1.0.0b66Fixed a bug with store() and non-primary key auto-incrementing columns 7/5/10
1.0.0b65Fixed bugs with inspect() making some min_value and max_value elements available for non-numeric types, fixed reflect() to list the min_value and max_value elements 6/8/10
1.0.0b64BackwardsCompatibilityBreak - changed validate()'s returned messages array to have field name keys - added the option to validate() to remove field names from messages 5/26/10
1.0.0b63Changed how is_subclass_of() is used to work around a bug in 5.2.x 4/6/10
1.0.0b62Fixed a bug that could cause infinite recursion starting in v1.0.0b60 4/2/10
1.0.0b61Fixed issues with handling populate actions when working with mapped classes 3/31/10
1.0.0b60Fixed issues with handling associate and has actions when working with mapped classes, added validateClass() 3/30/10
1.0.0b59Changed an extended UTF-8 arrow character into the correct -> 3/29/10
1.0.0b58Fixed reflect() to specify the value returned from set methods 3/15/10
1.0.0b57Added the post::loadFromIdentityMap() hook and fixed __construct() to always call the post::__construct() hook 3/14/10
1.0.0b56Fixed $force_cascade in delete() to work even when the restricted relationship is once-removed through an unrestricted relationship 3/9/10
1.0.0b55Fixed load() to that related records are cleared, requiring them to be loaded from the database 3/4/10
1.0.0b54Fixed detection of route name for one-to-one relationships in delete() 3/3/10
1.0.0b53Fixed a bug where related records with a primary key that contained a foreign key with an on update cascade clause would be deleted when changing the value of the column referenced by the foreign key 12/17/09
1.0.0b52Backwards Compatibility Break - Added the $force_cascade parameter to delete() and store() - enabled calling prepare() and encode() for non-column get methods, added ::has{RelatedRecords}() methods 12/16/09
1.0.0b51Made changed() properly recognize that a blank string and NULL are equivalent due to the way that set() casts values 11/14/09
1.0.0b50Fixed a bug with trying to load by a multi-column primary key where one of the columns was not specified 11/13/09
1.0.0b49Fixed a bug affecting where conditions with columns that are not null but have a default value 11/3/09
1.0.0b48Updated code for the new fORMDatabase and fORMSchema APIs 10/28/09
1.0.0b47Changed ::associate{RelatedRecords}(), ::link{RelatedRecords}() and ::populate{RelatedRecords}() to allow for method chaining 10/22/09
1.0.0b46Changed SQL statements to use value placeholders and identifier escaping 10/22/09
1.0.0b45Added support for !~, &~, >< and OR comparisons to checkConditions(), made object handling in checkConditions() more robust 9/21/09
1.0.0b44Updated code for new fValidationException API 9/18/09
1.0.0b43Updated code for new fRecordSet API 9/16/09
1.0.0b42Corrected a grammar bug in hash() 9/9/09
1.0.0b41Fixed a bug in the last version that would cause issues with classes containing a custom class to table mapping 9/1/09
1.0.0b40Added a check to the configuration part of __construct() to ensure modelled tables have primary keys 8/26/09
1.0.0b39Changed set{ColumnName}() methods to return the record for method chaining, fixed a bug with loading by multi-column unique constraints, fixed a bug with load() 8/26/09
1.0.0b38Updated changed() to do a strict comparison when at least one value is NULL 8/17/09
1.0.0b37Changed __construct() to allow any Iterator object instead of just fResult 8/12/09
1.0.0b36Fixed a bug with setting NULL values from v1.0.0b33 8/10/09
1.0.0b35Fixed a bug with unescaping data in loadFromResult() from v1.0.0b33 8/10/09
1.0.0b34Added the ability to compare fActiveRecord objects in checkConditions() 8/7/09
1.0.0b33Performance enhancements to __call() and __construct() 8/7/09
1.0.0b32Changed delete() to remove auto-incrementing primary keys after the post::delete() hook 7/29/09
1.0.0b31Fixed a bug with loading a record by a multi-column primary key, fixed one-to-one relationship API 7/21/09
1.0.0b30Updated reflect() for new fORM::callReflectCallbacks() API 7/13/09
1.0.0b29Updated to use new fORM::callInspectCallbacks() method 7/13/09
1.0.0b28Fixed a bug where records would break the identity map at the end of store() 7/9/09
1.0.0b27Changed hash() from a protected method to a static public/internal method that requires the class name for non-fActiveRecord values 7/9/09
1.0.0b26Added checkConditions() from fRecordSet 7/8/09
1.0.0b25Updated validate() to use new fORMValidation API, including new message search/replace functionality 7/1/09
1.0.0b24Changed validate() to remove duplicate validation messages 6/30/09
1.0.0b23Updated code for new fORMValidation::validateRelated() API 6/26/09
1.0.0b22Added support for the $formatting parameter to encode methods on char, text and varchar columns 6/19/09
1.0.0b21Performance tweaks and updates for fORM and fORMRelated API changes 6/15/09
1.0.0b20Changed replacement values in preg_replace() calls to be properly escaped 6/11/09
1.0.0b19Added list{RelatedRecords}() methods, updated code for new fORMRelated API 6/2/09
1.0.0b18Changed store() to use new fORMRelated::store() method 6/2/09
1.0.0b17Added some missing parameter information to reflect() 6/1/09
1.0.0b16Fixed bugs in __clone() and replicate() related to recursive relationships 5/20/09
1.0.0b15Fixed an incorrect variable reference in store() 5/6/09
1.0.0b14store() no longer tries to get an auto-incrementing ID from the database if a value was set 5/2/09
1.0.0b13delete(), load(), populate() and store() now return the record to allow for method chaining 3/23/09
1.0.0b12set() now removes commas from integers and floats to prevent validation issues 3/22/09
1.0.0b11encode() no longer adds commas to floats 3/22/09
1.0.0b10__wakeup() no longer registers the record as the definitive copy in the identity map 3/22/09
1.0.0b9Changed __construct() to populate database default values when a non-existing record is instantiated 1/12/09
1.0.0b8Fixed exists() to properly detect cases when an existing record has one or more NULL values in the primary key 1/11/09
1.0.0b7Fixed __construct() to not trigger the post::__construct() hook when force-configured 12/30/08
1.0.0b6__construct() now accepts an associative array matching any unique key or primary key, fixed the post::__construct() hook to be called once for each record 12/26/08
1.0.0b5Fixed replicate() to use plural record names for related records 12/12/08
1.0.0b4Added replicate() to allow cloning along with related records 12/12/08
1.0.0b3Changed __clone() to clone objects contains in the values and cache arrays 12/11/08
1.0.0b2Added the __clone() method to properly duplicate a record 12/4/08
1.0.0bThe initial implementation 8/4/07

Static Variables

::$callback_cache protected

Caches callbacks for methods

Type

array

::$configured protected

An array of flags indicating a class has been configured

Type

array

::$identity_map protected

Maps objects via their primary key

Type

array

::$method_name_cache protected

Caches method name parsings

Type

array

::$replicate_level protected

Keeps track of the recursive call level of replication so we can clear the map

Type

integer

::$replicate_map protected

Keeps a list of records that have been replicated

Type

array

::$unescape_map protected

Contains a list of what columns in each class need to be unescaped and what data type they are

Type

array

Variables

->cache protected

A data store for caching data related to a record, the structure of this is completely up to the developer using it

Type

array

->old_values protected

The old values for this record

Column names are the keys, but a column key will only be present if a value has changed. The value associated with each key is an array of old values with the first entry being the oldest value. The static methods assign(), changed(), hasOld() and retrieveOld() are the best way to interact with this array.

Type

array

Records that are related to the current record via some relationship

This array is used to cache related records so that a database query is not required each time related records are accessed. The fORMRelated class handles most of the interaction with this array.

Type

array

->values protected

The values for this record

This array always contains every column in the database table as a key with the value being the current value.

Type

array

Static Methods

::assign() 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

Sets a value to the $values array, preserving the old value in $old_values

Signature

void assign( array &$values, array &$old_values, string $column, mixed $value )

Parameters

array &$values The current values
array &$old_values The old values
string $column The column to set
mixed $value The value to set

::changed() 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

Checks to see if a value has changed

Signature

boolean changed( array &$values, array &$old_values, string $column )

Parameters

array &$values The current values
array &$old_values The old values
string $column The column to check

Returns

If the value for the column specified has changed

::checkClass() 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

Ensures a class extends fActiveRecord

Signature

boolean checkClass( string $class )

Parameters

string $class The class to check

Returns

If the class is an fActiveRecord descendant

::checkConditions() 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

Checks to see if a record matches all of the conditions

Signature

boolean checkConditions( fActiveRecord $record, array $conditions )

Parameters

fActiveRecord $record The record to check
array $conditions The conditions to check - see fRecordSet::filter() for format details

Returns

If the record meets all conditions

::clearIdentityMap() public

Clears the identity map

Signature

void clearIdentityMap( )

::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

::forceConfigure() 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

Ensures that configure() has been called for the class

Signature

void forceConfigure( string $class )

Parameters

string $class The class to configure

::hash() 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

Takes a row of data or a primary key and makes a hash from the primary key

Signature

string|NULL hash( fActiveRecord|array|string|int $record, string $class=NULL )

Parameters

fActiveRecord|array|string|int $record An fActiveRecord object, an array of the records data, an array of primary key data or a scalar primary key value
string $class The class name, if $record isn't an fActiveRecord

Returns

A hash of the record's primary key value or NULL if the record doesn't exist yet

::hasOld() 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

Checks to see if an old value exists for a column

Signature

boolean hasOld( array &$old_values, string $column )

Parameters

array &$old_values The old values
string $column The column to set

Returns

If an old value for that column exists

::reset() 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

Resets the configuration of the class

Signature

void reset( )

::retrieveOld() 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

Retrieves the oldest value for a column or all old values

Signature

mixed retrieveOld( array &$old_values, string $column, mixed $default=NULL, boolean $return_all=FALSE )

Parameters

array &$old_values The old values
string $column The column to get
mixed $default The default value to return if no value exists
boolean $return_all Return the array of all old values for this column instead of just the oldest

Returns

The old value for the column

::validateClass() 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

Ensures a class extends fActiveRecord

Signature

void validateClass( string $class )

Parameters

string $class The class to verify

Methods

->__construct() public

Creates a new record or loads one from the database - if a primary key or unique key is provided the record will be loaded

Signature

fActiveRecord __construct( mixed $key=NULL )

Parameters

mixed $key The primary key or unique key value(s) - single column primary keys will accept a scalar value, all others must be an associative array of (string) {column} => (mixed) {value}

Throws

fNotFoundException
When the record specified by $key can not be found in the database

->__call() public

Handles all method calls for columns, related records and hook callbacks

Dynamically handles get, set, prepare, encode and inspect methods for each column in this record. Method names are in the form verbColumName().

This method also handles associate, build, count, has, and link verbs for records in many-to-many relationships; build, count, has and populate verbs for all related records in one-to-many relationships and create, has and populate verbs for all related records in one-to-one relationships, and the create verb for all related records in many-to-one relationships.

Method callbacks registered through fORM::registerActiveRecordMethod() will be delegated via this method.

Signature

mixed __call( string $method_name, array $parameters )

Parameters

string $method_name The name of the method called
array $parameters The parameters passed

Returns

The value returned by the method called

->__clone() 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 a clone of a record

If the record has an auto incrementing primary key, the primary key will be erased in the clone. If the primary key is not auto incrementing, the primary key will be left as-is in the clone. In either situation the clone will return FALSE from the exists() method until store() is called.

Signature

fActiveRecord __clone( )

->__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

->__wakeup() 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

Configure itself when coming out of the session. Records from the session are NOT hooked into the identity map.

Signature

void __wakeup( )

->configure() protected

Allows the programmer to set features for the class

This method is only called once per page load for each class.

Signature

void configure( )

->constructInsertParams() protected

Creates the fDatabase::translatedQuery() insert statement params

Signature

array constructInsertParams( )

Returns

The parameters for an fDatabase::translatedQuery() SQL insert statement

->constructUpdateParams() protected

Creates the fDatabase::translatedQuery() update statement params

Signature

array constructUpdateParams( )

Returns

The parameters for an fDatabase::translatedQuery() SQL update statement

->delete() public

Deletes a record from the database, but does not destroy the object

This method will start a database transaction if one is not already active.

Signature

fActiveRecord delete( boolean $force_cascade=FALSE )

Parameters

boolean $force_cascade When TRUE, this will cause all child objects to be deleted, even if the ON DELETE clause is RESTRICT or NO ACTION

Returns

The record object, to allow for method chaining

->encode() protected

Retrieves a value from the record and prepares it for output into an HTML form element.

Below are the transformations performed:

  • varchar, char, text: will run through fHTML::encode(), if TRUE is passed the text will be run through fHTMLconvertNewLinks() and fHTML::makeLinks()
  • float: takes 1 parameter to specify the number of decimal places
  • date, time, timestamp: format() will be called on the fDate/fTime/fTimestamp object with the 1 parameter specified
  • objects: the object will be converted to a string by __toString() or a (string) cast and then will be run through fHTML::encode()
  • all other data types: the value will be run through fHTML::encode()

Signature

string encode( string $column, string $formatting=NULL )

Parameters

string $column The name of the column to retrieve
string $formatting The formatting string

Returns

The encoded value for the column specified

->exists() public

Checks to see if the record exists in the database

Signature

boolean exists( )

Returns

If the record exists in the database

->fetchResultFromUniqueKey() protected

Loads a record from the database based on a UNIQUE key

Signature

void fetchResultFromUniqueKey( array $values )

Parameters

array $values The UNIQUE key values to try and load with

Throws

fNotFoundException

->get() protected

Retrieves a value from the record

Signature

mixed get( string $column )

Parameters

string $column The name of the column to retrieve

Returns

The value for the column specified

->inspect() protected

Retrieves information about a column

Signature

mixed inspect( string $column, string $element=NULL )

Parameters

string $column The name of the column to inspect
string $element The metadata element to retrieve

Returns

The metadata array for the column, or the metadata element specified

->load() public

Loads a record from the database

Signature

fActiveRecord load( )

Returns

The record object, to allow for method chaining

Throws

fNotFoundException
When the record could not be found in the database

->loadFromIdentityMap() protected

Tries to load the object (via references to class vars) from the fORM identity map

Signature

boolean loadFromIdentityMap( array $row, string $hash )

Parameters

array $row The data source for the primary key values
string $hash The unique hash for this record

Returns

If the load was successful

->loadFromResult() protected

Loads a record from the database directly from a result object

Signature

boolean loadFromResult( Iterator $result, boolean $ignore_identity_map=FALSE )

Parameters

Iterator $result The result object to use for loading the current object
boolean $ignore_identity_map If the identity map should be ignored and the values loaded no matter what

Returns

If the record was loaded from the identity map

->populate() public

Sets the values for this record by getting values from the request through the fRequest class

Signature

fActiveRecord populate( )

Returns

The record object, to allow for method chaining

->prepare() protected

Retrieves a value from the record and prepares it for output into html.

Below are the transformations performed:

  • varchar, char, text: will run through fHTML::prepare(), if TRUE is passed the text will be run through fHTMLconvertNewLinks() and fHTML::makeLinks()
  • boolean: will return 'Yes' or 'No'
  • integer: will add thousands/millions/etc. separators
  • float: will add thousands/millions/etc. separators and takes 1 parameter to specify the number of decimal places
  • date, time, timestamp: format() will be called on the fDate/fTime/fTimestamp object with the 1 parameter specified
  • objects: the object will be converted to a string by __toString() or a (string) cast and then will be run through fHTML::prepare()

Signature

string prepare( string $column, mixed $formatting=NULL )

Parameters

string $column The name of the column to retrieve
mixed $formatting The formatting parameter, if applicable

Returns

The formatted value for the column specified

->reflect() public

Generates the method signatures for all methods (including dynamic ones)

Signature

array reflect( boolean $include_doc_comments=FALSE )

Parameters

boolean $include_doc_comments If the doc block comments for each method should be included

Returns

An associative array of method name => method signature

->replicate() public

Generates a clone of the current record, removing any auto incremented primary key value and allowing for replicating related records

This method will accept three different sets of parameters:

  • No parameters: this object will be cloned
  • A single TRUE value: this object plus all many-to-many associations and all child records (recursively) will be cloned
  • Any number of plural related record class names: the many-to-many associations or child records that correspond to the classes specified will be cloned

The class names specified can be a simple class name if there is only a single route between the two corresponding database tables. If there is more than one route between the two tables, the class name should be substituted with a string in the format 'RelatedClass{route}'.

Signature

fActiveRecord replicate( string $related_class=NULL [, ... ] )

Parameters

string $related_class [, ... ] The plural related class to replicate - see method description for details

Returns

The cloned record

->set() protected

Sets a value to the record

Signature

fActiveRecord set( string $column, mixed $value )

Parameters

string $column The column to set the value to
mixed $value The value to set

Returns

This record, to allow for method chaining

->store() public

Stores a record in the database, whether existing or new

This method will start database and filesystem transactions if they have not already been started.

Signature

fActiveRecord store( boolean $force_cascade=FALSE )

Parameters

boolean $force_cascade When storing related records, this will force deleting child records even if they have their own children in a relationship with an RESTRICT or NO ACTION for the ON DELETE clause

Returns

The record object, to allow for method chaining

Throws

fValidationException
When validate() throws an exception

->validate() public

Validates the values of the record against the database and any additional validation rules

Signature

void|array validate( boolean $return_messages=FALSE, boolean $remove_column_names=FALSE )

Parameters

boolean $return_messages If an array of validation messages should be returned instead of an exception being thrown
boolean $remove_column_names If column names should be removed from the returned messages, leaving just the message itself

Returns

If $return_messages is TRUE, an array of validation messages will be returned

Throws

fValidationException
When the record, or one of the associated records, violates one of the validation rules for the class or can not be properly stored in the database