This is documentation for Kohana v2.3.x. For v3.x documentation, see .

Table of Contents

<< Back to ORM Main Page

Advanced Topics

Clarification on differences between has_one and belongs_to

At first glance it may seem as though has_one and belongs_to serve the same purpose and can be used interchangeably - this is not the case. The difference between the two is in the location of the foreign key.

class User_Model extends ORM {
    protected $has_one = array('portrait');
class Portrait_Model extends ORM {
    protected $belongs_to = array('user');

In the above example, each user has one (and only 1) portrait. Each portrait belongs to only 1 user. The portraits table should contain the foreign key referencing the user, user_id. In a has_one and belongs_to 1-to-1 relationship, the foreign key always lies in the model containing the belongs_to declaration (in this case, the Portrait_Model's table).

Aliasing: Enhancing the meaning of your relationships

Many times the default relationships used within ORM do not effectively communicate the true meaning. In the example used previously in the Getting Started section, users can be related to blog posts as both authors and editors. To define this dual-relationship an alias can be used to allow multiple users to have relationships to the post. Aliasing allows multiple objects of the same type to be related to another object. Aliasing can also be used to change the name of the related object in order to more effectively communicate the purpose of the relationship more clearly.

The array key is the alias name and the array value, the model name that it maps to.

class Blog_Post_Model extends ORM {
    protected $belongs_to = array('author' => 'user', 'editor' => 'user');

Now we can access both the author and the editor of the blog post like this:

$post = ORM::factory('blog_post', 1);
echo $post->author->username;
echo $post->editor->username;

The blog_posts database table would have 2 columns now, blog_posts.author_id and blog_posts.editor_id, and both would have values that exist in

Note: Aliases can also be used in reverse within the has_one relationship as well.

has_many ''through'' relationships

If you want similar functionality to has_and_belongs_to_many, but want to have additional data/columns stored in the pivot table for the relationships, you can use a has_many through relationship. This looks similar to aliasing:

class Post_Model extends ORM {
    protected $has_many = array('categories'=>'posts_categories');
class Posts_Category_Model extends ORM {

Above the Post_Model is linked to different categories through the posts_categories pivot table. You must also create a model for the pivot table Posts_Category_Model. You can now access both the categories and the pivot table by using the following:

$post = ORM::factory('post', $post_id);
foreach ($post->categories as $category)
{ ... }
foreach ($post->posts_categories as $pivot)
{ ... }

Note: You should have an ID column for the pivot table (which, unlike has_and_belongs_to_many, doesn't require one)

Multiple has_and_belongs_to_many relationships between the same two tables

Consider this scenario. You have a system that stores articles, each article can have multiple authors and contributors. Authors and contributors are the same type of object, just a different association to an article. To accomplish this sort of functionality, you would have the core two tables; articles and authors. You would also have TWO pivot tables titled authors_articles and contributors_articles. Each pivot table would contain the columns; id, article_id and author_id.

Your Article_Model would look something like this:

class Article_Model extends ORM {
    protected $has_and_belongs_to_many = array('authors_articles' => 'authors','contributors_articles' => 'contributors');

In the Author_Model and Contributor_Model you will need to override the $table_name value, so both point to the author table.

class Author_Model extends ORM {
	protected $table_name = 'authors';
class Contributor_Model extends ORM {
	protected $table_name = 'authors';

Optimizing One-to-One Relationships using with()

ORM uses lazy loading by default, which defers initialization of an object until it is needed. This typically results in an additional query when related data is requested in a one-to-one relationship. The with() method in ORM can be used to force the use of a JOIN in a one-to-one relationship, resulting in only one query being called. You can also bind nested one-to-one relationships using a colon.

// This uses 1 SQL query to fetch the user, associated city, and associated country.
$users = ORM::factory('user')->with('city')->with('city:country')->find_all();
foreach($users as $user) {
  echo $user->city->country->name;

You can also set the $load_with property of the ORM model to bind automatically.

class User_Model extends ORM {
    protected $load_with = array('city');

Using different unique keys to load ORM models

By default, ORM uses the id column as the identifier for the unique row within the database. However it is possible for ORM to load an object using a different unique key from your table. ORM uses a method called unique_key to load data and this method can be overloaded within your ORM model to allow other columns to be used.

The example demonstrates the use of unique_key within an ORM model. The id is checked for data type. If the datatype is not a digit and is a string, the column shortname will be used to load the model.

public function unique_key($id = NULL)
	if ( ! empty($id) AND is_string($id) AND ! ctype_digit($id) )
		return 'shortname';
	return parent::unique_key($id);

If you intend to you use custom unique keys within your application, it is a good idea to ensure you correctly index all columns being used as a unique identifier. This will ensure that as your application scales, performance is not adversely effected.

Assuming the homepage record has an ID of 1, including the unique_key method within your ORM model allows the following constructor methods in your code.

// Using the ORM::factory method
$my_page = ORM::factory( 'Page', 'homepage' );
// Using the standard constructor
$my_other_page = new Page_Model( 'homepage' );
$my_old_method = new Page_Model( 1 );

$my_page, $my_other_page and $my_old_method will all contain the same record.

Simple method to use a different primary key

If you have a table that uses a primary key other than id, you can simply override the $primary_key property in your model to have ORM use your custom primary key to load your model.

In the following example, a Geo model is defined with a primary key of zip as opposed to the standard ORM id.

class Geo extends ORM {
    protected $primary_key = 'zip';

ORM Tree

ORM tree is an ORM extension that allows creating an object relationship with itself. Typical use of this library can be a category hierarchy, in other words parent ↔ childrens link.

Your database schema will need to include a parent ID column.

class Category_Model extends ORM_Tree
    protected $ORM_Tree_children = 'categories';
    // Set the column which holds this models parent
    // Default is parent_id
    protected $ORM_Tree_parent_key = 'parent_id';
echo Kohana::debug(ORM::factory("Category", 42)->children->as_array());
//returns the children for the category with id 42
echo Kohana::debug(ORM::factory("Category", 4)->parent->name);
//returns the parent name of the category with ID 4

Validation using ORM

ORM has the ability to validate and save data automatically. Any errors encountered during validation can be used to feedback to the view using the standard Validation Library error reporting method.

To use Validation in an ORM model a set of validation rules and filters must be defined within a public method called validate, which overloads the ORM::validate() method. See Examples: Combining ORM and Validation for further details and code samples.

<< Back to ORM Main Page

libraries/orm/advanced.txt · Last modified: 2010/02/18 18:27 by jordanlev