AkObject | --AkBaseModel | --AkAssociatedActiveRecord | --AkActiveRecord
Located in File: /AkActiveRecord.php
See the mapping rules in table_name and the full example in README.txt for more insight.
== Creation ==
Active Records accepts constructor parameters either in an array or as a list of parameters in a specific format. The array method is especially useful when you're receiving the data from somewhere else, like a HTTP request. It works like this:
You can also use a parameter list initialization.:
$user = new User('name->', 'David', 'occupation->', 'Code Artist');
And of course you can just create a bare object and specify the attributes after the fact:
== Conditions ==
Conditions can either be specified as a string or an array representing the WHERE-part of an SQL statement. The array form is to be used when the condition input is tainted and requires sanitization. The string form can be used for statements that doesn't involve tainted data. Examples:
The <tt>authenticateUnsafely</tt> method inserts the parameters directly into the query and is thus susceptible to SQL-injection attacks if the <tt>$user_name</tt> and <tt>$password</tt> parameters come directly from a HTTP request. The <tt>authenticateSafely</tt> method, on the other hand, will sanitize the <tt>$user_name</tt> and <tt>$password</tt> before inserting them in the query, which will ensure that an attacker can't escape the query and fake the login (or worse).
When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That's done by replacing the question marks with symbols and supplying a hash with values for the matching symbol keys:
== Accessing attributes before they have been type casted ==
Some times you want to be able to read the raw attribute data without having the column-determined type cast run its course first. That can be done by using the <attribute>_before_type_cast accessors that all attributes have. For example, if your Account model has a balance attribute, you can call $Account->balance_before_type_cast or $Account->id_before_type_cast.
This is especially useful in validation situations where the user might supply a string for an integer field and you want to display the original string back in an error message. Accessing the attribute normally would type cast the string to 0, which isn't what you want.
== Saving arrays, hashes, and other non-mappable objects in text columns ==
Active Record can serialize any object in text columns. To do so, you must specify this with by setting the attribute serialize with a comma separated list of columns or an array. This makes it possible to store arrays, hashes, and other non-mappeable objects without doing any additional work. Example:
== Single table inheritance ==
Active Record allows inheritance by storing the name of the class in a column that by default is called "type" (can be changed by overwriting <tt>AkActiveRecord->_inheritanceColumn</tt>). This means that an inheritance looking like this:
When you do $Firm->create('name =>', "akelos"), this record will be saved in the companies table with type = "Firm". You can then fetch this row again using $Company->find('first', "name = '37signals'") and it will return a Firm object.
If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
Note, all the attributes for all the cases are kept in the same table. Read more: http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
== Connection to multiple databases in different models ==
Connections are usually created through AkActiveRecord->establishConnection and retrieved by AkActiveRecord->connection. All classes inheriting from AkActiveRecord will use this connection. But you can also set a class-specific connection. For example, if $Course is a AkActiveRecord, but resides in a different database you can just say $Course->establishConnection and $Course and all its subclasses will use this connection instead.
Active Records will automatically record creation and/or update timestamps of database objects if fields of the names created_at/created_on or updated_at/updated_on are present. Date only: created_on, updated_on Date and time: created_at, updated_at
This behavior can be turned off by setting <tt>$this->_recordTimestamps = false</tt>.
Constructor __construct (line 257)
Overrides : AkObject::__construct() Class constructor, overriden in descendant classes
Destructor __destruct (line 313)
Overrides : AkObject::__destruct() Class destructor, overriden in descendant classes
Method actsAs (line 4471)
Example: $this->actsAs('list', array('scope' => 'todo_list'));
Method actsLike (line 4540)
Method addCombinedAttributeConfiguration (line 2154)
Method addConditions (line 1370)
Method addError (line 4271)
If no $message is supplied, "invalid" is assumed.
Method addErrorOnBlank (line 4294)
Method addErrorOnBoundaryBreaking (line 4309)
If the length is above the boundary, the too_long_message message will be used. If below, the too_short_message.
Method addErrorOnBoundryBreaking (line 4326)
Method addErrorOnEmpty (line 4280)
Method addErrorToBase (line 4250)
Method addObserver (line 4203)
Method attributesFromColumnDefinition (line 2518)
Method average (line 4885)
$Person->average('age');
Method beforeCreate (line 3411)
before or after an alteration of the object state. This can be used to make sure that associated and dependent objects are deleted when destroy is called (by overwriting beforeDestroy) or to massage attributes before they're validated (by overwriting beforeValidation). As an example of the callbacks initiated, consider the AkActiveRecord->save() call:
That's a total of 15 callbacks, which gives you immense power to react and prepare for each state in the Active Record lifecycle.
Examples: class CreditCard extends ActiveRecord { // Strip everything but digits, so the user can specify "555 234 34" or // "5552-3434" or both will mean "55523434" function beforeValidationOnCreate { if(!empty($this->number)){ $this->number = ereg_replace('[^0-9]*','',$this->number); } } }
class Subscription extends ActiveRecord { // Note: This is not implemented yet var $beforeCreate = 'recordSignup';
function recordSignup() { $this->signed_up_on = date("Y-m-d"); } }
class Firm extends ActiveRecord { //Destroys the associated clients and people when the firm is destroyed // Note: This is not implemented yet var $beforeDestroy = array('destroyAssociatedPeople', 'destroyAssociatedClients');
function destroyAssociatedPeople() { $Person = new Person(); $Person->destroyAll("firm_id=>", $this->id); }
function destroyAssociatedClients() { $Client = new Client(); $Client->destroyAll("client_of=>", $this->id); } }
== Canceling callbacks ==
If a before* callback returns false, all the later callbacks and the associated action are cancelled. If an after* callback returns false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks defined as methods on the model, which are called last.
Override this methods to hook Active Records
Method calculate (line 4947)
Options such as 'conditions', 'order', 'group', 'having', and 'joins' can be passed to customize the query.
There are two basic forms of output: * Single aggregate value: The single value is type cast to integer for COUNT, float for AVG, and the given column's type for everything else. * Grouped values: This returns an ordered hash of the values and groups them by the 'group' option. It takes a column name.
$values = $Person->maximum('age', array('group' => 'last_name')); echo $values["Drake"] => 43
Options: * <tt>'conditions'</tt>: An SQL fragment like "administrator = 1" or array( "user_name = ?", username ). See conditions in the intro. * <tt>'joins'</tt>: An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". (Rarely needed). The records will be returned read-only since they will have attributes that do not correspond to the table's columns. * <tt>'order'</tt>: An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations). * <tt>'group'</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. * <tt>'select'</tt>: By default, this is * as in SELECT * FROM, but can be changed if you for example want to do a join. * <tt>'distinct'</tt>: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ...
Examples: $Person->calculate('count', 'all'); // The same as $Person->count(); $Person->average('age'); // SELECT AVG(age) FROM people... $Person->minimum('age', array('conditions' => array('last_name != ?', 'Drake'))); // Selects the minimum age for everyone with a last name other than 'Drake' $Person->minimum('age', array('having' => 'min(age) > 17', 'group' => 'last'_name)); // Selects the minimum age for any family without any minors
Method castAttributeForDatabase (line 3151)
Method castAttributeFromDatabase (line 3215)
Method clearErrors (line 4421)
Method cloneRecord (line 343)
Method collect (line 4729)
$people_for_select = Ak::select($People->find(),'id','email');
Returns something like: array ( array ('10' => 'jose@example.com'), array ('15' => 'alicia@example.com'), array ('16' => 'hilario@example.com'), array ('18' => 'bermi@example.com') );
Method composeCombinedAttribute (line 2185)
Method constructFinderSql (line 1347)
Method count (line 4873)
* Count all: By not passing any parameters to count, it will return a count of all the rows for the model. * Count by conditions or joins * Count using options will find the row count matched by the options used.
The last approach, count using options, accepts an option hash as the only parameter. The options are:
* <tt>'conditions'</tt>: An SQL fragment like "administrator = 1" or array("user_name = ?", $username ). See conditions in the intro. * <tt>'joins'</tt>: An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". (Rarely needed). * <tt>'order'</tt>: An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations). * <tt>'group'</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. * <tt>'select'</tt>: By default, this is * as in SELECT * FROM, but can be changed if you for example want to do a join. * <tt>'distinct'</tt>: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ...
Examples for counting all: $Person->count(); // returns the total count of all people
Examples for count by +conditions+ and +joins+ (this has been deprecated): $Person->count("age > 26"); // returns the number of people older than 26 $Person->find("age > 26 AND job.salary > 60000", "LEFT JOIN jobs on jobs.person_id = ".$Person->id); // returns the total number of rows matching the conditions and joins fetched by SELECT COUNT(*).
Examples for count with options: $Person->count('conditions' => "age > 26"); $Person->count('conditions' => "age > 26 AND job.salary > 60000", 'joins' => "LEFT JOIN jobs on jobs.person_id = $Person->id"); // finds the number of rows matching the conditions and joins. $Person->count('id', 'conditions' => "age > 26"); // Performs a COUNT(id) $Person->count('all', 'conditions' => "age > 26"); // Performs a COUNT(*) ('all' is an alias for '*')
Note: $Person->count('all') will not work because it will use 'all' as the condition. Use $Person->count() instead.
Method countBySql (line 578)
$Product->countBySql("SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id");
Method countErrors (line 4430)
Method create (line 393)
Overrides : AkAssociatedActiveRecord::create() parent method not documented
If the save fail under validations, the unsaved object is still returned.
Method createOrUpdate (line 410)
Method dbugging (line 4599)
Method debug (line 4610)
Method decomposeCombinedAttribute (line 2260)
Method decrementAndSaveAttribute (line 1854)
Method decrementAttribute (line 1843)
Method decrementCounter (line 1835)
Method delete (line 723)
Method deleteAll (line 742)
Important note: Conditions are not sanitized yet so beware of accepting variable conditions when using this function
Method descendsFromActiveRecord (line 1522)