1
0
mirror of https://github.com/dg/dibi.git synced 2025-09-02 18:42:36 +02:00

Compare commits

...

56 Commits

Author SHA1 Message Date
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
63 changed files with 859 additions and 1655 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/vendor
/composer.lock

19
composer.json Normal file
View File

@@ -0,0 +1,19 @@
{
"name": "dibi/dibi",
"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", "GPLv2", "GPLv3"],
"authors": [
{
"name": "David Grudl",
"homepage": "http://davidgrudl.com"
}
],
"require-dev": {
"nette/tester": "@dev"
},
"autoload": {
"classmap": ["dibi/"]
}
}

View File

@@ -12,13 +12,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()
@@ -47,7 +47,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,56 @@
<?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['productionMode'];
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

@@ -52,13 +52,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');
}
}
@@ -83,7 +89,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(
@@ -101,9 +107,13 @@ class DibiNettePanel extends DibiObject implements IBarPanel
*/
public function getTab()
{
$totalTime = 0;
foreach ($this->events as $event) {
$totalTime += $event->time;
}
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" />'
. dibi::$numOfQueries . ' queries'
. (dibi::$totalTime ? ' / ' . sprintf('%0.1f', dibi::$totalTime * 1000) . 'ms' : '')
. count($this->events) . ' queries'
. ($totalTime ? ' / ' . sprintf('%0.1f', $totalTime * 1000) . 'ms' : '')
. '</span>';
}
@@ -115,9 +125,10 @@ class DibiNettePanel extends DibiObject implements IBarPanel
*/
public function getPanel()
{
$s = NULL;
$totalTime = $s = NULL;
$h = 'htmlSpecialChars';
foreach ($this->events as $event) {
$totalTime += $event->time;
$explain = NULL; // EXPLAIN is called here to work SELECT FOUND_ROWS()
if ($this->explain && $event->type === DibiEvent::SELECT) {
try {
@@ -133,7 +144,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);
@@ -155,7 +166,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: ' . dibi::$numOfQueries . (dibi::$totalTime === NULL ? '' : ', time: ' . sprintf('%0.3f', dibi::$totalTime * 1000) . ' ms') . '</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

@@ -39,7 +39,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__) . '/Nette/DibiNettePanel.php';
require_once dirname(__FILE__) . '/bridges/Nette/DibiNettePanel.php';
}
@@ -80,7 +80,7 @@ class dibi
FIELD_TIME = dibi::TIME;
/** version */
const VERSION = '2.0',
const VERSION = '2.1.0',
REVISION = '$WCREV$ released on $WCDATE$';
/** sorting order */
@@ -620,13 +620,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";
}
}
@@ -641,17 +646,36 @@ class dibi
private static function highlightCallback($matches)
{
if (!empty($matches[1])) // comment
if (!empty($matches[1])) { // comment
return '<em style="color:gray">' . $matches[1] . '</em>';
if (!empty($matches[2])) // error
} elseif (!empty($matches[2])) { // error
return '<strong style="color:red">' . $matches[2] . '</strong>';
if (!empty($matches[3])) // most important keywords
} elseif (!empty($matches[3])) { // most important keywords
return '<strong style="color:blue">' . $matches[3] . '</strong>';
if (!empty($matches[4])) // other keywords
} elseif (!empty($matches[4])) { // other keywords
return '<strong style="color:green">' . $matches[4] . '</strong>';
}
}
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

@@ -373,7 +373,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.");
}
@@ -390,7 +390,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

@@ -10,6 +10,9 @@
*/
require_once dirname(__FILE__) . '/DibiMsSql2005Reflector.php';
/**
* The dibi driver for MS SQL Driver 2005 database.
*
@@ -70,6 +73,9 @@ 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']);
}
@@ -198,7 +204,7 @@ class DibiMsSql2005Driver extends DibiObject implements IDibiDriver, IDibiResult
*/
public function getReflector()
{
throw new DibiNotSupportedException;
return new DibiMssql2005Reflector($this);
}
@@ -237,7 +243,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;
@@ -297,7 +303,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) {
@@ -375,14 +381,12 @@ class DibiMsSql2005Driver extends DibiObject implements IDibiDriver, IDibiResult
*/
public function getResultColumns()
{
$count = sqlsrv_num_fields($this->resultSet);
$columns = array();
for ($i = 0; $i < $count; $i++) {
$row = (array) sqlsrv_field_metadata($this->resultSet, $i);
foreach ((array) sqlsrv_field_metadata($this->resultSet) as $fieldMetadata) {
$columns[] = array(
'name' => $row['Name'],
'fullname' => $row['Name'],
'nativetype' => $row['Type'],
'name' => $fieldMetadata['Name'],
'fullname' => $fieldMetadata['Name'],
'nativetype' => $fieldMetadata['Type'],
);
}
return $columns;

View File

@@ -0,0 +1,142 @@
<?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

@@ -9,7 +9,7 @@
* 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,231 +1,225 @@
<?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;
}
$table = $this->driver->escape($table, dibi::TEXT);
$result = $this->driver->query("
SELECT MAX(rowcnt)
FROM sys.sysindexes
WHERE id=OBJECT_ID({$table})
");
$row = $result->fetch(FALSE);
if (!is_array($row) || count($row) < 1) {
if ($fallback) {
$row = $this->driver->query("SELECT COUNT(*) FROM {$table}")->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 = '{$table}'
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)
{
$table = $this->driver->escape($table, dibi::TEXT);
$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 = {$table}
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)
{
$table = $this->driver->escape($table, dibi::TEXT);
$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)={$table}
");
$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

@@ -10,7 +10,7 @@
*/
require_once dirname(__FILE__) . '/mysql.reflector.php';
require_once dirname(__FILE__) . '/DibiMySqlReflector.php';
/**
@@ -80,6 +80,7 @@ class DibiMySqlDriver extends DibiObject implements IDibiDriver, IDibiResultDriv
// default values
DibiConnection::alias($config, 'flags', 'options');
if (!isset($config['charset'])) $config['charset'] = 'utf8';
if (!isset($config['timezone'])) $config['timezone'] = date('P');
if (!isset($config['username'])) $config['username'] = ini_get('mysql.default_user');
if (!isset($config['password'])) $config['password'] = ini_get('mysql.default_password');
if (!isset($config['host'])) {
@@ -131,7 +132,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

@@ -68,7 +68,7 @@ class DibiMySqlReflector extends DibiObject implements IDibiReflector
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = $table AND TABLE_SCHEMA = DATABASE()
");*/
$res = $this->driver->query("SHOW FULL COLUMNS FROM `$table`");
$res = $this->driver->query("SHOW FULL COLUMNS FROM {$this->driver->escape($table, dibi::IDENTIFIER)}");
$columns = array();
while ($row = $res->fetch(TRUE)) {
$type = explode('(', $row['Type']);
@@ -103,7 +103,7 @@ class DibiMySqlReflector extends DibiObject implements IDibiReflector
WHERE TABLE_NAME = $table AND TABLE_SCHEMA = DATABASE()
AND REFERENCED_COLUMN_NAME IS NULL
");*/
$res = $this->driver->query("SHOW INDEX FROM `$table`");
$res = $this->driver->query("SHOW INDEX FROM {$this->driver->escape($table, dibi::IDENTIFIER)}");
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$indexes[$row['Key_name']]['name'] = $row['Key_name'];

View File

@@ -10,7 +10,7 @@
*/
require_once dirname(__FILE__) . '/mysql.reflector.php';
require_once dirname(__FILE__) . '/DibiMySqlReflector.php';
/**
@@ -81,6 +81,7 @@ class DibiMySqliDriver extends DibiObject implements IDibiDriver, IDibiResultDri
} else {
// default values
if (!isset($config['charset'])) $config['charset'] = 'utf8';
if (!isset($config['timezone'])) $config['timezone'] = date('P');
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');
@@ -132,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']);
}
@@ -194,7 +197,7 @@ class DibiMySqliDriver extends DibiObject implements IDibiDriver, IDibiResultDri
*/
public function getAffectedRows()
{
return mysqli_affected_rows($this->connection);
return mysqli_affected_rows($this->connection) === -1 ? FALSE : mysqli_affected_rows($this->connection);
}

View File

@@ -21,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
@@ -70,8 +71,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) {

View File

@@ -10,8 +10,8 @@
*/
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';
/**
@@ -285,6 +285,9 @@ class DibiPdoDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
case 'mssql':
return '[' . str_replace(array('[', ']'), array('[[', ']]'), $value) . ']';
case 'sqlsrv':
return '[' . str_replace(']', ']]', $value) . ']';
default:
return $value;
}
@@ -372,8 +375,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
@@ -451,7 +455,10 @@ class DibiPdoDriver extends DibiObject implements IDibiDriver, IDibiResultDriver
}
// PHP < 5.2.3 compatibility
// @see: http://php.net/manual/en/pdostatement.getcolumnmeta.php#pdostatement.getcolumnmeta.changelog
$row['table'] = isset($row['table']) ? $row['table'] : NULL;
$row = $row + array(
'table' => NULL,
'native_type' => 'VAR_STRING',
);
$columns[] = array(
'name' => $row['name'],

View File

@@ -10,7 +10,7 @@
*/
require_once dirname(__FILE__) . '/sqlite.reflector.php';
require_once dirname(__FILE__) . '/DibiSqliteReflector.php';
/**

View File

@@ -10,7 +10,7 @@
*/
require_once dirname(__FILE__) . '/sqlite.reflector.php';
require_once dirname(__FILE__) . '/DibiSqliteReflector.php';
/**

View File

@@ -60,16 +60,16 @@ class DibiSqliteReflector extends DibiObject implements IDibiReflector
public function getColumns($table)
{
$meta = $this->driver->query("
SELECT sql FROM sqlite_master WHERE type = 'table' AND name = '$table'
SELECT sql FROM sqlite_master WHERE type = 'table' AND name = {$this->driver->escape($table, dibi::TEXT)}
UNION ALL
SELECT sql FROM sqlite_temp_master WHERE type = 'table' AND name = '$table'"
)->fetch(TRUE);
SELECT sql FROM sqlite_temp_master WHERE type = 'table' AND name = {$this->driver->escape($table, dibi::TEXT)}
")->fetch(TRUE);
$res = $this->driver->query("PRAGMA table_info([$table])");
$res = $this->driver->query("PRAGMA table_info({$this->driver->escape($table, dibi::IDENTIFIER)})");
$columns = array();
while ($row = $res->fetch(TRUE)) {
$column = $row['name'];
$pattern = "/(\"$column\"|\[$column\]|$column)\s+[^,]+\s+PRIMARY\s+KEY\s+AUTOINCREMENT/Ui";
$pattern = "/(\"$column\"|\[$column\]|$column)\\s+[^,]+\\s+PRIMARY\\s+KEY\\s+AUTOINCREMENT/Ui";
$type = explode('(', $row['type']);
$columns[] = array(
'name' => $column,
@@ -95,7 +95,7 @@ class DibiSqliteReflector extends DibiObject implements IDibiReflector
*/
public function getIndexes($table)
{
$res = $this->driver->query("PRAGMA index_list([$table])");
$res = $this->driver->query("PRAGMA index_list({$this->driver->escape($table, dibi::IDENTIFIER)})");
$indexes = array();
while ($row = $res->fetch(TRUE)) {
$indexes[$row['name']]['name'] = $row['name'];
@@ -103,7 +103,7 @@ class DibiSqliteReflector extends DibiObject implements IDibiReflector
}
foreach ($indexes as $index => $values) {
$res = $this->driver->query("PRAGMA index_info([$index])");
$res = $this->driver->query("PRAGMA index_info({$this->driver->escape($index, dibi::IDENTIFIER)})");
while ($row = $res->fetch(TRUE)) {
$indexes[$index]['columns'][$row['seqno']] = $row['name'];
}
@@ -150,7 +150,7 @@ class DibiSqliteReflector extends DibiObject implements IDibiReflector
if (!($this->driver instanceof DibiSqlite3Driver)) {
// throw new DibiNotSupportedException; // @see http://www.sqlite.org/foreignkeys.html
}
$res = $this->driver->query("PRAGMA foreign_key_list([$table])");
$res = $this->driver->query("PRAGMA foreign_key_list({$this->driver->escape($table, dibi::IDENTIFIER)})");
$keys = array();
while ($row = $res->fetch(TRUE)) {
$keys[$row['id']]['name'] = $row['id']; // foreign key name

View File

@@ -89,10 +89,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'.");
@@ -338,9 +338,8 @@ class DibiConnection extends DibiObject
{
$this->connected || $this->connect();
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::QUERY, $sql) : NULL;
dibi::$numOfQueries++;
dibi::$sql = $sql;
$event = $this->onEvent ? new DibiEvent($this, DibiEvent::QUERY, $sql) : NULL;
try {
$res = $this->driver->query($sql);
@@ -690,6 +689,10 @@ class DibiConnection extends DibiObject
$count++;
}
}
if (trim($sql) !== '') {
$this->driver->query($sql);
$count++;
}
fclose($handle);
return $count;
}

View File

@@ -75,7 +75,7 @@ class DibiDataSource extends DibiObject implements IDataSource
/**
* Selects columns to query.
* @param string|array column name or array of column names
* @param string column alias
* @param string column alias
* @return DibiDataSource provides a fluent interface
*/
public function select($col, $as = NULL)
@@ -113,7 +113,7 @@ class DibiDataSource extends DibiObject implements IDataSource
/**
* Selects columns to order by.
* @param string|array column name or array of column names
* @param string sorting direction
* @param string sorting direction
* @return DibiDataSource provides a fluent interface
*/
public function orderBy($row, $sorting = 'ASC')

View File

@@ -621,13 +621,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

@@ -80,6 +80,8 @@ class DibiEvent
}
dibi::$elapsedTime = FALSE;
dibi::$numOfQueries++;
dibi::$sql = $sql;
}

View File

@@ -28,6 +28,12 @@ class DibiFirePhpLogger extends DibiObject
/** @var int */
public $filter;
/** @var int Elapsed time for all queries */
public $totalTime = 0;
/** @var int Number of all queries */
public $numOfQueries = 0;
/** @var array */
private static $fireTable = array(array('Time', 'SQL Statement', 'Rows', 'Connection'));
@@ -60,10 +66,12 @@ class DibiFirePhpLogger extends DibiObject
return;
}
$this->totalTime += $event->time;
$this->numOfQueries++;
self::$fireTable[] = array(
sprintf('%0.3f', $event->time * 1000),
strlen($event->sql) > self::$maxLength ? substr($event->sql, 0, self::$maxLength) . '...' : $event->sql,
$event->result instanceof Exception ? 'ERROR' : $event->count,
$event->result instanceof Exception ? 'ERROR' : (string) $event->count,
$event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
);
@@ -74,7 +82,7 @@ class DibiFirePhpLogger extends DibiObject
$payload = json_encode(array(
array(
'Type' => 'TABLE',
'Label' => 'dibi profiler (' . dibi::$numOfQueries . ' SQL queries took ' . sprintf('%0.3f', dibi::$totalTime * 1000) . ' ms)',
'Label' => 'dibi profiler (' . $this->numOfQueries . ' SQL queries took ' . sprintf('%0.3f', $this->totalTime * 1000) . ' ms)',
),
self::$fireTable,
));

View File

@@ -181,7 +181,7 @@ class DibiFluent extends DibiObject implements IDataSource
if ($arg === TRUE) { // flag
return $this;
} elseif (is_string($arg) && preg_match('#^[a-z:_][a-z0-9_.:]*$#i', $arg)) { // identifier
} elseif (is_string($arg) && preg_match('#^[a-z:_][a-z0-9_.:]*\z#i', $arg)) { // identifier
$args = array('%n', $arg);
} elseif (is_array($arg) || ($arg instanceof Traversable && !$arg instanceof self)) { // any array

View File

@@ -54,6 +54,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();
@@ -203,6 +206,19 @@ class DibiResult extends DibiObject implements IDataSource
/**
* Set a factory to create fetched object instances. These should extend the DibiRow class.
* @param callback
* @return DibiResult provides a fluent interface
*/
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
@@ -216,7 +232,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;
@@ -514,7 +532,7 @@ class DibiResult extends DibiObject implements IDataSource
$row[$key] = is_float($tmp = $value * 1) ? $value : $tmp;
} elseif ($type === dibi::FLOAT) {
$row[$key] = (string) ($tmp = (float) $value) === $value ? $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';
@@ -636,37 +654,68 @@ 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);
if ($len > $maxLen) $maxLen = $len;
}
}
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";
}
echo "\t</tr>\n";
$i++;
}
if ($i === 0) echo "empty result set\n";
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

@@ -218,7 +218,7 @@ final class DibiTranslator extends DibiObject
} else {
$v = $this->formatValue($v, $pair[1]);
if ($pair[1] === 'l' || $pair[1] === 'in') {
if ($pair[1] === 'l' || $pair[1] === 'in') {
$op = 'IN ';
} elseif (strpos($pair[1], 'like') !== FALSE) {
$op = 'LIKE ';
@@ -353,7 +353,7 @@ final class DibiTranslator extends DibiObject
case 'i': // signed int
case 'u': // unsigned int, ignored
// support for long numbers - keep them unchanged
if (is_string($value) && preg_match('#[+-]?\d++(e\d+)?$#A', $value)) {
if (is_string($value) && preg_match('#[+-]?\d++(e\d+)?\z#A', $value)) {
return $value;
} else {
return $value === NULL ? 'NULL' : (string) (int) ($value + 0);
@@ -364,7 +364,7 @@ final class DibiTranslator extends DibiObject
if (is_string($value) && is_numeric($value) && strpos($value, 'x') === FALSE) {
return $value; // something like -9E-005 is accepted by SQL, HEX values are not
} else {
return $value === NULL ? 'NULL' : rtrim(rtrim(number_format($value + 0, 5, '.', ''), '0'), '.');
return $value === NULL ? 'NULL' : rtrim(rtrim(number_format($value + 0, 10, '.', ''), '0'), '.');
}
case 'd': // date
@@ -436,7 +436,7 @@ final class DibiTranslator extends DibiObject
return (string) $value;
} elseif (is_float($value)) {
return rtrim(rtrim(number_format($value, 5, '.', ''), '0'), '.');
return rtrim(rtrim(number_format($value, 10, '.', ''), '0'), '.');
} elseif (is_bool($value)) {
return $this->driver->escape($value, dibi::BOOL);

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,14 +10,28 @@
<?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
ndebug();
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'data/sample.sdb',
'profiler' => array(
'run' => TRUE,
)
));
// throws error because SQL is bad
dibi::query('SELECT * FROM customers WHERE customer_id < ?', 38);
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'data/sample.sdb',

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',
));
@@ -56,3 +56,11 @@ 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)
@@ -40,8 +39,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

@@ -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(

57
license.md Normal file
View File

@@ -0,0 +1,57 @@
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

18
readme.md Normal file
View File

@@ -0,0 +1,18 @@
[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.
Refer to the `examples` directory for examples. Dibi documentation is
available on the [homepage](http://dibiphp.com).
Dibi requires PHP 5.2.0 or later. It has been tested with PHP 5.5 too.

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,17 +4,15 @@
* 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());
@@ -23,8 +21,8 @@ $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 );
@@ -32,8 +30,8 @@ $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 );
@@ -41,32 +39,5 @@ $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 (revision $WCREV$ released on $WCDATE$)
Dibi 2.1.0 (revision $WCREV$ released on $WCDATE$)