summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBharat Mediratta <bharat@menalto.com>2009-05-18 00:14:07 +0000
committerBharat Mediratta <bharat@menalto.com>2009-05-18 00:14:07 +0000
commitfd0c0a608a5de2b26c29d3c44a7929e5a3b2c042 (patch)
tree387f2628cae3580b7f09682de6e908d002c5fbb0
parent5a6aef9c23930b1de609c9914297e0f97bc49a11 (diff)
Updated kohana and modules/unit_test to upstream r4356
-rw-r--r--kohana/config/sql_types.php3
-rw-r--r--kohana/core/Benchmark.php2
-rw-r--r--kohana/core/Kohana.php239
-rw-r--r--kohana/helpers/arr.php49
-rw-r--r--kohana/helpers/date.php8
-rw-r--r--kohana/helpers/expires.php3
-rw-r--r--kohana/helpers/feed.php6
-rw-r--r--kohana/helpers/form.php2
-rw-r--r--kohana/helpers/request.php2
-rw-r--r--kohana/helpers/valid.php2
-rw-r--r--kohana/libraries/Cache.php12
-rw-r--r--kohana/libraries/Database.php6
-rw-r--r--kohana/libraries/ORM.php34
-rw-r--r--kohana/libraries/Router.php13
-rw-r--r--kohana/libraries/drivers/Database.php14
-rw-r--r--kohana/libraries/drivers/Database/Mssql.php55
-rw-r--r--kohana/libraries/drivers/Database/Mysql.php107
-rw-r--r--kohana/libraries/drivers/Database/Mysqli.php39
-rw-r--r--kohana/libraries/drivers/Database/Pdosqlite.php37
-rw-r--r--kohana/libraries/drivers/Database/Pgsql.php99
-rw-r--r--kohana/views/kohana_error_disabled.php6
-rw-r--r--kohana/views/kohana_error_page.php6
-rw-r--r--modules/unit_test/i18n/en_US/unit_test.php2
-rw-r--r--modules/unit_test/libraries/Unit_Test.php20
-rw-r--r--modules/unit_test/views/kohana_unit_test_cli.php36
25 files changed, 430 insertions, 372 deletions
diff --git a/kohana/config/sql_types.php b/kohana/config/sql_types.php
index 69a0a631..a4a44bda 100644
--- a/kohana/config/sql_types.php
+++ b/kohana/config/sql_types.php
@@ -32,7 +32,8 @@ $config = array
);
// DOUBLE
-$config['double'] = $config['double unsigned'] = $config['decimal'] = $config['real'] = $config['numeric'] = $config['float'];
+$config['double'] = $config['double precision'] = $config['decimal'] = $config['real'] = $config['numeric'] = $config['float'];
+$config['double unsigned'] = $config['float unsigned'];
// BIT
$config['bit'] = $config['boolean'];
diff --git a/kohana/core/Benchmark.php b/kohana/core/Benchmark.php
index 09909126..3bb6d04f 100644
--- a/kohana/core/Benchmark.php
+++ b/kohana/core/Benchmark.php
@@ -109,7 +109,7 @@ final class Benchmark {
*
* @return integer
*/
- private function memory_usage()
+ private static function memory_usage()
{
static $func;
diff --git a/kohana/core/Kohana.php b/kohana/core/Kohana.php
index 0ee6f631..ed87902e 100644
--- a/kohana/core/Kohana.php
+++ b/kohana/core/Kohana.php
@@ -209,12 +209,6 @@ final class Kohana {
{
Benchmark::start(SYSTEM_BENCHMARK.'_controller_setup');
- if (Router::$method[0] === '_')
- {
- // Do not allow access to hidden methods
- Event::run('system.404');
- }
-
// Include the Controller file
require Router::$controller_path;
@@ -249,6 +243,13 @@ final class Kohana {
// Load the controller method
$method = $class->getMethod(Router::$method);
+ // Method exists
+ if (Router::$method[0] === '_')
+ {
+ // Do not allow access to hidden methods
+ Event::run('system.404');
+ }
+
if ($method->isProtected() or $method->isPrivate())
{
// Do not attempt to invoke protected methods
@@ -806,126 +807,140 @@ final class Kohana {
*/
public static function exception_handler($exception, $message = NULL, $file = NULL, $line = NULL)
{
- // PHP errors have 5 args, always
- $PHP_ERROR = (func_num_args() === 5);
-
- // Test to see if errors should be displayed
- if ($PHP_ERROR AND (error_reporting() & $exception) === 0)
- return;
-
- // This is useful for hooks to determine if a page has an error
- self::$has_error = TRUE;
-
- // Error handling will use exactly 5 args, every time
- if ($PHP_ERROR)
- {
- $code = $exception;
- $type = 'PHP Error';
- $template = 'kohana_error_page';
- }
- else
- {
- $code = $exception->getCode();
- $type = get_class($exception);
- $message = $exception->getMessage();
- $file = $exception->getFile();
- $line = $exception->getLine();
- $template = ($exception instanceof Kohana_Exception) ? $exception->getTemplate() : 'kohana_error_page';
- }
-
- if (is_numeric($code))
- {
- $codes = self::lang('errors');
-
- if ( ! empty($codes[$code]))
+ try
+ {
+ // PHP errors have 5 args, always
+ $PHP_ERROR = (func_num_args() === 5);
+
+ // Test to see if errors should be displayed
+ if ($PHP_ERROR AND (error_reporting() & $exception) === 0)
+ return;
+
+ // This is useful for hooks to determine if a page has an error
+ self::$has_error = TRUE;
+
+ // Error handling will use exactly 5 args, every time
+ if ($PHP_ERROR)
+ {
+ $code = $exception;
+ $type = 'PHP Error';
+ $template = 'kohana_error_page';
+ }
+ else
{
- list($level, $error, $description) = $codes[$code];
+ $code = $exception->getCode();
+ $type = get_class($exception);
+ $message = $exception->getMessage();
+ $file = $exception->getFile();
+ $line = $exception->getLine();
+ $template = ($exception instanceof Kohana_Exception) ? $exception->getTemplate() : 'kohana_error_page';
+ }
+
+ if (is_numeric($code))
+ {
+ $codes = self::lang('errors');
+
+ if ( ! empty($codes[$code]))
+ {
+ list($level, $error, $description) = $codes[$code];
+ }
+ else
+ {
+ $level = 1;
+ $error = $PHP_ERROR ? 'Unknown Error' : get_class($exception);
+ $description = '';
+ }
}
else
{
- $level = 1;
- $error = $PHP_ERROR ? 'Unknown Error' : get_class($exception);
+ // Custom error message, this will never be logged
+ $level = 5;
+ $error = $code;
$description = '';
}
- }
- else
- {
- // Custom error message, this will never be logged
- $level = 5;
- $error = $code;
- $description = '';
- }
-
- // Remove the DOCROOT from the path, as a security precaution
- $file = str_replace('\\', '/', realpath($file));
- $file = preg_replace('|^'.preg_quote(DOCROOT).'|', '', $file);
-
- if ($level <= self::$configuration['core']['log_threshold'])
- {
- // Log the error
- self::log('error', self::lang('core.uncaught_exception', $type, $message, $file, $line));
- }
-
- if ($PHP_ERROR)
- {
- $description = self::lang('errors.'.E_RECOVERABLE_ERROR);
- $description = is_array($description) ? $description[2] : '';
-
- if ( ! headers_sent())
+
+ // Remove the DOCROOT from the path, as a security precaution
+ $file = str_replace('\\', '/', realpath($file));
+ $file = preg_replace('|^'.preg_quote(DOCROOT).'|', '', $file);
+
+ if ($level <= self::$configuration['core']['log_threshold'])
{
- // Send the 500 header
- header('HTTP/1.1 500 Internal Server Error');
+ // Log the error
+ self::log('error', self::lang('core.uncaught_exception', $type, $message, $file, $line));
}
- }
- else
- {
- if (method_exists($exception, 'sendHeaders') AND ! headers_sent())
+
+ if ($PHP_ERROR)
{
- // Send the headers if they have not already been sent
- $exception->sendHeaders();
+ $description = self::lang('errors.'.E_RECOVERABLE_ERROR);
+ $description = is_array($description) ? $description[2] : '';
+
+ if ( ! headers_sent())
+ {
+ // Send the 500 header
+ header('HTTP/1.1 500 Internal Server Error');
+ }
}
- }
-
- while (ob_get_level() > self::$buffer_level)
- {
- // Close open buffers
- ob_end_clean();
- }
-
- // Test if display_errors is on
- if (self::$configuration['core']['display_errors'] === TRUE)
- {
- if ( ! IN_PRODUCTION AND $line != FALSE)
+ else
{
- // Remove the first entry of debug_backtrace(), it is the exception_handler call
- $trace = $PHP_ERROR ? array_slice(debug_backtrace(), 1) : $exception->getTrace();
-
- // Beautify backtrace
- $trace = self::backtrace($trace);
+ if (method_exists($exception, 'sendHeaders') AND ! headers_sent())
+ {
+ // Send the headers if they have not already been sent
+ $exception->sendHeaders();
+ }
}
-
- // Load the error
- require self::find_file('views', empty($template) ? 'kohana_error_page' : $template);
- }
- else
- {
- // Get the i18n messages
- $error = self::lang('core.generic_error');
- $message = self::lang('core.errors_disabled', url::site(), url::site(Router::$current_uri));
-
- // Load the errors_disabled view
- require self::find_file('views', 'kohana_error_disabled');
+
+ while (ob_get_level() > self::$buffer_level)
+ {
+ // Close open buffers
+ ob_end_clean();
+ }
+
+ // Test if display_errors is on
+ if (self::$configuration['core']['display_errors'] === TRUE)
+ {
+ if ( ! IN_PRODUCTION AND $line != FALSE)
+ {
+ // Remove the first entry of debug_backtrace(), it is the exception_handler call
+ $trace = $PHP_ERROR ? array_slice(debug_backtrace(), 1) : $exception->getTrace();
+
+ // Beautify backtrace
+ $trace = self::backtrace($trace);
+ }
+
+ // Load the error
+ require self::find_file('views', empty($template) ? 'kohana_error_page' : $template);
+ }
+ else
+ {
+ // Get the i18n messages
+ $error = self::lang('core.generic_error');
+ $message = self::lang('core.errors_disabled', url::site(), url::site(Router::$current_uri));
+
+ // Load the errors_disabled view
+ require self::find_file('views', 'kohana_error_disabled');
+ }
+
+ if ( ! Event::has_run('system.shutdown'))
+ {
+ // Run the shutdown even to ensure a clean exit
+ Event::run('system.shutdown');
+ }
+
+ // Turn off error reporting
+ error_reporting(0);
+ exit;
}
-
- if ( ! Event::has_run('system.shutdown'))
+ catch (Exception $e)
{
- // Run the shutdown even to ensure a clean exit
- Event::run('system.shutdown');
+ if (IN_PRODUCTION)
+ {
+ die('Fatal Error');
+ }
+ else
+ {
+ die('Fatal Error: '.$e->getMessage().' File: '.$e->getFile().' Line: '.$e->getLine());
+ }
}
-
- // Turn off error reporting
- error_reporting(0);
- exit;
}
/**
@@ -1027,7 +1042,7 @@ final class Kohana {
*
* @throws Kohana_Exception if file is required and not found
* @param string directory to search in
- * @param string filename to look for (including extension only if 4th parameter is TRUE)
+ * @param string filename to look for (without extension)
* @param boolean file required
* @param string file extension
* @return array if the type is config, i18n or l10n
diff --git a/kohana/helpers/arr.php b/kohana/helpers/arr.php
index 87f2be1f..9f0dc097 100644
--- a/kohana/helpers/arr.php
+++ b/kohana/helpers/arr.php
@@ -152,52 +152,43 @@ class arr_Core {
}
/**
- * Binary search algorithm.
- *
- * @param mixed the value to search for
- * @param array an array of values to search in
- * @param boolean return false, or the nearest value
- * @param mixed sort the array before searching it
- * @return integer
+ * @param mixed $needle the value to search for
+ * @param array $haystack an array of values to search in
+ * @param boolean $sort sort the array now
+ * @return integer|FALSE the index of the match or FALSE when not found
*/
- public static function binary_search($needle, $haystack, $nearest = FALSE, $sort = FALSE)
+ public static function binary_search($needle, $haystack, $sort = FALSE)
{
- if ($sort === TRUE)
+ if ($sort)
{
sort($haystack);
}
- $high = count($haystack);
+ $high = count($haystack) - 1;
$low = 0;
- while ($high - $low > 1)
+ while ($low <= $high)
{
- $probe = ($high + $low) / 2;
- if ($haystack[$probe] < $needle)
+ $mid = ($low + $high) >> 1;
+
+ if ($haystack[$mid] < $needle)
{
- $low = $probe;
+ $low = $mid + 1;
+ }
+ elseif ($haystack[$mid] > $needle)
+ {
+ $high = $mid - 1;
}
else
{
- $high = $probe;
+ return $mid;
}
}
- if ($high == count($haystack) OR $haystack[$high] != $needle)
- {
- if ($nearest === FALSE)
- return FALSE;
-
- // return the nearest value
- $high_distance = $haystack[ceil($low)] - $needle;
- $low_distance = $needle - $haystack[floor($low)];
-
- return ($high_distance >= $low_distance) ? $haystack[ceil($low)] : $haystack[floor($low)];
- }
-
- return $high;
+ return FALSE;
}
+
/**
* Emulates array_merge_recursive, but appends numeric keys and replaces
* associative keys, instead of appending all keys.
@@ -318,4 +309,4 @@ class arr_Core {
return $object;
}
-} // End arr \ No newline at end of file
+} // End arr
diff --git a/kohana/helpers/date.php b/kohana/helpers/date.php
index b926e626..1a5bbacb 100644
--- a/kohana/helpers/date.php
+++ b/kohana/helpers/date.php
@@ -374,7 +374,7 @@ class date_Core {
$span = array();
foreach ($difference as $name => $amount)
{
- if ($name !== $last AND $amount === 0)
+ if ($amount === 0)
{
// Skip empty amounts
continue;
@@ -384,6 +384,12 @@ class date_Core {
$span[] = ($name === $last ? ' and ' : ', ').$amount.' '.($amount === 1 ? inflector::singular($name) : $name);
}
+ // If the difference is less than 60 seconds, remove the preceding and.
+ if (count($span) === 1)
+ {
+ $span[0] = ltrim($span[0], 'and ');
+ }
+
// Replace difference by making the span into a string
$difference = trim(implode('', $span), ',');
}
diff --git a/kohana/helpers/expires.php b/kohana/helpers/expires.php
index 454cf12a..8d8ef0f8 100644
--- a/kohana/helpers/expires.php
+++ b/kohana/helpers/expires.php
@@ -88,7 +88,8 @@ class expires_Core {
{
foreach (headers_list() as $header)
{
- if (stripos($header, 'Last-Modified:') === 0 OR stripos($header, 'Expires:') === 0)
+ if ((session_cache_limiter() == '' AND stripos($header, 'Last-Modified:') === 0)
+ OR stripos($header, 'Expires:') === 0)
{
return FALSE;
}
diff --git a/kohana/helpers/feed.php b/kohana/helpers/feed.php
index c1e0b81f..a84ec512 100644
--- a/kohana/helpers/feed.php
+++ b/kohana/helpers/feed.php
@@ -65,13 +65,15 @@ class feed_Core {
*
* @param array feed information
* @param array items to add to the feed
+ * @param string define which format to use
+ * @param string define which encoding to use
* @return string
*/
- public static function create($info, $items, $format = 'rss2')
+ public static function create($info, $items, $format = 'rss2', $encoding = 'UTF-8')
{
$info += array('title' => 'Generated Feed', 'link' => '', 'generator' => 'KohanaPHP');
- $feed = '<?xml version="1.0"?><rss version="2.0"><channel></channel></rss>';
+ $feed = '<?xml version="1.0" encoding="'.$encoding.'"?><rss version="2.0"><channel></channel></rss>';
$feed = simplexml_load_string($feed);
foreach ($info as $name => $value)
diff --git a/kohana/helpers/form.php b/kohana/helpers/form.php
index 0eaec0dc..70b98167 100644
--- a/kohana/helpers/form.php
+++ b/kohana/helpers/form.php
@@ -233,7 +233,7 @@ class form_Core {
*
* @param string|array input name or an array of HTML attributes
* @param array select options, when using a name
- * @param string option key that should be selected by default
+ * @param string|array option key(s) that should be selected by default
* @param string a string to be attached to the end of the attributes
* @return string
*/
diff --git a/kohana/helpers/request.php b/kohana/helpers/request.php
index 625f9226..091a9d68 100644
--- a/kohana/helpers/request.php
+++ b/kohana/helpers/request.php
@@ -33,7 +33,7 @@ class request_Core {
if (strpos($ref, url::base(FALSE)) === 0)
{
// Remove the base URL from the referrer
- $ref = substr($ref, strlen(url::base(TRUE)));
+ $ref = substr($ref, strlen(url::base(FALSE)));
}
}
diff --git a/kohana/helpers/valid.php b/kohana/helpers/valid.php
index 88cca584..25f90f68 100644
--- a/kohana/helpers/valid.php
+++ b/kohana/helpers/valid.php
@@ -277,7 +277,7 @@ class valid_Core {
{
// Use localeconv to set the decimal_point value: Usually a comma or period.
$locale = localeconv();
- return (preg_match('/^-?[0-9'.$locale['decimal_point'].']++$/D', (string) $str));
+ return (bool) preg_match('/^-?[0-9'.$locale['decimal_point'].']++$/D', (string) $str);
}
/**
diff --git a/kohana/libraries/Cache.php b/kohana/libraries/Cache.php
index 3fb5a31c..3dcf0312 100644
--- a/kohana/libraries/Cache.php
+++ b/kohana/libraries/Cache.php
@@ -135,13 +135,13 @@ class Cache_Core {
* Set a cache item by id. Tags may also be added and a custom lifetime
* can be set. Non-string data is automatically serialized.
*
- * @param string unique cache id
- * @param mixed data to cache
- * @param array tags for this item
- * @param integer number of seconds until the cache expires
+ * @param string unique cache id
+ * @param mixed data to cache
+ * @param array|string tags for this item
+ * @param integer number of seconds until the cache expires
* @return boolean
*/
- function set($id, $data, array $tags = NULL, $lifetime = NULL)
+ function set($id, $data, $tags = NULL, $lifetime = NULL)
{
if (is_resource($data))
throw new Kohana_Exception('cache.resources');
@@ -155,7 +155,7 @@ class Cache_Core {
$lifetime = $this->config['lifetime'];
}
- return $this->driver->set($id, $data, $tags, $lifetime);
+ return $this->driver->set($id, $data, (array) $tags, $lifetime);
}
/**
diff --git a/kohana/libraries/Database.php b/kohana/libraries/Database.php
index 49241675..59e47621 100644
--- a/kohana/libraries/Database.php
+++ b/kohana/libraries/Database.php
@@ -341,10 +341,10 @@ class Database_Core {
foreach ($sql as $val)
{
- if (($val = trim($val)) === '') continue;
-
if (is_string($val))
{
+ if (($val = trim($val)) === '') continue;
+
// TODO: Temporary solution, this should be moved to database driver (AS is checked for twice)
if (stripos($val, ' AS ') !== FALSE)
{
@@ -1187,7 +1187,7 @@ class Database_Core {
{
$this->link or $this->connect();
- return $this->driver->list_tables($this);
+ return $this->driver->list_tables();
}
/**
diff --git a/kohana/libraries/ORM.php b/kohana/libraries/ORM.php
index 4cbec50a..ae214649 100644
--- a/kohana/libraries/ORM.php
+++ b/kohana/libraries/ORM.php
@@ -319,8 +319,9 @@ class ORM_Core {
elseif (in_array($column, $this->has_many))
{
// one<>many relationship
- return $this->related[$column] = ORM::factory(inflector::singular($column))
- ->where($this->foreign_key($column, $column), $this->object[$this->primary_key])
+ $model = ORM::factory(inflector::singular($column));
+ return $this->related[$column] = $model
+ ->where($this->foreign_key($column, $model->table_name), $this->object[$this->primary_key])
->find_all();
}
elseif (in_array($column, $this->has_and_belongs_to_many))
@@ -638,10 +639,10 @@ class ORM_Core {
*/
public function validate(Validation $array, $save = FALSE)
{
+ $safe_array = $array->safe_array();
+
if ( ! $array->submitted())
{
- $safe_array = $array->safe_array();
-
foreach ($safe_array as $key => $value)
{
// Get the value from this object
@@ -661,12 +662,16 @@ class ORM_Core {
// Validate the array
if ($status = $array->validate())
{
- $safe_array = $array->safe_array();
+ // Grab only set fields (excludes missing data, unlike safe_array)
+ $fields = $array->as_array();
- foreach ($safe_array as $key => $value)
+ foreach ($fields as $key => $value)
{
- // Set new data
- $this->$key = $value;
+ if (isset($safe_array[$key]))
+ {
+ // Set new data, ignoring any missing fields or fields without rules
+ $this->$key = $value;
+ }
}
if ($save === TRUE OR is_string($save))
@@ -840,7 +845,7 @@ class ORM_Core {
elseif (is_null($ids))
{
// Delete all records
- $this->db->where(TRUE);
+ $this->db->where('1=1');
}
else
{
@@ -902,7 +907,7 @@ class ORM_Core {
else
{
// Load table columns
- ORM::$column_cache[$this->object_name] = $this->table_columns = $this->db->list_fields($this->table_name, TRUE);
+ ORM::$column_cache[$this->object_name] = $this->table_columns = $this->list_fields();
}
}
@@ -1021,11 +1026,16 @@ class ORM_Core {
/**
* Proxy method to Database list_fields.
*
- * @param string table name
+ * @param string table name or NULL to use this table
* @return array
*/
- public function list_fields($table)
+ public function list_fields($table = NULL)
{
+ if ($table === NULL)
+ {
+ $table = $this->table_name;
+ }
+
// Proxy to database
return $this->db->list_fields($table);
}
diff --git a/kohana/libraries/Router.php b/kohana/libraries/Router.php
index 172c5f92..a47a9993 100644
--- a/kohana/libraries/Router.php
+++ b/kohana/libraries/Router.php
@@ -213,15 +213,12 @@ class Router_Core {
elseif (isset($_SERVER['PHP_SELF']) AND $_SERVER['PHP_SELF'])
{
Router::$current_uri = $_SERVER['PHP_SELF'];
- }
-
- // The front controller directory and filename
- $fc = substr(realpath($_SERVER['SCRIPT_FILENAME']), strlen(DOCROOT));
- if (($strpos_fc = strpos(Router::$current_uri, $fc)) !== FALSE)
- {
- // Remove the front controller from the current uri
- Router::$current_uri = substr(Router::$current_uri, $strpos_fc + strlen($fc));
+ if (($strpos_fc = strpos(Router::$current_uri, KOHANA)) !== FALSE)
+ {
+ // Remove the front controller from the current uri
+ Router::$current_uri = substr(Router::$current_uri, $strpos_fc + strlen(KOHANA));
+ }
}
// Remove slashes from the start and end of the URI
diff --git a/kohana/libraries/drivers/Database.php b/kohana/libraries/drivers/Database.php
index 96562240..f5adf924 100644
--- a/kohana/libraries/drivers/Database.php
+++ b/kohana/libraries/drivers/Database.php
@@ -11,7 +11,7 @@
*/
abstract class Database_Driver {
- static $query_cache;
+ protected $query_cache;
/**
* Connect to our database.
@@ -124,7 +124,7 @@ abstract class Database_Driver {
}
else
{
- if ( ! $this->has_operator($key))
+ if ( ! $this->has_operator($key) AND ! empty($key))
{
$key = $this->escape_column($key).' =';
}
@@ -290,7 +290,7 @@ abstract class Database_Driver {
*/
public function has_operator($str)
{
- return (bool) preg_match('/[<>!=]|\sIS(?:\s+NOT\s+)?\b/i', trim($str));
+ return (bool) preg_match('/[<>!=]|\sIS(?:\s+NOT\s+)?\b|BETWEEN/i', trim($str));
}
/**
@@ -337,7 +337,7 @@ abstract class Database_Driver {
*
* @return array
*/
- abstract public function list_tables(Database $db);
+ abstract public function list_tables();
/**
* Lists all fields in a table.
@@ -431,11 +431,11 @@ abstract class Database_Driver {
{
if (empty($sql))
{
- self::$query_cache = array();
+ $this->query_cache = array();
}
else
{
- unset(self::$query_cache[$this->query_hash($sql)]);
+ unset($this->query_cache[$this->query_hash($sql)]);
}
Kohana::log('debug', 'Database cache cleared: '.get_class($this));
@@ -633,4 +633,4 @@ abstract class Database_Result implements ArrayAccess, Iterator, Countable {
return $this->offsetExists($this->current_row);
}
-} // End Database Result Interface \ No newline at end of file
+} // End Database Result Interface
diff --git a/kohana/libraries/drivers/Database/Mssql.php b/kohana/libraries/drivers/Database/Mssql.php
index 3e89faba..6947679a 100644
--- a/kohana/libraries/drivers/Database/Mssql.php
+++ b/kohana/libraries/drivers/Database/Mssql.php
@@ -89,19 +89,19 @@ class Database_Mssql_Driver extends Database_Driver
{
$hash = $this->query_hash($sql);
- if ( ! isset(self::$query_cache[$hash]))
+ if ( ! isset($this->query_cache[$hash]))
{
// Set the cached object
- self::$query_cache[$hash] = new Mssql_Result(mssql_query($sql, $this->link), $this->link, $this->db_config['object'], $sql);
+ $this->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();
+ $this->query_cache[$hash]->rewind();
}
// Return the cached query
- return self::$query_cache[$hash];
+ return $this->query_cache[$hash];
}
return new Mssql_Result(mssql_query($sql, $this->link), $this->link, $this->db_config['object'], $sql);
@@ -128,9 +128,22 @@ class Database_Mssql_Driver extends Database_Driver
if (!$this->db_config['escape'])
return $column;
- if (strtolower($column) == 'count(*)' OR $column == '*')
+ if ($column == '*')
return $column;
+ // This matches any functions we support to SELECT.
+ if ( preg_match('/(avg|count|sum|max|min)\(\s*(.*)\s*\)(\s*as\s*(.+)?)?/i', $column, $matches))
+ {
+ if ( count($matches) == 3)
+ {
+ return $matches[1].'('.$this->escape_column($matches[2]).')';
+ }
+ else if ( count($matches) == 5)
+ {
+ return $matches[1].'('.$this->escape_column($matches[2]).') AS '.$this->escape_column($matches[2]);
+ }
+ }
+
// This matches any modifiers we support to SELECT.
if ( ! preg_match('/\b(?:rand|all|distinct(?:row)?|high_priority|sql_(?:small_result|b(?:ig_result|uffer_result)|no_cache|ca(?:che|lc_found_rows)))\s/i', $column))
{
@@ -251,7 +264,7 @@ class Database_Mssql_Driver extends Database_Driver
return preg_replace($characters, $replace, $str);
}
- public function list_tables(Database $db)
+ public function list_tables()
{
$sql = 'SHOW TABLES FROM ['.$this->db_config['connection']['database'].']';
$result = $this->query($sql)->result(FALSE, MSSQL_ASSOC);
@@ -272,36 +285,22 @@ class Database_Mssql_Driver extends Database_Driver
public function list_fields($table)
{
- static $tables;
+ $result = array();
- if (empty($tables[$table]))
+ foreach ($this->field_data($table) as $row)
{
- foreach ($this->field_data($table) as $row)
- {
- // Make an associative array
- $tables[$table][$row->Field] = $this->sql_type($row->Type);
- }
+ // Make an associative array
+ $result[$row->Field] = $this->sql_type($row->Type);
}
- return $tables[$table];
+ return $result;
}
public function field_data($table)
{
- $columns = array();
-
- if ($query = MSSQL_query('SHOW COLUMNS FROM '.$this->escape_table($table), $this->link))
- {
- if (MSSQL_num_rows($query) > 0)
- {
- while ($row = MSSQL_fetch_object($query))
- {
- $columns[] = $row;
- }
- }
- }
+ $query = $this->query('SHOW COLUMNS FROM '.$this->escape_table($table), $this->link);
- return $columns;
+ return $query->result_array(TRUE);
}
}
@@ -460,4 +459,4 @@ class Mssql_Result extends Database_Result {
return mssql_data_seek($this->result, $offset);
}
-} // End mssql_Result Class \ No newline at end of file
+} // End mssql_Result Class
diff --git a/kohana/libraries/drivers/Database/Mysql.php b/kohana/libraries/drivers/Database/Mysql.php
index 9315ed1f..978de459 100644
--- a/kohana/libraries/drivers/Database/Mysql.php
+++ b/kohana/libraries/drivers/Database/Mysql.php
@@ -22,12 +22,6 @@ class Database_Mysql_Driver extends Database_Driver {
protected $db_config;
/**
- * Performance caches.
- */
- private $tables_cache;
- private $fields_cache;
-
- /**
* Sets the config for the class.
*
* @param array database configuration
@@ -35,8 +29,6 @@ class Database_Mysql_Driver extends Database_Driver {
public function __construct($config)
{
$this->db_config = $config;
- $this->tables_cache = array();
- $this->fields_cache = array();
Kohana::log('debug', 'MySQL Database Driver Initialized');
}
@@ -85,23 +77,23 @@ class Database_Mysql_Driver extends Database_Driver {
public function query($sql)
{
// Only cache if it's turned on, and only cache if it's not a write statement
- if ($this->db_config['cache'] AND ! preg_match('#\b(?:INSERT|UPDATE|REPLACE|SET)\b#i', $sql))
+ if ($this->db_config['cache'] AND ! preg_match('#\b(?:INSERT|UPDATE|REPLACE|SET|DELETE|TRUNCATE)\b#i', $sql))
{
$hash = $this->query_hash($sql);
- if ( ! isset(self::$query_cache[$hash]))
+ if ( ! isset($this->query_cache[$hash]))
{
// Set the cached object
- self::$query_cache[$hash] = new Mysql_Result(mysql_query($sql, $this->link), $this->link, $this->db_config['object'], $sql);
+ $this->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();
+ $this->query_cache[$hash]->rewind();
}
// Return the cached query
- return self::$query_cache[$hash];
+ return $this->query_cache[$hash];
}
return new Mysql_Result(mysql_query($sql, $this->link), $this->link, $this->db_config['object'], $sql);
@@ -136,9 +128,22 @@ class Database_Mysql_Driver extends Database_Driver {
if (!$this->db_config['escape'])
return $column;
- if (strtolower($column) == 'count(*)' OR $column == '*')
+ if ($column == '*')
return $column;
+ // This matches any functions we support to SELECT.
+ if ( preg_match('/(avg|count|sum|max|min)\(\s*(.*)\s*\)(\s*as\s*(.+)?)?/i', $column, $matches))
+ {
+ if ( count($matches) == 3)
+ {
+ return $matches[1].'('.$this->escape_column($matches[2]).')';
+ }
+ else if ( count($matches) == 5)
+ {
+ return $matches[1].'('.$this->escape_column($matches[2]).') AS '.$this->escape_column($matches[2]);
+ }
+ }
+
// This matches any modifiers we support to SELECT.
if ( ! preg_match('/\b(?:rand|all|distinct(?:row)?|high_priority|sql_(?:small_result|b(?:ig_result|uffer_result)|no_cache|ca(?:che|lc_found_rows)))\s/i', $column))
{
@@ -217,8 +222,8 @@ class Database_Mysql_Driver extends Database_Driver {
{
$froms[] = $this->escape_column($from);
}
- $sql .= "\nFROM ";
- $sql .= implode(', ', $froms);
+ $sql .= "\nFROM (";
+ $sql .= implode(', ', $froms).")";
}
if (count($database['join']) > 0)
@@ -273,11 +278,11 @@ class Database_Mysql_Driver extends Database_Driver {
return mysql_real_escape_string($str, $this->link);
}
- public function list_tables(Database $db)
+ public function list_tables()
{
- $tables =& $this->tables_cache;
+ $tables = array();
- if (empty($tables) AND $query = $db->query('SHOW TABLES FROM '.$this->escape_table($this->db_config['connection']['database'])))
+ if ($query = $this->query('SHOW TABLES FROM '.$this->escape_table($this->db_config['connection']['database'])))
{
foreach ($query->result(FALSE) as $row)
{
@@ -295,63 +300,37 @@ class Database_Mysql_Driver extends Database_Driver {
public function list_fields($table)
{
- $tables =& $this->fields_cache;
+ $result = NULL;
- if (empty($tables[$table]))
+ foreach ($this->field_data($table) as $row)
{
- foreach ($this->field_data($table) as $row)
+ // Make an associative array
+ $result[$row->Field] = $this->sql_type($row->Type);
+
+ if ($row->Key === 'PRI' AND $row->Extra === 'auto_increment')
+ {
+ // For sequenced (AUTO_INCREMENT) tables
+ $result[$row->Field]['sequenced'] = TRUE;
+ }
+
+ if ($row->Null === 'YES')
{
- // Make an associative array
- $tables[$table][$row->Field] = $this->sql_type($row->Type);
-
- if ($row->Key === 'PRI' AND $row->Extra === 'auto_increment')
- {
- // For sequenced (AUTO_INCREMENT) tables
- $tables[$table][$row->Field]['sequenced'] = TRUE;
- }
-
- if ($row->Null === 'YES')
- {
- // Set NULL status
- $tables[$table][$row->Field]['null'] = TRUE;
- }
+ // Set NULL status
+ $result[$row->Field]['null'] = TRUE;
}
}
- if (!isset($tables[$table]))
+ if (!isset($result))
throw new Kohana_Database_Exception('database.table_not_found', $table);
- return $tables[$table];
+ return $result;
}
public function field_data($table)
{
- $columns = array();
-
- if ($query = mysql_query('SHOW COLUMNS FROM '.$this->escape_table($table), $this->link))
- {
- if (mysql_num_rows($query))
- {
- while ($row = mysql_fetch_object($query))
- {
- $columns[] = $row;
- }
- }
- }
+ $result = $this->query('SHOW COLUMNS FROM '.$this->escape_table($table));
- return $columns;
- }
-
- /**
- * Clears the internal query cache.
- *
- * @param string SQL query
- */
- public function clear_cache($sql = NULL)
- {
- parent::clear_cache($sql);
- $this->tables_cache = array();
- $this->fields_cache = array();
+ return $result->result_array(TRUE);
}
} // End Database_Mysql_Driver Class
@@ -514,4 +493,4 @@ class Mysql_Result extends Database_Result {
}
}
-} // End Mysql_Result Class \ No newline at end of file
+} // End Mysql_Result Class
diff --git a/kohana/libraries/drivers/Database/Mysqli.php b/kohana/libraries/drivers/Database/Mysqli.php
index 13a81281..f15e4283 100644
--- a/kohana/libraries/drivers/Database/Mysqli.php
+++ b/kohana/libraries/drivers/Database/Mysqli.php
@@ -68,23 +68,23 @@ class Database_Mysqli_Driver extends Database_Mysql_Driver {
public function query($sql)
{
// Only cache if it's turned on, and only cache if it's not a write statement
- if ($this->db_config['cache'] AND ! preg_match('#\b(?:INSERT|UPDATE|REPLACE|SET)\b#i', $sql))
+ if ($this->db_config['cache'] AND ! preg_match('#\b(?:INSERT|UPDATE|REPLACE|SET|DELETE|TRUNCATE)\b#i', $sql))
{
$hash = $this->query_hash($sql);
- if ( ! isset(self::$query_cache[$hash]))
+ if ( ! isset($this->query_cache[$hash]))
{
// Set the cached object
- self::$query_cache[$hash] = new Kohana_Mysqli_Result($this->link, $this->db_config['object'], $sql);
+ $this->query_cache[$hash] = new Kohana_Mysqli_Result($this->link, $this->db_config['object'], $sql);
}
else
{
// Rewind cached result
- self::$query_cache[$hash]->rewind();
+ $this->query_cache[$hash]->rewind();
}
// Return the cached query
- return self::$query_cache[$hash];
+ return $this->query_cache[$hash];
}
return new Kohana_Mysqli_Result($this->link, $this->db_config['object'], $sql);
@@ -111,22 +111,6 @@ class Database_Mysqli_Driver extends Database_Mysql_Driver {
return $this->link->error;
}
- public function field_data($table)
- {
- $columns = array();
- $query = $this->link->query('SHOW COLUMNS FROM '.$this->escape_table($table));
-
- if (is_object($query))
- {
- while ($row = $query->fetch_object())
- {
- $columns[] = $row;
- }
- }
-
- return $columns;
- }
-
} // End Database_Mysqli_Driver Class
/**
@@ -299,12 +283,15 @@ class Kohana_Mysqli_Result extends Database_Result {
public function seek($offset)
{
- if ( ! $this->offsetExists($offset))
- return FALSE;
+ if ($this->offsetExists($offset) AND $this->result->data_seek($offset))
+ {
+ // Set the current row to the offset
+ $this->current_row = $offset;
- $this->result->data_seek($offset);
+ return TRUE;
+ }
- return TRUE;
+ return FALSE;
}
public function offsetGet($offset)
@@ -368,4 +355,4 @@ class Kohana_Mysqli_Statement {
$this->stmt->execute();
return $this->stmt;
}
-} \ No newline at end of file
+}
diff --git a/kohana/libraries/drivers/Database/Pdosqlite.php b/kohana/libraries/drivers/Database/Pdosqlite.php
index 5a512877..c2d1bb21 100644
--- a/kohana/libraries/drivers/Database/Pdosqlite.php
+++ b/kohana/libraries/drivers/Database/Pdosqlite.php
@@ -43,7 +43,7 @@ class Database_Pdosqlite_Driver extends Database_Driver {
array(PDO::ATTR_PERSISTENT => $this->db_config['persistent']));
$this->link->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL);
- $this->link->query('PRAGMA count_changes=1;');
+ //$this->link->query('PRAGMA count_changes=1;');
if ($charset = $this->db_config['character_set'])
{
@@ -63,7 +63,7 @@ class Database_Pdosqlite_Driver extends Database_Driver {
public function query($sql)
{
- try
+ try
{
$sth = $this->link->prepare($sql);
}
@@ -92,9 +92,22 @@ class Database_Pdosqlite_Driver extends Database_Driver {
if ( ! $this->db_config['escape'])
return $column;
- if (strtolower($column) == 'count(*)' OR $column == '*')
+ if ($column == '*')
return $column;
+ // This matches any functions we support to SELECT.
+ if ( preg_match('/(avg|count|sum|max|min)\(\s*(.*)\s*\)(\s*as\s*(.+)?)?/i', $column, $matches))
+ {
+ if ( count($matches) == 3)
+ {
+ return $matches[1].'('.$this->escape_column($matches[2]).')';
+ }
+ else if ( count($matches) == 5)
+ {
+ return $matches[1].'('.$this->escape_column($matches[2]).') AS '.$this->escape_column($matches[2]);
+ }
+ }
+
// This matches any modifiers we support to SELECT.
if ( ! preg_match('/\b(?:rand|all|distinct(?:row)?|high_priority|sql_(?:small_result|b(?:ig_result|uffer_result)|no_cache|ca(?:che|lc_found_rows)))\s/i', $column))
{
@@ -205,12 +218,12 @@ class Database_Pdosqlite_Driver extends Database_Driver {
return $res;
}
- public function list_tables(Database $db)
+ public function list_tables()
{
$sql = "SELECT `name` FROM `sqlite_master` WHERE `type`='table' ORDER BY `name`;";
try
{
- $result = $db->query($sql)->result(FALSE, PDO::FETCH_ASSOC);
+ $result = $this->query($sql)->result(FALSE, PDO::FETCH_ASSOC);
$tables = array();
foreach ($result as $row)
{
@@ -298,14 +311,12 @@ class Pdosqlite_Result extends Database_Result {
{
if (is_object($result) OR $result = $link->prepare($sql))
{
- // run the query
- try
+ // run the query. Return true if success, false otherwise
+ if( ! $result->execute())
{
- $result->execute();
- }
- catch (PDOException $e)
- {
- throw new Kohana_Database_Exception('database.error', $e->getMessage());
+ // Throw Kohana Exception with error message. See PDOStatement errorInfo() method
+ $arr_infos = $result->errorInfo();
+ throw new Kohana_Database_Exception('database.error', $arr_infos[2]);
}
if (preg_match('/^SELECT|PRAGMA|EXPLAIN/i', $sql))
@@ -320,6 +331,8 @@ class Pdosqlite_Result extends Database_Result {
elseif (preg_match('/^DELETE|INSERT|UPDATE/i', $sql))
{
$this->insert_id = $link->lastInsertId();
+
+ $this->total_rows = $result->rowCount();
}
}
else
diff --git a/kohana/libraries/drivers/Database/Pgsql.php b/kohana/libraries/drivers/Database/Pgsql.php
index 62a33ad6..c8a7d819 100644
--- a/kohana/libraries/drivers/Database/Pgsql.php
+++ b/kohana/libraries/drivers/Database/Pgsql.php
@@ -68,18 +68,18 @@ class Database_Pgsql_Driver extends Database_Driver {
{
$hash = $this->query_hash($sql);
- if ( ! isset(self::$query_cache[$hash]))
+ if ( ! isset($this->query_cache[$hash]))
{
// Set the cached object
- self::$query_cache[$hash] = new Pgsql_Result(pg_query($this->link, $sql), $this->link, $this->db_config['object'], $sql);
+ $this->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();
+ $this->query_cache[$hash]->rewind();
}
- return self::$query_cache[$hash];
+ return $this->query_cache[$hash];
}
// Suppress warning triggered when a database error occurs (e.g., a constraint violation)
@@ -104,9 +104,22 @@ class Database_Pgsql_Driver extends Database_Driver {
if (!$this->db_config['escape'])
return $column;
- if (strtolower($column) == 'count(*)' OR $column == '*')
+ if ($column == '*')
return $column;
+ // This matches any functions we support to SELECT.
+ if ( preg_match('/(avg|count|sum|max|min)\(\s*(.*)\s*\)(\s*as\s*(.+)?)?/i', $column, $matches))
+ {
+ if ( count($matches) == 3)
+ {
+ return $matches[1].'('.$this->escape_column($matches[2]).')';
+ }
+ else if ( count($matches) == 5)
+ {
+ return $matches[1].'('.$this->escape_column($matches[2]).') AS '.$this->escape_column($matches[2]);
+ }
+ }
+
// This matches any modifiers we support to SELECT.
if ( ! preg_match('/\b(?:all|distinct)\s/i', $column))
{
@@ -147,14 +160,14 @@ class Database_Pgsql_Driver extends Database_Driver {
{
$prefix = ($num_regexs == 0) ? '' : $type;
- return $prefix.' '.$this->escape_column($field).' REGEXP \''.$this->escape_str($match).'\'';
+ return $prefix.' '.$this->escape_column($field).' ~* \''.$this->escape_str($match).'\'';
}
public function notregex($field, $match, $type, $num_regexs)
{
$prefix = $num_regexs == 0 ? '' : $type;
- return $prefix.' '.$this->escape_column($field).' NOT REGEXP \''.$this->escape_str($match) . '\'';
+ return $prefix.' '.$this->escape_column($field).' !~* \''.$this->escape_str($match) . '\'';
}
public function limit($limit, $offset = 0)
@@ -225,10 +238,10 @@ class Database_Pgsql_Driver extends Database_Driver {
return pg_escape_string($this->link, $str);
}
- public function list_tables(Database $db)
+ public function list_tables()
{
$sql = 'SELECT table_schema || \'.\' || table_name FROM information_schema.tables WHERE table_schema NOT IN (\'pg_catalog\', \'information_schema\')';
- $result = $db->query($sql)->result(FALSE, PGSQL_ASSOC);
+ $result = $this->query($sql)->result(FALSE, PGSQL_ASSOC);
$retval = array();
foreach ($result as $row)
@@ -246,39 +259,34 @@ class Database_Pgsql_Driver extends Database_Driver {
public function list_fields($table)
{
- static $tables;
+ $result = NULL;
- if (empty($tables[$table]))
+ foreach ($this->field_data($table) as $row)
{
- foreach ($this->field_data($table) as $row)
+ // Make an associative array
+ $result[$row->column_name] = $this->sql_type($row->data_type);
+
+ if (!strncmp($row->column_default, 'nextval(', 8))
+ {
+ $result[$row->column_name]['sequenced'] = TRUE;
+ }
+
+ if ($row->is_nullable === 'YES')
{
- // Make an associative array
- $tables[$table][$row->column_name] = $this->sql_type($row->data_type);
-
- if (!strncmp($row->column_default, 'nextval(', 8))
- {
- $tables[$table][$row->column_name]['sequenced'] = TRUE;
- }
-
- if ($row->is_nullable === 'YES')
- {
- $tables[$table][$row->column_name]['null'] = TRUE;
- }
+ $result[$row->column_name]['null'] = TRUE;
}
}
- if (!isset($tables[$table]))
+ if (!isset($result))
throw new Kohana_Database_Exception('database.table_not_found', $table);
- return $tables[$table];
+ return $result;
}
public function field_data($table)
{
- $columns = array();
-
// http://www.postgresql.org/docs/8.3/static/infoschema-columns.html
- $result = pg_query($this->link, '
+ $result = $this->query('
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
@@ -286,15 +294,7 @@ class Database_Pgsql_Driver extends Database_Driver {
ORDER BY ordinal_position
');
- if ($result)
- {
- while ($row = pg_fetch_object($result))
- {
- $columns[] = $row;
- }
- }
-
- return $columns;
+ return $result->result_array(TRUE);
}
} // End Database_Pgsql_Driver Class
@@ -318,6 +318,7 @@ class Pgsql_Result extends Database_Result {
*/
public function __construct($result, $link, $object = TRUE, $sql)
{
+ $this->link = $link;
$this->result = $result;
// If the query is a resource, it was a SELECT, SHOW, DESCRIBE, EXPLAIN query
@@ -418,9 +419,14 @@ class Pgsql_Result extends Database_Result {
}
}
- while ($row = $fetch($this->result, NULL, $type))
+ if ($this->total_rows)
{
- $rows[] = $row;
+ pg_result_seek($this->result, 0);
+
+ while ($row = $fetch($this->result, NULL, $type))
+ {
+ $rows[] = $row;
+ }
}
return $rows;
@@ -450,10 +456,15 @@ class Pgsql_Result extends Database_Result {
public function seek($offset)
{
- if ( ! $this->offsetExists($offset))
- return FALSE;
+ if ($this->offsetExists($offset) AND pg_result_seek($this->result, $offset))
+ {
+ // Set the current row to the offset
+ $this->current_row = $offset;
- return pg_result_seek($this->result, $offset);
+ return TRUE;
+ }
+
+ return FALSE;
}
public function list_fields()
@@ -524,4 +535,4 @@ class Kohana_Pgsql_Statement {
{
return $this;
}
-} \ No newline at end of file
+}
diff --git a/kohana/views/kohana_error_disabled.php b/kohana/views/kohana_error_disabled.php
index ed44b396..cd911328 100644
--- a/kohana/views/kohana_error_disabled.php
+++ b/kohana/views/kohana_error_disabled.php
@@ -2,13 +2,13 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
+<style type="text/css">
+<?php include Kohana::find_file('views', 'kohana_errors', FALSE, 'css') ?>
+</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title><?php echo $error ?></title>
</head>
<body>
-<style type="text/css">
-<?php include Kohana::find_file('views', 'kohana_errors', FALSE, 'css') ?>
-</style>
<div id="framework_error" style="width:24em;margin:50px auto;">
<h3><?php echo html::specialchars($error) ?></h3>
<p style="text-align:center"><?php echo $message ?></p>
diff --git a/kohana/views/kohana_error_page.php b/kohana/views/kohana_error_page.php
index 572e057d..944064cc 100644
--- a/kohana/views/kohana_error_page.php
+++ b/kohana/views/kohana_error_page.php
@@ -2,14 +2,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
+<style type="text/css">
+<?php include Kohana::find_file('views', 'kohana_errors', FALSE, 'css') ?>
+</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title><?php echo $error ?></title>
<base href="http://php.net/" />
</head>
<body>
-<style type="text/css">
-<?php include Kohana::find_file('views', 'kohana_errors', FALSE, 'css') ?>
-</style>
<div id="framework_error" style="width:42em;margin:20px auto;">
<h3><?php echo html::specialchars($error) ?></h3>
<p><?php echo html::specialchars($description) ?></p>
diff --git a/modules/unit_test/i18n/en_US/unit_test.php b/modules/unit_test/i18n/en_US/unit_test.php
index 34ff1c11..a4ec7c57 100644
--- a/modules/unit_test/i18n/en_US/unit_test.php
+++ b/modules/unit_test/i18n/en_US/unit_test.php
@@ -2,6 +2,8 @@
$lang = array
(
+ 'class' => 'Class',
+ 'method' => 'Method',
'invalid_test_path' => 'Failed to open test path: %s.',
'duplicate_test_class' => 'Duplicate test class named %s found in %s.',
'test_class_not_found' => 'No test class by the name of %s found in %s.',
diff --git a/modules/unit_test/libraries/Unit_Test.php b/modules/unit_test/libraries/Unit_Test.php
index cf8b85f0..debf53ab 100644
--- a/modules/unit_test/libraries/Unit_Test.php
+++ b/modules/unit_test/libraries/Unit_Test.php
@@ -211,13 +211,21 @@ class Unit_Test_Core {
// Hide passed tests from the report?
$hide_passed = (bool) (($hide_passed !== NULL) ? $hide_passed : Kohana::config('unit_test.hide_passed', FALSE, FALSE));
-
+
+
+ if (PHP_SAPI == 'cli')
+ {
+ $report = View::factory('kohana_unit_test_cli');
+ }
+ else
+ {
+ $report = View::factory('kohana_unit_test');
+ }
// Render unit_test report
- return View::factory('kohana_unit_test')
- ->set('results', $this->results)
- ->set('stats', $this->stats)
- ->set('hide_passed', $hide_passed)
- ->render();
+ return $report->set('results', $this->results)
+ ->set('stats', $this->stats)
+ ->set('hide_passed', $hide_passed)
+ ->render();
}
/**
diff --git a/modules/unit_test/views/kohana_unit_test_cli.php b/modules/unit_test/views/kohana_unit_test_cli.php
new file mode 100644
index 00000000..b0a9b6d4
--- /dev/null
+++ b/modules/unit_test/views/kohana_unit_test_cli.php
@@ -0,0 +1,36 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+
+foreach ($results as $class => $methods)
+{
+ echo "\n\n" . Kohana::lang('unit_test.class') . ': ' . $class . "\n\n";
+ printf('%s: %.2f%%', Kohana::lang('unit_test.score'), $stats[$class]['score']);
+ echo ",\n" . Kohana::lang('unit_test.total'), ': ', $stats[$class]['total'] . ",\n";
+ echo Kohana::lang('unit_test.passed'), ': ', $stats[$class]['passed'] . ",\n";
+ echo Kohana::lang('unit_test.failed'), ': ', $stats[$class]['failed'] . ",\n";
+ echo Kohana::lang('unit_test.errors'), ': ', $stats[$class]['errors'] . "\n\n";
+
+ if (empty($methods))
+ {
+ echo Kohana::lang('unit_test.no_tests_found');
+ }
+ else
+ {
+ foreach ($methods as $method => $result)
+ {
+ // Hide passed tests from report
+ if ($result === TRUE AND $hide_passed === TRUE)
+ continue;
+
+ echo Kohana::lang('unit_test.method') . ': ' . $method . ': ';
+
+ if ($result === TRUE)
+ {
+ echo Kohana::lang('unit_test.passed') . "\n";
+ }
+ else
+ {
+ echo Kohana::lang('unit_test.failed') . "\n\t" . $result->getMessage() . "\n";
+ }
+ }
+ }
+} \ No newline at end of file