^Todo|Fill in missing stuff on subpages, Missing methods, __get properties, clearer explanation/example of the difference between the "loaded" and "saved" properties|
====== Object Relational Mapping (ORM) Library ======
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 [[wp>convention over configuration]], much of the repetition of writing queries to [[wp>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.
===== Table of Contents =====
* [[libraries:orm:starting|Getting Started]]
* [[libraries:orm:working|Working with ORM]]
* [[libraries:orm:examples|Examples]]
* [[libraries:orm:advanced|Advanced Topics]]
** *If you are new to ORM, start by reading the [[libraries:orm:starting|Getting Started]] section.**
===== ORM's Relationship to the Database Library =====
The majority of ORM questions that get asked are to do with how the ORM library uses the [[libraries:database|Database]] library. **It is important to understand that nearly all of the [[libraries:database|Database]] [[libraries:database:builder|Query Builder]] methods are available to use on ORM objects.** The only query builder methods which cannot be used are:
* query - Use ORM's find and find_all methods for select queries, and its save and delete methods for inserts, updates and deletes.
* get - Use ORM's find and find_all methods instead.
* insert - Use ORM's save method instead
* update - Use ORM's save method instead
* delete - Use ORM's delete and delete_all methods instead
** If you do not understand the [[libraries:database|Database]] library's query builder - you should start there before using ORM **
===== ORM API Reference =====
Examples of the most commonly used ORM methods and properties are listed below for quick reference. Please refer to the [[http://api.kohanaphp.com|Kohana API Documentation]] for a complete list of all available methods and properties.
===== Methods =====
All of the default public and protected methods of ORM are listed here.
==== factory ====
Static method used to load ORM objects:
$object = ORM::factory($model_name, $row_id = NULL);
==== find ====
Find executes the database query, gets one row and sets the current object to the result.
// find the article with primary key = 1
$object = ORM::factory('article')->find(1);
echo $object->title;
// find an article by title
$object = ORM::factory('article')->where('title', $title)->find();
An object is returned even if no row is found. To test the object to see if it contains a result use [[orm#loaded]].
==== find_all ====
Find_all executes a database query and returns the multiple records using the ORM_Iterator
$articles = ORM::factory('article')->find_all();
foreach($articles as $article)
{
echo $article->title;
}
Also you can get a range of the multiple records using additional parameters (like in SQL LIMIT; note that MySQL confusingly adopts the opposite order)
$limit = 10;
$offset = 30;
//it will return 10 records started from row #30
$articles = ORM::factory('article')->find_all($limit,$offset);
==== where ====
[[http://docs.kohanaphp.com/libraries/database/builder#where|where() is documented here]].
==== orwhere ====
[[http://docs.kohanaphp.com/libraries/database/builder#orwhere|orwhere() is documented here]].
==== save ====
Save the current object into the database. If the object has no 'id' set it will insert a new record, else it will update. Note: You need to call //save()// after add() and remove() to save changes to related tables.
$article = ORM::factory('article', 1);
$article->title = 'New title';
$article->save();
//Newly created objects will always be reloaded after they are saved, to properly account for default values of columns.//
==== clear ====
Clears the state of an object, making it empty for reuse.
$article = ORM::factory('article', 1);
// Article is now empty
$article->clear();
var_dump($article->loaded); // returns FALSE
==== reload ====
Reloads the ORM object from the database. If ''$this->reload_on_wakeup'' is enabled, [[http://php.net/unserialize|unserializing]] an object will cause it to be reloaded.
$article = ORM::factory('article', 1);
$article->title = 'A different title';
// Article title will be reset to the saved state
$article->reload();
var_dump($article->title); // returns the original title
==== delete ====
Delete deletes current object or object with the given id.
$article = ORM::factory('article', 1);
$article->delete();
// OR
ORM::factory('article')->delete(1); // Only uses one query instead of two
==== delete_all ====
Delete_all deletes multiple objects. Will delete all objects of this type with no arguments, or an array can be used to specify the IDs to delete.
// Deletes all records
ORM::factory('article')->delete_all();
// Deletes records with ID 1, 2, 4, and 5
ORM::factory('article')->delete_all(array(1,2,4,5));
Delete_all can also be used to delete records based on a where clause.
//Delete all records that are part of the category of id 1
ORM::factory('article')->where(array('category_id' => 1))->delete_all();
==== as_array ====
Returns the current object in array format.
$article = ORM::factory('article', 1)->as_array();
echo $article['title'];
==== select_list ====
Generates a key/value pair array of all the objects. The function accepts two column names as parameters: the first column is the value and the second column is the name or description. This is especially useful when used in conjunction with the form helper to automatically build and populate selection menus.
The following example generates links to all articles followed by an HTML select form element pre-populated with all articles.
$articles = ORM::factory('article')->select_list('id', 'title');
foreach ($articles as $id => $title)
{
// Display a list of links
echo html::anchor('articles/'.$id, $title);
}
// Display a dropdown list
echo form::dropdown('articles', $articles);
==== has ====
Tests if an object has a many-to-many relationship with another object. The following code will test if the user has the ''login'' role. This method always returns a boolean.
$user = ORM::factory('user', 1);
//either retrieve relationship by primary primary key
$user->has(ORM::factory('role', 1));
// or if you have overloaded the ORM::unique_key() method in your model to allow retrieval by other unique columns
$user->has(ORM::factory('role', 'login'));
==== add ====
Adds a relationship to an object that has a many-to-many relationship. The following code will add the admin role to a user. Note that you need to call the **save()** method to add the relationship and related records. ORM does not automatically save your changes.
$user = ORM::factory('user', 1);
$user->add(ORM::factory('role', 'admin'));
$user->save();
[[libraries/orm/starting#has_and_belongs_to_many|Alternative syntax]] is also available to add multiple relationships in a many-to-many pivot table using ''array(id, id)'' syntax.
==== remove ====
Remove a relationship from an object that has a many-to-many relationship. The following code will remove the ''login'' role from the user. Note that you need to call the **save()** method to remove the relationship and related records. ORM does not automatically save your changes.
$user = ORM::factory('user', 1);
$user->remove(ORM::factory('role', 'login'));
$user->save();
[[orm#has_and_belongs_to_many|Alternative syntax]] is also available to add/update multiple relationships in a many-to-many pivot table using ''array(id, id)'' syntax. Id's excluded from the array will be removed.
==== with ====
Binds a one-to-one relationship using a JOIN. This is useful in situations where you do not want to use lazy-loading, thus improving performance. 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.
==== foreign_key() ====
''public function foreign_key($table = NULL, $prefix_table = NULL)''
Determines the name of a foreign key for a specific table.
Parameters:
- string|bool|null Related table name, null or (bool) true
- string|null The prefix table name (used for JOINs) or null
// Sets $model->object_name.'_'.$model->primary_key, ie user_id
$join_col = $model->foreign_key();
// Sets $model->table_name.'.'.$model->primary_key, ie users.id
$join_col = $model->foreign_key(TRUE);
// Sets $join_table.'.'.$model->object_name.'_'.$model->primary_key, ie blogs_users.user_id
$join_col = $model->foreign_key(NULL,$join_table);
See also the protected property $foreign_key.
==== join_table() ====
''public function join_table($table)''
This uses alphabetical comparison to choose the name of the join table.
Parameters:
- string The name of the table to join with.
This creates either ''$model->table_name'_'.$table'' or ''$table.'_'.$model->table_name''
Example: The joining table of users and roles would be roles_users, because "r" comes before "u". Joining products and categories would result in categories_products, because "c" comes before "p".
$user = ORM::factory('user');
echo $user->join_table('roles'); // roles_users
The order is standard English order: zoo > zebra > robber > ocean > angel > aardvark
==== count_all() ====
Count all results found.
**Example:**
$db = ORM::factory('article')->where('tags', 'bali');
echo $db->count_all();
==== count_last_query() ====
Count how many results found on last query.
**Example:**
$db = ORM::factory('user')->where('hometown', 'bali');
echo $db->count_last_query();
===== Properties =====
ORM has several public object properties which can be used for various purposes. By default, all of these properties are managed by ORM and will change dynamically based on object. They should never be manually set in a model.
==== loaded ====
Boolean for seeing whether the current object has been loaded from the database. This can be used to test if an object has been successfully loaded.
$article = ORM::factory('article', 1);
if ($article->loaded==TRUE)
{
echo 'loaded article ', $article->id;
}
else
{
echo 'no article by that id exists';
}
==== changed ====
Array used by ORM to keep track of changes made to columns in an ORM model prior to saving. You can check the status of a specific column by using ''isset($this->changed['name'])''.
The ''changed'' property is very useful within the context of an overloaded save() method in your ORM Model. Overloading the save() method allows you to perform extra processing, filtering or data integrity checks prior to saving any new/updated data for your ORM Model.
// overload the save method in your ORM Model
public function save()
{
if (isset($this->changed['name']))
{
// set the slug when the name changes -- 'my-post-name'
$this->slug = url::title($this->name);
}
}
==== saved ====
Boolean for checking whether the current object is saved.
$article = ORM::factory('article', 1);
if($article->saved==FALSE)
{
echo 'not saved';
}
$article->save();
if($article->saved==TRUE)
{
echo 'saved';
}
==== object_name ====
The simple name of the object. If my class is named ''Blog_Post_Model'', then ''blog_post'' is the ''object_name''.
==== primary_key ====
The column name of the primary key. If your primary key is a foreign key, then you specify that as your primary key.
// This example uses field 'usercode' as primary key
class User_Model extends ORM {
protected $primary_key = 'usercode';
}
==== primary_val ====
A convenience value corresponding to a column in the table. By default it is set to ''name.'' It can be used as a more human-friendly identifier for table rows. For instance, if you had a ''users'' table, you might set it to ''username.''
class User_Model extends ORM {
protected $primary_val = 'username';
}
==== table_name ====
The name of the database table that holds the records.
// This example use 'usuarios' table for User_Model
class User_Model extends ORM {
protected $table_name = 'usuarios';
}
==== table_columns ====
The database table column information that is being used.
class User_Model extends ORM {
protected $table_columns = array('id','username','last_login','anotherfield');
}
==== sorting ====
An array of sorting parameters that should be applied to queries. By default, results are sorted by ''id ASC''. You can add multiple columns and directions to this property.
class User_Model extends ORM {
protected $sorting = array('last_login' => 'desc', 'username' => 'asc');
}
==== load_with ====
Allows you to specify which relations should always be joined.
class Blog_Post_Model extends ORM {
protected $load_with = array('user');
}
**[[libraries:orm:starting|Continue to the next section: Getting Started >>]]**