biakaveron edited this page Sep 13, 2010 · 15 revisions
Clone this wiki locally

ORM for Kohana 3.0

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';

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.


3.0 implements validation much differently than in the 2.x line. Whereas in 2.x the validation was done on an arbitrary data array passed to the ORM’s validation method, 3.0 validates the data of the model itself.

In order to set an array of data, you can use the new values() method of ORM. Each ORM model now has 4 validation members: $_rules, $_callbacks, $_filters, and $_labels. Refer to the validation documentation with information on how these work. Here is an example:

class Model_User extends ORM
  protected $_rules = array('name' => array('not_empty' => NULL), 'username' => array('not_empty' => NULL, 'alphanumeric' => NULL));
  protected $_filters = array(TRUE => array('trim' => NULL));

$user = ORM::factory('user');

When check() is called, the ORM creates the Validate object if necessary, setting up rules, callbacks, labels and filters via the _validate() method. The check() method is then called on the Validate object itself.


You should have a thorough understanding of relationships before reading below. A good “cheat sheet” can be found here:
Relationship Cheat Sheet

The only difference is that KO3 ORM will not have a has_many_and_belongs_to relationship type. To support these, you will use the more versatile has_many relationship type with a “through” model which is described below.


A belongs_to relationship is defined below:

protected $_belongs_to = array('[alias name]' => array('model' => '[model name]', 'foreign_key' => '[column]'))

You can omit any or all of the keys/values in the array on the right, in which case defaults are used:

protected $_belongs_to = array('[alias name]' => array())

The alias name is what is used to access the related model. An example of the above in a Post model would be:

protected $_belongs_to = array('user' => array())

To access the user model, you would use $post->user. Since we’re using the defaults above, the alias name will be used for the model name, and the foreign key in the posts table will be the alias name followed by _id, or user_id (you can change the _id suffix by modifying the $foreign_key_suffix)

Let’s now assume that you want to access the user model via $post->author and you want the foreign key to be named simply my_author:

protected $_belongs_to = array('author' => array('model' => 'user', 'foreign_key' => 'my_author')


The standard has_many relationship will likely fall on the other side of the belongs_to relationship. In the above, a post belongs to a user. From the user’s perspective, a user has many posts. A has_many relationship is defined below:

protected $_has_many = array('[alias name]' => array('model' => '[model name]', 'foreign_key' => '[column]'))

Again, you can omit all keys in the right array to use the defaults:

protected $_has_many = array('[alias name]' => array())

For our user and post example, this would look like the following in the user model:

protected $_has_many = array('posts' => array())

Using the above, the posts could be access using $user->posts->find_all(). Notice the find_all() used in this example. With belongs_to and has_one relationship types, the model is already loaded with necessary data. For has_many relationships, however, you may want to limit the number of results or add additional conditions to the SQL query; you can do so prior to the find_all().

The model name used by default will be the singular name of the alias using the inflector class. In this case, posts uses post as the model name. The foreign key used by default is the owner model’s name followed by _id. In this case, the foreign key will be user_id and it must exist in the posts table as before.

Let’s assume now you want to access the posts using the name stories instead, and are still using the my_author key as in the belongs_to example. You would define your has_many relationship as:

protected $_has_many = array('stories' => array('model' => 'post', 'foreign_key' => 'my_author'))


A has_one relationship almost identical to a has_many relationship. In a has_one relationship, there can be 1 and only 1 relationship (rather than 1 or more in a has_many). Although a poor example, you might assume a user can only have one post or story, rather than many.

has_many “through”

A has_many “through” relationship is used for many-to-many relationships. For instance, let’s assume now we have an additional model, called Category. Posts may belong to more than one category, and each category may have more than one post. To link them together, an additional model (and table) is needed with columns for a post_id and a category_id. We’ll name the model for this Post_Category and the corresponding table post_categories.

To define the has_many “through” relationship, the same syntax for standard has_many relationships is used with the addition of a ‘through’ parameter. Let’s assume we’re working with the Post model:

protected $_has_many = array('categories' => array('model' => 'category', 'through' => 'post_category'))

In the Category model:

protected $_has_many = array('posts' => array('model' => 'post', 'through' => 'post_category'))

In the Post_Category model:

protected $_belongs_to = array('post' => array(), 'category' => array())

Defaults were used in the belongs_to relationships above, but you could override these if you wish to use aliasing, etc. To access the categories and posts, you simply use $post->categories->find_all() and $category->posts->find_all()

Methods are available to check for, add, and remove relationships for many-to-many relationships. Let’s assume you have a $post model loaded, and a $category model loaded as well. You can check to see if the $post is related to this $category with the following call:

$post->has('category', $category)

The first parameter is the alias name to use (in case your post model has more than one relationship to the category model – although this will be rare) and the second is the model to check for a relationship with.

Assuming you want to add the relationship (by creating a new record in the post_categories table), you would simply do:

$post->add('category', $category)

To remove:

$post->remove('category', $category)