1
0
mirror of https://github.com/dg/dibi.git synced 2025-08-30 17:29:53 +02:00

Compare commits

..

64 Commits

Author SHA1 Message Date
David Grudl
2c3fe68c6c Released version 2.1.1 2013-10-16 21:39:29 +02:00
Jan Tvrdik
008371f3e7 composer.json: fix compatibility with dg/dibi requirements 2013-10-16 21:37:29 +02:00
David Grudl
105327f8e6 typos 2013-10-16 21:37:29 +02:00
David Grudl
d04eb76abb typos & whitespace 2013-10-16 21:37:26 +02:00
David Grudl
0b49f7da94 added examples to readme.md 2013-10-16 21:37:11 +02:00
Rossler Jan
0884cd4007 DibiResult: fixed illegal offset type in fetchPairs. 2013-10-16 21:34:09 +02:00
Miloslav Hůla
acc6ecb0d2 DibiResult: fixed normalization of time when begins by 00: 2013-10-16 21:34:08 +02:00
Jáchym Toušek
b21d592e07 Fixed usage of deprecated parameter 2013-10-16 21:34:08 +02:00
David Grudl
dc4fe8b398 Released version 2.1.0 2013-06-23 02:34:14 +02:00
David Grudl
de7bf09eca improved readme & license 2013-06-23 02:34:14 +02:00
David Grudl
aac5ae9932 typos 2013-06-23 02:34:13 +02:00
David Grudl
d055eefb9a Revert "updated Nette\Debugger"
This reverts commit c08918e034.
2013-06-23 02:12:51 +02:00
David Grudl
93d996ef6d DibiNettePanel is compatible with Nette Framework 2.1 [Closes #97] 2013-06-23 01:56:08 +02:00
David Grudl
e5b2ca46d8 added extension for Nette Framework 2.1 (and examples) [Closes #93] 2013-06-23 01:56:07 +02:00
David Grudl
c305b8b674 Nette extension renamed to DibiNette20Extension and moved to bridges/Nette 2013-06-22 18:29:36 +02:00
David Grudl
1382a1021f all file names correspond with class name 2013-06-22 18:29:35 +02:00
David Grudl
d01ede6aee DibiDatabaseInfo: updated patterns in detectType() [Closes #95] 2013-06-22 16:39:54 +02:00
David Grudl
b94b97873a Merge pull request #96 from jasir/firebird-getrowcount
Firebird driver: getRowCount throws NotSupportedException
2013-06-12 05:05:46 -07:00
jasir
849b9b66fa Firebird driver: getRowCount throws NotSupportedException 2013-06-11 17:56:52 +02:00
David Grudl
41c150932c Merge pull request #92 from hrach/patch-1
Fixed toggling explain for latest Nette Framework
2013-05-24 02:10:42 -07:00
Jan Škrášek
981c78a078 Fixed toggling explain for latest Nette Framework 2013-05-24 01:42:38 +02:00
David Grudl
cbdcc3f832 Merge pull request #85 from foglcz/bug-84
Throw entire callstack for interbase-based databases.
2013-04-11 02:39:31 -07:00
David Grudl
593aa0351a Merge pull request #83 from milo/sqlsrv-fixes
Sqlsrv fixes
2013-04-11 02:37:46 -07:00
Pavel Ptacek
9b4d58878c Throw entire callstack for interbase-based databases. The errors given by firebird are multiline, exceptions get thrown from inside the logic. (.*) matches everything up until first line by default - this mitigates the problem and mathes the entire rest of the string (= including multilines) 2013-04-11 04:51:09 +02:00
Miloslav Hůla
0ebe7ad84f DibiMsSql2005Driver: fixed identifier escaping
Annoted link to MS SQL doc does not talk about open bracket '[' escaping, only closing bracket ']'.

dibi::query('CREATE TABLE %n (id INT)', 'abc[]def');
 - old: creates table 'abc[[]def'
 - new: creates table 'abc[]def'
2013-04-10 12:08:11 +02:00
Miloslav Hůla
4ea885f2b9 DibiPdoDriver: added identifier escaping for sqlsrv 2013-04-10 12:08:11 +02:00
Miloslav Hůla
3634673ffa DibiPdoDriver: applyLimit() for sqlsrv driver
Added table alias has been tested with MS SQL Server 2012 directly and over ODBC.
2013-04-10 12:08:10 +02:00
Miloslav Hůla
8e5898a11b DibiMsSql2005Driver: default charset set to UTF-8
If charset is not specified in config, NULL is passed as connection option and 'Invalid value type for option CharacterSet was specified.  String type was expected.' is thrown.
2013-04-10 12:07:27 +02:00
David Grudl
2c9cbe9b0c DibiResult: fixed detection of "123.000" as float [Closes #67] 2013-04-03 14:38:12 +02:00
David Grudl
326376159f composer: renamed to dibi/dibi 2013-04-03 14:36:18 +02:00
David Grudl
d09fc7d837 MySQLI: mysqli_affected_rows() returns -1 on error [Closes #80] 2013-04-03 13:57:48 +02:00
Teyras
388067cb5d DibiResult: added setRowFactory() [Closes #26] 2013-04-02 00:51:57 +02:00
David Grudl
8a07e1fbe4 renamed directory tools -> vendor 2013-03-15 05:14:09 +01:00
David Grudl
ff675e32d1 Merge pull request #81 from HosipLan/bugfix/notice
PdoDriver: fix notice undefined index native_type
2013-03-14 05:59:34 -07:00
Filip Procházka
cbca529ff8 PdoDriver: fix notice undefined index native_type 2013-03-01 17:31:21 +01:00
Daniel Kouba
9001afe7ca MSSQL2005 driver: autoincrement determination fixed 2012-12-30 02:56:21 +01:00
Daniel Kouba
16b254fce1 MSSQL2005 applyLimit fixed
Conflicts:
	dibi/drivers/mssql2005.php
	dibi/drivers/mssql2005.reflector.php
2012-12-16 23:42:09 +01:00
David Grudl
10fdecfc13 updated examples 2012-12-16 23:39:32 +01:00
David Grudl
322a110f75 Merge pull request #75 from whipsterCZ/patch-3
Column size is string or NULL
2012-12-16 14:37:50 -08:00
Daniel Kouba
188acf1f76 Column size is string or NULL
Issue #74
2012-12-11 15:09:21 +01:00
David Grudl
8cda1401ff Merge pull request #70 from DragonJake/cli-enhancements
DibiResult::dump() a obarvování v CLI módu
2012-12-04 05:50:44 -08:00
David Grudl
9a605573a2 released 2.0.1 2012-12-04 14:40:06 +01:00
David Grudl
d09e490f1b reflectors: table names are correctly escaped 2012-12-04 14:35:53 +01:00
David Grudl
865e44c30f DibiTranslator: number of decimal points changed to 10 2012-12-04 14:22:50 +01:00
David Grudl
c08918e034 updated Nette\Debugger 2012-12-04 14:15:32 +01:00
David Grudl
c385888f9a dibi::$sql is always set 2012-12-04 14:15:31 +01:00
David Grudl
6c82e777e1 added Nette\Tester 2012-12-04 14:15:31 +01:00
David Grudl
b4de8daed3 fixed invalid escaping sequences in double quoted strings, used \z instead of $ 2012-12-04 14:15:31 +01:00
Daniel Kouba
7696fc36e1 Added MSSQL 2005 Reflector 2012-12-04 14:15:26 +01:00
Jakub Krčma
627c102add dibi: colorized SQL dump in CLI mode 2012-10-03 23:08:10 +02:00
Jakub Krčma
6ced2d3af2 DibiResult: added simple dump in CLI mode 2012-10-03 23:06:54 +02:00
Jakub Krčma
927fc858d2 MySQL & MySQLi: added timezone configuration option 2012-10-03 21:13:03 +02:00
Jirka Chadima
f355b8ede7 Allow forcing a persistent connection via driver configuration 2012-08-28 15:38:12 +02:00
David Grudl
dfda0b4d96 DibiConnection: fixed loadFromFile() and loading file without semicolon [Closes #63] 2012-04-05 20:08:51 +02:00
Jan Marek
c1537c1d36 added composer.json 2012-03-30 22:15:57 +02:00
David Grudl
973c2452a7 DibiTranslator: number of decimal points changed to 20 2012-02-29 00:08:31 +01:00
David Grudl
38742aee57 Merge pull request #61 from milo/fix-fire-logger
DibiFirePhpLogger: Fix undefined property access
2012-02-12 14:32:15 -08:00
Miloslav Hůla
b2744174f7 DibiFirePhpLogger: Fix undefined property access 2012-02-11 17:36:15 +01:00
David Grudl
9b7b964696 numOfQueries and totalTime moved to profilers 2012-02-06 18:23:15 +01:00
David Grudl
06642ec9ee Merge pull request #56 from Andrewsville/multiple-connections-nettepanel-fix
Fixed NettePanel output for multiple connections
2012-02-06 09:04:27 -08:00
David Grudl
a2ad4faf49 Merge pull request #58 from milo/fix-mssql
Fix DibiMsSql2005Driver::getResultColumns()
2012-02-06 07:25:27 -08:00
Miloslav Hůla
4be92b62f8 typos 2012-02-06 13:55:40 +01:00
Miloslav Hůla
52986705d8 Fix DibiMsSql2005Driver::getResultColumns() 2012-02-06 13:43:17 +01:00
Ondrej Nespor
0c51f6c9ea Fixed NettePanel output for multiple connections 2012-02-05 01:25:03 +01:00
72 changed files with 1062 additions and 1656 deletions

4
.gitattributes vendored
View File

@@ -1,4 +0,0 @@
.gitattributes export-ignore
.gitignore export-ignore
.travis.yml export-ignore
tests/ export-ignore

View File

@@ -3,13 +3,19 @@
"description": "Dibi is Database Abstraction Library for PHP 5.",
"keywords": ["database", "dbal", "mysql", "postgresql", "sqlite", "mssql", "oracle", "access", "pdo", "odbc"],
"homepage": "http://dibiphp.com/",
"license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
"license": ["BSD-3", "GPLv2", "GPLv3"],
"authors": [
{
"name": "David Grudl",
"homepage": "http://davidgrudl.com"
}
],
"require-dev": {
"nette/tester": "@dev"
},
"replace": {
"dg/dibi": "self.version"
},
"autoload": {
"classmap": ["dibi/"]
}

View File

@@ -11,13 +11,13 @@
/**
* Dibi extension for Nette Framework. Creates 'connection' service.
* Dibi extension for Nette Framework 2.0. Creates 'connection' service.
*
* @author David Grudl
* @package dibi\nette
* @phpversion 5.3
*/
class DibiNetteExtension extends Nette\Config\CompilerExtension
class DibiNette20Extension extends Nette\Config\CompilerExtension
{
public function loadConfiguration()
@@ -46,7 +46,7 @@ class DibiNetteExtension extends Nette\Config\CompilerExtension
$panel = $container->addDefinition($this->prefix('panel'))
->setClass('DibiNettePanel')
->addSetup('Nette\Diagnostics\Debugger::$bar->addPanel(?)', array('@self'))
->addSetup('Nette\Diagnostics\Debugger::$blueScreen->addPanel(?)', array(array('@self', 'renderException')));
->addSetup('Nette\Diagnostics\Debugger::$blueScreen->addPanel(?)', array('DibiNettePanel::renderException'));
$connection->addSetup('$service->onEvent[] = ?', array(array($panel, 'logEvent')));
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
/**
* Dibi extension for Nette Framework 2.1. Creates 'connection' service.
*
* @author David Grudl
* @package dibi\nette
* @phpversion 5.3
*/
class DibiNette21Extension extends Nette\DI\CompilerExtension
{
public function loadConfiguration()
{
$container = $this->getContainerBuilder();
$config = $this->getConfig();
$useProfiler = isset($config['profiler'])
? $config['profiler']
: $container->parameters['debugMode'];
unset($config['profiler']);
if (isset($config['flags'])) {
$flags = 0;
foreach ((array) $config['flags'] as $flag) {
$flags |= constant($flag);
}
$config['flags'] = $flags;
}
$connection = $container->addDefinition($this->prefix('connection'))
->setClass('DibiConnection', array($config));
if ($useProfiler) {
$panel = $container->addDefinition($this->prefix('panel'))
->setClass('DibiNettePanel')
->addSetup('Nette\Diagnostics\Debugger::getBar()->addPanel(?)', array('@self'))
->addSetup('Nette\Diagnostics\Debugger::getBlueScreen()->addPanel(?)', array('DibiNettePanel::renderException'));
$connection->addSetup('$service->onEvent[] = ?', array(array($panel, 'logEvent')));
}
}
}

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -44,13 +48,19 @@ class DibiNettePanel extends DibiObject implements IBarPanel
if (is_callable('Nette\Diagnostics\Debugger::enable') && !class_exists('NDebugger')) {
class_alias('Nette\Diagnostics\Debugger', 'NDebugger'); // PHP 5.2 code compatibility
}
if (is_callable('NDebugger::enable')) {
NDebugger::$bar && NDebugger::$bar->addPanel($this);
NDebugger::$blueScreen && NDebugger::$blueScreen->addPanel(array($this, 'renderException'), __CLASS__);
if (is_callable('NDebugger::enable') && is_callable('NDebugger::getBlueScreen')) { // Nette Framework 2.1
NDebugger::getBar()->addPanel($this);
NDebugger::getBlueScreen()->addPanel(array(__CLASS__, 'renderException'));
$connection->onEvent[] = array($this, 'logEvent');
} elseif (is_callable('Debugger::enable')) {
} elseif (is_callable('NDebugger::enable')) { // Nette Framework 2.0 (for PHP 5.3 or PHP 5.2 prefixed)
NDebugger::$bar && NDebugger::$bar->addPanel($this);
NDebugger::$blueScreen && NDebugger::$blueScreen->addPanel(array(__CLASS__, 'renderException'), __CLASS__);
$connection->onEvent[] = array($this, 'logEvent');
} elseif (is_callable('Debugger::enable') && !is_callable('Debugger::getBlueScreen')) { // Nette Framework 2.0 for PHP 5.2 non-prefixed
Debugger::$bar && Debugger::$bar->addPanel($this);
Debugger::$blueScreen && Debugger::$blueScreen->addPanel(array($this, 'renderException'), __CLASS__);
Debugger::$blueScreen && Debugger::$blueScreen->addPanel(array(__CLASS__, 'renderException'), __CLASS__);
$connection->onEvent[] = array($this, 'logEvent');
}
}
@@ -73,7 +83,7 @@ class DibiNettePanel extends DibiObject implements IBarPanel
* Returns blue-screen custom tab.
* @return mixed
*/
public function renderException($e)
public static function renderException($e)
{
if ($e instanceof DibiException && $e->getSql()) {
return array(
@@ -96,7 +106,7 @@ class DibiNettePanel extends DibiObject implements IBarPanel
}
return '<span title="dibi"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAEYSURBVBgZBcHPio5hGAfg6/2+R980k6wmJgsJ5U/ZOAqbSc2GnXOwUg7BESgLUeIQ1GSjLFnMwsKGGg1qxJRmPM97/1zXFAAAAEADdlfZzr26miup2svnelq7d2aYgt3rebl585wN6+K3I1/9fJe7O/uIePP2SypJkiRJ0vMhr55FLCA3zgIAOK9uQ4MS361ZOSX+OrTvkgINSjS/HIvhjxNNFGgQsbSmabohKDNoUGLohsls6BaiQIMSs2FYmnXdUsygQYmumy3Nhi6igwalDEOJEjPKP7CA2aFNK8Bkyy3fdNCg7r9/fW3jgpVJbDmy5+PB2IYp4MXFelQ7izPrhkPHB+P5/PjhD5gCgCenx+VR/dODEwD+A3T7nqbxwf1HAAAAAElFTkSuQmCC" />'
. count($this->events) . ' queries'
. ($totalTime ? sprintf(' / %0.1f ms', $totalTime * 1000) : '')
. ($totalTime ? ' / ' . sprintf('%0.1f', $totalTime * 1000) . 'ms' : '')
. '</span>';
}
@@ -126,7 +136,7 @@ class DibiNettePanel extends DibiObject implements IBarPanel
if ($explain) {
static $counter;
$counter++;
$s .= "<br /><a href='#' class='nette-toggler' rel='#nette-debug-DibiProfiler-row-$counter'>explain&nbsp;&#x25ba;</a>";
$s .= "<br /><a href='#nette-debug-DibiProfiler-row-$counter' class='nette-toggler nette-toggle-collapsed' rel='#nette-debug-DibiProfiler-row-$counter'>explain</a>";
}
$s .= '</td><td class="nette-DibiProfiler-sql">' . dibi::dump(strlen($event->sql) > self::$maxLength ? substr($event->sql, 0, self::$maxLength) . '...' : $event->sql, TRUE);
@@ -148,7 +158,7 @@ class DibiNettePanel extends DibiObject implements IBarPanel
'<style> #nette-debug td.nette-DibiProfiler-sql { background: white !important }
#nette-debug .nette-DibiProfiler-source { color: #999 !important }
#nette-debug nette-DibiProfiler tr table { margin: 8px 0; max-height: 150px; overflow:auto } </style>
<h1>Queries: ' . count($this->events) . ($totalTime === NULL ? '' : sprintf(', time: %0.3f ms', $totalTime * 1000)) . '</h1>
<h1>Queries: ' . count($this->events) . ($totalTime === NULL ? '' : ', time: ' . sprintf('%0.3f', $totalTime * 1000) . ' ms') . '</h1>
<div class="nette-inner nette-DibiProfiler">
<table>
<tr><th>Time&nbsp;ms</th><th>SQL Statement</th><th>Rows</th><th>Connection</th></tr>' . $s . '

View File

@@ -0,0 +1,17 @@
# Requires Nette Framework 2.0 for PHP 5.3
#
# In bootstrap.php append these lines after line $configurator = new Nette\Config\Configurator;
#
# $configurator->onCompile[] = function($configurator, $compiler) {
# $compiler->addExtension('dibi', new DibiNette20Extension);
# };
#
# This will create service named 'dibi.connection'.
common:
dibi:
host: localhost
username: root
password: ***
database: foo
lazy: TRUE

View File

@@ -0,0 +1,12 @@
# This will create service named 'dibi.connection'.
# Requires Nette Framework 2.1
extensions:
dibi: DibiNette21Extension
dibi:
host: localhost
username: root
password: ***
database: foo
lazy: TRUE

View File

@@ -4,6 +4,9 @@
* dibi - smart database abstraction layer (http://dibiphp.com)
*
* Copyright (c) 2005, 2012 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -14,6 +17,8 @@ if (version_compare(PHP_VERSION, '5.2.0', '<')) {
throw new Exception('dibi needs PHP 5.2.0 or newer.');
}
@set_magic_quotes_runtime(FALSE); // intentionally @
require_once dirname(__FILE__) . '/libs/interfaces.php';
require_once dirname(__FILE__) . '/libs/DibiDateTime.php';
@@ -33,7 +38,7 @@ require_once dirname(__FILE__) . '/libs/DibiEvent.php';
require_once dirname(__FILE__) . '/libs/DibiFileLogger.php';
require_once dirname(__FILE__) . '/libs/DibiFirePhpLogger.php';
if (interface_exists('Nette\Diagnostics\IBarPanel') || interface_exists('IBarPanel')) {
require_once dirname(__FILE__) . '/bridges/Nette-2.0/DibiNettePanel.php';
require_once dirname(__FILE__) . '/bridges/Nette/DibiNettePanel.php';
}
@@ -71,8 +76,8 @@ class dibi
FIELD_TIME = dibi::TIME;
/** version */
const VERSION = '2.0.5',
REVISION = 'released on 2015-01-13';
const VERSION = '2.1.1',
REVISION = '$WCREV$ released on $WCDATE$';
/** sorting order */
const ASC = 'ASC',
@@ -262,7 +267,7 @@ class dibi
/**
* Executes SQL query and fetch results - Monostate for DibiConnection::query() & fetchAll().
* @param array|mixed one or more arguments
* @return DibiRow[]
* @return array of DibiRow
* @throws DibiException
*/
public static function fetchAll($args)
@@ -478,7 +483,7 @@ class dibi
*/
public static function datetime($time = NULL)
{
trigger_error(__METHOD__ . '() is deprecated; create DibiDateTime object instead.', E_USER_WARNING);
trigger_error(__METHOD__ . '() is deprecated; create DateTime object instead.', E_USER_WARNING);
return new DibiDateTime($time);
}
@@ -488,7 +493,7 @@ class dibi
*/
public static function date($date = NULL)
{
trigger_error(__METHOD__ . '() is deprecated; create DibiDateTime object instead.', E_USER_WARNING);
trigger_error(__METHOD__ . '() is deprecated; create DateTime object instead.', E_USER_WARNING);
return new DibiDateTime($date);
}
@@ -570,13 +575,18 @@ class dibi
$sql = wordwrap($sql, 100);
$sql = preg_replace("#([ \t]*\r?\n){2,}#", "\n", $sql);
// syntax highlight
$highlighter = "#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is";
if (PHP_SAPI === 'cli') {
if (substr(getenv('TERM'), 0, 5) === 'xterm') {
$sql = preg_replace_callback($highlighter, array('dibi', 'cliHighlightCallback'), $sql);
}
echo trim($sql) . "\n\n";
} else {
// syntax highlight
$sql = htmlSpecialChars($sql);
$sql = preg_replace_callback("#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is", array('dibi', 'highlightCallback'), $sql);
echo '<pre class="dump">', trim($sql), "</pre>\n";
$sql = preg_replace_callback($highlighter, array('dibi', 'highlightCallback'), $sql);
echo '<pre class="dump">', trim($sql), "</pre>\n\n";
}
}
@@ -604,4 +614,21 @@ class dibi
}
}
private static function cliHighlightCallback($matches)
{
if (!empty($matches[1])) { // comment
return "\033[1;30m" . $matches[1] . "\033[0m";
} elseif (!empty($matches[2])) { // error
return "\033[1;31m" . $matches[2] . "\033[0m";
} elseif (!empty($matches[3])) { // most important keywords
return "\033[1;34m" . $matches[3] . "\033[0m";
} elseif (!empty($matches[4])) { // other keywords
return "\033[1;32m" . $matches[4] . "\033[0m";
}
}
}

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -66,11 +70,13 @@ class DibiFirebirdDriver extends DibiObject implements IDibiDriver, IDibiResultD
} else {
// default values
if (!isset($config['username'])) $config['username'] = ini_get('ibase.default_password');
if (!isset($config['password'])) $config['password'] = ini_get('ibase.default_user');
if (!isset($config['database'])) $config['database'] = ini_get('ibase.default_db');
if (!isset($config['charset'])) $config['charset'] = ini_get('ibase.default_charset');
if (!isset($config['buffers'])) $config['buffers'] = 0;
$config += array(
'username' => ini_get('ibase.default_password'),
'password' => ini_get('ibase.default_user'),
'database' => ini_get('ibase.default_db'),
'charset' => ini_get('ibase.default_charset'),
'buffers' => 0,
);
DibiDriverException::tryError();
if (empty($config['persistent'])) {
@@ -346,7 +352,7 @@ class DibiFirebirdDriver extends DibiObject implements IDibiDriver, IDibiResultD
*/
public function getRowCount()
{
return ibase_num_fields($this->resultSet);
throw new DibiNotSupportedException("Firebird/Interbase do not support returning number of rows in result set.");
}
@@ -362,7 +368,7 @@ class DibiFirebirdDriver extends DibiObject implements IDibiDriver, IDibiResultD
if (DibiDriverException::catchError($msg)) {
if (ibase_errcode() == self::ERROR_EXCEPTION_THROWN) {
preg_match('/exception (\d+) (\w+) (.*)/i', ibase_errmsg(), $match);
preg_match('/exception (\d+) (\w+) (.*)/is', ibase_errmsg(), $match);
throw new DibiProcedureException($match[3], $match[1], $match[2], dibi::$sql);
} else {

View File

@@ -2,10 +2,17 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/DibiMsSql2005Reflector.php';
/**
* The dibi driver for MS SQL Driver 2005 database.
*
@@ -64,6 +71,11 @@ class DibiMsSql2005Driver extends DibiObject implements IDibiDriver, IDibiResult
$this->connection = $config['resource'];
} else {
// Default values
if (!isset($config['options']['CharacterSet'])) {
$config['options']['CharacterSet'] = 'UTF-8';
}
$this->connection = sqlsrv_connect($config['host'], (array) $config['options']);
}
@@ -183,7 +195,7 @@ class DibiMsSql2005Driver extends DibiObject implements IDibiDriver, IDibiResult
*/
public function getReflector()
{
throw new DibiNotSupportedException;
return new DibiMssql2005Reflector($this);
}
@@ -219,7 +231,7 @@ class DibiMsSql2005Driver extends DibiObject implements IDibiDriver, IDibiResult
case dibi::IDENTIFIER:
// @see http://msdn.microsoft.com/en-us/library/ms176027.aspx
return '[' . str_replace(array('[', ']'), array('[[', ']]'), $value) . ']';
return '[' . str_replace(']', ']]', $value) . ']';
case dibi::BOOL:
return $value ? 1 : 0;
@@ -273,7 +285,7 @@ class DibiMsSql2005Driver extends DibiObject implements IDibiDriver, IDibiResult
{
// offset support is missing
if ($limit >= 0) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') AS T ';
}
if ($offset) {

View File

@@ -0,0 +1,137 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
/**
* The dibi reflector for MSSQL2005 databases.
*
* @author Daniel Kouba
* @package dibi\drivers
* @internal
*/
class DibiMsSql2005Reflector extends DibiObject implements IDibiReflector
{
/** @var IDibiDriver */
private $driver;
public function __construct(IDibiDriver $driver)
{
$this->driver = $driver;
}
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$res = $this->driver->query('SELECT TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES');
$tables = array();
while ($row = $res->fetch(FALSE)) {
$tables[] = array(
'name' => $row[0],
'view' => isset($row[1]) && $row[1] === 'VIEW',
);
}
return $tables;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$res = $this->driver->query("
SELECT c.name as COLUMN_NAME, c.is_identity AS AUTO_INCREMENT
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
WHERE t.name = {$this->driver->escape($table, dibi::TEXT)}
");
$autoIncrements = array();
while ($row = $res->fetch(TRUE)) {
$autoIncrements[$row['COLUMN_NAME']] = (bool) $row['AUTO_INCREMENT'];
}
$res = $this->driver->query("
SELECT C.COLUMN_NAME, C.DATA_TYPE, C.CHARACTER_MAXIMUM_LENGTH , C.COLUMN_DEFAULT , C.NUMERIC_PRECISION, C.NUMERIC_SCALE , C.IS_NULLABLE, Case When Z.CONSTRAINT_NAME Is Null Then 0 Else 1 End As IsPartOfPrimaryKey
FROM INFORMATION_SCHEMA.COLUMNS As C
Outer Apply (
SELECT CCU.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS As TC
Join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE As CCU
On CCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
WHERE TC.TABLE_SCHEMA = C.TABLE_SCHEMA
And TC.TABLE_NAME = C.TABLE_NAME
And TC.CONSTRAINT_TYPE = 'PRIMARY KEY'
And CCU.COLUMN_NAME = C.COLUMN_NAME
) As Z
WHERE C.TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}
");
$columns = array();
while ($row = $res->fetch(TRUE)) {
$columns[] = array(
'name' => $row['COLUMN_NAME'],
'table' => $table,
'nativetype' => strtoupper($row['DATA_TYPE']),
'size' => $row['CHARACTER_MAXIMUM_LENGTH'],
'unsigned' => TRUE,
'nullable' => $row['IS_NULLABLE'] === 'YES',
'default' => $row['COLUMN_DEFAULT'],
'autoincrement' => $autoIncrements[$row['COLUMN_NAME']],
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$keyUsagesRes = $this->driver->query("SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}");
$keyUsages = array();
while( $row = $keyUsagesRes->fetch(TRUE) ) {
$keyUsages[$row['CONSTRAINT_NAME']][(int) $row['ORDINAL_POSITION'] - 1] = $row['COLUMN_NAME'];
}
$res = $this->driver->query("SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}");
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$indexes[$row['CONSTRAINT_NAME']]['name'] = $row['CONSTRAINT_NAME'];
$indexes[$row['CONSTRAINT_NAME']]['unique'] = $row['CONSTRAINT_TYPE'] === 'UNIQUE';
$indexes[$row['CONSTRAINT_NAME']]['primary'] = $row['CONSTRAINT_TYPE'] === 'PRIMARY KEY';
$indexes[$row['CONSTRAINT_NAME']]['columns'] = isset($keyUsages[$row['CONSTRAINT_NAME']]) ? $keyUsages[$row['CONSTRAINT_NAME']] : array();
}
return array_values($indexes);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new DibiNotImplementedException;
}
}

View File

@@ -2,10 +2,14 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/mssql.reflector.php';
require_once dirname(__FILE__) . '/DibiMsSqlReflector.php';
/**
* The dibi driver for MS SQL database.

View File

@@ -1,216 +1,219 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005, 2010 David Grudl (http://davidgrudl.com)
*
* @package dibi\drivers
*/
/**
* The dibi reflector for MsSQL databases.
*
* @author Steven Bredenberg
* @package dibi\drivers
* @internal
*/
class DibiMsSqlReflector extends DibiObject implements IDibiReflector
{
/** @var IDibiDriver */
private $driver;
public function __construct(IDibiDriver $driver)
{
$this->driver = $driver;
}
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$res = $this->driver->query("
SELECT TABLE_NAME, TABLE_TYPE
FROM INFORMATION_SCHEMA.TABLES
");
$tables = array();
while ($row = $res->fetch(FALSE)) {
$tables[] = array(
'name' => $row[0],
'view' => isset($row[1]) && $row[1] === 'VIEW',
);
}
return $tables;
}
/**
* Returns count of rows in a table
* @param string
* @return integer
*/
public function getTableCount($table, $fallback=true)
{
if (empty($table)) {
return false;
}
$result = $this->driver->query("
SELECT MAX(rowcnt)
FROM sys.sysindexes
WHERE id=OBJECT_ID({$this->driver->escape($table, dibi::IDENTIFIER)})
");
$row = $result->fetch(FALSE);
if (!is_array($row) || count($row) < 1) {
if ($fallback) {
$row = $this->driver->query("SELECT COUNT(*) FROM {$this->driver->escape($table, dibi::IDENTIFIER)}")->fetch(FALSE);
$count = intval($row[0]);
} else {
$count = false;
}
} else {
$count = intval($row[0]);
}
return $count;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$res = $this->driver->query("
SELECT * FROM
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}
ORDER BY TABLE_NAME, ORDINAL_POSITION
");
$columns = array();
while ($row = $res->fetch(TRUE)) {
$size = false;
$type = strtoupper($row['DATA_TYPE']);
$size_cols = array(
'DATETIME'=>'DATETIME_PRECISION',
'DECIMAL'=>'NUMERIC_PRECISION',
'CHAR'=>'CHARACTER_MAXIMUM_LENGTH',
'NCHAR'=>'CHARACTER_OCTET_LENGTH',
'NVARCHAR'=>'CHARACTER_OCTET_LENGTH',
'VARCHAR'=>'CHARACTER_OCTET_LENGTH'
);
if (isset($size_cols[$type])) {
if ($size_cols[$type]) {
$size = $row[$size_cols[$type]];
}
}
$columns[] = array(
'name' => $row['COLUMN_NAME'],
'table' => $table,
'nativetype' => $type,
'size' => $size,
'unsigned' => NULL,
'nullable' => $row['IS_NULLABLE'] === 'YES',
'default' => $row['COLUMN_DEFAULT'],
'autoincrement' => false,
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$res = $this->driver->query(
"SELECT ind.name index_name, ind.index_id, ic.index_column_id,
col.name column_name, ind.is_unique, ind.is_primary_key
FROM sys.indexes ind
INNER JOIN sys.index_columns ic ON
(ind.object_id = ic.object_id AND ind.index_id = ic.index_id)
INNER JOIN sys.columns col ON
(ic.object_id = col.object_id and ic.column_id = col.column_id)
INNER JOIN sys.tables t ON
(ind.object_id = t.object_id)
WHERE t.name = {$this->driver->escape($table, dibi::TEXT)}
AND t.is_ms_shipped = 0
ORDER BY
t.name, ind.name, ind.index_id, ic.index_column_id
");
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$index_name = $row['index_name'];
if (!isset($indexes[$index_name])) {
$indexes[$index_name] = array();
$indexes[$index_name]['name'] = $index_name;
$indexes[$index_name]['unique'] = (bool)$row['is_unique'];
$indexes[$index_name]['primary'] = (bool)$row['is_primary_key'];
$indexes[$index_name]['columns'] = array();
}
$indexes[$index_name]['columns'][] = $row['column_name'];
}
return array_values($indexes);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
$res = $this->driver->query("
SELECT f.name AS foreign_key,
OBJECT_NAME(f.parent_object_id) AS table_name,
COL_NAME(fc.parent_object_id,
fc.parent_column_id) AS column_name,
OBJECT_NAME (f.referenced_object_id) AS reference_table_name,
COL_NAME(fc.referenced_object_id,
fc.referenced_column_id) AS reference_column_name,
fc.*
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id
WHERE OBJECT_NAME(f.parent_object_id) = {$this->driver->escape($table, dibi::TEXT)}
");
$keys = array();
while ($row = $res->fetch(TRUE)) {
$key_name = $row['foreign_key'];
if (!isset($keys[$key_name])) {
$keys[$key_name]['name'] = $row['foreign_key']; // foreign key name
$keys[$key_name]['local'] = array($row['column_name']); // local columns
$keys[$key_name]['table'] = $row['reference_table_name']; // referenced table
$keys[$key_name]['foreign'] = array($row['reference_column_name']); // referenced columns
$keys[$key_name]['onDelete'] = false;
$keys[$key_name]['onUpdate'] = false;
} else {
$keys[$key_name]['local'][] = $row['column_name']; // local columns
$keys[$key_name]['foreign'][] = $row['reference_column_name']; // referenced columns
}
}
return array_values($keys);
}
}
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005, 2010 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*
* @package dibi\drivers
*/
/**
* The dibi reflector for MsSQL databases.
*
* @author Steven Bredenberg
* @package dibi\drivers
* @internal
*/
class DibiMsSqlReflector extends DibiObject implements IDibiReflector
{
/** @var IDibiDriver */
private $driver;
public function __construct(IDibiDriver $driver)
{
$this->driver = $driver;
}
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$res = $this->driver->query("
SELECT TABLE_NAME, TABLE_TYPE
FROM INFORMATION_SCHEMA.TABLES
");
$tables = array();
while ($row = $res->fetch(FALSE)) {
$tables[] = array(
'name' => $row[0],
'view' => isset($row[1]) && $row[1] === 'VIEW',
);
}
return $tables;
}
/**
* Returns count of rows in a table
* @param string
* @return integer
*/
public function getTableCount($table, $fallback=true)
{
if (empty($table)) {
return false;
}
$result = $this->driver->query("
SELECT MAX(rowcnt)
FROM sys.sysindexes
WHERE id=OBJECT_ID({$this->driver->escape($table, dibi::IDENTIFIER)})
");
$row = $result->fetch(FALSE);
if (!is_array($row) || count($row) < 1) {
if ($fallback) {
$row = $this->driver->query("SELECT COUNT(*) FROM {$this->driver->escape($table, dibi::IDENTIFIER)}")->fetch(FALSE);
$count = intval($row[0]);
} else {
$count = false;
}
} else {
$count = intval($row[0]);
}
return $count;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$res = $this->driver->query("
SELECT * FROM
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = {$this->driver->escape($table, dibi::TEXT)}
ORDER BY TABLE_NAME, ORDINAL_POSITION
");
$columns = array();
while ($row = $res->fetch(TRUE)) {
$size = false;
$type = strtoupper($row['DATA_TYPE']);
$size_cols = array(
'DATETIME'=>'DATETIME_PRECISION',
'DECIMAL'=>'NUMERIC_PRECISION',
'CHAR'=>'CHARACTER_MAXIMUM_LENGTH',
'NCHAR'=>'CHARACTER_OCTET_LENGTH',
'NVARCHAR'=>'CHARACTER_OCTET_LENGTH',
'VARCHAR'=>'CHARACTER_OCTET_LENGTH'
);
if (isset($size_cols[$type])) {
if ($size_cols[$type]) {
$size = $row[$size_cols[$type]];
}
}
$columns[] = array(
'name' => $row['COLUMN_NAME'],
'table' => $table,
'nativetype' => $type,
'size' => $size,
'unsigned' => NULL,
'nullable' => $row['IS_NULLABLE'] === 'YES',
'default' => $row['COLUMN_DEFAULT'],
'autoincrement' => false,
'vendor' => $row,
);
}
return $columns;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$res = $this->driver->query(
"SELECT ind.name index_name, ind.index_id, ic.index_column_id,
col.name column_name, ind.is_unique, ind.is_primary_key
FROM sys.indexes ind
INNER JOIN sys.index_columns ic ON
(ind.object_id = ic.object_id AND ind.index_id = ic.index_id)
INNER JOIN sys.columns col ON
(ic.object_id = col.object_id and ic.column_id = col.column_id)
INNER JOIN sys.tables t ON
(ind.object_id = t.object_id)
WHERE t.name = {$this->driver->escape($table, dibi::TEXT)}
AND t.is_ms_shipped = 0
ORDER BY
t.name, ind.name, ind.index_id, ic.index_column_id
");
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$index_name = $row['index_name'];
if (!isset($indexes[$index_name])) {
$indexes[$index_name] = array();
$indexes[$index_name]['name'] = $index_name;
$indexes[$index_name]['unique'] = (bool)$row['is_unique'];
$indexes[$index_name]['primary'] = (bool)$row['is_primary_key'];
$indexes[$index_name]['columns'] = array();
}
$indexes[$index_name]['columns'][] = $row['column_name'];
}
return array_values($indexes);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
$res = $this->driver->query("
SELECT f.name AS foreign_key,
OBJECT_NAME(f.parent_object_id) AS table_name,
COL_NAME(fc.parent_object_id,
fc.parent_column_id) AS column_name,
OBJECT_NAME (f.referenced_object_id) AS reference_table_name,
COL_NAME(fc.referenced_object_id,
fc.referenced_column_id) AS reference_column_name,
fc.*
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id
WHERE OBJECT_NAME(f.parent_object_id) = {$this->driver->escape($table, dibi::TEXT)}
");
$keys = array();
while ($row = $res->fetch(TRUE)) {
$key_name = $row['foreign_key'];
if (!isset($keys[$key_name])) {
$keys[$key_name]['name'] = $row['foreign_key']; // foreign key name
$keys[$key_name]['local'] = array($row['column_name']); // local columns
$keys[$key_name]['table'] = $row['reference_table_name']; // referenced table
$keys[$key_name]['foreign'] = array($row['reference_column_name']); // referenced columns
$keys[$key_name]['onDelete'] = false;
$keys[$key_name]['onUpdate'] = false;
} else {
$keys[$key_name]['local'][] = $row['column_name']; // local columns
$keys[$key_name]['foreign'][] = $row['reference_column_name']; // referenced columns
}
}
return array_values($keys);
}
}

View File

@@ -2,11 +2,15 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/mysql.reflector.php';
require_once dirname(__FILE__) . '/DibiMySqlReflector.php';
/**
@@ -73,9 +77,12 @@ class DibiMySqlDriver extends DibiObject implements IDibiDriver, IDibiResultDriv
} else {
// default values
DibiConnection::alias($config, 'flags', 'options');
if (!isset($config['charset'])) $config['charset'] = 'utf8';
if (!isset($config['username'])) $config['username'] = ini_get('mysql.default_user');
if (!isset($config['password'])) $config['password'] = ini_get('mysql.default_password');
$config += array(
'charset' => 'utf8',
'timezone' => date('P'),
'username' => ini_get('mysql.default_user'),
'password' => ini_get('mysql.default_password'),
);
if (!isset($config['host'])) {
$host = ini_get('mysql.default_host');
if ($host) {
@@ -127,7 +134,9 @@ class DibiMySqlDriver extends DibiObject implements IDibiDriver, IDibiResultDriv
$this->query("SET sql_mode='$config[sqlmode]'");
}
$this->query("SET time_zone='" . date('P') . "'");
if (isset($config['timezone'])) {
$this->query("SET time_zone='$config[timezone]'");
}
$this->buffered = empty($config['unbuffered']);
}

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,11 +2,15 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/mysql.reflector.php';
require_once dirname(__FILE__) . '/DibiMySqlReflector.php';
/**
@@ -74,11 +78,14 @@ class DibiMySqliDriver extends DibiObject implements IDibiDriver, IDibiResultDri
} else {
// default values
if (!isset($config['charset'])) $config['charset'] = 'utf8';
if (!isset($config['username'])) $config['username'] = ini_get('mysqli.default_user');
if (!isset($config['password'])) $config['password'] = ini_get('mysqli.default_pw');
if (!isset($config['socket'])) $config['socket'] = ini_get('mysqli.default_socket');
if (!isset($config['port'])) $config['port'] = NULL;
$config += array(
'charset' => 'utf8',
'timezone' => date('P'),
'username' => ini_get('mysqli.default_user'),
'password' => ini_get('mysqli.default_pw'),
'socket' => ini_get('mysqli.default_socket'),
'port' => NULL,
);
if (!isset($config['host'])) {
$host = ini_get('mysqli.default_host');
if ($host) {
@@ -126,7 +133,9 @@ class DibiMySqliDriver extends DibiObject implements IDibiDriver, IDibiResultDri
$this->query("SET sql_mode='$config[sqlmode]'");
}
$this->query("SET time_zone='" . date('P') . "'");
if (isset($config['timezone'])) {
$this->query("SET time_zone='$config[timezone]'");
}
$this->buffered = empty($config['unbuffered']);
}
@@ -452,7 +461,7 @@ class DibiMySqliDriver extends DibiObject implements IDibiDriver, IDibiResultDri
public function getResultResource()
{
$this->autoFree = FALSE;
return $this->resultSet === NULL || $this->resultSet->type === NULL ? NULL : $this->resultSet;
return @$this->resultSet->type === NULL ? NULL : $this->resultSet;
}
}

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -60,9 +64,11 @@ class DibiOdbcDriver extends DibiObject implements IDibiDriver, IDibiResultDrive
$this->connection = $config['resource'];
} else {
// default values
if (!isset($config['username'])) $config['username'] = ini_get('odbc.default_user');
if (!isset($config['password'])) $config['password'] = ini_get('odbc.default_pw');
if (!isset($config['dsn'])) $config['dsn'] = ini_get('odbc.default_db');
$config += array(
'username' => ini_get('odbc.default_user'),
'password' => ini_get('odbc.default_pw'),
'dsn' => ini_get('odbc.default_db'),
);
if (empty($config['persistent'])) {
$this->connection = @odbc_connect($config['dsn'], $config['username'], $config['password']); // intentionally @

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -17,6 +21,7 @@
* - formatDate => how to format date in SQL (@see date)
* - formatDateTime => how to format datetime in SQL (@see date)
* - resource (resource) => existing connection resource
* - persistent => Creates persistent connections with oci_pconnect instead of oci_new_connect
* - lazy, profiler, result, substitutes, ... => see DibiConnection options
*
* @author David Grudl
@@ -64,8 +69,10 @@ class DibiOracleDriver extends DibiObject implements IDibiDriver, IDibiResultDri
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
} elseif (empty($config['persistent'])) {
$this->connection = @oci_new_connect($config['username'], $config['password'], $config['database'], $config['charset']); // intentionally @
} else {
$this->connection = @oci_pconnect($config['username'], $config['password'], $config['database'], $config['charset']); // intentionally @
}
if (!$this->connection) {
@@ -281,7 +288,9 @@ class DibiOracleDriver extends DibiObject implements IDibiDriver, IDibiResultDri
{
if ($offset > 0) {
// see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
$sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t ' . ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '') . ') WHERE "__rnum" > '. (int) $offset;
$sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t '
. ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '')
. ') WHERE "__rnum" > '. (int) $offset;
} elseif ($limit >= 0) {
$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit;

View File

@@ -2,12 +2,16 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/mysql.reflector.php';
require_once dirname(__FILE__) . '/sqlite.reflector.php';
require_once dirname(__FILE__) . '/DibiMySqlReflector.php';
require_once dirname(__FILE__) . '/DibiSqliteReflector.php';
/**
@@ -255,7 +259,6 @@ class DibiPdoDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
case 'mysql':
return '`' . str_replace('`', '``', $value) . '`';
case 'oci':
case 'pgsql':
return '"' . str_replace('"', '""', $value) . '"';
@@ -264,9 +267,13 @@ class DibiPdoDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
return '[' . strtr($value, '[]', ' ') . ']';
case 'odbc':
case 'oci': // TODO: not tested
case 'mssql':
return '[' . str_replace(array('[', ']'), array('[[', ']]'), $value) . ']';
case 'sqlsrv':
return '[' . str_replace(']', ']]', $value) . ']';
default:
return $value;
}
@@ -346,7 +353,9 @@ class DibiPdoDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
case 'oci':
if ($offset > 0) {
$sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t ' . ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '') . ') WHERE "__rnum" > '. (int) $offset;
$sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t '
. ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '')
. ') WHERE "__rnum" > '. (int) $offset;
} elseif ($limit >= 0) {
$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit;
}
@@ -354,8 +363,9 @@ class DibiPdoDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
case 'odbc':
case 'mssql':
case 'sqlsrv':
if ($offset < 1) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t';
break;
}
// intentionally break omitted

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -61,7 +65,9 @@ class DibiPostgreDriver extends DibiObject implements IDibiDriver, IDibiResultDr
$this->connection = $config['resource'];
} else {
if (!isset($config['charset'])) $config['charset'] = 'utf8';
$config += array(
'charset' => 'utf8',
);
if (isset($config['string'])) {
$string = $config['string'];
} else {
@@ -314,7 +320,7 @@ class DibiPostgreDriver extends DibiObject implements IDibiDriver, IDibiResultDr
$value = pg_escape_string($this->connection, $value);
} else {
$value = pg_escape_string($value);
}
}
$value = strtr($value, array( '%' => '\\\\%', '_' => '\\\\_'));
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
@@ -480,7 +486,7 @@ class DibiPostgreDriver extends DibiObject implements IDibiDriver, IDibiResultDr
*/
public function getColumns($table)
{
$_table = $this->escape($this->escape($table, dibi::IDENTIFIER), dibi::TEXT);
$_table = $this->escape($table, dibi::TEXT);
$res = $this->query("
SELECT indkey
FROM pg_class
@@ -520,7 +526,7 @@ class DibiPostgreDriver extends DibiObject implements IDibiDriver, IDibiResultDr
*/
public function getIndexes($table)
{
$_table = $this->escape($this->escape($table, dibi::IDENTIFIER), dibi::TEXT);
$_table = $this->escape($table, dibi::TEXT);
$res = $this->query("
SELECT ordinal_position, column_name
FROM information_schema.columns
@@ -561,7 +567,7 @@ class DibiPostgreDriver extends DibiObject implements IDibiDriver, IDibiResultDr
*/
public function getForeignKeys($table)
{
$_table = $this->escape($this->escape($table, dibi::IDENTIFIER), dibi::TEXT);
$_table = $this->escape($table, dibi::TEXT);
$res = $this->query("
SELECT

View File

@@ -2,11 +2,15 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/sqlite.reflector.php';
require_once dirname(__FILE__) . '/DibiSqliteReflector.php';
/**
@@ -281,7 +285,7 @@ class DibiSqlite3Driver extends DibiObject implements IDibiDriver, IDibiResultDr
public function applyLimit(& $sql, $limit, $offset)
{
if ($limit >= 0 || $offset > 0) {
$sql .= ' LIMIT ' . $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
$sql .= ' LIMIT ' . (int) $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
}
}

View File

@@ -2,11 +2,15 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/sqlite.reflector.php';
require_once dirname(__FILE__) . '/DibiSqliteReflector.php';
/**
@@ -285,7 +289,7 @@ class DibiSqliteDriver extends DibiObject implements IDibiDriver, IDibiResultDri
public function applyLimit(& $sql, $limit, $offset)
{
if ($limit >= 0 || $offset > 0) {
$sql .= ' LIMIT ' . $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
$sql .= ' LIMIT ' . (int) $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
}
}

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -83,10 +87,10 @@ class DibiConnection extends DibiObject
$config['driver'] = dibi::$defaultDriver;
}
$driver = preg_replace('#[^a-z0-9_]#', '_', strtolower($config['driver']));
$class = "Dibi" . $driver . "Driver";
$class = preg_replace(array('#\W#', '#sql#'), array('_', 'Sql'), ucfirst(strtolower($config['driver'])));
$class = "Dibi{$class}Driver";
if (!class_exists($class, FALSE)) {
include_once dirname(__FILE__) . "/../drivers/$driver.php";
include_once dirname(__FILE__) . "/../drivers/$class.php";
if (!class_exists($class, FALSE)) {
throw new DibiException("Unable to create instance of dibi driver '$class'.");
@@ -586,7 +590,7 @@ class DibiConnection extends DibiObject
/**
* Executes SQL query and fetch results - shortcut for query() & fetchAll().
* @param array|mixed one or more arguments
* @return DibiRow[]
* @return array of DibiRow
* @throws DibiException
*/
public function fetchAll($args)

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -45,7 +49,7 @@ class DibiDatabaseInfo extends DibiObject
/**
* @return DibiTableInfo[]
* @return array of DibiTableInfo
*/
public function getTables()
{
@@ -55,7 +59,7 @@ class DibiDatabaseInfo extends DibiObject
/**
* @return string[]
* @return array of string
*/
public function getTableNames()
{
@@ -177,7 +181,7 @@ class DibiTableInfo extends DibiObject
/**
* @return DibiColumnInfo[]
* @return array of DibiColumnInfo
*/
public function getColumns()
{
@@ -187,7 +191,7 @@ class DibiTableInfo extends DibiObject
/**
* @return string[]
* @return array of string
*/
public function getColumnNames()
{
@@ -229,7 +233,7 @@ class DibiTableInfo extends DibiObject
/**
* @return DibiForeignKeyInfo[]
* @return array of DibiForeignKeyInfo
*/
public function getForeignKeys()
{
@@ -239,7 +243,7 @@ class DibiTableInfo extends DibiObject
/**
* @return DibiIndexInfo[]
* @return array of DibiIndexInfo
*/
public function getIndexes()
{
@@ -332,7 +336,7 @@ class DibiResultInfo extends DibiObject
/**
* @return DibiColumnInfo[]
* @return array of DibiColumnInfo
*/
public function getColumns()
{
@@ -343,7 +347,7 @@ class DibiResultInfo extends DibiObject
/**
* @param bool
* @return string[]
* @return array of string
*/
public function getColumnNames($fullNames = FALSE)
{
@@ -569,13 +573,13 @@ class DibiColumnInfo extends DibiObject
static $patterns = array(
'^_' => dibi::TEXT, // PostgreSQL arrays
'BYTEA|BLOB|BIN' => dibi::BINARY,
'TEXT|CHAR' => dibi::TEXT,
'YEAR|BYTE|COUNTER|SERIAL|INT|LONG' => dibi::INTEGER,
'TEXT|CHAR|POINT|INTERVAL' => dibi::TEXT,
'YEAR|BYTE|COUNTER|SERIAL|INT|LONG|SHORT' => dibi::INTEGER,
'CURRENCY|REAL|MONEY|FLOAT|DOUBLE|DECIMAL|NUMERIC|NUMBER' => dibi::FLOAT,
'^TIME$' => dibi::TIME,
'TIME' => dibi::DATETIME, // DATETIME, TIMESTAMP
'DATE' => dibi::DATE,
'BOOL|BIT' => dibi::BOOL,
'BOOL' => dibi::BOOL,
);
foreach ($patterns as $s => $val) {

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -60,7 +64,7 @@ class DibiFileLogger extends DibiObject
fwrite($handle,
"OK: " . $event->sql
. ($event->count ? ";\n-- rows: " . $event->count : '')
. "\n-- takes: " . sprintf('%0.3f ms', $event->time * 1000)
. "\n-- takes: " . sprintf('%0.3f', $event->time * 1000) . ' ms'
. "\n-- source: " . implode(':', $event->source)
. "\n-- driver: " . $event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
. "\n-- " . date('Y-m-d H:i:s')

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -10,7 +14,6 @@
* SQL literal value.
*
* @author David Grudl
* @package dibi
*/
class DibiLiteral extends DibiObject
{

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -49,6 +53,9 @@ class DibiResult extends DibiObject implements IDataSource
/** @var string returned object class */
private $rowClass = 'DibiRow';
/** @var Callback returned object factory*/
private $rowFactory;
/** @var array format */
private $formats = array();
@@ -184,6 +191,18 @@ class DibiResult extends DibiObject implements IDataSource
}
/**
* Set a factory to create fetched object instances. These should extend the DibiRow class.
* @param callback
* @return self
*/
public function setRowFactory($callback)
{
$this->rowFactory = $callback;
return $this;
}
/**
* Fetches the row at current position, process optional type conversion.
* and moves the internal cursor to the next position
@@ -197,7 +216,9 @@ class DibiResult extends DibiObject implements IDataSource
}
$this->fetched = TRUE;
$this->normalize($row);
if ($this->rowClass) {
if ($this->rowFactory) {
return call_user_func($this->rowFactory, $row);
} elseif ($this->rowClass) {
$row = new $this->rowClass($row);
}
return $row;
@@ -224,7 +245,7 @@ class DibiResult extends DibiObject implements IDataSource
* Fetches all records from table.
* @param int offset
* @param int limit
* @return DibiRow[]
* @return array of DibiRow
*/
final public function fetchAll($offset = NULL, $limit = NULL)
{
@@ -454,7 +475,7 @@ class DibiResult extends DibiObject implements IDataSource
}
do {
$data[ $row[$key] ] = $row[$value];
$data[ (string) $row[$key] ] = $row[$value];
} while ($row = $this->fetch());
return $data;
@@ -497,7 +518,7 @@ class DibiResult extends DibiObject implements IDataSource
$row[$key] = is_float($tmp = $value * 1) ? $value : $tmp;
} elseif ($type === dibi::FLOAT) {
$row[$key] = ltrim((string) ($tmp = (float) $value), '0') === ltrim(rtrim(rtrim($value, '0'), '.'), '0') ? $tmp : $value;
$row[$key] = (string) ($tmp = (float) $value) === rtrim(rtrim($value, '0'), '.') ? $tmp : $value;
} elseif ($type === dibi::BOOL) {
$row[$key] = ((bool) $value) && $value !== 'f' && $value !== 'F';
@@ -609,37 +630,70 @@ class DibiResult extends DibiObject implements IDataSource
/**
* Displays complete result set as HTML table for debug purposes.
* Displays complete result set as HTML or text table for debug purposes.
* @return void
*/
final public function dump()
{
$i = 0;
$this->seek(0);
while ($row = $this->fetch()) {
if ($i === 0) {
echo "\n<table class=\"dump\">\n<thead>\n\t<tr>\n\t\t<th>#row</th>\n";
foreach ($row as $col => $foo) {
echo "\t\t<th>" . htmlSpecialChars($col) . "</th>\n";
if (PHP_SAPI === 'cli') {
$hasColors = (substr(getenv('TERM'), 0, 5) === 'xterm');
$maxLen = 0;
while ($row = $this->fetch()) {
if ($i === 0) {
foreach ($row as $col => $foo) {
$len = mb_strlen($col);
$maxLen = max($len, $maxLen);
}
}
echo "\t</tr>\n</thead>\n<tbody>\n";
if ($hasColors) {
echo "\033[1;37m#row: $i\033[0m\n";
} else {
echo "#row: $i\n";
}
foreach ($row as $col => $val) {
$spaces = $maxLen - mb_strlen($col) + 2;
echo "$col" . str_repeat(" ", $spaces) . "$val\n";
}
echo "\n";
$i++;
}
echo "\t<tr>\n\t\t<th>", $i, "</th>\n";
foreach ($row as $col) {
//if (is_object($col)) $col = $col->__toString();
echo "\t\t<td>", htmlSpecialChars($col), "</td>\n";
if ($i === 0) {
echo "empty result set\n";
}
echo "\t</tr>\n";
$i++;
}
echo "\n";
if ($i === 0) {
echo '<p><em>empty result set</em></p>';
} else {
echo "</tbody>\n</table>\n";
while ($row = $this->fetch()) {
if ($i === 0) {
echo "\n<table class=\"dump\">\n<thead>\n\t<tr>\n\t\t<th>#row</th>\n";
foreach ($row as $col => $foo) {
echo "\t\t<th>" . htmlSpecialChars($col) . "</th>\n";
}
echo "\t</tr>\n</thead>\n<tbody>\n";
}
echo "\t<tr>\n\t\t<th>", $i, "</th>\n";
foreach ($row as $col) {
//if (is_object($col)) $col = $col->__toString();
echo "\t\t<td>", htmlSpecialChars($col), "</td>\n";
}
echo "\t</tr>\n";
$i++;
}
if ($i === 0) {
echo '<p><em>empty result set</em></p>';
} else {
echo "</tbody>\n</table>\n";
}
}
}

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/
@@ -39,7 +43,7 @@ class DibiRow implements ArrayAccess, IteratorAggregate, Countable
{
$time = $this[$key];
if (!$time instanceof DibiDateTime) {
if ((int) $time === 0 && substr((string) $time, 0, 3) !== '00:') { // '', NULL, FALSE, '0000-00-00', ...
if ((int) $time === 0) { // '', NULL, FALSE, '0000-00-00', ...
return NULL;
}
$time = new DibiDateTime(is_numeric($time) ? date('Y-m-d H:i:s', $time) : $time);
@@ -56,7 +60,10 @@ class DibiRow implements ArrayAccess, IteratorAggregate, Countable
public function asTimestamp($key)
{
trigger_error(__METHOD__ . '() is deprecated.', E_USER_WARNING);
return $this->asDateTime($key, 'U');
$time = $this[$key];
return (int) $time === 0 // '', NULL, FALSE, '0000-00-00', ...
? NULL
: (is_numeric($time) ? (int) $time : strtotime($time));
}

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -2,7 +2,11 @@
/**
* This file is part of the "dibi" - smart database abstraction layer.
*
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
*
* For the full copyright and license information, please view
* the file license.txt that was distributed with this source code.
*/

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
// connects to SQlite using dibi class

BIN
examples/data/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
dibi::connect(array(

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
dibi::connect(array(

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
ndebug();

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
dibi::connect(array(

View File

@@ -10,8 +10,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
// enable Nette Debugger

View File

@@ -1,5 +1,7 @@
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<style> html { background: url(data/arrow.png) no-repeat bottom right; height: 100%; } </style>
<h1>Nette Debugger & Variables | dibi</h1>
<p>Dibi can dump variables via Nette Debugger, part of Nette Framework.</p>
@@ -10,8 +12,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
// enable Nette Debugger

View File

@@ -4,13 +4,13 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'data/sample.sdb',
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));
@@ -53,3 +53,10 @@ dibi::test('
%else 1 LIMIT 10 %end'
);
// -> SELECT * FROM customers WHERE LIMIT 10
// IF()
dibi::test('UPDATE products SET', array(
'price' => array('IF(price_fixed, price, ?)', 123),
));
// -> SELECT * FROM customers WHERE LIMIT 10

View File

@@ -4,15 +4,15 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'data/sample.sdb',
'driver' => 'sqlite3',
'database' => 'data/sample.s3db',
));

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
ndebug();
date_default_timezone_set('Europe/Prague');
@@ -27,11 +27,10 @@ $res->setType('customer_id', Dibi::INTEGER)
dump( $res->fetch() );
// outputs:
// object(DibiRow)#3 (3) {
// customer_id => int(1)
// name => string(11) "Dave Lister"
// added => object(DateTime53) {}
// }
// DibiRow(3) {
// customer_id => 1
// name => "Dave Lister" (11)
// added => "2007-03-11 17:20:03" (19)
// using auto-detection (works well with MySQL or other strictly typed databases)
@@ -39,8 +38,7 @@ $res = dibi::query('SELECT * FROM [customers]');
dump( $res->fetch() );
// outputs:
// object(DibiRow)#3 (3) {
// customer_id => int(1)
// name => string(11) "Dave Lister"
// added => string(15) "17:20 11.3.2007"
// }
// DibiRow(3) {
// customer_id => 1
// name => "Dave Lister" (11)
// added => "2007-03-11 17:20:03" (19)

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
ndebug();

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
dibi::connect(array(

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');

View File

@@ -1,4 +1,4 @@
<?php ob_start(1) // needed by FirePHP ?>
<?php ob_start() // needed by FirePHP ?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
@@ -6,8 +6,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
dibi::connect(array(

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
dibi::connect(array(

View File

@@ -4,8 +4,8 @@
<?php
require_once 'Nette/Debugger.php';
require_once '../dibi/dibi.php';
require dirname(__FILE__) . '/Nette/Debugger.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
dibi::connect(array(

55
license.md Normal file
View File

@@ -0,0 +1,55 @@
Licenses
========
Good news! You may use Dibi under the terms of either the New BSD License
or the GNU General Public License (GPL) version 2 or 3.
The BSD License is recommended for most projects. It is easy to understand and it
places almost no restrictions on what you can do with the framework. If the GPL
fits better to your project, you can use the framework under this license.
You don't have to notify anyone which license you are using. You can freely
use Dibi in commercial projects as long as the copyright header
remains intact.
New BSD License
---------------
Copyright (c) 2004, 2013 David Grudl (http://davidgrudl.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of "Dibi" nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
This software is provided by the copyright holders and contributors "as is" and
any express or implied warranties, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose are
disclaimed. In no event shall the copyright owner or contributors be liable for
any direct, indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitute goods or services;
loss of use, data, or profits; or business interruption) however caused and on
any theory of liability, whether in contract, strict liability, or tort
(including negligence or otherwise) arising in any way out of the use of this
software, even if advised of the possibility of such damage.
GNU General Public License
--------------------------
GPL licenses are very very long, so instead of including them here we offer
you URLs with full text:
- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)

View File

@@ -1,61 +0,0 @@
Licenses
========
Good news! You may use Dibi under the terms of either the New BSD License
or the GNU General Public License (GPL) version 2 or 3.
The BSD License is recommended for most projects. It is easy to understand and it
places almost no restrictions on what you can do with the library. If the GPL
fits better to your project, you can use the Dibi under this license.
You don't have to notify anyone which license you are using. You can freely
use Dibi in commercial projects as long as the copyright header
remains intact.
Please do not use word "Dibi" in the name of your project or top-level domain,
and choose a name that stands on its own merits. If your stuff is good,
it will not take long to establish a reputation for yourselves.
New BSD License
---------------
Copyright (c) 2005, 2012 David Grudl (http://davidgrudl.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of "Dibi" nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
GNU General Public License
--------------------------
GPL licenses are very very long, so instead of including them here we offer
you URLs with full text:
- GPL version 2: http://www.gnu.org/licenses/gpl-2.0.html
- GPL version 3: http://www.gnu.org/licenses/gpl-3.0.html

126
readme.md Normal file
View File

@@ -0,0 +1,126 @@
[Dibi](http://dibiphp.com) - smart database layer for PHP
=========================================================
Database access functions in PHP are not standardised. This library
hides the differences between them, a above all, it gives you a very handy interface.
The best way how to install Dibi is to use a [Composer](http://getcomposer.org/download):
php composer.phar require dibi/dibi
Or you can download a latest package from http://dibiphp.com. In this
package is also `Dibi.minified`, shrinked single-file version of whole Dibi,
useful when you don't want to modify library, but just use it.
Dibi requires PHP 5.2.0 or later. It has been tested with PHP 5.5 too.
Examples
--------
Refer to the `examples` directory for examples. Dibi documentation is
available on the [homepage](http://dibiphp.com).
Connect to database:
```php
// connect to database (static way)
dibi::connect(array(
'driver' => 'mysql',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
));
// or object way; in all other examples use $connection-> instead of dibi::
$connection = new DibiConnection($options);
```
SELECT, INSERT, UPDATE
```php
dibi::query('SELECT * FROM users WHERE id = ?', $id);
$arr = array(
'name' => 'John',
'is_admin' => TRUE,
);
dibi::query('INSERT INTO users', $arr);
// INSERT INTO users (`name`, `is_admin`) VALUES ('John', 1)
dibi::query('UPDATE users SET', $arr, 'WHERE `id`=?', $x);
// UPDATE users SET `name`='John', `is_admin`=1 WHERE `id` = 123
dibi::query('UPDATE users SET', array(
'title' => array('SHA1(?)', 'tajneheslo'),
));
// UPDATE users SET 'title' = SHA1('tajneheslo')
```
Getting results
```php
$result = dibi::query('SELECT * FROM users');
$value = $result->fetchSingle(); // single value
$all = $result->fetchAll(); // all rows
$assoc = $result->fetchAssoc('id'); // all rows as associative array
$pairs = $result->fetchPairs('customerID', 'name'); // all rows as key => value pairs
// iterating
foreach ($result as $n => $row) {
print_r($row);
}
```
Modifiers for arrays:
```php
dibi::query('SELECT * FROM users WHERE %and', array(
array('number > ?', 10),
array('number < ?', 100),
));
// SELECT * FROM users WHERE (number > 10) AND (number < 100)
```
<table>
<tr><td> %and </td><td> </td><td> `[key]=val AND [key2]="val2" AND ...` </td></tr>
<tr><td> %or </td><td> </td><td> `[key]=val OR [key2]="val2" OR ...` </td></tr>
<tr><td> %a </td><td> assoc </td><td> `[key]=val, [key2]="val2", ...` </td></tr>
<tr><td> %l %in </td><td> list </td><td> `(val, "val2", ...)` </td></tr>
<tr><td> %v </td><td> values </td><td> `([key], [key2], ...) VALUES (val, "val2", ...)` </td></tr>
<tr><td> %m </td><td> multivalues </td><td> `([key], [key2], ...) VALUES (val, "val2", ...), (val, "val2", ...), ...` </td></tr>
<tr><td> %by </td><td> ordering </td><td> `[key] ASC, [key2] DESC ...` </td></tr>
<tr><td> %n </td><td> identifiers </td><td> `[key], [key2] AS alias, ...` </td></tr>
<tr><td> other </td><td> - </td><td> `val, val2, ...` </td></tr>
</table>
Modifiers for LIKE
```php
dibi::query("SELECT * FROM table WHERE name LIKE %like~", $query);
```
<table>
<tr><td> %like~ </td><td> begins with </td></tr>
<tr><td> %~like </td><td> ends with </td></tr>
<tr><td> %~like~ </td><td> contains </td></tr>
</table>
DateTime:
```php
dibi::query('UPDATE users SET', array(
'time' => new DateTime,
));
// UPDATE users SET ('2008-01-01 01:08:10')
```
Testing:
```php
echo dibi::$sql; // last SQL query
echo dibi::$elapsedTime;
echo dibi::$numOfQueries;
echo dibi::$totalTime;

View File

@@ -1,31 +0,0 @@
Introduction
------------
Thank you for downloading Dibi!
Database access functions in PHP are not standardised. This is class library
to hide the differences between the different databases access.
Documentation and Examples
--------------------------
Refer to the 'examples' directory for examples. Dibi documentation is
available on the homepage:
http://dibiphp.com
Dibi.minified
-------------
This is shrinked single-file version of whole Dibi, useful when you don't
want to modify library, but just use it.
This is exactly the same as normal version, just only comments and
whitespaces are removed.
-----
For more information, visit the author's weblog (in czech language):
http://phpfashion.com

View File

@@ -4,16 +4,14 @@
* Test: Cloning of DibiFluent
*
* @author David Grudl
* @category Dibi
* @subpackage UnitTests
*/
require dirname(__FILE__) . '/initialize.php';
require dirname(__FILE__) . '/bootstrap.php';
dibi::connect($config['sqlite']);
dibi::connect($config['sqlite3']);
$fluent = new DibiFluent(dibi::getConnection());
@@ -22,48 +20,21 @@ $dolly = clone $fluent;
$dolly->where('y=1');
$dolly->clause('FOO');
$fluent->test();
$dolly->test();
Assert::same( 'SELECT * FROM [table] WHERE x=1', (string) $fluent );
Assert::same( 'SELECT * FROM [table] WHERE x=1 AND y=1 FOO', (string) $dolly );
$fluent = dibi::select('id')->from('table')->where('id = %i',1);
$dolly = clone $fluent;
$dolly->where('cd = %i',5);
$fluent->test();
$dolly->test();
Assert::same( 'SELECT [id] FROM [table] WHERE id = 1', (string) $fluent );
Assert::same( 'SELECT [id] FROM [table] WHERE id = 1 AND cd = 5', (string) $dolly );
$fluent = dibi::select("*")->from("table");
$dolly = clone $fluent;
$dolly->removeClause("select")->select("count(*)");
$fluent->test();
$dolly->test();
__halt_compiler() ?>
------EXPECT------
SELECT *
FROM [table]
WHERE x=1
SELECT *
FROM [table]
WHERE x=1 AND y=1 FOO
SELECT [id]
FROM [table]
WHERE id = 1
SELECT [id]
FROM [table]
WHERE id = 1 AND cd = 5
SELECT *
FROM [table]
SELECT count(*)
FROM [table]
Assert::same( 'SELECT * FROM [table]', (string) $fluent );
Assert::same( 'SELECT count(*) FROM [table]', (string) $dolly );

View File

@@ -1,138 +0,0 @@
<?php
/**
* Nette Framework
*
* @copyright Copyright (c) 2004 David Grudl
* @license http://nette.org/license Nette license
* @link http://nette.org
* @category Nette
* @package Nette\Test
*/
/**
* Asseratation test helpers.
*
* @author David Grudl
* @package Nette\Test
*/
class Assert
{
/**
* Checks assertation.
* @param mixed expected
* @param mixed actual
* @return void
*/
public static function same($expected, $actual)
{
if ($actual !== $expected) {
self::note('Failed asserting that ' . self::dump($actual) . ' is not identical to ' . self::dump($expected));
}
}
/**
* Checks TRUE assertation.
* @param mixed actual
* @return void
*/
public static function true($actual)
{
if ($actual !== TRUE) {
self::note('Failed asserting that ' . self::dump($actual) . ' is not TRUE');
}
}
/**
* Checks FALSE assertation.
* @param mixed actual
* @return void
*/
public static function false($actual)
{
if ($actual !== FALSE) {
self::note('Failed asserting that ' . self::dump($actual) . ' is not FALSE');
}
}
/**
* Checks NULL assertation.
* @param mixed actual
* @return void
*/
public static function null($actual)
{
if ($actual !== NULL) {
self::note('Failed asserting that ' . self::dump($actual) . ' is not NULL');
}
}
/**
* Dumps information about a variable in readable format.
* @param mixed variable to dump
* @return void
*/
private static function dump($var)
{
if (is_bool($var)) {
return $var ? 'TRUE' : 'FALSE';
} elseif ($var === NULL) {
return "NULL";
} elseif (is_int($var)) {
return "$var";
} elseif (is_float($var)) {
return "$var";
} elseif (is_string($var)) {
return var_export($var, TRUE);
} elseif (is_array($var)) {
return "array(" . count($var) . ")";
} elseif ($var instanceof Exception) {
return 'Exception ' . get_class($var) . ': ' . ($var->getCode() ? '#' . $var->getCode() . ' ' : '') . $var->getMessage();
} elseif (is_object($var)) {
$arr = (array) $var;
return "object(" . get_class($var) . ") (" . count($arr) . ")";
} elseif (is_resource($var)) {
return "resource(" . get_resource_type($var) . ")";
} else {
return "unknown type";
}
}
/**
* Returns message and file and line from call stack.
* @param string
* @return void
*/
private static function note($message)
{
echo $message;
$trace = debug_backtrace();
if (isset($trace[1]['file'], $trace[1]['line'])) {
echo ' in file ' . $trace[1]['file'] . ' on line ' . $trace[1]['line'];
}
echo "\n\n";
}
}

View File

@@ -1,43 +0,0 @@
Nette Test Framework (v0.3)
---------------------------
<?php
require_once dirname(__FILE__) . '/TestRunner.php';
/**
* Help
*/
if (!isset($_SERVER['argv'][1])) { ?>
Usage:
php RunTests.php [options] [file or directory]
Options:
-p <php> Specify PHP-CGI executable to run.
-c <path> Look for php.ini in directory <path> or use <path> as php.ini.
-d key=val Define INI entry 'key' with value 'val'.
-l <path> Specify path to shared library files (LD_LIBRARY_PATH)
-e <name> Load php environment <name>
-s Show information about skipped tests
<?php
}
/**
* Execute tests
*/
try {
@unlink(dirname(__FILE__) . '/coverage.tmp'); // @ - file may not exist
$manager = new TestRunner;
$manager->parseConfigFile();
$manager->parseArguments();
$res = $manager->run();
die($res ? 0 : 1);
} catch (Exception $e) {
echo 'Error: ', $e->getMessage(), "\n";
die(2);
}

View File

@@ -1,400 +0,0 @@
<?php
/**
* Nette Framework
*
* @copyright Copyright (c) 2004 David Grudl
* @license http://nette.org/license Nette license
* @link http://nette.org
* @category Nette
* @package Nette\Test
*/
/**
* Single test case.
*
* @author David Grudl
* @package Nette\Test
*/
class TestCase
{
/** @var string test file */
private $file;
/** @var array test file multiparts */
private $sections;
/** @var string test output */
private $output;
/** @var string output headers in raw format */
private $headers;
/** @var string PHP command line */
private $cmdLine;
/** @var string PHP command line */
private $phpVersion;
/** @var array */
private static $cachedPhp;
/**
* @param string test file name
* @param string PHP command line
* @return void
*/
public function __construct($testFile)
{
$this->file = (string) $testFile;
$this->sections = self::parseSections($this->file);
}
/**
* Runs single test.
* @return void
*/
public function run()
{
// pre-skip?
$options = $this->sections['options'];
if (isset($options['skip'])) {
$message = $options['skip'] ? $options['skip'] : 'No message.';
throw new TestCaseException($message, TestCaseException::SKIPPED);
} elseif (isset($options['phpversion'])) {
$operator = '>=';
if (preg_match('#^(<=|le|<|lt|==|=|eq|!=|<>|ne|>=|ge|>|gt)#', $options['phpversion'], $matches)) {
$options['phpversion'] = trim(substr($options['phpversion'], strlen($matches[1])));
$operator = $matches[1];
}
if (version_compare($options['phpversion'], $this->phpVersion, $operator)) {
throw new TestCaseException("Requires PHP $operator $options[phpversion].", TestCaseException::SKIPPED);
}
}
$this->execute();
$output = $this->output;
$headers = array_change_key_case(self::parseLines($this->headers, ':'), CASE_LOWER);
$tests = 0;
// post-skip?
if (isset($headers['x-nette-test-skip'])) {
throw new TestCaseException($headers['x-nette-test-skip'], TestCaseException::SKIPPED);
}
// compare output
$expectedOutput = $this->getExpectedOutput();
if ($expectedOutput !== NULL) {
$tests++;
$binary = (bool) preg_match('#[\x00-\x08\x0B\x0C\x0E-\x1F]#', $expectedOutput);
if ($binary) {
if ($expectedOutput !== $output) {
throw new TestCaseException("Binary output doesn't match.");
}
} else {
$output = self::normalize($output, isset($options['keeptrailingspaces']));
$expectedOutput = self::normalize($expectedOutput, isset($options['keeptrailingspaces']));
if (!$this->compare($output, $expectedOutput)) {
throw new TestCaseException("Output doesn't match.");
}
}
}
// compare headers
$expectedHeaders = $this->getExpectedHeaders();
if ($expectedHeaders !== NULL) {
$tests++;
$expectedHeaders = self::normalize($expectedHeaders, FALSE);
$expectedHeaders = array_change_key_case(self::parseLines($expectedHeaders, ':'), CASE_LOWER);
foreach ($expectedHeaders as $name => $header) {
if (!isset($headers[$name])) {
throw new TestCaseException("Missing header '$name'.");
} elseif (!$this->compare($headers[$name], $header)) {
throw new TestCaseException("Header '$name' doesn't match.");
}
}
}
if (!$tests) { // expecting no output
if (trim($output) !== '') {
throw new TestCaseException("Empty output doesn't match.");
}
}
}
/**
* Sets PHP command line.
* @param string
* @param string
* @param string
* @return TestCase provides a fluent interface
*/
public function setPhp($binary, $args, $environment)
{
if (isset(self::$cachedPhp[$binary])) {
$this->phpVersion = self::$cachedPhp[$binary];
} else {
exec($environment . escapeshellarg($binary) . ' -v', $output, $res);
if ($res !== 0 && $res !== 255) {
throw new Exception("Unable to execute '$binary -v'.");
}
if (!preg_match('#^PHP (\S+).*cli#i', $output[0], $matches)) {
throw new Exception("Unable to detect PHP version (output: $output[0]).");
}
$this->phpVersion = self::$cachedPhp[$binary] = $matches[1];
}
$this->cmdLine = $environment . escapeshellarg($binary) . $args;
return $this;
}
/**
* Execute test.
* @return array
*/
private function execute()
{
$this->headers = $this->output = NULL;
$tempFile = tempnam('', 'tmp');
if (!$tempFile) {
throw new Exception("Unable to create temporary file.");
}
$command = $this->cmdLine;
if (isset($this->sections['options']['phpini'])) {
foreach (explode(';', $this->sections['options']['phpini']) as $item) {
$command .= " -d " . escapeshellarg(trim($item));
}
}
$command .= ' ' . escapeshellarg($this->file) . ' > ' . escapeshellarg($tempFile);
chdir(dirname($this->file));
exec($command, $foo, $res);
if ($res === 255) {
// exit_status 255 => parse or fatal error
} elseif ($res !== 0) {
throw new Exception("Unable to execute '$command'.");
}
$this->output = file_get_contents($tempFile);
unlink($tempFile);
}
/**
* Returns test file section.
* @return string
*/
public function getSection($name)
{
return isset($this->sections[$name]) ? $this->sections[$name] : NULL;
}
/**
* Returns test name.
* @return string
*/
public function getName()
{
return $this->sections['options']['name'];
}
/**
* Returns test output.
* @return string
*/
public function getOutput()
{
return $this->output;
}
/**
* Returns output headers.
* @return string
*/
public function getHeaders()
{
return $this->headers;
}
/**
* Returns expected output.
* @return string
*/
public function getExpectedOutput()
{
if (isset($this->sections['expect'])) {
return $this->sections['expect'];
} elseif (is_file($expFile = str_replace('.phpt', '', $this->file) . '.expect')) {
return file_get_contents($expFile);
} else {
return NULL;
}
}
/**
* Returns expected headers.
* @return string
*/
public function getExpectedHeaders()
{
return $this->getSection('expectheaders');
}
/********************* helpers ****************d*g**/
/**
* Splits file into sections.
* @param string file
* @return array
*/
public static function parseSections($testFile)
{
$content = file_get_contents($testFile);
$sections = array(
'options' => array(),
);
// phpDoc
$phpDoc = preg_match('#^/\*\*(.*?)\*/#ms', $content, $matches) ? trim($matches[1]) : '';
preg_match_all('#^\s*\*\s*@(\S+)(.*)#mi', $phpDoc, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$sections['options'][strtolower($match[1])] = isset($match[2]) ? trim($match[2]) : TRUE;
}
$sections['options']['name'] = preg_match('#^\s*\*\s*TEST:(.*)#mi', $phpDoc, $matches) ? trim($matches[1]) : $testFile;
// file parts
$tmp = preg_split('#^-{3,}([^\s-]+)-{1,}(?:\r?\n|$)#m', $content, -1, PREG_SPLIT_DELIM_CAPTURE);
$i = 1;
while (isset($tmp[$i])) {
$sections[strtolower($tmp[$i])] = $tmp[$i+1];
$i += 2;
}
return $sections;
}
/**
* Splits HTTP headers into array.
* @param string
* @param string
* @return array
*/
public static function parseLines($raw, $separator)
{
$headers = array();
foreach (explode("\r\n", $raw) as $header) {
$a = strpos($header, $separator);
if ($a !== FALSE) {
$headers[trim(substr($header, 0, $a))] = (string) trim(substr($header, $a + 1));
}
}
return $headers;
}
/**
* Compares results.
* @param string
* @param string
* @return bool
*/
public static function compare($left, $right)
{
$right = strtr($right, array(
'%a%' => '[^\r\n]+', // one or more of anything except the end of line characters
'%a?%'=> '[^\r\n]*', // zero or more of anything except the end of line characters
'%A%' => '.+', // one or more of anything including the end of line characters
'%A?%'=> '.*', // zero or more of anything including the end of line characters
'%s%' => '[\t ]+', // one or more white space characters except the end of line characters
'%s?%'=> '[\t ]*', // zero or more white space characters except the end of line characters
'%S%' => '\S+', // one or more of characters except the white space
'%S?%'=> '\S*', // zero or more of characters except the white space
'%c%' => '[^\r\n]', // a single character of any sort (except the end of line)
'%d%' => '[0-9]+', // one or more digits
'%d?%'=> '[0-9]*', // zero or more digits
'%i%' => '[+-]?[0-9]+', // signed integer value
'%f%' => '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', // floating point number
'%h%' => '[0-9a-fA-F]+',// one or more HEX digits
'%ns%'=> '(?:[_0-9a-zA-Z\\\\]+\\\\|N)?',// PHP namespace
'%[^' => '[^', // reg-exp
'%[' => '[', // reg-exp
']%' => ']+', // reg-exp
'.' => '\.', '\\' => '\\\\', '+' => '\+', '*' => '\*', '?' => '\?', '[' => '\[', '^' => '\^', ']' => '\]', '$' => '\$', '(' => '\(', ')' => '\)', // preg quote
'{' => '\{', '}' => '\}', '=' => '\=', '!' => '\!', '>' => '\>', '<' => '\<', '|' => '\|', ':' => '\:', '-' => '\-', "\x00" => '\000', '#' => '\#', // preg quote
));
return (bool) preg_match("#^$right$#s", $left);
}
/**
* Normalizes whitespace
* @param string
* @param bool
* @return string
*/
public static function normalize($s, $keepTrailingSpaces)
{
$s = str_replace("\n", PHP_EOL, str_replace("\r\n", "\n", $s)); // normalize EOL
if (!$keepTrailingSpaces) {
$s = preg_replace("#[\t ]+(\r?\n)#", '$1', $s); // multiline right trim
$s = rtrim($s); // ending trim
}
return $s;
}
}
/**
* Single test exception.
*
* @author David Grudl
* @package Nette\Test
*/
class TestCaseException extends Exception
{
const SKIPPED = 1;
}

View File

@@ -1,312 +0,0 @@
<?php
/**
* Nette Framework
*
* @copyright Copyright (c) 2004 David Grudl
* @license http://nette.org/license Nette license
* @link http://nette.org
* @category Nette
* @package Nette\Test
*/
require dirname(__FILE__) . '/TestCase.php';
/**
* Test helpers.
*
* @author David Grudl
* @package Nette\Test
*/
class TestHelpers
{
/** @var int */
static public $maxDepth = 5;
/** @var array */
private static $sections;
/**
* Configures PHP and environment.
* @return void
*/
public static function startup()
{
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', TRUE);
ini_set('html_errors', FALSE);
ini_set('log_errors', FALSE);
$_SERVER = array_intersect_key($_SERVER, array_flip(array('PHP_SELF', 'SCRIPT_NAME', 'SERVER_ADDR', 'SERVER_SOFTWARE', 'HTTP_HOST', 'DOCUMENT_ROOT', 'OS')));
$_SERVER['REQUEST_TIME'] = 1234567890;
$_ENV = array();
if (PHP_SAPI !== 'cli') {
header('Content-Type: text/plain; charset=utf-8');
}
if (extension_loaded('xdebug')) {
xdebug_disable();
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
register_shutdown_function(array(__CLASS__, 'prepareSaveCoverage'));
}
set_exception_handler(array(__CLASS__, 'exceptionHandler'));
}
/**
* Purges directory.
* @param string
* @return void
*/
public static function purge($dir)
{
@mkdir($dir); // @ - directory may already exist
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::CHILD_FIRST) as $entry) {
if ($entry->getBasename() === '.gitignore') {
// ignore
} elseif ($entry->isDir()) {
rmdir($entry);
} else {
unlink($entry);
}
}
}
/**
* Returns current test section.
* @param string
* @param string
* @return mixed
*/
public static function getSection($file, $section)
{
if (!isset(self::$sections[$file])) {
self::$sections[$file] = TestCase::parseSections($file);
}
$lowerSection = strtolower($section);
if (!isset(self::$sections[$file][$lowerSection])) {
throw new Exception("Missing section '$section' in file '$file'.");
}
if (in_array($section, array('GET', 'POST', 'SERVER'), TRUE)) {
return TestCase::parseLines(self::$sections[$file][$lowerSection], '=');
} else {
return self::$sections[$file][$lowerSection];
}
}
/**
* Writes new message.
* @param string
* @return void
*/
public static function note($message = NULL)
{
echo $message ? "$message\n\n" : "===\n\n";
}
/**
* Dumps information about a variable in readable format.
* @param mixed variable to dump
* @param string
* @return mixed variable itself or dump
*/
public static function dump($var, $message = NULL)
{
if ($message) {
echo $message . (preg_match('#[.:?]$#', $message) ? ' ' : ': ');
}
self::_dump($var, 0);
echo "\n";
return $var;
}
private static function _dump(& $var, $level = 0)
{
static $tableUtf, $tableBin, $reBinary = '#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u';
if ($tableUtf === NULL) {
foreach (range("\x00", "\xFF") as $ch) {
if (ord($ch) < 32 && strpos("\r\n\t", $ch) === FALSE) $tableUtf[$ch] = $tableBin[$ch] = '\\x' . str_pad(dechex(ord($ch)), 2, '0', STR_PAD_LEFT);
elseif (ord($ch) < 127) $tableUtf[$ch] = $tableBin[$ch] = $ch;
else { $tableUtf[$ch] = $ch; $tableBin[$ch] = '\\x' . dechex(ord($ch)); }
}
$tableBin["\\"] = '\\\\';
$tableBin["\r"] = '\\r';
$tableBin["\n"] = '\\n';
$tableBin["\t"] = '\\t';
$tableUtf['\\x'] = $tableBin['\\x'] = '\\\\x';
}
if (is_bool($var)) {
echo ($var ? 'TRUE' : 'FALSE') . "\n";
} elseif ($var === NULL) {
echo "NULL\n";
} elseif (is_int($var)) {
echo "$var\n";
} elseif (is_float($var)) {
$var = (string) $var;
if (strpos($var, '.') === FALSE) $var .= '.0';
echo "$var\n";
} elseif (is_string($var)) {
$s = strtr($var, preg_match($reBinary, $var) || preg_last_error() ? $tableBin : $tableUtf);
echo "\"$s\"\n";
} elseif (is_array($var)) {
echo "array(";
$space = str_repeat("\t", $level);
static $marker;
if ($marker === NULL) $marker = uniqid("\x00", TRUE);
if (empty($var)) {
} elseif (isset($var[$marker])) {
echo " *RECURSION* ";
} elseif ($level < self::$maxDepth) {
echo "\n";
$vector = range(0, count($var) - 1) === array_keys($var);
$var[$marker] = 0;
foreach ($var as $k => &$v) {
if ($k === $marker) continue;
if ($vector) {
echo "$space\t";
} else {
$k = is_int($k) ? $k : '"' . strtr($k, preg_match($reBinary, $k) || preg_last_error() ? $tableBin : $tableUtf) . '"';
echo "$space\t$k => ";
}
self::_dump($v, $level + 1);
}
unset($var[$marker]);
echo "$space";
} else {
echo " ... ";
}
echo ")\n";
} elseif ($var instanceof Exception) {
echo 'Exception ', get_class($var), ': ', ($var->getCode() ? '#' . $var->getCode() . ' ' : '') . $var->getMessage(), "\n";
} elseif (is_object($var)) {
$arr = (array) $var;
echo get_class($var) . "(";
$space = str_repeat("\t", $level);
static $list = array();
if (empty($arr)) {
} elseif (in_array($var, $list, TRUE)) {
echo " *RECURSION* ";
} elseif ($level < self::$maxDepth) {
echo "\n";
$list[] = $var;
foreach ($arr as $k => &$v) {
$m = '';
if ($k[0] === "\x00") {
$m = $k[1] === '*' ? ' protected' : ' private';
$k = substr($k, strrpos($k, "\x00") + 1);
}
$k = strtr($k, preg_match($reBinary, $k) || preg_last_error() ? $tableBin : $tableUtf);
echo "$space\t\"$k\"$m => ";
echo self::_dump($v, $level + 1);
}
array_pop($list);
echo "$space";
} else {
echo " ... ";
}
echo ")\n";
} elseif (is_resource($var)) {
echo get_resource_type($var) . " resource\n";
} else {
echo "unknown type\n";
}
}
/**
* Custom exception handler.
* @param Exception
* @return void
*/
public static function exceptionHandler(Exception $exception)
{
echo 'Error: Uncaught ';
echo $exception;
}
/**
* Coverage saving helper.
* @return void
*/
public static function prepareSaveCoverage()
{
register_shutdown_function(array(__CLASS__, 'saveCoverage'));
}
/**
* Saves information about code coverage.
* @return void
*/
public static function saveCoverage()
{
$file = dirname(__FILE__) . '/coverage.tmp';
$coverage = @unserialize(file_get_contents($file));
$root = realpath(dirname(__FILE__) . '/../../Nette') . DIRECTORY_SEPARATOR;
foreach (xdebug_get_code_coverage() as $filename => $lines) {
if (strncmp($root, $filename, strlen($root))) continue;
foreach ($lines as $num => $val) {
if (empty($coverage[$filename][$num]) || $val > 0) {
$coverage[$filename][$num] = $val; // -1 => untested; -2 => dead code
}
}
}
file_put_contents($file, serialize($coverage));
}
/**
* Skips this test.
* @return void
*/
public static function skip($message = 'No message.')
{
header('X-Nette-Test-Skip: '. $message);
exit;
}
}

View File

@@ -1,230 +0,0 @@
<?php
/**
* Nette Framework
*
* @copyright Copyright (c) 2004 David Grudl
* @license http://nette.org/license Nette license
* @link http://nette.org
* @category Nette
* @package Nette\Test
*/
require dirname(__FILE__) . '/TestCase.php';
/**
* Test runner.
*
* @author David Grudl
* @package Nette\Test
*/
class TestRunner
{
const OUTPUT = 'output';
const EXPECTED = 'expect';
const HEADERS = 'headers';
/** @var string path to test file/directory */
public $path;
/** @var string php-cgi binary */
public $phpBinary;
/** @var string php-cgi command-line arguments */
public $phpArgs;
/** @var string php-cgi environment variables */
public $phpEnvironment;
/** @var bool display skipped tests information? */
public $displaySkipped = FALSE;
/**
* Runs all tests.
* @return void
*/
public function run()
{
$count = 0;
$failed = $passed = $skipped = array();
if (is_file($this->path)) {
$files = array($this->path);
} else {
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->path));
}
foreach ($files as $entry) {
$entry = (string) $entry;
$info = pathinfo($entry);
if (!isset($info['extension']) || $info['extension'] !== 'phpt') {
continue;
}
$count++;
$testCase = new TestCase($entry);
$testCase->setPhp($this->phpBinary, $this->phpArgs, $this->phpEnvironment);
try {
$testCase->run();
echo '.';
$passed[] = array($testCase->getName(), $entry);
} catch (TestCaseException $e) {
if ($e->getCode() === TestCaseException::SKIPPED) {
echo 's';
$skipped[] = array($testCase->getName(), $entry, $e->getMessage());
} else {
echo 'F';
$failed[] = array($testCase->getName(), $entry, $e->getMessage());
$this->log($entry, $testCase->getOutput(), self::OUTPUT);
$this->log($entry, $testCase->getExpectedOutput(), self::EXPECTED);
if ($testCase->getExpectedHeaders() !== NULL) {
$this->log($entry, $testCase->getHeaders(), self::OUTPUT, self::HEADERS);
$this->log($entry, $testCase->getExpectedHeaders(), self::EXPECTED, self::HEADERS);
}
}
}
}
$failedCount = count($failed);
$skippedCount = count($skipped);
if ($this->displaySkipped && $skippedCount) {
echo "\n\nSkipped:\n";
foreach ($skipped as $i => $item) {
list($name, $file, $message) = $item;
echo "\n", ($i + 1), ") $name\n $message\n $file\n";
}
}
if (!$count) {
echo "No tests found\n";
} elseif ($failedCount) {
echo "\n\nFailures:\n";
foreach ($failed as $i => $item) {
list($name, $file, $message) = $item;
echo "\n", ($i + 1), ") $name\n $message\n $file\n";
}
echo "\nFAILURES! ($count tests, $failedCount failures, $skippedCount skipped)\n";
return FALSE;
} else {
echo "\n\nOK ($count tests, $skippedCount skipped)\n";
}
return TRUE;
}
/**
* Returns output file for logging.
* @param string
* @param string
* @param string
* @param string
* @return void
*/
public function log($testFile, $content, $type, $section = '')
{
$file = dirname($testFile) . '/' . $type . '/' . basename($testFile, '.phpt') . ($section ? ".$section" : '') . '.raw';
@mkdir(dirname($file)); // @ - directory may already exist
file_put_contents($file, $content);
}
/**
* Parses configuration file.
* @return void
*/
public function parseConfigFile()
{
$configFile = dirname(__FILE__) . '/config.ini';
if (file_exists($configFile)) {
$this->config = parse_ini_file($configFile, TRUE);
if ($this->config === FALSE) {
throw new Exception('Config file parsing failed.');
}
foreach ($this->config as & $environment) {
$environment += array(
'binary' => 'php-cgi',
'args' => '',
'environment' => '',
);
// shorthand options
if (isset($environment['php.ini'])) {
$environment['args'] .= ' -c '. escapeshellarg($environment['php.ini']);
}
if (isset($environment['libraries'])) {
$environment['environment'] .= 'LD_LIBRARY_PATH='. escapeshellarg($environment['libraries']) .' ';
}
}
}
}
/**
* Parses command line arguments.
* @return void
*/
public function parseArguments()
{
$this->phpBinary = 'php-cgi';
$this->phpArgs = '';
$this->phpEnvironment = '';
$this->path = getcwd(); // current directory
$args = new ArrayIterator(array_slice(isset($_SERVER['argv']) ? $_SERVER['argv'] : array(), 1));
foreach ($args as $arg) {
if (!preg_match('#^[-/][a-z]$#', $arg)) {
if ($path = realpath($arg)) {
$this->path = $path;
} else {
throw new Exception("Invalid path '$arg'.");
}
} else switch ($arg[1]) {
case 'p':
$args->next();
$this->phpBinary = $args->current();
break;
case 'c':
case 'd':
$args->next();
$this->phpArgs .= " -$arg[1] " . escapeshellarg($args->current());
break;
case 'l':
$args->next();
$this->phpEnvironment .= 'LD_LIBRARY_PATH='. escapeshellarg($args->current()) . ' ';
break;
case 'e':
$args->next();
$name = $args->current();
if (!isset($this->config[$name])) {
throw new Exception("Unknown environment name '$name'.");
}
$this->phpBinary = $this->config[$name]['binary'];
$this->phpArgs = $this->config[$name]['args'];
$this->phpEnvironment = $this->config[$name]['environment'];
break;
case 's':
$this->displaySkipped = TRUE;
break;
default:
throw new Exception("Unknown option -$arg[1].");
exit;
}
}
}
}

18
tests/bootstrap.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
/**
* Test initialization and helpers.
*
* @author David Grudl
* @package Nette\Test
*/
require dirname(__FILE__) . '/../vendor/nette/tester/Tester/bootstrap.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
class_alias('Tester\Assert', 'Assert');
// load connections
define('DIR', dirname(__FILE__));
$config = parse_ini_file(dirname(__FILE__) . '/config.ini', TRUE);

View File

@@ -1,26 +0,0 @@
<?php
/**
* Test initialization and helpers.
*
* @author David Grudl
* @package Nette\Test
*/
require dirname(__FILE__) . '/NetteTest/TestHelpers.php';
require dirname(__FILE__) . '/NetteTest/Assert.php';
require dirname(__FILE__) . '/../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
TestHelpers::startup();
if (function_exists('class_alias')) {
class_alias('TestHelpers', 'T');
} else {
class T extends TestHelpers {}
}
// load connections
define('DIR', dirname(__FILE__));
$config = parse_ini_file('config.ini', TRUE);

View File

@@ -1 +1 @@
Dibi 2.0.5 (released on 2015-01-13)
Dibi 2.1.1 (revision $WCREV$ released on $WCDATE$)