diff options
-rw-r--r-- | kohana/libraries/Database.php | 2 | ||||
-rw-r--r-- | kohana/libraries/ORM.php | 113 |
2 files changed, 85 insertions, 30 deletions
diff --git a/kohana/libraries/Database.php b/kohana/libraries/Database.php index 2c73f080..ca4f6512 100644 --- a/kohana/libraries/Database.php +++ b/kohana/libraries/Database.php @@ -1094,8 +1094,6 @@ class Database_Core { { $this->link or $this->connect(); - $this->reset_select(); - return $this->driver->list_tables($this); } diff --git a/kohana/libraries/ORM.php b/kohana/libraries/ORM.php index 8d00c9ed..a26fdcdd 100644 --- a/kohana/libraries/ORM.php +++ b/kohana/libraries/ORM.php @@ -1,4 +1,5 @@ -<?php defined('SYSPATH') OR die('No direct access allowed.'); +<?php + /** * [Object Relational Mapping][ref-orm] (ORM) is a method of abstracting database * access to standard PHP calls. All table rows are represented as model objects, @@ -24,7 +25,7 @@ class ORM_Core { protected $has_and_belongs_to_many = array(); // Relationships that should always be joined - protected $load_with = NULL; + protected $load_with = array(); // Current object protected $object = array(); @@ -59,6 +60,9 @@ class ORM_Core { // Database configuration protected $db = 'default'; protected $db_applied = array(); + + // With calls already applied + protected $with_applied = array(); /** * Creates and returns a new model. @@ -91,18 +95,16 @@ class ORM_Core { // Initialize database $this->__initialize(); - if ($id === NULL OR $id === '') - { - // Clear the object - $this->clear(); - } - elseif (is_object($id)) + // Clear the object + $this->clear(); + + if (is_object($id)) { // Load an object $this->load_values((array) $id); } - else - { + elseif (!empty($id)) + { // Find an object $this->find($id); } @@ -333,7 +335,7 @@ class ORM_Core { 'object_name', 'object_plural', // Object 'primary_key', 'primary_val', 'table_name', 'table_columns', // Table 'loaded', 'saved', // Status - 'has_one', 'belongs_to', 'has_many', 'has_and_belongs_to_many', // Relationships + 'has_one', 'belongs_to', 'has_many', 'has_and_belongs_to_many', 'load_with' // Relationships ))) { // Model meta information @@ -438,47 +440,94 @@ class ORM_Core { { return $this->object; } - + + /** + * Binds another one-to-one object to this model. One-to-one objects + * can be nested using 'object1:object2' syntax + * + * @param string $object + * @return void + */ public function with($object) { + // Don't join anything already joined + if (isset($this->with_applied[$object])) + return $this; + $prefix = $table = $object; + // Split object parts + $objects = explode(':', $object); + $object = $this; + foreach ($objects as $object_part) + { + // Go down the line of objects to find the given target + $parent = $object; + $object = $parent->related_object($object_part); + + if ( ! $object) + { + // Can't find related object + return $this; + } + } + + $table = $object_part; + if ($this->table_names_plural) { $table = inflector::plural($table); } + + // Pop-off top object to get the parent object (user:photo:tag's parent is user:photo) + array_pop($objects); + $parent_prefix = implode(':', $objects); - if ( ! ($object = $this->related_object($object))) + if (empty($parent_prefix)) { - return $this; + // Use this table name itself for the parent prefix + $parent_prefix = $this->table_name; } - + else + { + if( ! isset($this->with_applied[$parent_prefix])) + { + // If the parent object hasn't been joined yet, do it first (otherwise LEFT JOINs fail) + $this->with($parent_prefix); + } + } + + // Add to with_applied to prevent duplicate joins + $this->with_applied[$prefix] = TRUE; + // Use the keys of the empty object to determine the columns $select = array_keys($object->as_array()); foreach ($select as $i => $column) { // Add the prefix so that load_result can determine the relationship - $select[$i] = $object->table_name.'.'.$column.' AS '.$prefix.':'.$column; + $select[$i] = $prefix.'.'.$column.' AS '.$prefix.':'.$column; } // Select all of the prefixed keys in the object $this->db->select($select); - $foreign_key = $prefix.'_'.$object->primary_key; + // Use last object part to generate foreign key + $foreign_key = $object_part.'_'.$object->primary_key; - if (array_key_exists($foreign_key, $this->object)) - { - $join_col1 = $object->foreign_key(TRUE); - $join_col2 = $this->table_name.'.'.$foreign_key; + if (array_key_exists($foreign_key, $parent->object)) + { + // Foreign key exists in the joined object's parent + $join_col1 = $object->foreign_key(TRUE, $prefix); + $join_col2 = $parent_prefix.'.'.$foreign_key; } else { - $join_col1 = $this->foreign_key(NULL, $table); - $join_col2 = $this->foreign_key(TRUE); + $join_col1 = $parent->foreign_key(NULL, $prefix); + $join_col2 = $parent_prefix.'.'.$parent->primary_key; } // Join the related object into the result - $this->db->join($object->table_name, $join_col1, $join_col2, 'LEFT'); + $this->db->join($object->table_name.' AS '.$prefix, $join_col1, $join_col2, 'LEFT'); return $this; } @@ -502,7 +551,7 @@ class ORM_Core { else { // Search for a specific column - $this->db->where($this->unique_key($id), $id); + $this->db->where($this->table_name.'.'.$this->unique_key($id), $id); } } @@ -1044,8 +1093,16 @@ class ORM_Core { { if ($table === TRUE) { - // Return the name of this table's PK - return $this->table_name.'.'.$this->primary_key; + if (is_string($prefix_table)) + { + // Use prefix table name and this table's PK + return $prefix_table.'.'.$this->primary_key; + } + else + { + // Return the name of this table's PK + return $this->table_name.'.'.$this->primary_key; + } } if (is_string($prefix_table)) @@ -1347,4 +1404,4 @@ class ORM_Core { return $relations; } -} // End ORM
\ No newline at end of file +} // End ORM |