PHPonTrax
[ class tree: PHPonTrax ] [ index: PHPonTrax ] [ all elements ]
Prev Next
ActiveRecord

ActiveRecord

Base class for the active record design pattern

Table of Contents

Introduction

Heart of Active Record design pattern. Encapsulates all access to data in corresponding table. Enforces domain rules. Never instantiated directly. Subclass for each table.

Each subclass of this class is associated with a database table in the Model section of the Model-View-Controller architecture. By convention, the name of each subclass is the CamelCase singular form of the table name, which is in the lower_case_underscore plural notation. For example, a table named "order_details" would be associated with a subclass of ActiveRecord named "OrderDetail", and a table named "people" would be associated with subclass "Person". Naming convention encapsulated in Inflector class.

Convention: primary key of each table is column named "id".

For a discussion of the ActiveRecord design pattern, see "Patterns of Enterprise Application Architecture" by Martin Fowler, pp. 160-164.

When object constructed, the format of a row in the associated table is retrieved from the database and stored in object variable $content_columns. The data values of the columns are stored as object variable with the same name as the column. Therefore, it is not possible to have a column with the same name as an object variable

Basic Methods

Create

Before you can use the subclass of ActiveRecord associated with a table, you must install the table definition in the database. For example:

drop table if exists person_names;
create table person_names
  (id         int auto_increment primary key,
   prefix     varchar(20) null,
   first_name varchar(40) null,
   mi         char(1)     null,
   last_name  varchar(40) null,
   suffix     varchar(20) null);

With the table definition installed in the database, you can create an object that references that table. The constructor for PersonName connects to the database and reads the definition for table person_names to find the names of its columns, which then become the names of the related attributes of the object.

class PersonName extends ActiveRecord {
};
$p = new PersonName;    
$p->first_name = "Lo";
$p->last_name  = "Phat";
$p->suffix     = "MD";
$result = $p->save();

$result will be true if the row was saved successfully, false otherwise. Slightly more compact ways to say the same thing:

$p = new PersonName;    
$result = $p->save(array("first_name" => "Lo","last_name" => "Phat",
                     "suffix" => "MD"));

or assign attribute values in the constructor:

$p = new PersonName(array("first_name" => "Lo","last_name" => "Phat",
                     "suffix" => "MD"));    
$result = $p->save();

You can define the class so that it requires certain validation tests in order to be saved. Here is a definition that will generate an error on save() if either "first_name" or "last_name" is left blank. When you call save(), the object is inspected for method names like 'validate_*' where '*' is the name of a column. All such methods are executed, and the results are tested. The return must be an array with true or false in the first element, and an error message in the second if the first is false. If any of the 'validate_*' methods returns false, the save fails:

class PersonName extends ActiveRecord {
    //  Function to validate first name not blank
    function validate_first_name() {
        if ($this->first_name == '') {
            return array(false, "first name is blank");
        } else {
            return array(true);
        }}
    //  Function to validate last name not blank
    function validate_last_name() {
        if ($this->last_name == '') {
            return array(false, "last name is blank");
        } else {
            return array(true);
        }}
};
$result = $p->save(array("suffix" => "MD"));
if ($result == false) {
   //  Errors are listed in array $p->errors
   echo "save failed:\n";
   foreach ($p->errors as $key => $value) {
       echo "  field $key: $value\n";
   }
}

This will output:

save failed:
  field first_name: first name is blank
  field last_name: last name is blank

If you misspell an attribute, the misspelled name will become an attribute of the object, but it will not be saved because it is not the name of a column. This will not result in an error message (unless that attribute fails validation): For example:

$p = new PersonName(array("first_name" => "Lo","last_name" => "Phat",
                     "sufix" => "MD"));    
$result = $p->save();

This will not fail, but the attribute $p->sufix will not be saved. Instead, column 'suffix' will be set to '' (empty string).


Read

The find*() methods search the table associated with this class for rows that match some argument and return a new object of this class for each matching row. In the simplest case, you know the value of the id column of the row you want:

$p = new PersonName();
$rs = $p->find("42");
//  $rs is a new object representing the row with id 42,
//  or false if it wasn't found.  $p object remains empty.

You can ask for multiple id values with one find:

$rs = $p->find(array("17","23","65"));
//  $rs is an array containing zero or more new objects representing the
//  matching rows.  The keys of the array are the id values that matched.

You can search the table more generally with the find_all() method, which allows you to provide an SQL clause to describe the match rule. For example:

$rs = $p->find_all("last_name='Dover'");
//  $rs is an array containing zero or more new objects representing the
//  matching rows.  The keys of the array are the id values that matched.

The argument you provide must be a valid SQL WHERE clause and it must contain an '='.

If you omit the argument or provide an argument of null, you get all rows in the table.

You can also use a second argument to control the order of the results. This argument must be a valid SQL ORDER BY clause. For example:

$rs = $p->find_all("last_name='Dover'","last_name,first_name");

The find_first() method returns only the first matching row. Is there a doctor in the house?

$rs = $p->find_first("prefix='Dr.'");
//  $rs is a new object representing the first row with prefix 'Dr.',
//  or false if none was found

An error, such as incorrect SQL, causes an ActiveRecordError exception to be thrown. Note that it is not an error for no matching rows to be found.


Update

@todo Update tutorial


Delete

@todo Delete tutorial


SQL Aggregate Functions

SQL defines aggregate functions AVG(), COUNT(), MAX(), MIN() and SUM(). Not all DBMS's implement all of them. Implemented by methods avg_all(), count_all(), max_all(), min_all() and sum_all(). Parameters: [0]: If present, expression to apply the aggregate function to. Otherwise, '*' will be used. NOTE:SQL uses '*' only for the COUNT() function, where it means "including rows with NULL in this column". [1]: argument to WHERE clause [2]: joins??? @todo. Joins parameter Method call is calculated from list in $aggregrations

avg_all()

@todo Document avg_all()


count_all()

@todo Document count_all()


max_all()

@todo Document max_all()


min_all()

@todo Document min_all()


sum_all()

@todo Document sum_all()



Associations

@todo Document associations

belongs_to

has_one

has_many

has_and_belongs_to_many

Prev   Next
ActionController DateHelper

Documentation generated on Thu, 04 May 2006 19:46:55 -0600 by phpDocumentor 1.3.0RC4