ActiveRecord_BaseAn ActiveRecord implementation for PHP 5.
Designed to eventually offer as much of the functionality available in Ruby on Rails's ActiveRecord implementation as is feasible, this is a base class for building data models capable of storing and retrieving themselves from permanent storage (a database) and whose attributes are largely driven by the database schema as opposed to being defined in the class. That's a long-winded way of saying ActiveRecord is a fast way to create objects that mirror a database table.
Take, for example, a table created with the following SQL:
To create an active record class linked to this table, all you need to write is:
That's it. Your User class (note User is singular while the table users is plural) now automatically has properties named id, username, full_name, password_hash, disabled, and last_login. It also inherits convenient finder and save methods from the base ActiveRecord class and includes conveniences for easily updating an object with values submitted from a web form.
For those already familiar with the Rails implemenation, it's worth nothing several significant differences between it and this implementation. Most notably, methods wich apply to the table or class as a whole are not implemented as static methods. This is due to a number of limitations in PHP. Specifically, PHP does not provide any visibility about the scope in which it was called to static method. For example, let's say a static method foo is defined on a class A and a class B inherits from class A but does not definie it's own method foo. Within method foo you have no way of knowing whether it was invoked by calling A::foo() or B::foo, and that distinction is critical for any ActiveRecord implementation. For related reasons, it would also not possible for class B to override other static methods defined by A and have A call those methods. That is necessary if derived classes want to provide any class-specific behavior at the class or table level. Finally, PHP does not have facilities for true class-level metadata or behavior (there's no Class class that every object has an instance of, only a class name). At the time this code was being developed, PHP announced the availability of "late static bindings" beginning in version 5.3.0. While that may address some of the issues, it's still somewhat unclear how easy it would be for a base class to understand the calling scope when being called in the context of a derived class, and the desire to support as many 5.x versions of PHP as possible ruled that out as a viable alternative. So, in a nutshell, you'll need an instance of a class before doing any operations at all.
Example:
The other significant deviation from the approach used by rails is in the area of class initialization. Ruby allows more than just method and property definitions within the body of a class or module. It's possible to invoke methods and they in turn can affect the definition of your class or module. Of course, PHP doesn't have any kind of facility like that, which means we need another way to indicate things like use a different table name or primary key for this class. For this implementation, we introduce a method named init_class which is invoked only once during a script's lifecycle when the class should first be initialized. Other ActiveRecord implementations have used different approaches, including using attributes to indicate this information. We felt this approach provided for the most readable and easily documented code and also gives the most flexibility by allowing the execution of arbitrary code at startup.
For clarification, here's an example of defining a UserProfile class which maps to a table named users (instead of user_profiles, as would otherwise be assumed):
A more subtle, but important, difference from Rails is the handling of derived classes. Like Rails, this class implements single table inheritance. Let's say we have two classes:
Here, as in Rails, instances of both classes would be stored on a table named user. Which class each record was an instance of would be distinguished through the use of a type column, which would have the value 'User' for User instances and 'AdminUser' for AdminUser instances. Things get different, however, when additional abstract classes find their way into the mix. Take, for example:
In this case, both User and AdminUser objects would be stored in a table named myapp_users, not myapp_my_active_record. That's because this implementation ignores abstract base classes for the pupose of table naming. As shown here, that can be conveniently used to set policy which is inherited by derived classes. In Ruby this same effect can be achieved by redefining portions of the ActiveRecord::Base class, but, of course, that's much less easily achieved (if at all) in PHP.
The final important convention to note in this class is the naming convention used for mutator and accessor methods. The get method for a property named foo will have the signature foo(). The set method for a property named foo will have the signature set_foo(). This is helpful not only for tracking down the mutators and accessors for your favorite properties, but also for defining custom methods for accessing or setting properties created from database columns. Let's say, for example, I want to always return the last_login property for my User object as an instance of a custom objected named MyDateTime, and likewise I want to always accept an object of the same type when setting the property. I can easily set that up like so:
Note the use of the read_attribute and write_attribute methods here to gain access to the underlying object properties. Even though only these two methods have been declared, they will also be used anytime the corresponding public properties are accessed. Take for example these lines of code:
The first line will actually invoke the last_login() method, and the second will invoke the set_last_login() method. That's because the base ActiveRecord class actually maps all access to non-existent properties to the corresponding accessor or mutator method. The byproduct of this behavior is that many of the methods defined on the ActiveRecord class can also be accessed as though they were public properties.
Events
ActiveRecord supports the following event lifecycle:
Example:
Located in /activerecord/lib/ActiveRecord/Base.php (line 476)
| Class | Description |
|---|---|
Migration_Record
|
mixed
$attributes
(line 493)
Attributes
mixed
$cached_attributes
(line 509)
A collection of cached attribute values
mixed
$errors
(line 505)
Any errors that apply to this object
mixed
$logger
(line 489)
Cached logger
mixed
$metaInf
(line 485)
Class meta information
mixed
$new_record
(line 497)
Indicates whether this is a new record or not
mixed
$readonly
(line 501)
Indicates whether this record is read-only or not
Constructor __construct (line 2187)
Constructor
Accepts an optional associative array of attribute names and values as the initial values to set on the object.
Note that although this behavior is not very clearly explained in the PHP documentation, if derived classes do not specify a constructor, they will inherit this one by default.
accessible_attributes (line 1357)
Return a list of all attributes which have been made accessible to mass assignment by passing them to attr_accessible (the list is always maintained in sorted order).
add_conditions (line 2880)
Add conditions fragment to a SQL statement
add_event_listener (line 1438)
Add an event listener to this class.
add_joins (line 2869)
Add join fragment to a SQL statement
add_limit (line 2957)
Add limit information to the SQL statement
add_method_proxy (line 3234)
Define a proxy for a method name.
A proxied method allows the addition of "virtual" methods to a class which are actually invoked on another object. This is useful for features such as associations which need to define additional methods dynamically.
Methods calls made to the other object include two additional parameters which are always the first two parameters passed. They are the ActiveRecord_Base instance the call is being invoked on and an ActiveRecord_Proxy object which allows direct access to the attributes for the object.
Example:
add_order (line 2897)
Add order by fragment to a SQL statement
after_create (line 1505)
Register a method on this class to be called after a save operation is performed for a new record.
after_destroy (line 1608)
Register a method on this class to be called after the record is destroyed.
after_save (line 1526)
Register a method on this class to be called after any save operation is performed.
after_update (line 1516)
Register a method on this class to be called after a save operation is performed for a record being updated (non-new record).
after_validation (line 1588)
Register a method on this class to be called after any validation operation is performed.
after_validation_on_create (line 1567)
Register a method on this class to be called after a validation operation is performed for a new record.
after_validation_on_update (line 1578)
Register a method on this class to be called after a validation operation is performed for a record being updated (non-new record).
assemble_finder_options (line 3163)
Create an options parameter for passing to a find_* method using the output from create_finder_attribute_hash
attributes (line 2218)
Returns this object's attributes as an associative array.
attributes_for_set (line 3472)
Return the list of column names and attribute values for use in the SET clause of an UPDATE statement. The primary key column is excluded.
attributes_from_column_definition (line 2989)
Return an associative array of attributes representing the default values for the fields on this class's table. The array keys are the field names and the values are the default values.
attributes_protected_by_default (line 3093)
Return a list of attributes which are never permitted in mass-assignment. The returned list must be sorted. By default, the returned list include the primary key and inheritance column.
attribute_names (line 2711)
Returns an array of names for the attributes available on this object. The returned list is sorted alphabetically.
attribute_present (line 2684)
Returns true if the named attribute exists for this object and has a non-empty value (not null, false, 0, the empty string, or any empty array).
attr_accessible (line 1334)
Accepts the names of one or more attributes which are allowed to
be assigned through mass assignment in this class (assignment through the constructor, create method, set_attributes method, etc.). If this method is used, only those attributes specified as accessible are allowed to be assigned through mass assignment.
attr_protected (line 1291)
Accepts the names of one or more attributes which are protected from mass assignment in this class (assignment through the constructor, create method, set_attributes method, etc.).
base_class_name (line 3055)
Traverses the list of this class's parents to return the oldest ancestor which is not abstract (this is for single table inheritance since inherited classes uses the base class's table.
before_create (line 1484)
Register a method on this class to be called before a save operation is performed for a new record.
before_destroy (line 1598)
Register a method on this class to be called before the record is destroyed.
before_save (line 1474)
Register a method on this class to be called before any save operation is performed.
before_update (line 1495)
Register a method on this class to be called before a save operation is performed for a record being updated (non-new record).
before_validation (line 1536)
Register a method on this class to be called before any validation operation is performed.
before_validation_on_create (line 1546)
Register a method on this class to be called before a validation operation is performed for a new record.
before_validation_on_update (line 1557)
Register a method on this class to be called before a validation operation is performed for a record being updated (non-new record).
belongs_to (line 1972)
Specifies a one to one association with another class where the foreign key resides in this class.
For example:
Implies a table structure like:
A belongs_to association adds four methods to the class:
class_name (line 1405)
Turn a table name back into a class name. This follows the reverse rules of the table_name method. So, for example, "my_objects" becomes "MyObject".
columns (line 1206)
Return an array of ActiveRecord_Column objects for the table associated with this class.
columns_for_insert (line 3489)
Return the list of all attribute names prepared for use in an insert statement
columns_hash (line 1226)
Returns an associative array of column objects keyed by column name for the table associated with this class.
column_for_attribute (line 1281)
Returns the column object for the named attribute
column_names (line 1241)
Returns an array of column names as strings.
connection (line 1072)
Return the database connection for this class
content_columns (line 1260)
Returns an array of column objects suitable for direct editing
by a user. The primary key; the inheritance column; all columns ending in _id or _count; and any columns named created_at, created_on, updated_at, updated_on, or lock version are omitted from the returned list.
count (line 959)
Returns a count of records matching the provided criteria.
Accepted options are the same as for find_all().
Example
count_by_sql (line 985)
Returns the result of an SQL statement that should only include a COUNT(*) -- or equivalent -- in the SELECT clause.
Example
create (line 742)
Create and save (validation permitting) an object. The newly created object is returned. If validation fails, the unsaved object is still returned.
Example:
create_finder_attribute_hash (line 3133)
Extract attribute names from an "_and_" separated string and construct an associative array using a corresponding array of arguments.
create_or_fail (line 758)
Like create, but calls save_or_fail, so if validation fails, an exception is thrown.
create_or_update (line 3376)
Handles performing the correct save operation for the object.
create_record (line 3435)
Create a new record in the database for this object
decrement (line 2623)
Subtracts one from the value of the named attribute. If the attribute is null, it is first initialized to zero before subtracting one.
decrement_and_save (line 2636)
Decrements the named attribute and saves the object.
decrement_counter (line 1037)
Similar to increment_counter, but decrements the specified counter instead.
This example decrements the in_stock field for the Product with id 204:
delete (line 816)
Deletes the record with the given id (or records with the given
ids). The record is not instantiated first, so no callbacks are triggered. As with find, this method accepts one or more arguments. Any arrays which are passed are assumed to be an array of ids.
delete_all (line 923)
Destroys all records that match the given conditions. The
records are not instantiated first, and, as such, no callbacks are triggered. As with the conditions option for a find* method, the conditions argument is a SQL fragment suitable for use in a where clause. The conditions parameter may be a string or an array with the first elementing containing the SQL fragment and the remaining containing parameters.
Returns a count of records that were deleted.
Examples:
delete_cached_attribute (line 3366)
delete_cached_attribute removes a temporary value previously set with write_cached_attribute
destroy (line 2522)
Delete the record from the database
destroy_all (line 893)
Destroys the objects for a set of records that match the given
conditions. As with the conditions option for a find* method, the conditions argument is a SQL fragment suitable for use in a where clause. The conditions parameter may be a string or an array with the first elementing containing the SQL fragment and the remaining containing parameters.
Examples:
ensure_proper_type (line 3003)
Sets the inheritance column value for this object if needed.
exists (line 711)
Accepts an id or set of conditions and returns true if a
matching record exists, otherwise it returns false. If the test parameter is an array, it is assumed to contain conditions in the same format used with the 'conditions' option for find. Anything else is assumed to be an id.
Example:
find (line 540)
Find one or more records with the specified id(s). This function accepts one or more ids as it's argument. If an array is passed, it is assumed to be a list of ids.
Returns the record or records with the given ids. In the case of a single id, a single object is returned. In the case of multiple ids, an array of objects is returned. The count of objects found must match the count of ids or an exception is thrown.
Example:
find_all (line 628)
Retrieve all records matching the provided criteria.
Options are:
Example:
find_by_sql (line 666)
Retrieve records by a raw SQL statement instead of through the normal find helper methods.
Returns an array containing all matching records found. If no matches are found, an empty array is returned.
Example:
find_first (line 592)
Retrieve the first record matching the provided criteria.
Options are:
Example:
fire_event (line 3513)
Notifies any registered event listeners
get_meta_info (line 2828)
Called internally to access the class-level meta information
has_attribute (line 2701)
Returns true if this object has the named attribute (even if it is empty)
has_cached_attribute (line 3320)
Returns true if this object has a cached attribute with the provided name. See write_cached_attribute for more information on cached attributes.
has_many (line 2127)
Specifies a one to many association with another class where the foreign key resides in the other class.
For example:
Implies a table structure like:
A has_many association adds four methods to the class:
has_one (line 2042)
Specifies a one to one association with another class where the foreign key resides in the other class.
For example:
Implies a table structure like:
A has_one association adds four methods to the class:
id (line 2457)
The id method/property always accesses the primary key column, even if the primary key is named something else.
id_before_type_cast (line 2466)
Access the value of the primary key column before the type cast
increment (line 2597)
Adds one to the value of the named attribute. If the attribute is null, it is first initialized to zero before adding one.
increment_and_save (line 2610)
Increments the named attribute and saves the object.
increment_counter (line 1019)
Increments the specified counter for the given id by one.
This example increments the hits field for the Document with id 204:
inheritance_column (line 1183)
Return the name of the column used for single table inheritance.
init_class (line 2809)
Called to initialize class-specific information such as associations, validations, etc. Derived classes should implement this method to specify these class-specific details.
instantiate (line 2843)
Create a new instance of an object from a record. This handles single table inheritance, allowing different types of objects to be instantiated from the same table.
is_first_concrete_descendent (line 2924)
Determine if this class is the first concrete descendent from ActiveRecord_Base.
is_valid (line 2751)
Determine if this record is valid
load_meta_info (line 1047)
This is invoked automatically by ActiveRecord_InfoMgr when the class-level meta information should be loaded.
logger (line 2817)
Return this class's logger
model (line 2160)
A convenience method that calls Support_Util::model()
This method exists purely for more concise code creation. All three of the examples below perform the same operation:
new_record (line 2486)
Returns true if a corresponding record does not yet exist for this object in the database (a new object which has not yet been saved).
primary_key (line 1105)
Return the name of this class's primary key. Default is 'id'.
process_includes (line 2908)
Handle include processing for a result set
protected_attributes (line 1313)
Return a list of all attributes which have been protected from mass assignment (the list is always maintained in sorted order).
proxy (line 2782)
Return a proxy object for this class.
Proxies are used by external classes which dynamically extend the functionality of an ActiveRecord class.
proxy_method_for (line 3184)
Return the proxy method for a given method name, or null if none declared.
readonly (line 2722)
Returns the setting of the read-only flag for this object
read_attribute (line 3281)
Returns the value of an attribute type cast to the correct data type.
read_attribute_before_type_cast (line 3294)
Returns the value of an attribute without performing any type casting.
read_cached_attribute (line 3334)
Return the value stored in the attribute cache for the given name.
If no value is in the cache, returns null. Note that a null value does not indicate the attribute has no value, only that no cached value is present. See write_cached_attribute for more information on cached attributes.
reload (line 2669)
Reloads the attributes for this object from the database.
remove_attributes_protected_from_mass_assignment (line 3107)
Remove attributes protected from mass assignment from an associative array
remove_event_listener (line 1454)
Remove an event listener from this class.
reverse_type_cast (line 3046)
Type cast a value from PHP code into a value suitable for use in
SQL. By default, this method just delegates to the column definition, but, like type_cast, it exists as a hook for derived classes to be able to extend the column definition's behavior on an application-wide basis. For example, if you have a different class you use to represent dates, or another data type for enums in MySQL. Note that this is not the correct place to handle field-specific type casts for an individual field (for example, if the 'foo' field for class 'Bar' is stored as a string but has a wrapper class that is used in PHP code). Overrides for individual fields are best handled by defining accessor and mutator (get/set) methods for those fields.
run_validations (line 3538)
Evaluate all validations of a given type associated with this object
save (line 2499)
Save the object to the database. If no record yet exists for the object, a new one is created. Otherwise, the existing record is updated.
save_or_fail (line 2511)
Saves the object to the database. If the save operation does not succeed, a RecordNotSaved exception is thrown.
send_parent (line 3074)
Invoke a named method on an blank instance of our parent class if our parent is not abstract.
sequence_name (line 1388)
Return the name of this class's sequence. This function may be overridden by derived classes. The default name is actually determined by providing the table name and primary key name to the connection. It then builds an appropriate sequence name.
set_attributes (line 2203)
Allows setting of multiple attributes at once by passing an associative array. The array keys are the attribute names and the array values are the values to assign.
set_connection (line 1087)
Sets the database connection for this class
set_id (line 2475)
Set the value of the primary key
set_inheritance_column (line 1196)
Set the name of the column used for single table inheritance.
set_primary_key (line 1096)
Set the field name used as this class's primary key.
set_readonly (line 2731)
Change the setting of the read-only flag for this object
set_sequence_name (line 1376)
Set the name of this class's sequence.
set_table_name (line 1118)
Set the name of this class's table.
set_table_name_prefix (line 1154)
Set the prefix to add to the table name
set_table_name_suffix (line 1174)
Set the suffix to add to the table name
table_exists (line 1422)
Determine whether the table associated with this class exists or not.
table_name (line 1130)
Return the name of this class's table. This function may be overridden by derived classes. By default it infers the name of the table by converting the mixed case name of the class to an underscore format and pluralizing the name.
table_name_prefix (line 1143)
Return any prefix to add to the table name
table_name_suffix (line 1163)
Return any suffix to add to the table name
toggle (line 2648)
Sets an attribute with a true value to false and anything else to true.
toggle_and_save (line 2660)
Toggles the named attribute and saves the object.
type_cast (line 3025)
Type cast a raw column value to a value suitable for use in PHP
code. By default, this method just delegates to the column definition, but it exists as a hook for derived classes to be able to extend the column definition's behavior on an application-wide basis. For example, if you have a different class you want to use to represent dates, or another data type for enums in MySQL. Note that this is not the correct place to handle field-specific type casts for an individual field (for example, if the 'foo' field for class 'Bar' is stored as a string but has a wrapper class that is used in PHP code). Overrides for individual fields are best handled by defining accessor and mutator (get/set) methods for those fields.
type_condition (line 2947)
Return condition SQL fragment for single table inheritance
Note: this is considerably less robust than the Rails active record implementation. Rails includes subclasses, whereas this does not. Reason being that it is not only cumbersome to determine descendents in PHP, but it would only ever be practical to determine descendents which have already been loaded/declared. This is only a factor if you have more than two levels of inheritance (in which case it would be a good idea to override this).
update (line 787)
Find an object by id and update the attributes specified in an associative array. The object is automatically saved (validation permitting) and is then returned.
Multiple objects may updated at once by passing an array of ids and an array of attribute arrays. In that case, an array of updated objects is returned.
Example:
update_all (line 854)
Updates a set of records given a SQL fragment for use inside a
SET clause and an optional set of conditions. As with the conditions option for a find* method, the conditions argument is a SQL fragment suitable for use in a where clause. Either parameter may be a string or an array with the first element containing the SQL fragment and the remaining containing parameters.
Returns a count of records that were updated.
Examples:
update_attribute (line 2555)
Updates a single attribute on this object and then saves the object.
update_attributes (line 2570)
Updates a list of attriubtes from an associative array and then saves the object.
update_attributes_or_fail (line 2584)
Operates the same as update_attributes(), but calls save_or_fail, so a RecordNotSaved exception is thrown if the save operation does not succeed.
update_record (line 3403)
Update the record associated with the object
validate (line 3255)
Perform validation checks applicable any time the record is saved. Use errors()->add($attribute, $message) to record any errors.
validates_confirmation_of (line 1638)
Add one or more validations for fields which have a confirmation field that must contain an identical value.
Example
Options include:
validates_exclusion_of (line 1868)
Add a validation for a field that is allowed to have any value not in a given list.
Example
Options include:
validates_format_of (line 1793)
Add a validation for the format of a field. The format is validated using a perl-compatible regular expression.
Example
Options include:
validates_inclusion_of (line 1830)
Add a validation for a field that is only allowed to have a value in a given list.
Example
Options include:
validates_length_of (line 1711)
Add one or more validations for fields lengths. Length refers to the number of characters in the field (string length).
Example
Options include:
validates_numericality_of (line 1906)
Add a validation for a field that must be numeric.
Example
Options include:
validates_presence_of (line 1671)
Add one or more validations for fields which may not be empty.
Example
Options include:
validates_uniqueness_of (line 1753)
Add one or more validations for fields which must be unique accross records.
Example
Options include:
validate_find_options (line 2967)
Validates the options provided to a find method
validate_on_create (line 3263)
Perform validation checks applicable only before saving a new record. Use errors()->add($attribute, $message) to record any errors.
validate_on_update (line 3271)
Perform validation checks applicable only before saving an existing record. Use errors()->add($attribute, $message) to record any errors.
validate_options (line 2975)
Validates a provided set of options against an allowed set
validation_name_to_type (line 3559)
Convert a string name of a validation type to the class constant
values_for_insert (line 3499)
Return the list of all attribute values prepared for use in an insert statement
write_attribute (line 3304)
Set the value of a named attribute. Empty strings for numeric fields are treated as NULL.
write_cached_attribute (line 3354)
write_cached_attribute allows the object to store a temporary value
in an attribute cache. Values placed in the cache are ignored when saving or serializing the object. The cache is intended as a place to store attribute values that have been type cast when casting is an expensive operation and for storing dummy attributes (such as a password confirmation field) which are not persisted. The cache is never checked by the default attribute read mechanism. It is the responsibility of the object to implement any logic related to retrieving cached values as the correct time.
__call (line 2361)
Allow dynamic use of accessor and mutator methods for column values. Accessors follow the format column_name() and mutators follow the format set_column_name($arg).
Also enables dynamic finder methods. Dynamic finder methods come in a variety of flavors:
Example:
__get (line 2257)
Allow reading of attributes and reader methods as properties
__isset (line 2298)
Allow use of isset with record attributes as though they were public properties. Unlike other access to properties, this will not defer to to existing reader methods, only actual record properties can be tested.
__set (line 2228)
Allow writing of attributes and use of set methods as properties
__sleep (line 2435)
Discard meta data and database connections not specific to this
instance prior to serialization
__unset (line 2313)
Allow use of unset with record attributes as though they were public properties. Unlike other access to properties, this will not defer to to existing set methods, only actual record properties can be unset.
This has the effect of setting any existing property on the object to NULL.
Documentation generated on Wed, 25 Apr 2012 09:46:40 -0700 by phpDocumentor 1.4.3