1 <?php defined('SYSPATH') OR die('No direct access allowed.');
3 * [Object Relational Mapping][ref-orm] (ORM) is a method of abstracting database
4 * access to standard PHP calls. All table rows are represented as model objects,
5 * with object properties representing row data. ORM in Kohana generally follows
6 * the [Active Record][ref-act] pattern.
8 * [ref-orm]: http://wikipedia.org/wiki/Object-relational_mapping
9 * [ref-act]: http://wikipedia.org/wiki/Active_record
11 * $Id: ORM.php 4354 2009-05-15 16:51:37Z kiall $
15 * @copyright (c) 2007-2008 Kohana Team
16 * @license http://kohanaphp.com/license.html
20 // Current relationships
21 protected $has_one = array();
22 protected $belongs_to = array();
23 protected $has_many = array();
24 protected $has_and_belongs_to_many = array();
26 // Relationships that should always be joined
27 protected $load_with = array();
30 protected $object = array();
31 protected $changed = array();
32 protected $related = array();
33 protected $loaded = FALSE;
34 protected $saved = FALSE;
38 protected $object_relations = array();
39 protected $changed_relations = array();
41 // Model table information
42 protected $object_name;
43 protected $object_plural;
44 protected $table_name;
45 protected $table_columns;
46 protected $ignored_columns;
48 // Table primary key and value
49 protected $primary_key = 'id';
50 protected $primary_val = 'name';
52 // Array of foreign key name overloads
53 protected $foreign_key = array();
55 // Model configuration
56 protected $table_names_plural = TRUE;
57 protected $reload_on_wakeup = TRUE;
59 // Database configuration
60 protected $db = 'default';
61 protected $db_applied = array();
63 // With calls already applied
64 protected $with_applied = array();
66 // Stores column information for ORM models
67 protected static $column_cache = array();
70 * Creates and returns a new model.
73 * @param string model name
74 * @param mixed parameter for find()
77 public static function factory($model, $id = NULL)
80 $model = ucfirst($model).'_Model';
82 return new $model($id);
86 * Prepares the model database connection and loads the object.
88 * @param mixed parameter for find or object to load
91 public function __construct($id = NULL)
93 // Set the object name and plural name
94 $this->object_name = strtolower(substr(get_class($this), 0, -6));
95 $this->object_plural = inflector::plural($this->object_name);
97 if (!isset($this->sorting))
100 $this->sorting = array($this->primary_key => 'asc');
103 // Initialize database
104 $this->__initialize();
112 $this->load_values((array) $id);
122 * Prepares the model database connection, determines the table name,
123 * and loads column information.
127 public function __initialize()
129 if ( ! is_object($this->db))
131 // Get database instance
132 $this->db = Database::instance($this->db);
135 if (empty($this->table_name))
137 // Table name is the same as the object name
138 $this->table_name = $this->object_name;
140 if ($this->table_names_plural === TRUE)
142 // Make the table name plural
143 $this->table_name = inflector::plural($this->table_name);
147 if (is_array($this->ignored_columns))
149 // Make the ignored columns mirrored = mirrored
150 $this->ignored_columns = array_combine($this->ignored_columns, $this->ignored_columns);
153 // Load column information
154 $this->reload_columns();
158 * Allows serialization of only the object data and state, to prevent
159 * "stale" objects being unserialized, which also requires less memory.
163 public function __sleep()
165 // Store only information about the object
166 return array('object_name', 'object', 'changed', 'loaded', 'saved', 'sorting');
170 * Prepares the database connection and reloads the object.
174 public function __wakeup()
176 // Initialize database
177 $this->__initialize();
179 if ($this->reload_on_wakeup === TRUE)
187 * Handles pass-through to database methods. Calls to query methods
188 * (query, get, insert, update) are not allowed. Query builder methods
191 * @param string method name
192 * @param array method arguments
195 public function __call($method, array $args)
197 if (method_exists($this->db, $method))
199 if (in_array($method, array('query', 'get', 'insert', 'update', 'delete')))
200 throw new Kohana_Exception('orm.query_methods_not_allowed');
202 // Method has been applied to the database
203 $this->db_applied[$method] = $method;
205 // Number of arguments passed
206 $num_args = count($args);
208 if ($method === 'select' AND $num_args > 3)
210 // Call select() manually to avoid call_user_func_array
211 $this->db->select($args);
215 // We use switch here to manually call the database methods. This is
216 // done for speed: call_user_func_array can take over 300% longer to
217 // make calls. Most database methods are 4 arguments or less, so this
218 // avoids almost any calls to call_user_func_array.
223 if (in_array($method, array('open_paren', 'close_paren', 'enable_cache', 'disable_cache')))
225 // Should return ORM, not Database
226 $this->db->$method();
230 // Support for things like reset_select, reset_write, list_tables
231 return $this->db->$method();
235 $this->db->$method($args[0]);
238 $this->db->$method($args[0], $args[1]);
241 $this->db->$method($args[0], $args[1], $args[2]);
244 $this->db->$method($args[0], $args[1], $args[2], $args[3]);
247 // Here comes the snail...
248 call_user_func_array(array($this->db, $method), $args);
257 throw new Kohana_Exception('core.invalid_method', $method, get_class($this));
262 * Handles retrieval of all model values, relationships, and metadata.
264 * @param string column name
267 public function __get($column)
269 if (array_key_exists($column, $this->object))
271 return $this->object[$column];
273 elseif (isset($this->related[$column]))
275 return $this->related[$column];
277 elseif ($column === 'primary_key_value')
279 return $this->object[$this->primary_key];
281 elseif ($model = $this->related_object($column))
283 // This handles the has_one and belongs_to relationships
285 if (in_array($model->object_name, $this->belongs_to) OR ! array_key_exists($this->foreign_key($column), $model->object))
287 // Foreign key lies in this table (this model belongs_to target model) OR an invalid has_one relationship
288 $where = array($model->table_name.'.'.$model->primary_key => $this->object[$this->foreign_key($column)]);
292 // Foreign key lies in the target table (this model has_one target model)
293 $where = array($this->foreign_key($column, $model->table_name) => $this->primary_key_value);
296 // one<>alias:one relationship
297 return $this->related[$column] = $model->find($where);
299 elseif (isset($this->has_many[$column]))
301 // Load the "middle" model
302 $through = ORM::factory(inflector::singular($this->has_many[$column]));
304 // Load the "end" model
305 $model = ORM::factory(inflector::singular($column));
307 // Join ON target model's primary key set to 'through' model's foreign key
308 // User-defined foreign keys must be defined in the 'through' model
309 $join_table = $through->table_name;
310 $join_col1 = $through->foreign_key($model->object_name, $join_table);
311 $join_col2 = $model->table_name.'.'.$model->primary_key;
313 // one<>alias:many relationship
314 return $this->related[$column] = $model
315 ->join($join_table, $join_col1, $join_col2)
316 ->where($through->foreign_key($this->object_name, $join_table), $this->object[$this->primary_key])
319 elseif (in_array($column, $this->has_many))
321 // one<>many relationship
322 $model = ORM::factory(inflector::singular($column));
323 return $this->related[$column] = $model
324 ->where($this->foreign_key($column, $model->table_name), $this->object[$this->primary_key])
327 elseif (in_array($column, $this->has_and_belongs_to_many))
329 // Load the remote model, always singular
330 $model = ORM::factory(inflector::singular($column));
332 if ($this->has($model, TRUE))
334 // many<>many relationship
335 return $this->related[$column] = $model
336 ->in($model->table_name.'.'.$model->primary_key, $this->changed_relations[$column])
341 // empty many<>many relationship
342 return $this->related[$column] = $model
343 ->where($model->table_name.'.'.$model->primary_key, NULL)
347 elseif (isset($this->ignored_columns[$column]))
351 elseif (in_array($column, array
353 'object_name', 'object_plural', // Object
354 'primary_key', 'primary_val', 'table_name', 'table_columns', // Table
355 'loaded', 'saved', // Status
356 'has_one', 'belongs_to', 'has_many', 'has_and_belongs_to_many', 'load_with' // Relationships
359 // Model meta information
360 return $this->$column;
364 throw new Kohana_Exception('core.invalid_property', $column, get_class($this));
369 * Handles setting of all model values, and tracks changes between values.
371 * @param string column name
372 * @param mixed column value
375 public function __set($column, $value)
377 if (isset($this->ignored_columns[$column]))
381 elseif (isset($this->object[$column]) OR array_key_exists($column, $this->object))
383 if (isset($this->table_columns[$column]))
386 $this->changed[$column] = $column;
388 // Object is no longer saved
389 $this->saved = FALSE;
392 $this->object[$column] = $this->load_type($column, $value);
394 elseif (in_array($column, $this->has_and_belongs_to_many) AND is_array($value))
397 $model = ORM::factory(inflector::singular($column));
399 if ( ! isset($this->object_relations[$column]))
405 // Change the relationships
406 $this->changed_relations[$column] = $value;
408 if (isset($this->related[$column]))
410 // Force a reload of the relationships
411 unset($this->related[$column]);
416 throw new Kohana_Exception('core.invalid_property', $column, get_class($this));
421 * Checks if object data is set.
423 * @param string column name
426 public function __isset($column)
428 return (isset($this->object[$column]) OR isset($this->related[$column]));
432 * Unsets object data.
434 * @param string column name
437 public function __unset($column)
439 unset($this->object[$column], $this->changed[$column], $this->related[$column]);
443 * Displays the primary key of a model when it is converted to a string.
447 public function __toString()
449 return (string) $this->object[$this->primary_key];
453 * Returns the values of this object as an array.
457 public function as_array()
461 foreach ($this->object as $key => $val)
463 // Reconstruct the array (calls __get)
464 $object[$key] = $this->$key;
471 * Binds another one-to-one object to this model. One-to-one objects
472 * can be nested using 'object1:object2' syntax
474 * @param string $target_path
477 public function with($target_path)
479 if (isset($this->with_applied[$target_path]))
481 // Don't join anything already joined
485 // Split object parts
486 $objects = explode(':', $target_path);
488 foreach ($objects as $object)
490 // Go down the line of objects to find the given target
492 $target = $parent->related_object($object);
496 // Can't find related object
501 $target_name = $object;
503 // Pop-off top object to get the parent object (user:photo:tag becomes user:photo - the parent table prefix)
505 $parent_path = implode(':', $objects);
507 if (empty($parent_path))
509 // Use this table name itself for the parent object
510 $parent_path = $this->table_name;
514 if( ! isset($this->with_applied[$parent_path]))
516 // If the parent object hasn't been joined yet, do it first (otherwise LEFT JOINs fail)
517 $this->with($parent_path);
521 // Add to with_applied to prevent duplicate joins
522 $this->with_applied[$target_path] = TRUE;
524 // Use the keys of the empty object to determine the columns
525 $select = array_keys($target->object);
526 foreach ($select as $i => $column)
528 // Add the prefix so that load_result can determine the relationship
529 $select[$i] = $target_path.'.'.$column.' AS '.$target_path.':'.$column;
533 // Select all of the prefixed keys in the object
534 $this->db->select($select);
536 if (in_array($target->object_name, $parent->belongs_to) OR ! isset($target->object[$parent->foreign_key($target_name)]))
538 // Parent belongs_to target, use target's primary key as join column
539 $join_col1 = $target->foreign_key(TRUE, $target_path);
540 $join_col2 = $parent->foreign_key($target_name, $parent_path);
544 // Parent has_one target, use parent's primary key as join column
545 $join_col2 = $parent->foreign_key(TRUE, $parent_path);
546 $join_col1 = $parent->foreign_key($target_name, $target_path);
549 // This allows for models to use different table prefixes (sharing the same database)
550 $join_table = new Database_Expression($target->db->table_prefix().$target->table_name.' AS '.$this->db->table_prefix().$target_path);
552 // Join the related object into the result
553 $this->db->join($join_table, $join_col1, $join_col2, 'LEFT');
559 * Finds and loads a single database row into the object.
562 * @param mixed primary key or an array of clauses
565 public function find($id = NULL)
571 // Search for all clauses
572 $this->db->where($id);
576 // Search for a specific column
577 $this->db->where($this->table_name.'.'.$this->unique_key($id), $id);
581 return $this->load_result();
585 * Finds multiple database rows and returns an iterator of the rows found.
588 * @param integer SQL limit
589 * @param integer SQL offset
590 * @return ORM_Iterator
592 public function find_all($limit = NULL, $offset = NULL)
594 if ($limit !== NULL AND ! isset($this->db_applied['limit']))
597 $this->limit($limit);
600 if ($offset !== NULL AND ! isset($this->db_applied['offset']))
603 $this->offset($offset);
606 return $this->load_result(TRUE);
610 * Creates a key/value array from all of the objects available. Uses find_all
611 * to find the objects.
613 * @param string key column
614 * @param string value column
617 public function select_list($key = NULL, $val = NULL)
621 $key = $this->primary_key;
626 $val = $this->primary_val;
629 // Return a select list from the results
630 return $this->select($key, $val)->find_all()->select_list($key, $val);
634 * Validates the current object. This method should generally be called
635 * via the model, after the $_POST Validation object has been created.
637 * @param object Validation array
640 public function validate(Validation $array, $save = FALSE)
642 $safe_array = $array->safe_array();
644 if ( ! $array->submitted())
646 foreach ($safe_array as $key => $value)
648 // Get the value from this object
649 $value = $this->$key;
651 if (is_object($value) AND $value instanceof ORM_Iterator)
653 // Convert the value to an array of primary keys
654 $value = $value->primary_key_array();
658 $array[$key] = $value;
662 // Validate the array
663 if ($status = $array->validate())
665 // Grab only set fields (excludes missing data, unlike safe_array)
666 $fields = $array->as_array();
668 foreach ($fields as $key => $value)
670 if (isset($safe_array[$key]))
672 // Set new data, ignoring any missing fields or fields without rules
673 $this->$key = $value;
677 if ($save === TRUE OR is_string($save))
682 if (is_string($save))
684 // Redirect to the saved page
685 url::redirect($save);
690 // Return validation status
695 * Saves the current object.
700 public function save()
702 if ( ! empty($this->changed))
705 foreach ($this->changed as $column)
707 // Compile changed data
708 $data[$column] = $this->object[$column];
711 if ($this->loaded === TRUE)
714 ->where($this->primary_key, $this->object[$this->primary_key])
715 ->update($this->table_name, $data);
717 // Object has been saved
723 ->insert($this->table_name, $data);
725 if ($query->count() > 0)
727 if (empty($this->object[$this->primary_key]))
729 // Load the insert id as the primary key
730 $this->object[$this->primary_key] = $query->insert_id();
733 // Object is now loaded and saved
734 $this->loaded = $this->saved = TRUE;
738 if ($this->saved === TRUE)
740 // All changes have been saved
741 $this->changed = array();
745 if ($this->saved === TRUE AND ! empty($this->changed_relations))
747 foreach ($this->changed_relations as $column => $values)
749 // All values that were added
750 $added = array_diff($values, $this->object_relations[$column]);
752 // All values that were saved
753 $removed = array_diff($this->object_relations[$column], $values);
755 if (empty($added) AND empty($removed))
761 // Clear related columns
762 unset($this->related[$column]);
765 $model = ORM::factory(inflector::singular($column));
767 if (($join_table = array_search($column, $this->has_and_belongs_to_many)) === FALSE)
770 if (is_int($join_table))
772 // No "through" table, load the default JOIN table
773 $join_table = $model->join_table($this->table_name);
776 // Foreign keys for the join table
777 $object_fk = $this->foreign_key(NULL);
778 $related_fk = $model->foreign_key(NULL);
780 if ( ! empty($added))
782 foreach ($added as $id)
784 // Insert the new relationship
785 $this->db->insert($join_table, array
787 $object_fk => $this->object[$this->primary_key],
793 if ( ! empty($removed))
796 ->where($object_fk, $this->object[$this->primary_key])
797 ->in($related_fk, $removed)
798 ->delete($join_table);
801 // Clear all relations for this column
802 unset($this->object_relations[$column], $this->changed_relations[$column]);
810 * Deletes the current object from the database. This does NOT destroy
811 * relationships that have been created with other objects.
816 public function delete($id = NULL)
818 if ($id === NULL AND $this->loaded)
820 // Use the the primary key value
821 $id = $this->object[$this->primary_key];
824 // Delete this object
825 $this->db->where($this->primary_key, $id)->delete($this->table_name);
827 return $this->clear();
831 * Delete all objects in the associated table. This does NOT destroy
832 * relationships that have been created with other objects.
835 * @param array ids to delete
838 public function delete_all($ids = NULL)
842 // Delete only given ids
843 $this->db->in($this->primary_key, $ids);
845 elseif (is_null($ids))
847 // Delete all records
848 $this->db->where('1=1');
852 // Do nothing - safeguard
856 // Delete all objects
857 $this->db->delete($this->table_name);
859 return $this->clear();
863 * Unloads the current object and clears the status.
868 public function clear()
870 // Create an array with all the columns set to NULL
871 $columns = array_keys($this->table_columns);
872 $values = array_combine($columns, array_fill(0, count($columns), NULL));
874 // Replace the current object with an empty one
875 $this->load_values($values);
881 * Reloads the current object from the database.
886 public function reload()
888 return $this->find($this->object[$this->primary_key]);
892 * Reload column definitions.
895 * @param boolean force reloading
898 public function reload_columns($force = FALSE)
900 if ($force === TRUE OR empty($this->table_columns))
902 if (isset(ORM::$column_cache[$this->object_name]))
904 // Use cached column information
905 $this->table_columns = ORM::$column_cache[$this->object_name];
909 // Load table columns
910 ORM::$column_cache[$this->object_name] = $this->table_columns = $this->list_fields();
918 * Tests if this object has a relationship to a different model.
920 * @param object related ORM model
921 * @param boolean check for any relations to given model
924 public function has(ORM $model, $any = FALSE)
926 // Determine plural or singular relation name
927 $related = ($model->table_names_plural === TRUE) ? $model->object_plural : $model->object_name;
929 if (($join_table = array_search($related, $this->has_and_belongs_to_many)) === FALSE)
932 if (is_int($join_table))
934 // No "through" table, load the default JOIN table
935 $join_table = $model->join_table($this->table_name);
938 if ( ! isset($this->object_relations[$related]))
940 // Load the object relationships
941 $this->changed_relations[$related] = $this->object_relations[$related] = $this->load_relations($join_table, $model);
944 if ( ! $model->empty_primary_key())
946 // Check if a specific object exists
947 return in_array($model->primary_key_value, $this->changed_relations[$related]);
951 // Check if any relations to given model exist
952 return ! empty($this->changed_relations[$related]);
961 * Adds a new relationship to between this model and another.
963 * @param object related ORM model
966 public function add(ORM $model)
968 if ($this->has($model))
971 // Get the faked column name
972 $column = $model->object_plural;
974 // Add the new relation to the update
975 $this->changed_relations[$column][] = $model->primary_key_value;
977 if (isset($this->related[$column]))
979 // Force a reload of the relationships
980 unset($this->related[$column]);
987 * Adds a new relationship to between this model and another.
989 * @param object related ORM model
992 public function remove(ORM $model)
994 if ( ! $this->has($model))
997 // Get the faked column name
998 $column = $model->object_plural;
1000 if (($key = array_search($model->primary_key_value, $this->changed_relations[$column])) === FALSE)
1003 // Remove the relationship
1004 unset($this->changed_relations[$column][$key]);
1006 if (isset($this->related[$column]))
1008 // Force a reload of the relationships
1009 unset($this->related[$column]);
1016 * Count the number of records in the table.
1020 public function count_all()
1022 // Return the total number of records in a table
1023 return $this->db->count_records($this->table_name);
1027 * Proxy method to Database list_fields.
1029 * @param string table name or NULL to use this table
1032 public function list_fields($table = NULL)
1034 if ($table === NULL)
1036 $table = $this->table_name;
1039 // Proxy to database
1040 return $this->db->list_fields($table);
1044 * Proxy method to Database field_data.
1046 * @param string table name
1049 public function field_data($table)
1051 // Proxy to database
1052 return $this->db->field_data($table);
1056 * Proxy method to Database field_data.
1059 * @param string SQL query to clear
1062 public function clear_cache($sql = NULL)
1064 // Proxy to database
1065 $this->db->clear_cache($sql);
1067 ORM::$column_cache = array();
1073 * Returns the unique key for a specific value. This method is expected
1074 * to be overloaded in models if the model has other unique columns.
1076 * @param mixed unique value
1079 public function unique_key($id)
1081 return $this->primary_key;
1085 * Determines the name of a foreign key for a specific table.
1087 * @param string related table name
1088 * @param string prefix table name (used for JOINs)
1091 public function foreign_key($table = NULL, $prefix_table = NULL)
1093 if ($table === TRUE)
1095 if (is_string($prefix_table))
1097 // Use prefix table name and this table's PK
1098 return $prefix_table.'.'.$this->primary_key;
1102 // Return the name of this table's PK
1103 return $this->table_name.'.'.$this->primary_key;
1107 if (is_string($prefix_table))
1109 // Add a period for prefix_table.column support
1110 $prefix_table .= '.';
1113 if (isset($this->foreign_key[$table]))
1115 // Use the defined foreign key name, no magic here!
1116 $foreign_key = $this->foreign_key[$table];
1120 if ( ! is_string($table) OR ! array_key_exists($table.'_'.$this->primary_key, $this->object))
1123 $table = $this->table_name;
1125 if (strpos($table, '.') !== FALSE)
1127 // Hack around support for PostgreSQL schemas
1128 list ($schema, $table) = explode('.', $table, 2);
1131 if ($this->table_names_plural === TRUE)
1133 // Make the key name singular
1134 $table = inflector::singular($table);
1138 $foreign_key = $table.'_'.$this->primary_key;
1141 return $prefix_table.$foreign_key;
1145 * This uses alphabetical comparison to choose the name of the table.
1147 * Example: The joining table of users and roles would be roles_users,
1148 * because "r" comes before "u". Joining products and categories would
1149 * result in categories_products, because "c" comes before "p".
1151 * Example: zoo > zebra > robber > ocean > angel > aardvark
1153 * @param string table name
1156 public function join_table($table)
1158 if ($this->table_name > $table)
1160 $table = $table.'_'.$this->table_name;
1164 $table = $this->table_name.'_'.$table;
1171 * Returns an ORM model for the given object name;
1173 * @param string object name
1176 protected function related_object($object)
1178 if (isset($this->has_one[$object]))
1180 $object = ORM::factory($this->has_one[$object]);
1182 elseif (isset($this->belongs_to[$object]))
1184 $object = ORM::factory($this->belongs_to[$object]);
1186 elseif (in_array($object, $this->has_one) OR in_array($object, $this->belongs_to))
1188 $object = ORM::factory($object);
1199 * Loads an array of values into into the current object.
1202 * @param array values to load
1205 public function load_values(array $values)
1207 if (array_key_exists($this->primary_key, $values))
1209 // Replace the object and reset the object status
1210 $this->object = $this->changed = $this->related = array();
1212 // Set the loaded and saved object status based on the primary key
1213 $this->loaded = $this->saved = ($values[$this->primary_key] !== NULL);
1219 foreach ($values as $column => $value)
1221 if (strpos($column, ':') === FALSE)
1223 if (isset($this->table_columns[$column]))
1225 // The type of the value can be determined, convert the value
1226 $value = $this->load_type($column, $value);
1229 $this->object[$column] = $value;
1233 list ($prefix, $column) = explode(':', $column, 2);
1235 $related[$prefix][$column] = $value;
1239 if ( ! empty($related))
1241 foreach ($related as $object => $values)
1243 // Load the related objects with the values in the result
1244 $this->related[$object] = $this->related_object($object)->load_values($values);
1252 * Loads a value according to the types defined by the column metadata.
1254 * @param string column name
1255 * @param mixed value to load
1258 protected function load_type($column, $value)
1260 $type = gettype($value);
1261 if ($type == 'object' OR $type == 'array' OR ! isset($this->table_columns[$column]))
1265 $column = $this->table_columns[$column];
1267 if ($value === NULL AND ! empty($column['null']))
1270 if ( ! empty($column['binary']) AND ! empty($column['exact']) AND (int) $column['length'] === 1)
1272 // Use boolean for BINARY(1) fields
1273 $column['type'] = 'boolean';
1276 switch ($column['type'])
1279 if ($value === '' AND ! empty($column['null']))
1281 // Forms will only submit strings, so empty integer values must be null
1284 elseif ((float) $value > PHP_INT_MAX)
1286 // This number cannot be represented by a PHP integer, so we convert it to a string
1287 $value = (string) $value;
1291 $value = (int) $value;
1295 $value = (float) $value;
1298 $value = (bool) $value;
1301 $value = (string) $value;
1309 * Loads a database result, either as a new object for this model, or as
1310 * an iterator for multiple rows.
1313 * @param boolean return an iterator or load a single row
1314 * @return ORM for single rows
1315 * @return ORM_Iterator for multiple rows
1317 protected function load_result($array = FALSE)
1319 if ($array === FALSE)
1321 // Only fetch 1 record
1322 $this->db->limit(1);
1325 if ( ! isset($this->db_applied['select']))
1327 // Select all columns by default
1328 $this->db->select($this->table_name.'.*');
1331 if ( ! empty($this->load_with))
1333 foreach ($this->load_with as $alias => $object)
1335 // Join each object into the results
1336 if (is_string($alias))
1339 $this->with($alias);
1344 $this->with($object);
1349 if ( ! isset($this->db_applied['orderby']) AND ! empty($this->sorting))
1352 foreach ($this->sorting as $column => $direction)
1354 if (strpos($column, '.') === FALSE)
1356 // Keeps sorting working properly when using JOINs on
1357 // tables with columns of the same name
1358 $column = $this->table_name.'.'.$column;
1361 $sorting[$column] = $direction;
1364 // Apply the user-defined sorting
1365 $this->db->orderby($sorting);
1369 $result = $this->db->get($this->table_name);
1371 if ($array === TRUE)
1373 // Return an iterated result
1374 return new ORM_Iterator($this, $result);
1377 if ($result->count() === 1)
1379 // Load object values
1380 $this->load_values($result->result(FALSE)->current());
1384 // Clear the object, nothing was found
1392 * Return an array of all the primary keys of the related table.
1394 * @param string table name
1395 * @param object ORM model to find relations of
1398 protected function load_relations($table, ORM $model)
1400 // Save the current query chain (otherwise the next call will clash)
1404 ->select($model->foreign_key(NULL).' AS id')
1406 ->where($this->foreign_key(NULL, $table), $this->object[$this->primary_key])
1412 $relations = array();
1413 foreach ($query as $row)
1415 $relations[] = $row->id;
1422 * Returns whether or not primary key is empty
1426 protected function empty_primary_key()
1428 return (empty($this->object[$this->primary_key]) AND $this->object[$this->primary_key] !== '0');