summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kohana/config/sql_types.php13
-rw-r--r--kohana/core/Bootstrap.php2
-rw-r--r--kohana/core/Event.php6
-rw-r--r--kohana/core/Kohana.php14
-rw-r--r--kohana/core/utf8/ord.php2
-rw-r--r--kohana/core/utf8/str_pad.php2
-rw-r--r--kohana/core/utf8/strcspn.php2
-rw-r--r--kohana/helpers/arr.php15
-rw-r--r--kohana/helpers/form.php36
-rw-r--r--kohana/helpers/url.php3
-rw-r--r--kohana/helpers/valid.php2
-rw-r--r--kohana/libraries/Controller.php16
-rw-r--r--kohana/libraries/Database.php45
-rw-r--r--kohana/libraries/Image.php50
-rw-r--r--kohana/libraries/Model.php4
-rw-r--r--kohana/libraries/ORM.php102
-rw-r--r--kohana/libraries/ORM_Tree.php18
-rw-r--r--kohana/libraries/View.php22
-rw-r--r--kohana/libraries/drivers/Database.php4
-rw-r--r--kohana/libraries/drivers/Database/Mssql.php7
-rw-r--r--kohana/libraries/drivers/Database/Mysql.php11
-rw-r--r--kohana/libraries/drivers/Database/Mysqli.php7
-rw-r--r--kohana/libraries/drivers/Database/Pgsql.php110
23 files changed, 267 insertions, 226 deletions
diff --git a/kohana/config/sql_types.php b/kohana/config/sql_types.php
index 2431c707..69a0a631 100644
--- a/kohana/config/sql_types.php
+++ b/kohana/config/sql_types.php
@@ -18,9 +18,11 @@ $config = array
'float unsigned' => array('type' => 'float', 'min' => 0),
'boolean' => array('type' => 'boolean'),
'time' => array('type' => 'string', 'format' => '00:00:00'),
+ 'time with time zone' => array('type' => 'string'),
'date' => array('type' => 'string', 'format' => '0000-00-00'),
'year' => array('type' => 'string', 'format' => '0000'),
'datetime' => array('type' => 'string', 'format' => '0000-00-00 00:00:00'),
+ 'timestamp with time zone' => array('type' => 'string'),
'char' => array('type' => 'string', 'exact' => TRUE),
'binary' => array('type' => 'string', 'binary' => TRUE, 'exact' => TRUE),
'varchar' => array('type' => 'string'),
@@ -36,7 +38,7 @@ $config['double'] = $config['double unsigned'] = $config['decimal'] = $config['r
$config['bit'] = $config['boolean'];
// TIMESTAMP
-$config['timestamp'] = $config['datetime'];
+$config['timestamp'] = $config['timestamp without time zone'] = $config['datetime'];
// ENUM
$config['enum'] = $config['set'] = $config['varchar'];
@@ -45,4 +47,11 @@ $config['enum'] = $config['set'] = $config['varchar'];
$config['tinytext'] = $config['mediumtext'] = $config['longtext'] = $config['text'];
// BLOB
-$config['tinyblob'] = $config['mediumblob'] = $config['longblob'] = $config['clob'] = $config['blob'];
+$config['tinyblob'] = $config['mediumblob'] = $config['longblob'] = $config['clob'] = $config['bytea'] = $config['blob'];
+
+// CHARACTER
+$config['character'] = $config['char'];
+$config['character varying'] = $config['varchar'];
+
+// TIME
+$config['time without time zone'] = $config['time'];
diff --git a/kohana/core/Bootstrap.php b/kohana/core/Bootstrap.php
index 57db1648..0190eb9d 100644
--- a/kohana/core/Bootstrap.php
+++ b/kohana/core/Bootstrap.php
@@ -10,7 +10,7 @@
* @license http://kohanaphp.com/license.html
*/
-define('KOHANA_VERSION', '2.3');
+define('KOHANA_VERSION', '2.3.2');
define('KOHANA_CODENAME', 'accipiter');
// Test of Kohana is running in Windows
diff --git a/kohana/core/Event.php b/kohana/core/Event.php
index 89c6a087..456dca09 100644
--- a/kohana/core/Event.php
+++ b/kohana/core/Event.php
@@ -212,10 +212,10 @@ final class Event {
// Do this to prevent data from getting 'stuck'
$clear_data = '';
self::$data =& $clear_data;
-
- // The event has been run!
- self::$has_run[$name] = $name;
}
+
+ // The event has been run!
+ self::$has_run[$name] = $name;
}
/**
diff --git a/kohana/core/Kohana.php b/kohana/core/Kohana.php
index 76964fbd..7f9b87da 100644
--- a/kohana/core/Kohana.php
+++ b/kohana/core/Kohana.php
@@ -105,7 +105,7 @@ final class Kohana {
$ER = error_reporting(~E_NOTICE & ~E_STRICT);
// Set the user agent
- self::$user_agent = trim($_SERVER['HTTP_USER_AGENT']);
+ self::$user_agent = ( ! empty($_SERVER['HTTP_USER_AGENT']) ? trim($_SERVER['HTTP_USER_AGENT']) : '');
if (function_exists('date_default_timezone_set'))
{
@@ -694,14 +694,14 @@ final class Kohana {
*/
public static function render($output)
{
- // Fetch memory usage in MB
- $memory = function_exists('memory_get_usage') ? (memory_get_usage() / 1024 / 1024) : 0;
-
- // Fetch benchmark for page execution time
- $benchmark = Benchmark::get(SYSTEM_BENCHMARK.'_total_execution');
-
if (self::config('core.render_stats') === TRUE)
{
+ // Fetch memory usage in MB
+ $memory = function_exists('memory_get_usage') ? (memory_get_usage() / 1024 / 1024) : 0;
+
+ // Fetch benchmark for page execution time
+ $benchmark = Benchmark::get(SYSTEM_BENCHMARK.'_total_execution');
+
// Replace the global template variables
$output = str_replace(
array
diff --git a/kohana/core/utf8/ord.php b/kohana/core/utf8/ord.php
index 29723b6b..76e31872 100644
--- a/kohana/core/utf8/ord.php
+++ b/kohana/core/utf8/ord.php
@@ -77,7 +77,7 @@ function _ord($chr)
if ($ord0 >= 252 AND $ord0 <= 253)
{
- return ($ord0 - 252) * 1073741824 + ($ord1 - 128) * 16777216 + ($ord2 - 128) * 262144 + ($ord3 - 128) * 4096 + ($ord4 - 128) * 64 + (ord($c[5]) - 128);
+ return ($ord0 - 252) * 1073741824 + ($ord1 - 128) * 16777216 + ($ord2 - 128) * 262144 + ($ord3 - 128) * 4096 + ($ord4 - 128) * 64 + (ord($chr[5]) - 128);
}
if ($ord0 >= 254 AND $ord0 <= 255)
diff --git a/kohana/core/utf8/str_pad.php b/kohana/core/utf8/str_pad.php
index 63e27f0e..aab4ccc7 100644
--- a/kohana/core/utf8/str_pad.php
+++ b/kohana/core/utf8/str_pad.php
@@ -50,5 +50,5 @@ function _str_pad($str, $final_str_length, $pad_str = ' ', $pad_type = STR_PAD_R
return $pad_left.$str.$pad_right;
}
- trigger_error('utf8::str_pad: Unknown padding type (' . $type . ')', E_USER_ERROR);
+ trigger_error('utf8::str_pad: Unknown padding type (' . $pad_type . ')', E_USER_ERROR);
} \ No newline at end of file
diff --git a/kohana/core/utf8/strcspn.php b/kohana/core/utf8/strcspn.php
index abd93d57..20d3e802 100644
--- a/kohana/core/utf8/strcspn.php
+++ b/kohana/core/utf8/strcspn.php
@@ -16,7 +16,7 @@ function _strcspn($str, $mask, $offset = NULL, $length = NULL)
if (utf8::is_ascii($str) AND utf8::is_ascii($mask))
return ($offset === NULL) ? strcspn($str, $mask) : (($length === NULL) ? strcspn($str, $mask, $offset) : strcspn($str, $mask, $offset, $length));
- if ($start !== NULL OR $length !== NULL)
+ if ($str !== NULL OR $length !== NULL)
{
$str = utf8::substr($str, $offset, $length);
}
diff --git a/kohana/helpers/arr.php b/kohana/helpers/arr.php
index 24b03d7f..87f2be1f 100644
--- a/kohana/helpers/arr.php
+++ b/kohana/helpers/arr.php
@@ -84,7 +84,7 @@ class arr_Core {
return $val;
}
-
+
/**
* Extract one or more keys from an array. Each key given after the first
* argument (the array) will be extracted. Keys that do not exist in the
@@ -251,13 +251,18 @@ class arr_Core {
* @param array input array(s) that will overwrite key array values
* @return array
*/
- public static function overwrite($array1)
+ public static function overwrite($array1, $array2)
{
- foreach (array_slice(func_get_args(), 1) as $array2)
+ foreach (array_intersect_key($array2, $array1) as $key => $value)
+ {
+ $array1[$key] = $value;
+ }
+
+ if (func_num_args() > 2)
{
- foreach ($array2 as $key => $value)
+ foreach (array_slice(func_get_args(), 2) as $array2)
{
- if (array_key_exists($key, $array1))
+ foreach (array_intersect_key($array2, $array1) as $key => $value)
{
$array1[$key] = $value;
}
diff --git a/kohana/helpers/form.php b/kohana/helpers/form.php
index bd656604..0eaec0dc 100644
--- a/kohana/helpers/form.php
+++ b/kohana/helpers/form.php
@@ -144,10 +144,9 @@ class form_Core {
* @param string|array input name or an array of HTML attributes
* @param string input value, when using a name
* @param string a string to be attached to the end of the attributes
- * @param boolean encode existing entities
* @return string
*/
- public static function input($data, $value = '', $extra = '', $double_encode = TRUE )
+ public static function input($data, $value = '', $extra = '')
{
if ( ! is_array($data))
{
@@ -161,9 +160,6 @@ class form_Core {
'value' => $value
);
- // For safe form data
- $data['value'] = html::specialchars($data['value'], $double_encode);
-
return '<input'.form::attributes($data).' '.$extra.' />';
}
@@ -216,7 +212,7 @@ class form_Core {
* @param boolean encode existing entities
* @return string
*/
- public static function textarea($data, $value = '', $extra = '', $double_encode = TRUE )
+ public static function textarea($data, $value = '', $extra = '', $double_encode = TRUE)
{
if ( ! is_array($data))
{
@@ -243,7 +239,6 @@ class form_Core {
*/
public static function dropdown($data, $options = NULL, $selected = NULL, $extra = '')
{
-
if ( ! is_array($data))
{
$data = array('name' => $data);
@@ -263,15 +258,23 @@ class form_Core {
}
}
+ if (is_array($selected))
+ {
+ // Multi-select box
+ $data['multiple'] = 'multiple';
+ }
+ else
+ {
+ // Single selection (but converted to an array)
+ $selected = array($selected);
+ }
+
$input = '<select'.form::attributes($data, 'select').' '.$extra.'>'."\n";
foreach ((array) $options as $key => $val)
{
// Key should always be a string
$key = (string) $key;
- // Selected must always be a string
- $selected = (string) $selected;
-
if (is_array($val))
{
$input .= '<optgroup label="'.$key.'">'."\n";
@@ -280,23 +283,14 @@ class form_Core {
// Inner key should always be a string
$inner_key = (string) $inner_key;
- if (is_array($selected))
- {
- $sel = in_array($inner_key, $selected, TRUE);
- }
- else
- {
- $sel = ($selected === $inner_key);
- }
-
- $sel = ($sel === TRUE) ? ' selected="selected"' : '';
+ $sel = in_array($inner_key, $selected) ? ' selected="selected"' : '';
$input .= '<option value="'.$inner_key.'"'.$sel.'>'.$inner_val.'</option>'."\n";
}
$input .= '</optgroup>'."\n";
}
else
{
- $sel = ($selected === $key) ? ' selected="selected"' : '';
+ $sel = in_array($key, $selected) ? ' selected="selected"' : '';
$input .= '<option value="'.$key.'"'.$sel.'>'.$val.'</option>'."\n";
}
}
diff --git a/kohana/helpers/url.php b/kohana/helpers/url.php
index 5b3b5fd2..46055299 100644
--- a/kohana/helpers/url.php
+++ b/kohana/helpers/url.php
@@ -243,6 +243,9 @@ class url_Core {
header('Location: '.$uri);
}
+ // We are about to exit, so run the send_headers event
+ Event::run('system.send_headers');
+
exit('<h1>'.$method.' - '.$codes[$method].'</h1>'.$output);
}
diff --git a/kohana/helpers/valid.php b/kohana/helpers/valid.php
index c2cefb5d..916a0c19 100644
--- a/kohana/helpers/valid.php
+++ b/kohana/helpers/valid.php
@@ -203,7 +203,7 @@ class valid_Core {
* @param string date to check
* @return boolean
*/
- public function date($str)
+ public static function date($str)
{
return (strtotime($str) !== FALSE);
}
diff --git a/kohana/libraries/Controller.php b/kohana/libraries/Controller.php
index 5f946bde..317f5f0c 100644
--- a/kohana/libraries/Controller.php
+++ b/kohana/libraries/Controller.php
@@ -66,18 +66,10 @@ abstract class Controller_Core {
// Import the view variables to local namespace
extract($kohana_input_data, EXTR_SKIP);
- try
- {
- // Views are straight HTML pages with embedded PHP, so importing them
- // this way insures that $this can be accessed as if the user was in
- // the controller, which gives the easiest access to libraries in views
- include $kohana_view_filename;
- }
- catch (Exception $e)
- {
- // Display the exception using its internal __toString method
- echo $e;
- }
+ // Views are straight HTML pages with embedded PHP, so importing them
+ // this way insures that $this can be accessed as if the user was in
+ // the controller, which gives the easiest access to libraries in views
+ include $kohana_view_filename;
// Fetch the output and close the buffer
return ob_get_clean();
diff --git a/kohana/libraries/Database.php b/kohana/libraries/Database.php
index adbbcf56..0e02ec59 100644
--- a/kohana/libraries/Database.php
+++ b/kohana/libraries/Database.php
@@ -341,7 +341,20 @@ class Database_Core {
{
if (($val = trim($val)) === '') continue;
- $this->from[] = $this->config['table_prefix'].$val;
+ // TODO: Temporary solution, this should be moved to database driver (AS is checked for twice)
+ if (stripos($val, ' AS ') !== FALSE)
+ {
+ $val = str_ireplace(' AS ', ' AS ', $val);
+
+ list($table, $alias) = explode(' AS ', $val);
+
+ // Attach prefix to both sides of the AS
+ $this->from[] = $this->config['table_prefix'].$table.' AS '.$this->config['table_prefix'].$alias;
+ }
+ else
+ {
+ $this->from[] = $this->config['table_prefix'].$val;
+ }
}
return $this;
@@ -379,14 +392,36 @@ class Database_Core {
foreach ($keys as $key => $value)
{
$key = (strpos($key, '.') !== FALSE) ? $this->config['table_prefix'].$key : $key;
- $cond[] = $this->driver->where($key, $this->driver->escape_column($this->config['table_prefix'].$value), 'AND ', count($cond), FALSE);
+
+ if (is_string($value))
+ {
+ // Only escape if it's a string
+ $value = $this->driver->escape_column($this->config['table_prefix'].$value);
+ }
+
+ $cond[] = $this->driver->where($key, $value, 'AND ', count($cond), FALSE);
}
if( ! is_array($this->join)) { $this->join = array(); }
foreach ((array) $table as $t)
{
- $join['tables'][] = $this->driver->escape_column($this->config['table_prefix'].$t);
+ // TODO: Temporary solution, this should be moved to database driver (AS is checked for twice)
+ if (stripos($t, ' AS ') !== FALSE)
+ {
+ $t = str_ireplace(' AS ', ' AS ', $t);
+
+ list($table, $alias) = explode(' AS ', $t);
+
+ // Attach prefix to both sides of the AS
+ $t = $this->config['table_prefix'].$table.' AS '.$this->config['table_prefix'].$alias;
+ }
+ else
+ {
+ $t = $this->config['table_prefix'].$t;
+ }
+
+ $join['tables'][] = $this->driver->escape_column($t);
}
$join['conditions'] = '('.trim(implode(' ', $cond)).')';
@@ -1278,7 +1313,7 @@ class Database_Core {
* @return Database_Core This Databaes object
*/
public function push()
- {
+ {
array_push($this->query_history, array(
$this->select,
$this->from,
@@ -1310,7 +1345,7 @@ class Database_Core {
// No history
return $this;
}
-
+
list(
$this->select,
$this->from,
diff --git a/kohana/libraries/Image.php b/kohana/libraries/Image.php
index 6fcce090..c9e82a1c 100644
--- a/kohana/libraries/Image.php
+++ b/kohana/libraries/Image.php
@@ -134,7 +134,7 @@ class Image_Core {
}
else
{
- throw new Kohana_Exception('core.invalid_property', $column, get_class($this));
+ throw new Kohana_Exception('core.invalid_property', $property, get_class($this));
}
}
@@ -358,39 +358,39 @@ class Image_Core {
chmod($new_image, $chmod);
}
}
-
+
// Reset actions. Subsequent save() or render() will not apply previous actions.
if ($keep_actions === FALSE)
$this->actions = array();
-
+
return $status;
}
-
- /**
- * Output the image to the browser.
- *
+
+ /**
+ * Output the image to the browser.
+ *
* @param boolean keep or discard image process actions
- * @return object
- */
- public function render($keep_actions = FALSE)
- {
- $new_image = $this->image['file'];
-
- // Separate the directory and filename
- $dir = pathinfo($new_image, PATHINFO_DIRNAME);
- $file = pathinfo($new_image, PATHINFO_BASENAME);
-
- // Normalize the path
- $dir = str_replace('\\', '/', realpath($dir)).'/';
-
- // Process the image with the driver
- $status = $this->driver->process($this->image, $this->actions, $dir, $file, $render = TRUE);
-
+ * @return object
+ */
+ public function render($keep_actions = FALSE)
+ {
+ $new_image = $this->image['file'];
+
+ // Separate the directory and filename
+ $dir = pathinfo($new_image, PATHINFO_DIRNAME);
+ $file = pathinfo($new_image, PATHINFO_BASENAME);
+
+ // Normalize the path
+ $dir = str_replace('\\', '/', realpath($dir)).'/';
+
+ // Process the image with the driver
+ $status = $this->driver->process($this->image, $this->actions, $dir, $file, $render = TRUE);
+
// Reset actions. Subsequent save() or render() will not apply previous actions.
if ($keep_actions === FALSE)
$this->actions = array();
-
- return $status;
+
+ return $status;
}
/**
diff --git a/kohana/libraries/Model.php b/kohana/libraries/Model.php
index 4134ff2d..9c78507b 100644
--- a/kohana/libraries/Model.php
+++ b/kohana/libraries/Model.php
@@ -12,7 +12,7 @@
class Model_Core {
// Database object
- protected $db;
+ protected $db = 'default';
/**
* Loads the database instance, if the database is not already loaded.
@@ -24,7 +24,7 @@ class Model_Core {
if ( ! is_object($this->db))
{
// Load the default database
- $this->db = Database::instance('default');
+ $this->db = Database::instance($this->db);
}
}
diff --git a/kohana/libraries/ORM.php b/kohana/libraries/ORM.php
index 16ac16f2..64229ee2 100644
--- a/kohana/libraries/ORM.php
+++ b/kohana/libraries/ORM.php
@@ -278,15 +278,15 @@ class ORM_Core {
{
// This handles the has_one and belongs_to relationships
- if (array_key_exists($column.'_'.$model->primary_key, $this->object))
+ if (in_array($model->object_name, $this->belongs_to) OR ! isset($model->object[$this->foreign_key($column)]))
{
- // Use the FK that exists in this model as the PK
- $where = array($model->table_name.'.'.$model->primary_key => $this->object[$column.'_'.$model->primary_key]);
+ // Foreign key lies in this table (this model belongs_to target model) OR an invalid has_one relationship
+ $where = array($model->table_name.'.'.$model->primary_key => $this->object[$this->foreign_key($column)]);
}
else
{
- // Use this model PK as the FK
- $where = array($this->foreign_key() => $this->object[$this->primary_key]);
+ // Foreign key lies in the target table (this model has_one target model)
+ $where = array($this->foreign_key($column, $model->table_name) => $this->primary_key_value);
}
// one<>alias:one relationship
@@ -300,22 +300,23 @@ class ORM_Core {
// Load the "end" model
$model = ORM::factory(inflector::singular($column));
- // Load JOIN info
+ // Join ON target model's primary key set to 'through' model's foreign key
+ // User-defined foreign keys must be defined in the 'through' model
$join_table = $through->table_name;
- $join_col1 = $model->foreign_key(NULL, $join_table);
- $join_col2 = $model->foreign_key(TRUE);
+ $join_col1 = $through->foreign_key($model->object_name, $join_table);
+ $join_col2 = $model->table_name.'.'.$model->primary_key;
// one<>alias:many relationship
return $this->related[$column] = $model
->join($join_table, $join_col1, $join_col2)
- ->where($this->foreign_key(NULL, $join_table), $this->object[$this->primary_key])
+ ->where($through->foreign_key($this->object_name, $join_table), $this->object[$this->primary_key])
->find_all();
}
elseif (in_array($column, $this->has_many))
{
// one<>many relationship
return $this->related[$column] = ORM::factory(inflector::singular($column))
- ->where($this->foreign_key($column), $this->object[$this->primary_key])
+ ->where($this->foreign_key($column, $column), $this->object[$this->primary_key])
->find_all();
}
elseif (in_array($column, $this->has_and_belongs_to_many))
@@ -461,91 +462,83 @@ class ORM_Core {
* Binds another one-to-one object to this model. One-to-one objects
* can be nested using 'object1:object2' syntax
*
- * @param string $object
+ * @param string $target_path
* @return void
*/
- public function with($object)
+ public function with($target_path)
{
- if (isset($this->with_applied[$object]))
+ if (isset($this->with_applied[$target_path]))
{
// Don't join anything already joined
return $this;
}
- $prefix = $table = $object;
-
// Split object parts
- $objects = explode(':', $object);
- $object = $this;
- foreach ($objects as $object_part)
+ $objects = explode(':', $target_path);
+ $target = $this;
+ foreach ($objects as $object)
{
// Go down the line of objects to find the given target
- $parent = $object;
- $object = $parent->related_object($object_part);
+ $parent = $target;
+ $target = $parent->related_object($object);
- if ( ! $object)
+ if ( ! $target)
{
// Can't find related object
return $this;
}
}
- $table = $object_part;
-
- if ($this->table_names_plural)
- {
- $table = inflector::plural($table);
- }
+ $target_name = $object;
- // Pop-off top object to get the parent object (user:photo:tag's parent is user:photo)
+ // Pop-off top object to get the parent object (user:photo:tag becomes user:photo - the parent table prefix)
array_pop($objects);
- $parent_prefix = implode(':', $objects);
+ $parent_path = implode(':', $objects);
- if (empty($parent_prefix))
+ if (empty($parent_path))
{
- // Use this table name itself for the parent prefix
- $parent_prefix = $this->table_name;
+ // Use this table name itself for the parent object
+ $parent_path = $this->table_name;
}
else
{
- if( ! isset($this->with_applied[$parent_prefix]))
+ if( ! isset($this->with_applied[$parent_path]))
{
// If the parent object hasn't been joined yet, do it first (otherwise LEFT JOINs fail)
- $this->with($parent_prefix);
+ $this->with($parent_path);
}
}
// Add to with_applied to prevent duplicate joins
- $this->with_applied[$prefix] = TRUE;
+ $this->with_applied[$target_path] = TRUE;
// Use the keys of the empty object to determine the columns
- $select = array_keys($object->as_array());
+ $select = array_keys($target->as_array());
foreach ($select as $i => $column)
{
// Add the prefix so that load_result can determine the relationship
- $select[$i] = $prefix.'.'.$column.' AS '.$prefix.':'.$column;
+ $select[$i] = $target_path.'.'.$column.' AS '.$target_path.':'.$column;
}
+
// Select all of the prefixed keys in the object
$this->db->select($select);
-
- // Use last object part to generate foreign key
- $foreign_key = $object_part.'_'.$object->primary_key;
-
- if (array_key_exists($foreign_key, $parent->object))
+
+ if (in_array($target->object_name, $parent->belongs_to) OR ! isset($target->object[$parent->foreign_key($target_name)]))
{
- // Foreign key exists in the joined object's parent
- $join_col1 = $object->foreign_key(TRUE, $prefix);
- $join_col2 = $parent_prefix.'.'.$foreign_key;
+ // Parent belongs_to target, use target's primary key as join column
+ $join_col1 = $target->foreign_key(TRUE, $target_path);
+ $join_col2 = $parent->foreign_key($target_name, $parent_path);
}
else
{
- $join_col1 = $parent->foreign_key(NULL, $prefix);
- $join_col2 = $parent_prefix.'.'.$parent->primary_key;
+ // Parent has_one target, use parent's primary key as join column
+ $join_col2 = $parent->foreign_key(TRUE, $parent_path);
+ $join_col1 = $parent->foreign_key($target_name, $target_path);
}
// Join the related object into the result
- $this->db->join($object->table_name.' AS '.$this->db->table_prefix().$prefix, $join_col1, $join_col2, 'LEFT');
+ $this->db->join($target->table_name.' AS '.$this->db->table_prefix().$target_path, $join_col1, $join_col2, 'LEFT');
return $this;
}
@@ -1360,10 +1353,19 @@ class ORM_Core {
if ( ! empty($this->load_with))
{
- foreach ($this->load_with as $object)
+ foreach ($this->load_with as $alias => $object)
{
// Join each object into the results
- $this->with($object);
+ if (is_string($alias))
+ {
+ // Use alias
+ $this->with($alias);
+ }
+ else
+ {
+ // Use object
+ $this->with($object);
+ }
}
}
diff --git a/kohana/libraries/ORM_Tree.php b/kohana/libraries/ORM_Tree.php
index 72f55540..def5fd59 100644
--- a/kohana/libraries/ORM_Tree.php
+++ b/kohana/libraries/ORM_Tree.php
@@ -13,10 +13,10 @@
class ORM_Tree_Core extends ORM {
// Name of the child
- protected $children;
+ protected $ORM_Tree_children;
// Parent keyword name
- protected $parent_key = 'parent_id';
+ protected $ORM_Tree_parent_key = 'parent_id';
/**
* Overload ORM::__get to support "parent" and "children" properties.
@@ -31,12 +31,12 @@ class ORM_Tree_Core extends ORM {
if (empty($this->related[$column]))
{
// Load child model
- $model = ORM::factory(inflector::singular($this->children));
+ $model = ORM::factory(inflector::singular($this->ORM_Tree_children));
- if (array_key_exists($this->parent_key, $this->object))
+ if (array_key_exists($this->ORM_Tree_parent_key, $this->object))
{
// Find children of this parent
- $model->where($model->primary_key, $this->object[$this->parent_key])->find();
+ $model->where($model->primary_key, $this->object[$this->ORM_Tree_parent_key])->find();
}
$this->related[$column] = $model;
@@ -48,13 +48,13 @@ class ORM_Tree_Core extends ORM {
{
if (empty($this->related[$column]))
{
- $model = ORM::factory(inflector::singular($this->children));
+ $model = ORM::factory(inflector::singular($this->ORM_Tree_children));
- if ($this->children === $this->table_name)
+ if ($this->ORM_Tree_children === $this->table_name)
{
// Load children within this table
$this->related[$column] = $model
- ->where($this->parent_key, $this->object[$this->primary_key])
+ ->where($this->ORM_Tree_parent_key, $this->object[$this->primary_key])
->find_all();
}
else
@@ -62,7 +62,7 @@ class ORM_Tree_Core extends ORM {
// Find first selection of children
$this->related[$column] = $model
->where($this->foreign_key(), $this->object[$this->primary_key])
- ->where($this->parent_key, NULL)
+ ->where($this->ORM_Tree_parent_key, NULL)
->find_all();
}
}
diff --git a/kohana/libraries/View.php b/kohana/libraries/View.php
index c440be10..5dba706c 100644
--- a/kohana/libraries/View.php
+++ b/kohana/libraries/View.php
@@ -56,7 +56,7 @@ class View_Core {
$this->kohana_local_data = array_merge($this->kohana_local_data, $data);
}
}
-
+
/**
* Magic method access to test for view property
*
@@ -129,7 +129,7 @@ class View_Core {
}
/**
- * Checks for a property existence in the view locally or globally. Unlike the built in __isset(),
+ * Checks for a property existence in the view locally or globally. Unlike the built in __isset(),
* this method can take an array of properties to test simultaneously.
*
* @param string $key property name to test for
@@ -147,7 +147,7 @@ class View_Core {
{
// Set the result to an array
$result = array();
-
+
// Foreach key
foreach ($key as $property)
{
@@ -184,9 +184,9 @@ class View_Core {
*
* @param string|array name of variable or an array of variables
* @param mixed value when using a named variable
- * @return object
+ * @return void
*/
- public function set_global($name, $value = NULL)
+ public static function set_global($name, $value = NULL)
{
if (is_array($name))
{
@@ -199,8 +199,6 @@ class View_Core {
{
self::$kohana_global_data[$name] = $value;
}
-
- return $this;
}
/**
@@ -241,7 +239,15 @@ class View_Core {
*/
public function __toString()
{
- return $this->render();
+ try
+ {
+ return $this->render();
+ }
+ catch (Exception $e)
+ {
+ // Display the exception using its internal __toString method
+ return (string) $e;
+ }
}
/**
diff --git a/kohana/libraries/drivers/Database.php b/kohana/libraries/drivers/Database.php
index d478aa6a..96562240 100644
--- a/kohana/libraries/drivers/Database.php
+++ b/kohana/libraries/drivers/Database.php
@@ -154,7 +154,7 @@ abstract class Database_Driver {
* @param int number of likes
* @return string
*/
- public function like($field, $match = '', $auto = TRUE, $type = 'AND ', $num_likes)
+ public function like($field, $match, $auto, $type, $num_likes)
{
$prefix = ($num_likes == 0) ? '' : $type;
@@ -178,7 +178,7 @@ abstract class Database_Driver {
* @param int number of likes
* @return string
*/
- public function notlike($field, $match = '', $auto = TRUE, $type = 'AND ', $num_likes)
+ public function notlike($field, $match, $auto, $type, $num_likes)
{
$prefix = ($num_likes == 0) ? '' : $type;
diff --git a/kohana/libraries/drivers/Database/Mssql.php b/kohana/libraries/drivers/Database/Mssql.php
index 401770a2..3e89faba 100644
--- a/kohana/libraries/drivers/Database/Mssql.php
+++ b/kohana/libraries/drivers/Database/Mssql.php
@@ -74,7 +74,7 @@ class Database_Mssql_Driver extends Database_Driver
*/
// Clear password after successful connect
- $this->config['connection']['pass'] = NULL;
+ $this->db_config['connection']['pass'] = NULL;
return $this->link;
}
@@ -94,6 +94,11 @@ class Database_Mssql_Driver extends Database_Driver
// Set the cached object
self::$query_cache[$hash] = new Mssql_Result(mssql_query($sql, $this->link), $this->link, $this->db_config['object'], $sql);
}
+ else
+ {
+ // Rewind cached result
+ self::$query_cache[$hash]->rewind();
+ }
// Return the cached query
return self::$query_cache[$hash];
diff --git a/kohana/libraries/drivers/Database/Mysql.php b/kohana/libraries/drivers/Database/Mysql.php
index f54b6d81..04d7ed65 100644
--- a/kohana/libraries/drivers/Database/Mysql.php
+++ b/kohana/libraries/drivers/Database/Mysql.php
@@ -74,7 +74,7 @@ class Database_Mysql_Driver extends Database_Driver {
}
// Clear password after successful connect
- $this->config['connection']['pass'] = NULL;
+ $this->db_config['connection']['pass'] = NULL;
return $this->link;
}
@@ -94,6 +94,11 @@ class Database_Mysql_Driver extends Database_Driver {
// Set the cached object
self::$query_cache[$hash] = new Mysql_Result(mysql_query($sql, $this->link), $this->link, $this->db_config['object'], $sql);
}
+ else
+ {
+ // Rewind cached result
+ self::$query_cache[$hash]->rewind();
+ }
// Return the cached query
return self::$query_cache[$hash];
@@ -170,14 +175,14 @@ class Database_Mysql_Driver extends Database_Driver {
return $column;
}
- public function regex($field, $match = '', $type = 'AND ', $num_regexs)
+ public function regex($field, $match, $type, $num_regexs)
{
$prefix = ($num_regexs == 0) ? '' : $type;
return $prefix.' '.$this->escape_column($field).' REGEXP \''.$this->escape_str($match).'\'';
}
- public function notregex($field, $match = '', $type = 'AND ', $num_regexs)
+ public function notregex($field, $match, $type, $num_regexs)
{
$prefix = $num_regexs == 0 ? '' : $type;
diff --git a/kohana/libraries/drivers/Database/Mysqli.php b/kohana/libraries/drivers/Database/Mysqli.php
index 795c576b..3d6bbfbf 100644
--- a/kohana/libraries/drivers/Database/Mysqli.php
+++ b/kohana/libraries/drivers/Database/Mysqli.php
@@ -57,7 +57,7 @@ class Database_Mysqli_Driver extends Database_Mysql_Driver {
}
// Clear password after successful connect
- $this->config['connection']['pass'] = NULL;
+ $this->db_config['connection']['pass'] = NULL;
return $this->link;
}
@@ -77,6 +77,11 @@ class Database_Mysqli_Driver extends Database_Mysql_Driver {
// Set the cached object
self::$query_cache[$hash] = new Kohana_Mysqli_Result($this->link, $this->db_config['object'], $sql);
}
+ else
+ {
+ // Rewind cached result
+ self::$query_cache[$hash]->rewind();
+ }
// Return the cached query
return self::$query_cache[$hash];
diff --git a/kohana/libraries/drivers/Database/Pgsql.php b/kohana/libraries/drivers/Database/Pgsql.php
index ff0a5ed5..9758de3c 100644
--- a/kohana/libraries/drivers/Database/Pgsql.php
+++ b/kohana/libraries/drivers/Database/Pgsql.php
@@ -53,7 +53,7 @@ class Database_Pgsql_Driver extends Database_Driver {
}
// Clear password after successful connect
- $this->config['connection']['pass'] = NULL;
+ $this->db_config['connection']['pass'] = NULL;
return $this->link;
}
@@ -73,6 +73,11 @@ class Database_Pgsql_Driver extends Database_Driver {
// Set the cached object
self::$query_cache[$hash] = new Pgsql_Result(pg_query($this->link, $sql), $this->link, $this->db_config['object'], $sql);
}
+ else
+ {
+ // Rewind cached result
+ self::$query_cache[$hash]->rewind();
+ }
return self::$query_cache[$hash];
}
@@ -137,14 +142,14 @@ class Database_Pgsql_Driver extends Database_Driver {
return $column;
}
- public function regex($field, $match = '', $type = 'AND ', $num_regexs)
+ public function regex($field, $match, $type, $num_regexs)
{
$prefix = ($num_regexs == 0) ? '' : $type;
return $prefix.' '.$this->escape_column($field).' REGEXP \''.$this->escape_str($match).'\'';
}
- public function notregex($field, $match = '', $type = 'AND ', $num_regexs)
+ public function notregex($field, $match, $type, $num_regexs)
{
$prefix = $num_regexs == 0 ? '' : $type;
@@ -244,84 +249,57 @@ class Database_Pgsql_Driver extends Database_Driver {
return pg_last_error($this->link);
}
- public function list_fields($table, $query = FALSE)
+ public function list_fields($table)
{
static $tables;
- if (is_object($query))
+ if (empty($tables[$table]))
{
- if (empty($tables[$table]))
+ foreach ($this->field_data($table) as $row)
{
- $tables[$table] = array();
+ // Make an associative array
+ $tables[$table][$row->column_name] = $this->sql_type($row->data_type);
- foreach ($query as $row)
+ if (!strncmp($row->column_default, 'nextval(', 8))
{
- $tables[$table][] = $row->Field;
+ $tables[$table][$row->column_name]['sequenced'] = TRUE;
}
- }
- return $tables[$table];
- }
-
- // WOW...REALLY?!?
- // Taken from http://www.postgresql.org/docs/7.4/interactive/catalogs.html
- $query = $this->query('SELECT
- -- Field
- pg_attribute.attname AS "Field",
- -- Type
- CASE pg_type.typname
- WHEN \'int2\' THEN \'smallint\'
- WHEN \'int4\' THEN \'int\'
- WHEN \'int8\' THEN \'bigint\'
- WHEN \'varchar\' THEN \'varchar(\' || pg_attribute.atttypmod-4 || \')\'
- ELSE pg_type.typname
- END AS "Type",
- -- Null
- CASE WHEN pg_attribute.attnotnull THEN \'NO\'
- ELSE \'YES\'
- END AS "Null",
- -- Default
- CASE pg_type.typname
- WHEN \'varchar\' THEN substring(pg_attrdef.adsrc from \'^(.*).*$\')
- ELSE pg_attrdef.adsrc
- END AS "Default"
-FROM pg_class
- INNER JOIN pg_attribute
- ON (pg_class.oid=pg_attribute.attrelid)
- INNER JOIN pg_type
- ON (pg_attribute.atttypid=pg_type.oid)
- LEFT JOIN pg_attrdef
- ON (pg_class.oid=pg_attrdef.adrelid AND pg_attribute.attnum=pg_attrdef.adnum)
-WHERE pg_class.relname=\''.$this->escape_str($table).'\' AND pg_attribute.attnum>=1 AND NOT pg_attribute.attisdropped
-ORDER BY pg_attribute.attnum');
-
- // Load the result as objects
- $query->result(TRUE);
-
- $fields = array();
- foreach ($query as $row)
+ if ($row->is_nullable === 'YES')
{
- $fields[$row->Field] = $row->Type;
+ $tables[$table][$row->column_name]['null'] = TRUE;
}
+ }
+ }
+
+ if (!isset($tables[$table]))
+ throw new Kohana_Database_Exception('database.table_not_found', $table);
- return $fields;
+ return $tables[$table];
}
public function field_data($table)
{
- // TODO: This whole function needs to be debugged.
- $query = pg_query('SELECT * FROM '.$this->escape_table($table).' LIMIT 1', $this->link);
- $fields = pg_num_fields($query);
- $table = array();
-
- for ($i=0; $i < $fields; $i++)
+ $columns = array();
+
+ // http://www.postgresql.org/docs/8.3/static/infoschema-columns.html
+ $result = pg_query($this->link, '
+ SELECT column_name, column_default, is_nullable, data_type, udt_name,
+ character_maximum_length, numeric_precision, numeric_precision_radix, numeric_scale
+ FROM information_schema.columns
+ WHERE table_name = \''. $this->escape_str($table) .'\'
+ ORDER BY ordinal_position
+ ');
+
+ if ($result)
{
- $table[$i]['type'] = pg_field_type($query, $i);
- $table[$i]['name'] = pg_field_name($query, $i);
- $table[$i]['len'] = pg_field_prtlen($query, $i);
+ while ($row = pg_fetch_object($result))
+ {
+ $columns[] = $row;
+ }
}
- return $table;
+ return $columns;
}
} // End Database_Pgsql_Driver Class
@@ -463,7 +441,7 @@ class Pgsql_Result extends Database_Result {
// tables that have no serial column.
$ER = error_reporting(0);
- $result = pg_query($query);
+ $result = pg_query($this->link, $query);
$insert_id = pg_fetch_array($result, NULL, PGSQL_ASSOC);
$this->insert_id = $insert_id['insert_id'];
@@ -486,9 +464,11 @@ class Pgsql_Result extends Database_Result {
public function list_fields()
{
$field_names = array();
- while ($field = pg_field_name($this->result))
+
+ $fields = pg_num_fields($this->result);
+ for ($i = 0; $i < $fields; ++$i)
{
- $field_names[] = $field->name;
+ $field_names[] = pg_field_name($this->result, $i);
}
return $field_names;