diff options
-rw-r--r-- | kohana/config/sql_types.php | 13 | ||||
-rw-r--r-- | kohana/core/Bootstrap.php | 2 | ||||
-rw-r--r-- | kohana/core/Event.php | 6 | ||||
-rw-r--r-- | kohana/core/Kohana.php | 14 | ||||
-rw-r--r-- | kohana/core/utf8/ord.php | 2 | ||||
-rw-r--r-- | kohana/core/utf8/str_pad.php | 2 | ||||
-rw-r--r-- | kohana/core/utf8/strcspn.php | 2 | ||||
-rw-r--r-- | kohana/helpers/arr.php | 15 | ||||
-rw-r--r-- | kohana/helpers/form.php | 36 | ||||
-rw-r--r-- | kohana/helpers/url.php | 3 | ||||
-rw-r--r-- | kohana/helpers/valid.php | 2 | ||||
-rw-r--r-- | kohana/libraries/Controller.php | 16 | ||||
-rw-r--r-- | kohana/libraries/Database.php | 45 | ||||
-rw-r--r-- | kohana/libraries/Image.php | 50 | ||||
-rw-r--r-- | kohana/libraries/Model.php | 4 | ||||
-rw-r--r-- | kohana/libraries/ORM.php | 102 | ||||
-rw-r--r-- | kohana/libraries/ORM_Tree.php | 18 | ||||
-rw-r--r-- | kohana/libraries/View.php | 22 | ||||
-rw-r--r-- | kohana/libraries/drivers/Database.php | 4 | ||||
-rw-r--r-- | kohana/libraries/drivers/Database/Mssql.php | 7 | ||||
-rw-r--r-- | kohana/libraries/drivers/Database/Mysql.php | 11 | ||||
-rw-r--r-- | kohana/libraries/drivers/Database/Mysqli.php | 7 | ||||
-rw-r--r-- | kohana/libraries/drivers/Database/Pgsql.php | 110 |
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; |