ORM

Object Relational Mapping (ORM) allows manipulation and control of data within a database as though it was a PHP object. Once you define the relationships ORM allows you to pull data from your database, manipulate the data in any way you like and then save the result back to the database without the use of SQL. By creating relationships between models that follow convention over configuration, much of the repetition of writing queries to create, read, update and delete information from the database can be reduced or entirely removed. All of the relationships can be handled automatically by the ORM library and you can access related data as standard object properties.

Note: Please be certain that you are using the latest 3.0.* checkout, latest versions can be found at http://dev.kohanaphp.com/projects/kohana3/files

Enable

First step is to enable and configure the database module.

The orm module is included with the Kohana 3.0 install but needs to be enabled before you can use it. In your application/bootstrap.php file modify the call to the Kohana::modules() method to include the orm module as in the following example.

  Kohana::modules(array(
  	'userguide'	 => MODPATH.'userguide',
  	'database'       => MODPATH.'database',   
  	'orm'    	 => MODPATH.'orm',        // orm access
  ));

No configuration file is necessary.

Model Definition

Simple

If your database matches naming conventions (mentioned on v2 docs) and you are not using a pdo connection, a model can be defined as simply as:

class Model_Account extends ORM
{ }

Customized

A model with some basic attributes defined:

class Model_Account extends ORM
{
    protected $_db = 'default'; // or any db group defined in database configuration
 
    protected $_table_name  = 'strange_tablename'; // default: accounts
    protected $_primary_key = 'strange_pkey';      // default: id
    protected $_primary_val = 'strange_name';      // default: name (column used as primary value)
 
    // default for $_table_columns: use db introspection to find columns and info
    // see http://v3.kohanaphp.com/guide/api/Database_MySQL#list_columns for all possible column attributes
    protected $_table_columns = array(
        'column_name'   => array('data_type' => 'int',    'is_nullable' => FALSE),
        'column_name2'  => array('data_type' => 'string', 'is_nullable' => TRUE),
    );
 
    // fields mentioned here can be accessed like properties, but will not be referenced in write operations
    protected $_ignored_columns = array(
        'helper_field',
    );
}

Note: In kohana 3.0.3 there is a bug in the orm when table_prefix is set in database configuration, avoid using this setting until 3.0.4

Defining Relationships

See jheathco's repo wiki for details on defining relationships.

Loading

To create an instance of a model, you can use the ORM::factory method or the ORM::__construct:

$user = ORM::factory('user');
// or
$user = new Model_User();

The constructor and factory methods also accept a primary key value to load the given model data:

// Load user ID 5
$user = ORM::factory('user', 5);

ORM::loaded checks to see if the given model has been loaded successfully.

(from http://github.com/kohana/userguide/blob/master/guide/tutorials.orm.md)

Lazy loading

3.0 ORM does not actually load a model’s data until it is absolutely necessary, unlike previous versions of ORM. For instance, if you do the following:

$user = ORM::factory('user', 1);
$user->name = 'Joe';
$user->save();

In the code above, there will only be 1 database query, and that is to update the record with primary key value of 1. No query will be done at this time to load the model’s data. A model’s data will only be loaded when it is necessary to increase performance and limit database overhead.

echo $user->name will, on the other hand, force a loading of the model’s data.

(from http://wiki.github.com/jheathco/kohana-orm/)

Writing

Simple Insert & Update

$user = ORM::factory('user', 1);
$user->name = 'Joe';
$user->save();

If additional insert/update logic is necessary on save, you can override the save() function in your model and use the same test the orm uses to determine if you are about to insert or update.

    public function save()
    {
        // if it's an insert...
        if ($this->empty_pk()
            || isset($this->_changed[$this->_primary_key])) {
 
            ... do insert logic ...
        }
 
        else {
            .. do update logic ...
        }
 
        return parent::save();
    }

You can update multiple records by using the ORM::save_all method:

$user = ORM::factory('user');
$user->name = 'Bob';
 
// Change all active records to name 'Bob'
 
$user->where('active', '=', TRUE)->save_all();

ORM::saved checks to see if the given model has been saved.

(from http://github.com/kohana/userguide/blob/master/guide/tutorials.orm.md)

Deletion

Deleting Records

Records are deleted with ORM::delete and ORM::delete_all. These methods operate in the same fashion as saving described above with the exception that ORM::delete takes one optional parameter, the id of the record to delete.

(from http://github.com/kohana/userguide/blob/master/guide/tutorials.orm.md)

Writes that use DB Expressions

All values assigned to a column are quoted and escaped to protect write queries against sql injection. If it is necessary to assign a column to the results of a database expression, use DB::expr()

$user = ORM::factory('user', 1);
$user->name = 'Joe';
$user->last_modified = DB::expr('now()');
$user->modified_count = DB::expr('modified_count + 1');
$user->save();

Warning: If expressions involve user input you are responsible for your own escaping.

Model Validation

You can list rules, filters and callbacks in your model by the $_rules, $_filters and $_callbacks properites (see validation documentation). Best practices for what rules to define in the model and how to check them is a hot topic. You decide.

class Model_Account extends ORM
{
    ... 
    protected $_rules = array(
        'name'      => array('not_empty' => null),
        'website'   => array('url'       => null),
        'zip'       => array('regex'     => array('/^\d{5}(\-\d{4})?$/')),
        'phone_num' => array('phone'     => array(array(10,11,14))),
    );
    protected $_filters = array(TRUE => array('trim' => NULL));
 
    protected $_callbacks = ... refer to validation docs
 
    protected $_labels = array(
        'column_name' => 'pretty name',
    );
}

usage:

$user = ORM::factory('user', 1);
$user->name = 'Joe';
$user->values($_POST);
if ($user->check()) {
    $user->save();
} else {
    $errors = $user->validate()->errors();
}

Validating Against Non-Model Fields

Occasionally you might have a rule that references both a model field and an independent form field (such as forcing a match between two password or email fields). For those who would rather this rule be in the model (rather than check this in the controller), you'll need to register the “outside” field in $_ignored_columns so that model validation can have access to it.

class Model_User extends ORM
{
    protected $_ignored_columns = array(
        'password_confirm',
    );
 
    protected $_rules = array(
        'password_confirm' => array('not_empty'=> null),
        'password'         => array('not_empty' => null, 'matches', array('password_confirm')),
    );
}

Reading

Note that if you do not understand the Database library's query builder, you should start there, as many of the functions of that library are available via the orm (see $_db_methods property for the full list of supported method calls)

Records are retrieved using the ORM::find and ORM::find_all method calls.

// This will grab the first active user with the name Bob
$user = ORM::factory('user')
    ->where('active', '=', TRUE)
    ->where('name', '=', 'Bob')
    ->find();
// This will grab all users with the name Bob
$users = ORM::factory('user')
    ...
    ->find_all();

When you are retrieving a list of models using ORM::find_all, you can iterate through them as you do with database results:

foreach ($users as $user)
{
    ...
}

find_all() lists are (once lazy loaded) an array of model objects. If you have a very large list you are working with, it may be best to pull that as an array using the database query library.

(from http://github.com/kohana/userguide/blob/master/guide/tutorials.orm.md)

orm.txt · Last modified: 2011/10/19 22:48 by tkteun