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

Compare commits

...

874 Commits
v1.1 ... master

Author SHA1 Message Date
David Grudl
4ea907a48c used attribute Deprecated 2025-08-07 00:33:05 +02:00
David Grudl
3beee64a30 drivers: escape*() methods moved to Engine [WIP] 2025-08-07 00:33:05 +02:00
David Grudl
33da2b839e renamed driver classes 2025-08-07 00:33:05 +02:00
David Grudl
8c34f8df43 renamed interfaces (BC break)
Dibi\Driver => Dibi\Drivers\Connection
Dibi\ResultDriver => Dibi\Drivers\Result
Dibi\Reflector => Dibi\Drivers\Engine
2025-08-07 00:33:05 +02:00
David Grudl
0834c12eaf removed IConnection (BC break) 2025-08-07 00:33:05 +02:00
David Grudl
cdeafe9b27 opened 6.0-dev 2025-08-07 00:33:05 +02:00
David Grudl
32b6976209 removed support for SQLServer < 2012, PostgreSQL < 9.3 2025-08-07 00:26:19 +02:00
David Grudl
f484630e56 readonly properties 2025-08-07 00:26:19 +02:00
David Grudl
611e051c02 optimized global function calls 2025-08-07 00:26:19 +02:00
David Grudl
7595a6d5bd composer: added psr-4 loader 2025-08-07 00:25:10 +02:00
David Grudl
494d7c1c21 composer: require stable packages outside of nette 2025-08-07 00:25:10 +02:00
David Grudl
658dbe388a support for PHP 8.5 2025-08-07 00:10:17 +02:00
David Grudl
c7fe0fef21 uses PHP 8.2 features 2025-08-07 00:10:17 +02:00
David Grudl
9151d1eb9c requires PHP 8.2 2025-08-07 00:08:29 +02:00
David Grudl
d76f40c2a4 opened 5.1-dev 2025-08-07 00:04:06 +02:00
David Grudl
befde664fe tests: improved descriptions 2025-08-07 00:00:40 +02:00
David Grudl
e1c4cbaece exception: use natural explanatory style 2025-08-07 00:00:40 +02:00
David Grudl
1df20ced10 cs 2025-08-07 00:00:40 +02:00
David Grudl
ce1ba4668b uses promoted properties 2025-08-07 00:00:40 +02:00
David Grudl
0f21a6ab3d removed dead code 2025-08-07 00:00:40 +02:00
David Grudl
78f552fe8e github actions updated 2025-08-07 00:00:40 +02:00
David Grudl
97053089e0 Released version 5.0.2 2024-09-03 03:18:11 +02:00
Lukáš Kotržena
2c7b35c29d Result::normalize() Fixed normalization of "-." numbers 2024-09-03 03:16:52 +02:00
Marek Bartoš
c04d2197e3 Translator: fixed numeric column formatting 2024-09-03 03:10:05 +02:00
Matěj Koubík
d342d8d78f DibiExtension3: fixed schema 2024-09-03 03:10:05 +02:00
David Grudl
7d8c39f42a cs 2024-09-03 03:00:38 +02:00
David Grudl
29b58d64dd PdoDriver: applied #332 #287 2024-09-03 03:00:38 +02:00
David Grudl
0a32bb5bdf support for PHP 8.4 2024-09-03 03:00:38 +02:00
David Grudl
d707b4ba0e PascalCase constants 2024-09-03 03:00:38 +02:00
David Grudl
490cf143ba GitHub actions fixed
- https://learn.microsoft.com/en-us/answers/questions/1853144/error-failed-to-initialize-container-mcr-microsoft
- https://learn.microsoft.com/en-us/sql/tools/sqlcmd/sqlcmd-utility?view=sql-server-ver16&tabs=go%2Cwindows&pivots=cs1-bash
2024-09-03 03:00:38 +02:00
stanley89
12ffa0ffd1 Tracy\Panel: fixed type error 2024-09-02 23:53:15 +02:00
David Grudl
23f65ef837 Revert "SqliteDriver: disables exceptions (is enabled since PHP 8.3)"
This reverts commit bb1f7d4b93.
2024-09-02 23:53:15 +02:00
David Grudl
86a71dde28 Released version 5.0.1 2023-11-25 14:08:47 +01:00
David Grudl
bb1f7d4b93 SqliteDriver: disables exceptions (is enabled since PHP 8.3) 2023-11-25 14:08:47 +01:00
David Grudl
680026747e added DibiExtension3 2023-11-25 14:08:47 +01:00
Jan Rössler
7ca47508cb PostgreReflector: detect IDENTITY columns as autoincrement 2023-11-05 20:38:26 +01:00
Jan Rössler
beba7b3592 PostgreReflector: fix autoincrement column detection 2023-11-05 20:38:26 +01:00
David Grudl
6cc7ce8e44 used PhpStorm Language attribute 2023-11-05 20:38:25 +01:00
Petr Hubík
92b8e6077e fix: PDO::errorInfo() can return NULL as a code, but Exception does not accept NULL code 2023-09-29 15:55:05 +02:00
David Grudl
e45638eab4 cs 2023-09-29 15:55:05 +02:00
Marek Bartoš
8564217bc1 Fluent: execute() has conditional return type 2023-09-05 12:40:51 +02:00
David Grudl
82c45c3076 Released version 5.0.0 2023-08-09 16:38:02 +02:00
Miloslav Hůla
df45bd3553 added object translators (#420)
The Translator is now capable to translate objects into Expression via object translators registered by the Connection.
2023-08-09 16:35:02 +02:00
Miloslav Hůla
fe22e230ce tests: remove dependency on dibi_test database name 2023-08-09 16:35:02 +02:00
David Grudl
8257532630 used native PHP 8 functions 2023-08-09 16:35:02 +02:00
David Grudl
08dfc37492 added PHP 8 typehints 2023-08-09 16:33:28 +02:00
David Grudl
7acef0c34b added property typehints 2023-08-09 16:33:28 +02:00
David Grudl
b01d97ac86 removed Dibi\Strict 2023-08-09 16:33:28 +02:00
David Grudl
8915b0343c removed support for PHP 7 2023-08-09 16:33:28 +02:00
David Grudl
d1a3362321 coding style 2023-08-09 16:33:28 +02:00
David Grudl
b6ead80202 composer: updated dependencies 2023-08-09 16:15:31 +02:00
David Grudl
a640ac2a8f requires PHP 8.0 2023-08-09 16:15:31 +02:00
David Grudl
87e702d1fc opened 5.0-dev 2023-08-09 16:15:31 +02:00
David Grudl
cb0cf4ba2f Released version 4.2.8 2023-08-09 16:15:07 +02:00
David Grudl
8e7df8374b drivers: removed auto-free feature 2023-08-09 16:15:07 +02:00
Marek Bartoš
848ac76fed Fluent: improved phpDoc 2023-08-09 16:15:07 +02:00
David Grudl
a0f2ca2fca typo 2023-08-09 16:15:04 +02:00
David Grudl
cf14987b42 cs 2023-08-05 19:56:38 +02:00
David Grudl
01c7ab63e3 tested in PHP 8.3 2023-08-05 19:50:57 +02:00
David Grudl
520119740d updated .gitattributes 2022-12-21 02:06:10 +01:00
Marek Štípek
7fa05f381b Event: detecting source without filesystem check (#428)
Co-authored-by: Marek Stipek <stipek@shoptet.cz>
2022-11-18 04:40:51 +01:00
David Grudl
3a962de553 cs 2022-10-13 03:58:51 +02:00
David Grudl
96e370b8fe updated github workflow 2022-10-13 03:51:11 +02:00
Jirka Hrazdil
ec0455ae00 Panel: typo (#421) 2022-09-06 04:32:10 +02:00
David Grudl
b61737311e support for PHP 8.2 2022-09-06 04:26:58 +02:00
David Grudl
9d5d430d3d Released version 4.2.6 2022-01-19 18:38:15 +01:00
Miloslav Hůla
04bb5ede3d Translator: convert BackedEnum to scalar
also closes (#412)
2022-01-18 16:15:30 +01:00
Andrej Rypo
7d82ce2ff6 MySqliDriver::getResource() fixed access to resource being closed prior to the call in PHP 8 (#410) 2021-12-12 18:00:04 +01:00
David Grudl
82150d120d cs nullable typehints 2021-12-12 17:46:56 +01:00
David Grudl
0f045c0986 cs whitespace 2021-12-12 03:52:44 +01:00
David Grudl
5646884899 cs 2021-12-12 03:52:44 +01:00
David Grudl
af33a354d6 removed ecs.php 2021-12-12 03:52:44 +01:00
David Grudl
a0c86747dc GitHub Actions updates 2021-12-06 19:05:06 +01:00
David Grudl
d70e274244 Released version 4.2.5 2021-11-29 13:48:16 +01:00
David Grudl
e05eb01233 fixed PHP 7.2 compatibility 2021-11-28 15:09:41 +01:00
David Grudl
2ac618ffff Date 0000-01-01 is valid [Closes #402] 2021-11-24 18:34:20 +01:00
Milan Otáhal
1881fea0e5 Profiler is not used in CLI mode 2021-11-24 18:34:20 +01:00
Jan Rössler
cb82357cfb Helpers::detectType(): detect PostgreSQL range types as Type::TEXT 2021-11-24 18:34:20 +01:00
Jan Rössler
0a29fcb502 PostgreReflector: fix reflection of matview columns on PostgreSQL 12+ 2021-11-24 18:34:20 +01:00
David Grudl
8270b7c1c3 support for PHP 8.1 2021-11-24 18:34:20 +01:00
David Grudl
73e16eb1a3 Released version 4.2.3 2021-07-23 10:49:27 +02:00
David Grudl
0b394a993d SqlsrvDriver: fixed after 40ad77cf [Closes #391][Closes #392] 2021-06-30 12:47:45 +02:00
David Grudl
df3edee70b removed travis 2021-04-23 20:54:50 +02:00
David Grudl
245da39a9f added github workflows 2021-04-23 20:53:38 +02:00
David Grudl
3df64fc3b3 fixed tests 2021-04-23 20:48:29 +02:00
David Grudl
95c3f72a17 Released version 4.2.2 2021-04-21 13:56:00 +02:00
David Grudl
d71caf0c75 Row: fixed ?? usage 2021-04-21 13:54:59 +02:00
Miloslav Hůla
3066fea2aa Connection: begin(), commit() & rollback() calls are forbidden in transaction() 2021-04-05 16:50:15 +02:00
Miloslav Hůla
b00e556289 Connection::transtaction() call can be nested 2021-04-05 16:50:15 +02:00
Miloslav Hůla
877dffd460 tests: use test() helper 2021-04-05 13:37:16 +02:00
Miloslav Hůla
7049949b14 Connection::transaction(): pass self as a callback argument 2021-04-05 13:37:16 +02:00
Miloslav Hůla
771e846a62 tests: Sqlite3 driver fix 2021-04-05 13:37:16 +02:00
David Grudl
4e056c52dd updated appveyor.yml 2021-03-10 16:53:34 +01:00
David Grudl
40ad77cf5f SqlsrvDriver: workaround for "Driver's SQLSetConnectAttr failed on ODBC <=13" bug 2021-03-10 16:42:33 +01:00
David Grudl
d09b462eef Released version 4.2.1 2021-03-01 15:17:15 +01:00
David Grudl
4c796a0e0f readme: added support me 2021-02-05 21:53:00 +01:00
Jan Kuchař
304af5185d PostgreSQL driver: escaping of save point name (#383) 2021-02-05 21:52:45 +01:00
David Grudl
e046935137 Strict: refactoring 2020-12-30 12:44:04 +01:00
Jan Kuchař
1a77048225 PostgreReflector: removed version check (#381) 2020-12-23 10:31:03 +01:00
David Grudl
ca74488636 Released version 4.2.0 2020-11-25 21:02:22 +01:00
David Grudl
07f994a0b5 added Connection::transaction() 2020-11-25 20:59:58 +01:00
David Grudl
5fa5acb724 Connection: added option [result][formatTimeInterval] that sets time-interval column decoding 2020-11-02 15:28:28 +01:00
David Grudl
98563d8165 Connection: added option [result][normalize] [Closes #367] 2020-11-02 15:28:28 +01:00
David Grudl
c464960239 Connection, Result: added format 'native' 2020-11-02 15:28:28 +01:00
David Grudl
a9e90d0b22 Connection, Results: refactorings, added Result::setFormats() 2020-11-02 15:28:28 +01:00
David Grudl
decb30de1e Connection::translateArg() removed (BC break) 2020-11-02 15:28:28 +01:00
David Grudl
f4e71e8855 requires PHP 7.2 2020-11-02 15:28:28 +01:00
David Grudl
39f59e0f08 opened 4.2-dev 2020-11-02 15:28:28 +01:00
David Grudl
0d2f643795 strict comparison 2020-11-02 15:27:54 +01:00
David Grudl
70d4246866 Tracy\Panel: table is sortable 2020-11-02 15:05:55 +01:00
David Grudl
34a1665915 coding style 2020-11-02 15:05:55 +01:00
David Grudl
b27db4a9aa updated gitattributes 2020-11-02 15:05:55 +01:00
David Grudl
212dd1ae55 updated phpstan 2020-11-02 15:05:55 +01:00
David Grudl
b9683f8a3c updated nette/coding-standard 2020-11-02 15:05:55 +01:00
David Grudl
177a800bff PdoDriver: changes error mode do ERRMODE_SILENT (for PHP 8.0) 2020-11-02 15:05:55 +01:00
David Grudl
fa6a1203a9 fixed compatibility with PHP 8 [Closes #379] 2020-11-02 15:05:55 +01:00
David Grudl
3f7171c7a4 tested on PHP 8.0 2020-10-30 13:50:54 +01:00
David Grudl
e4b6e769ee Dibi\Helpers::getSuggestion(): item may be an int, type cast fix (#378) 2020-10-14 12:00:23 +02:00
David Grudl
24d0b069d8 Helpers::getSuggestion(): support for reflection objects moved to Strict 2020-10-14 12:00:04 +02:00
David Grudl
34bc742245 refactoring 2020-10-08 16:49:47 +02:00
Miloslav Hůla
f5fa2255ff FileLogger: fixed object to string conversion with custom driver (#376) (#376)
Co-authored-by: Miloslav Hůla <miloslav.hula@fsv.cvut.cz>
2020-10-08 16:38:35 +02:00
Miloslav Hůla
7b02296f3e Tracy\Panel: fixed object to string converion error with custom driver (#373)
Co-authored-by: Miloslav Hůla <miloslav.hula@fsv.cvut.cz>
2020-10-08 16:38:35 +02:00
David Grudl
df4cddac1f Tracy\Panel: supports multiple connections [Closes #365]
Partially reverts "Tracy\Panel: one panel is used per connection"

This reverts commit ae6c8756b6.
2020-10-08 16:38:35 +02:00
groupnet
cc37121390 Postgre driver - add connect_type config parameter (#370)
- adds the option to pass the connect_type as config parameter
 - PHP default is 0, but to make this change non-breaking defauls to PGSQL_CONNECT_FORCE_NEW
 - see PHP docs: https://www.php.net/manual/en/function.pg-connect.php
2020-10-08 15:55:11 +02:00
LHavlicek
a95b409231 MySqliDriver: fixed DateInterval encoding (#371) 2020-10-08 15:55:11 +02:00
Jakub Bouček
3b057c2e35 MySqliDriver: added support for ping (#372) 2020-10-08 15:55:11 +02:00
David Grudl
f444b5d993 typo 2020-10-08 15:55:11 +02:00
David Grudl
6e41c4223b tests: test() with description 2020-10-08 15:55:11 +02:00
David Grudl
0ee4628712 SqlsrvDriver: improved escapeBinary [Closes #287] 2020-10-07 03:19:03 +02:00
David Grudl
ab3677203c added funding.yml 2020-10-07 03:19:03 +02:00
Jan Barášek
1bdf6e93d0 PhpStan fixes (#363) 2020-05-07 21:41:28 +02:00
David Grudl
ed2a827419 Released version 4.1.3 2020-03-26 04:10:39 +01:00
David Grudl
e46be6cee6 SqliteResult: workaround for PHP bug 79414 2020-03-26 04:10:39 +01:00
David Grudl
0f69d5d32c Result: does not drop the value if detection fails 2020-03-26 04:10:39 +01:00
Adam Klvač
e826e3a719 MySqliDriver: coalesced password to an empty string (#360)
mysqli::real_connect() expects parameter 3 to be string, yields an error on NULL.
2020-03-26 03:32:03 +01:00
David Grudl
6eac117f5f Result::fetchAssoc() DateTime in key is converted to string [Closes #359] 2020-03-03 17:18:37 +01:00
David Grudl
2a2c814b0a readme.md: updated 2020-03-03 16:50:43 +01:00
David Grudl
dfab3d711c added DummyDriver 2020-03-03 16:21:21 +01:00
David Grudl
34e16031f7 added phpstan.neon 2020-02-23 19:15:59 +01:00
David Grudl
73160e9418 travis: uses PHP 7.4 for coding checks 2020-02-23 19:08:21 +01:00
David Grudl
f18056a066 Released version 4.1.2 2020-02-23 18:50:27 +01:00
Milan Pála
0bd222b3f1 tests: added reconnect test (#352) 2020-02-23 18:50:27 +01:00
David Grudl
9f71f39470 Connection: translator is created/destructed in connect/disconnect [Closes #352][Closes #354] 2020-02-23 18:50:27 +01:00
Enrico Dias
0b0d805040 FileLogger: refactoring (#351) 2020-02-09 17:22:55 +01:00
Enrico Dias
8c761eac5c FileLogger: Add option to log errors only (#351) 2020-02-09 17:17:05 +01:00
groupnet
2f857c28d6 PostgreDriver: fixed persistent connections (#348)
- https://www.php.net/manual/en/function.pg-pconnect.php
2020-01-24 13:41:57 +01:00
David Grudl
efe1cbdc20 cs 2020-01-12 13:46:23 +01:00
David Grudl
21dad1d846 composer: license clarification 2020-01-07 11:53:19 +01:00
David Grudl
7d55fd03b0 composer: added PHPStan 2019-12-11 21:05:37 +01:00
Ashus
294787a26e Add support for escapeLike without % on any side (#346) (BC break) 2019-11-25 14:01:24 +01:00
David Grudl
9d4bef53d3 travis: added PHP 7.4 2019-11-19 20:15:32 +01:00
David Grudl
1db63d81e9 fixes for PHP 7.4 2019-11-19 01:49:22 +01:00
Adam Klvač
c7dee4d822 SqlsrvResult: fixed illegal false return value from sqlsrv_fetch_array() (#344)
On error, sqlsrv_fetch_array() returns false, which causes an error due to the return type declaration. This commit handles that by casting such value to null the same way other result drivers do it.
2019-11-19 01:30:34 +01:00
Miloslav Hůla
f2927a1b08 OracleResult: LONG type is textual [Closes #342] (#343) 2019-11-06 16:43:33 +01:00
David Grudl
b5a66fdb26 typo 2019-10-22 19:39:16 +02:00
David Grudl
c38f6991b0 Released version 4.1.0 2019-10-22 19:30:46 +02:00
David Grudl
faab306418 Translator: trims spaces from SQL [Closes #326] 2019-10-22 19:30:46 +02:00
Josef Drábek
74ba6cfd34 Use null coalescing operator (#340) 2019-10-17 22:12:54 +02:00
David Grudl
f46b7f4d79 travis: fixed databases 2019-09-30 10:59:15 +02:00
David Grudl
c1640c5e7b getInsertId() is be able to return negative ID's [Closes #336] 2019-09-18 10:35:26 +02:00
Pavel Janda
a2afac80f2 Connection: added option [result][formatJson] that sets json column decoding (text|object|array) (#335) 2019-09-09 19:48:01 +02:00
David Grudl
0535d57e6b implemented MySqliDriver::escapeDateInterval() 2019-08-30 18:55:20 +02:00
Jan Pecha
369768a62a added Driver::escapeDateInterval() (BC break) (#334) 2019-08-30 18:55:20 +02:00
David Grudl
78d6603bb0 Driver::escapeDate() & escapeDateTime() accepts only DateTimeInterface (BC break) 2019-08-30 18:55:15 +02:00
Tomáš Kuthan
7f22279333 SqlsrvDriver: Correct escaping of special characters (N prefix) (#332)
In case nvarchar type is used and e.g. chinese have to be saved, there have to be N in front of the value, this escaping works fine for varchar columns as well.
2019-08-30 18:54:06 +02:00
David Grudl
e66cb84cb5 removed deprecated stuff 2019-08-30 18:54:06 +02:00
David Grudl
5ab8afc704 opened 4.1-dev 2019-07-12 14:31:51 +02:00
magikstm
219882a962 readme: some minor corrections (#331) 2019-05-29 13:44:50 +02:00
Jiří Zralý
7e127f5914 Documentation: Added %N identifier (#330) 2019-04-16 21:50:55 +02:00
David Grudl
79f841ec90 Released version 4.0.2 2019-03-11 21:38:25 +01:00
pepa-linha
69eaa71fde Dibi\Fluent: add annotation for methods or() (#328) 2019-02-11 12:37:24 +01:00
David Grudl
f895493016 travis: finely segmented matrix, added PhpStan 2019-02-05 22:11:08 +01:00
Radovan Kepák
19172c801e Added new getTypes method (#327)
Added getTypes method, to get all columns and its types, this is faster then write foreach for getting all columns, and getColumns do not get column type (there is null)
2019-01-26 15:37:58 +01:00
Jan Kuchař
2b5683d0f2 PostgreDriver: fix indexes reflection for indexes on expressions (#323) 2018-12-15 00:47:26 +07:00
Jan Kuchař
76593b7da4 dibi: fix dibi::*() static methods annotations (#324) 2018-12-12 07:42:02 +07:00
Chrudos Vorlicek
dd2fd654be Result::normalize() Fix select float in format of e-notation (#317) master (#321) 2018-10-25 22:33:09 +02:00
David Grudl
12cbbb3140 travis: added PHP 7.3 2018-10-17 17:47:27 +02:00
David Grudl
811974139e Released version 4.0.1 2018-09-17 13:50:54 +02:00
David Grudl
7a49609468 test: fix for PHP 7.3 2018-09-17 13:45:50 +02:00
Jan Kuchař
89987f0cee PdoDriver: check for misconfigured PDO connections resource (#294) 2018-09-17 13:45:50 +02:00
David Grudl
b7e467ecac drivers: config in not passed via reference (BC break) 2018-09-17 13:45:50 +02:00
jan-oliva
fe0e7510af Firebird: Add escapeLike() (#300,#305) 2018-09-17 13:45:50 +02:00
Miloslav Hůla
eaf2494d90 Connection: added config option onConnect (#303)
onConnect option is an array of SQL queries run by Connection::query() right after a database connection is established.
2018-09-17 13:45:50 +02:00
Dalibor Korpar
168971292d Connection::update() Support updating multiple tables at once (#316) 2018-09-17 13:45:49 +02:00
David Grudl
95c424a71d Connection: accepts Driver instance (fixes 51fa3b9) [Closes #315] 2018-09-13 13:10:24 +02:00
David Grudl
4b85f0a973 travis: uses NCS 2 2018-09-13 03:28:02 +02:00
Jan Kuchař
e7539102cb fix: setType should accept null as type (#309) 2018-08-22 15:43:11 +02:00
David Grudl
0ad2dd70bc tests: added complex test for %like 2018-08-22 13:45:39 +02:00
Jan Kuchař
4abe874ce9 fix TypeError: substr() expects parameter 1 to be string, null given (#306) 2018-08-22 12:08:35 +02:00
Jan Kuchař
15df96bb22 fixed typehint (#307) 2018-08-22 12:08:03 +02:00
David Grudl
2870fb9b31 OdbcDriver: added option 'microseconds' 2018-08-09 22:55:09 +02:00
Pavel Kácha
c8dfb1f863 Dibi\Fluent: add annotations for methods and(), asc(), desc() #298 (#299) 2018-06-28 14:25:20 +02:00
David Grudl
9840c31995 updated donation links 2018-06-22 11:47:44 +02:00
Miroslav Koula
25fda3f8f1 DibiExtension: compatibility with Nette DI 3.x (#297)
Nette DI 3.x require $container->setFactory() usage except of $container->setClass()
2018-06-14 18:17:37 +02:00
Jan Endel
38128fbf9e typo
for example fluent:

$dibiConnection->select(‘id’)
    ->from(‘users’);

will not pass static analysis although is completely valid code.
2018-06-13 11:47:55 +02:00
Josef Drábek
73790f4321 PdoDriver::getInsertId() fixed 2018-05-30 14:00:54 +02:00
David Grudl
3930dafe3f Sqlite3Driver becomes alias for SqliteDriver 2018-05-23 17:14:32 +02:00
David Grudl
70b1e08d83 Released version 4.0.0 2018-05-11 19:57:59 +02:00
David Grudl
6419c62368 readme.md: updates 2018-05-11 19:57:59 +02:00
David Grudl
d3fe68fe1e Update Github templates
Thanks to Babel for inspiration <3
2018-05-10 22:34:43 +02:00
David Grudl
a6392db67d improved phpDoc, capitalized Dibi 2018-05-10 22:34:04 +02:00
David Grudl
a6d46c7006 Connection: begin, commit and rollback catches DriverException 2018-05-09 13:33:54 +02:00
David Grudl
bd8ce38320 MySqliDriver: refactoring, uses OOP style 2018-05-09 13:33:54 +02:00
David Grudl
8dff5b5b3c Connection::query() and Fluent::execute() always return Result, not the number of affected rows (BC break) 2018-05-09 13:26:13 +02:00
David Grudl
e291d4d825 type fixes 2018-05-09 13:26:13 +02:00
David Grudl
06a487532d Result: added getColumnCount() 2018-05-09 13:26:13 +02:00
David Grudl
923fc0f3c3 Connection: $connected replaced with $driver 2018-05-09 13:26:13 +02:00
David Grudl
51fa3b9086 Dibi\Driver::connect() replaced with constructor (BC break) 2018-05-09 13:22:46 +02:00
David Grudl
d4f30ddf5b typos 2018-05-09 13:22:46 +02:00
David Grudl
7c9b3caed9 PdoDriver: returns OracleReflector, PostgreReflector, SqlsrvReflector 2018-05-09 13:22:46 +02:00
David Grudl
3eb255899f result drivers: resultSet is not nullable 2018-05-09 13:22:46 +02:00
David Grudl
8c57b0aad9 drivers divided into Driver and Reflector (BC break) 2018-05-09 13:22:46 +02:00
David Grudl
7d704d7edd drivers divided into Driver and ResultDriver (BC break) 2018-05-09 11:44:43 +02:00
David Grudl
479520b864 typos 2018-05-09 11:43:45 +02:00
David Grudl
ca6f1c819a type improvements 2018-05-09 11:43:36 +02:00
David Grudl
9bcca8feb0 Revert "Result: fetch refactoring" [Close #284]
This reverts commit ab7683a3d2.
2018-05-09 11:43:36 +02:00
David Grudl
3c9a3da83a Result: JSON is always decoded as array [Closes #282] 2018-05-09 11:43:36 +02:00
David Grudl
76cff5c10a Result: calls unescapeBinary() only for strings [Closes #283] 2018-05-09 11:43:36 +02:00
David Grudl
bea524a621 removed MsSqlDriver (is not available in PHP7) 2018-05-09 11:43:09 +02:00
David Grudl
030554e1ae added dibi::stripMicroseconds 2018-04-19 13:03:38 +02:00
David Grudl
10324322be readme.md: updated 2018-04-19 13:03:38 +02:00
David Grudl
d7270e1f4d Strict: extension methods are deprecated 2018-04-19 13:03:38 +02:00
David Grudl
fbdd22de35 Connection::__construct() parameter config should be array (BC break) 2018-04-19 13:03:38 +02:00
David Grudl
0129d340d3 removed support for FirePHP 2018-04-19 13:03:38 +02:00
David Grudl
30dec49a9d Column: types adjustment 2018-04-19 13:03:38 +02:00
David Grudl
47179d5632 Sqlite3Driver: for SQLite 3 is not needed to strip [] from column names 2018-04-19 13:03:37 +02:00
David Grudl
cb067a6bec Sqlite3Driver: removed support for charset conversion (BC break!) 2018-04-19 13:03:37 +02:00
David Grudl
045e45a8c6 refactoring 2018-04-19 13:03:35 +02:00
David Grudl
5a2332899b type fixes 2018-04-17 15:23:51 +02:00
David Grudl
ab7683a3d2 Result: fetch refactoring 2018-04-17 15:23:51 +02:00
David Grudl
a6c53c7462 examples: dibi:: replaced with $dibi-> 2018-04-17 15:23:51 +02:00
Jan Endel
3ccd802814 add interface IConnection (#274) 2018-04-17 10:00:27 +02:00
Jan Dvořák
b1420cee0b Fluent: Remove return type for fetch method (#280) 2018-04-17 09:57:10 +02:00
David Grudl
3050aebb48 typo 2018-04-09 16:31:40 +02:00
David Grudl
cf0129a194 Translator: improved Expression usage 2018-04-06 02:56:22 +02:00
David Grudl
ccc035c8fb removed dibi::$defaultDriver (BC break) 2018-04-06 02:28:26 +02:00
David Grudl
2d523f6034 dibi: monostate implemented via __callStatic 2018-04-06 02:22:31 +02:00
David Grudl
6575630cad added Connection::expression() 2018-04-06 01:20:32 +02:00
David Grudl
6deb7f7d08 PdoDriver: improved detection of query result [Closes #279] 2018-03-28 18:03:39 +02:00
David Grudl
bc5e4e378c appveyor: improved 2018-03-23 17:53:13 +01:00
David Grudl
05999b4dde readme.md: better requirements info 2018-03-23 15:20:34 +01:00
David Grudl
e8638239e9 appveyor: use x64 PHP 2018-03-23 15:15:22 +01:00
David Grudl
5ad6cc1171 DateTime::modifyClone() is deprecated (BC break) 2018-03-23 13:45:39 +01:00
David Grudl
2dec5618a6 DateTime: added immutable usage detector™ 2018-03-23 13:45:39 +01:00
David Grudl
c386357850 DateTime extends DateTimeImmutable instead of DateTime (BC break) 2018-03-23 13:45:39 +01:00
David Grudl
8f47def4a2 DateTime: removed setTimestamp() and getTimestamp(), big int are supported in x64 PHP versions 2018-03-23 13:45:39 +01:00
David Grudl
0a19ccbf80 added JSON support [Closes #269] 2018-03-23 13:45:39 +01:00
David Grudl
7481c38759 reflection: removed Column::isUnsigned() (BC break) 2018-03-23 12:09:34 +01:00
David Grudl
714272bbbf examples: added notice when vendor/autoload.php not found 2018-03-23 11:58:09 +01:00
David Grudl
3616130959 added typehints 2018-03-21 16:36:47 +01:00
David Grudl
837b97b582 phpDoc: added $var name to @param 2018-03-21 13:38:58 +01:00
David Grudl
121234aa9a removed loader.php 2018-03-09 15:22:39 +01:00
David Grudl
a1ef432ae5 readme.md: static -> object 2018-03-09 15:01:30 +01:00
David Grudl
9b12106437 type fixes 2018-03-09 13:18:32 +01:00
David Grudl
3c7985bd22 appveyor: PHP is downloaded using cURL
"03/mar/2018: We've upgraded the server bandwidth. This is however still not sufficient to handle all empty user agent connections. Please update the user agent in your scripts accordingly or contact us so we can discuss it."
2018-03-08 13:52:34 +01:00
Korney Czukowski
432d0a8f7c Previous exception can now be passed to Dibi\Exception constructor (#275) 2018-02-16 14:11:59 +01:00
jahudka
3f020be15b Firebird: fix datetime precision (#277) (#273) 2018-02-16 10:47:00 +01:00
David Grudl
bff1e6310f loader: fixed missing class 'dibi.php' 2018-02-15 11:53:15 +01:00
Petr Bugyík
d2dbcfa43c drivers: changed self:: to static:: 2018-02-14 13:05:48 +01:00
David Grudl
c9c104249f coding style 2018-02-11 22:48:56 +01:00
Sean Snyder
5046929e28 PostgreDriver::getInsertId() Ensuring that an integer is returned, if postgres returned a string (#271) 2017-12-21 20:02:16 +01:00
Petr Kučera
cac571ee60 PdoDriver: Missing dblib in switch (#267)
Pull request #249 forgot about dblib in switch
2017-10-05 16:12:06 +02:00
David Grudl
49dca48c04 readme: updated 2017-09-26 16:04:35 +02:00
David Grudl
9a123f3263 coding style 2017-09-26 13:27:50 +02:00
David Grudl
e93bab27e9 Translator: Dibi\Expression should be used instead of array 2017-09-21 15:05:52 +02:00
David Grudl
499e3aea40 added Dibi\Expression [Closes #264] 2017-09-21 14:54:08 +02:00
David Grudl
832313bc73 whitespace 2017-09-21 14:17:14 +02:00
David Grudl
ecda8d0adf Translator: fixed %dt with DateTimeInterface object [Closes #263] 2017-09-21 14:03:37 +02:00
Miloslav Hůla
f29f52eb28 Fluent: fixed TypeError, query() may return Result|int 2017-09-07 21:28:29 +02:00
Miloslav Hůla
9eb0f1422c OdbcDriver, OracleDriver, SqlsrvDriver, Sqlite3Driver: query() returns ResultSet only when contains columns 2017-09-07 21:27:46 +02:00
David Grudl
b35b75d9c7 MySqliDriver: removed deprecated stuff 2017-09-07 21:27:30 +02:00
David Grudl
125db626e5 Connection, dibi: deprecated insertId() & affectedRows() 2017-09-07 21:27:30 +02:00
David Grudl
0531e82838 composer: used Tester 2 2017-09-07 21:25:28 +02:00
Miloslav Hůla
8647901d3c Tracy\Panel: fixed TypeError in renderException() 2017-09-06 18:50:10 +02:00
David Grudl
5c41282b88 coding standard: added exception for HashMap.php 2017-08-05 13:42:47 +02:00
Miloslav Hůla
6550b53175 tests: connection removed from bootstrap 2017-08-05 13:41:08 +02:00
Miloslav Hůla
0c09ad97ca HasmMap: fixed empty property name access
Introduced by 3891625cd1

PostgreSQL uses '::' syntax for type casting. Before this fix, HashMap returned ':\xff:' during SQL translation/substitution.
2017-08-05 13:33:36 +02:00
David Grudl
1b516786fb Microsoft SQL Server and MSSQL support for microseconds fix cont. 2017-07-26 19:25:38 +02:00
David Grudl
55523f4ed8 typo 2017-07-24 17:04:13 +02:00
David Grudl
ba927b4782 travis: use stages 2017-07-24 14:40:41 +02:00
Jan Pecha
afe728d07a Result::fetch() removed typehint (#257) 2017-07-22 11:14:39 +02:00
David Grudl
2d5ac775bc used safe casting to int (BC break) 2017-07-22 00:56:27 +02:00
David Grudl
49e90517b9 Translator: %i %f throws exception when value is not numeric (BC break) 2017-07-22 00:40:14 +02:00
David Grudl
1b59801bed removed unnecessary (int) 2017-07-22 00:40:13 +02:00
David Grudl
e755a59063 __toString() returns always string 2017-07-22 00:40:07 +02:00
hubipe
60978bb176 Microsoft SQL Server and MSSQL support for microseconds fix (#249) 2017-07-21 23:04:42 +02:00
David Grudl
cb9fd29207 strict type fixes [Closes #255][Closes #256] 2017-07-21 22:53:46 +02:00
David Grudl
662927d823 examples: uses composer autoload 2017-07-21 22:53:46 +02:00
David Grudl
4ed3e689a7 examples: added declare strict types 2017-07-21 22:53:46 +02:00
David Grudl
bced758bbd travis: tested using Nette Coding Standard 2017-07-21 22:53:46 +02:00
David Grudl
dac0a116a8 coding style: fixes in code 2017-07-21 22:53:46 +02:00
David Grudl
a299c622c3 coding style: TRUE/FALSE/NULL -> true/false/null 2017-07-21 22:53:45 +02:00
David Grudl
3b37295e78 coding style: fixed spaces & use statements order 2017-07-21 22:53:45 +02:00
David Grudl
1278907f39 OracleDriver: by default uses native date format 2017-07-21 22:53:45 +02:00
David Grudl
14ca289e59 readme: updated installation and requirements 2017-07-21 22:53:45 +02:00
David Grudl
a6028054d6 added declare(strict_types=1); 2017-06-10 03:45:33 +02:00
David Grudl
957d9281f3 strict type fixes 2017-06-10 03:45:32 +02:00
David Grudl
f9997f9b52 removed useless type juggling and checking 2017-06-10 03:45:32 +02:00
David Grudl
43045a0585 removed useless annotations @param and @return 2017-06-10 03:45:32 +02:00
David Grudl
859eada4e7 added PHP 7.1 scalar and return type hints 2017-06-10 03:45:29 +02:00
David Grudl
7d42317279 fetch(), fetchSingle(), getAffectedRows(), getInsertId() return NULL instead of FALSE on error (BC break) 2017-06-10 03:22:05 +02:00
David Grudl
5c514f6721 Translator::formatValue() second arg can be NULL 2017-06-10 03:17:00 +02:00
David Grudl
68e0aef469 used variadics (BC break: signatures are changed) 2017-06-10 03:17:00 +02:00
David Grudl
24180c76bd uses only DateTimeInterface & Throwable 2017-06-10 03:16:59 +02:00
David Grudl
3891625cd1 used PHP 7.1 features
- ::class
- ... argument unpacking
- removed call_user_func
- operator ??
- list()
- short <?=
2017-06-10 03:16:59 +02:00
David Grudl
750d70c77a removed DateTime::__wakeup 2017-06-10 03:16:59 +02:00
David Grudl
7f8e36c1e1 removed PHP < 7.1 support 2017-06-10 03:16:59 +02:00
David Grudl
e1598cc7da requires PHP 7.1 2017-06-10 03:16:59 +02:00
David Grudl
db8346a124 removed deprecated stuff 2017-06-10 03:16:59 +02:00
David Grudl
acc2d000c4 loader: old class names triggers E_USER_DEPRECATED, removed preloading (BC break) 2017-06-10 03:16:59 +02:00
David Grudl
85787cf9cd opened 4.0-dev 2017-06-10 03:08:16 +02:00
David Grudl
e45a86d58c Released version 3.1.0 2017-06-10 03:08:16 +02:00
David Grudl
e891bdd862 DibiExtension22: added $debugMode to constructor 2017-06-10 03:08:16 +02:00
David Grudl
8dc5567bdd Helpers::loadFromFile added $onProgress 2017-06-10 03:08:16 +02:00
David Grudl
e3bfac2316 Helpers::loadFromFile improved 2017-06-10 03:08:16 +02:00
David Grudl
53475ba05a loader: uses only Composer's autoloader 2017-06-10 03:08:14 +02:00
David Grudl
c219726914 removed bridges for Nette < 2.2 2017-06-10 03:06:01 +02:00
hubipe
ed0cb63df0 Support for microseconds (#246) 2017-06-10 03:06:01 +02:00
Aleš Culek
1ab69f3576 OracleDriver: added 'nativeDate' option, formatDate & formatDateTime are deprecated (#232) 2017-06-10 03:06:01 +02:00
David Grudl
70f29f6857 removed folder /dibi 2017-06-10 03:06:01 +02:00
David Grudl
d365077319 opened 3.1-dev 2017-06-10 03:05:55 +02:00
David Grudl
0e5d951dfb Released version 3.0.8 2017-06-10 03:05:18 +02:00
David Grudl
126422ad7e strict fixes 2017-06-10 03:05:18 +02:00
David Grudl
277f52c928 appveyor: is unable to start MSSQL 2012 & 2014 together 2017-06-10 02:58:47 +02:00
David Grudl
80ac569621 fixed phpDoc 2017-06-10 02:58:47 +02:00
David Grudl
d9628f933d coding style: removed space after reference & 2017-06-10 02:58:47 +02:00
David Grudl
f7009f3e0c Tracy\Panel: better typography 2017-06-10 02:58:47 +02:00
Jiří Trávníček
36d30c1fcf Dibi\Bridges\Tracy\Panel: host added to tracy panel [closes #250] (#251) 2017-06-10 02:58:44 +02:00
David Grudl
ae6c8756b6 Tracy\Panel: one panel is used per connection 2017-06-10 02:58:06 +02:00
David Grudl
6b2c996b16 Tracy\Panel: dump() may fails
related: https://forum.nette.org/cs/26790-error-dibi-bridges-tracy-panel-oracle
917971992f (commitcomment-18444224)
2017-06-09 12:12:07 +02:00
David Grudl
718c617764 travis: removed HHVM 2017-06-09 12:12:07 +02:00
David Grudl
6194152e67 examples: tracy is loaded before output [Closes #248] 2017-06-09 12:12:07 +02:00
David Grudl
d39603e23d updated .gitattributes 2017-06-09 12:12:07 +02:00
David Grudl
22e6ea4e40 Released version 3.0.7 2017-01-04 15:18:17 +01:00
David Grudl
f0d2c3f414 travis: removed PHP 7.1 from allowed failures 2017-01-04 15:18:17 +01:00
David Grudl
873ed3115d Connection::translateArgs() is protected [Closes #237] 2017-01-04 15:18:17 +01:00
Martin Dzíbela
73289d0569 PostgreSQL: add support for more than one schema in search_path (#239) 2017-01-04 15:18:17 +01:00
David Grudl
7b899ddda5 updated contributing.md, added GitHub templates 2017-01-04 15:18:17 +01:00
Ondřej Mirtes
8860268791 typos (#243) 2016-12-03 19:29:29 +01:00
Honza Machala
551b576271 Typos (#242) 2016-11-14 13:47:45 +01:00
David Grudl
74d0a78ec2 Result, Row: added support for datetime like 'Jun 17 2015 12:00:00:000AM' [Closes #180] 2016-09-02 17:36:37 +02:00
Aleš Culek
be7c3f095d Implemented OracleDriver::getColumns() (#233) 2016-08-09 22:37:45 +02:00
Radovan Kepák
3a6dc07da8 FirebirdDriver: Fixed DriverException throw (#231)
Fixed fetch Dibi\DriverException throw and more PHP warnings silenced
2016-08-09 22:36:44 +02:00
David Grudl
9b070bb737 Released version 3.0.6 2016-07-31 16:50:07 +02:00
David Grudl
917971992f Bridges\Tracy\Panel: silenced PHP warning
https://forum.nette.org/cs/26790-error-dibi-bridges-tracy-panel-oracle
2016-07-27 14:01:46 +02:00
Radovan Kepák
bc564555f8 FirebirdDriver: silenced PHP warning
If fetch have error, PHP show Warning, this is error by my opinion as Dibi Throw Exception with information, so the Warning is useless, and even more, if we catch exception, we still have warning.
2016-07-27 13:55:15 +02:00
David Grudl
3e20a6b8fc Dibi\DateTime::__wakeup() doesn't call parent after 8e8e6dfd [Closes #228] 2016-07-27 13:28:23 +02:00
David Grudl
c019e7cac2 tests: fixed compatibility with PHP 7.1 2016-07-21 14:38:56 +02:00
David Grudl
2294c195f4 Released version 3.0.5 2016-07-20 16:15:13 +02:00
David Grudl
25246529f7 Translator, Fluent: preserve dot in name after AS [Closes #224] 2016-07-20 16:13:33 +02:00
David Grudl
d405ec369b Translator: added %N 2016-07-20 16:13:32 +02:00
David Grudl
b7974fe192 travis: added PHP 7.1 2016-07-20 15:54:58 +02:00
David Grudl
80f1898e1b tests: removed deprecated 'storage_engine' 2016-07-20 15:50:33 +02:00
Roman Pavlík
8e8e6dfdca Dibi\DateTime: provides BC for serialized older versions [Closes #226] (#227) 2016-07-20 15:50:33 +02:00
Milan Pála
6510fcce25 Disconnect on not connected driver not fail (#222)
Sometimes database go away and Connection::isConnected() is returning TRUE. Prevent this should be posibble to disconnect on closed connection without error.
2016-07-20 15:50:32 +02:00
aldria
b7d84b90ef Correct limit and offset for Firebird Driver (#221)
SELECT [FIRST (<int-expr>)] [SKIP (<int-expr>)] <columns> FROM ...
2016-05-27 03:48:06 +02:00
David Grudl
2571e54f3c composer.json: replaces all dg/dibi versions 2016-05-04 20:13:50 +02:00
Aleš Culek
15e6d9f738 Implemented OracleDriver::getAffectedRows() 2016-05-03 08:55:22 +02:00
David Grudl
ddfd4a0f1a tests/travis: reports code coverage to Coveralls 2016-04-21 11:29:10 +02:00
David Grudl
4e838fc2b5 Released version 3.0.4 2016-04-06 19:09:24 +02:00
David Grudl
37487816db removed Strict from exceptions [Closes #216] 2016-04-06 18:52:42 +02:00
David Grudl
0c099bb2bc tests: a different .ini for PHP 5 and PHP 7 2016-03-20 19:23:57 +01:00
David Grudl
1786c861b9 Merge pull request #213 from castamir/php7sqlsrv
SqlsrvDriver: php7 compatibility
2016-03-20 16:34:36 +01:00
Mira Paulik
bc0578928f SqlsrvDriver: php7 compatibility 2016-03-20 13:50:10 +01:00
David Grudl
12a07ff6ad Merge pull request #212 from soukiii/master
Fluent: missing annotation
2016-03-18 17:16:23 +01:00
Petr Soukup
b50f59c64c Fluent: missing annotation 2016-03-18 15:40:16 +01:00
David Grudl
fdebf349f5 appveyor: test under PHP 7 2016-03-18 15:07:45 +01:00
David Grudl
954c2f25d0 Merge pull request #209 from castamir/sqlsrv_insert
SqlsrvDriver::getInsertId() last inserted id is from last statement instead of last inserted row
2016-02-29 23:37:17 +01:00
Mira Paulik
43dccb1ba2 SqlsrvDriver::getInsertId() last inserted id is from last statement instead of last inserted row regardless of the table that produced the value 2016-02-29 16:10:59 +01:00
David Grudl
352a683ec1 Released version 3.0.3 2016-02-21 02:07:19 +01:00
David Grudl
f4638796fb Helpers::detectType() detects VAR_STRING as Type::TEXT 2016-02-20 21:08:01 +01:00
David Grudl
4659f4550e DibiExtension22: added options 'explain' & 'filter' [Closes #203] 2016-02-10 00:08:27 +01:00
David Grudl
c3548465fb Merge pull request #204 from castamir/sqlsrv
SqlsrvDriver: fixed: sql server does not respond on non-string password
2016-02-09 23:19:53 +01:00
David Grudl
dda0bdbd67 Merge pull request #208 from ondrej-tuhacek/master
FirebirdDriver::delimite - Quotation marks for escaping identifiers
2016-02-04 16:08:25 +01:00
Ondřej Tuháček
7142be254b FirebirdDriver::delimite - Quotation marks for escaping identifiers 2016-02-04 13:29:06 +01:00
David Grudl
8948cc293c Released version 3.0.2 2016-01-29 15:46:23 +01:00
David Grudl
193252dc5f PdoDriver::applyLimit() is the same as SqlsrvDriver 2016-01-28 20:13:49 +01:00
Mira Paulik
6b2a46bcb8 appveyor: testing with SQL Server 2012 & 2014 2016-01-28 19:55:55 +01:00
Mira Paulik
2c01d993d0 SqlsrvReflector::getTables(): gets list of all tables from dbo schema only 2016-01-28 19:54:46 +01:00
Mira Paulik
e415157206 SqlsrvDriver::applyLimit(): fixed limit and offset behaviour for odbc 11+
SqlsrvReflector: changed constrains metadata loading from INFORMATION_SCHEMA to sys schema to get complete list of all constraints, not PK only
2016-01-28 19:48:49 +01:00
David Grudl
8a7dbcba86 Revert "removed MsSqlDriver (is not available with PHP 5.3 or later; replaced with SqlsrvDriver)"
This reverts commit ac1ab26e7a.
2016-01-24 22:52:18 +01:00
Mira Paulik
3b00115ee5 SqlsrvDriver: fixed: sql server does not respond on non-string credentials 2016-01-22 17:14:12 +01:00
David Grudl
4f2a0dac97 Released version 3.0.1 2015-12-16 15:15:56 +01:00
David Grudl
a13eb6f3d1 Merge pull request #200 from michal-kocarek/master
Allow disconnecting when passing PDO instance.
2015-12-16 15:02:43 +01:00
David Grudl
e3f01c879f uses https 2015-12-14 14:26:09 +01:00
Michal Kočárek
efae5808f0 PdoDriver: unset remaining references to PDO to allow disconnection 2015-12-14 12:40:41 +01:00
David Grudl
6a8a136c0a Merge pull request #199 from janlanger/patch-1
Helpers::detectType now resolves tinyint as integer
2015-12-06 23:30:38 +01:00
Jan Langer
bbb654fc27 Helpers::detectType resolves tinyint as integer 2015-12-06 22:03:06 +01:00
David Grudl
b6933815c7 Translator: added modifier %dt [Closes #198] 2015-12-05 11:33:28 +01:00
David Grudl
a8691eb8f5 Connection::substitute() fixed [Closes #197] 2015-11-26 12:24:57 +01:00
David Grudl
0cce3b9916 Strict: added support for the old way of adding extension methods [Closes #195] 2015-11-11 13:34:23 +01:00
David Grudl
98d1b2a519 MySqliDriver::createException() removed undefined ConnectionException [Closes #194] 2015-11-10 17:51:50 +01:00
David Grudl
f327212b57 Released version 3.0.0 2015-11-07 18:55:58 +01:00
David Grudl
ff22e8de09 Helpers::getSuggestion() better balance. Replacement is more expensive than insertion/deletion. 2015-11-07 02:31:14 +01:00
Petr Soukup
044fe4fc2a Fluent: added missing annotations [Closes #191] 2015-11-06 23:31:57 +01:00
David Grudl
e9c677c750 typo, docs 2015-11-06 23:31:56 +01:00
David Grudl
607ec8ae77 tests: not supported drivers are not skipped (except for 'mysql' on PHP 7) 2015-11-04 23:36:34 +01:00
David Grudl
deb56bb166 added appveyor.yml (thanks @mhujer) 2015-11-04 23:36:33 +01:00
David Grudl
5d44e55527 travis: uses own databases.travis.ini 2015-11-04 17:40:28 +01:00
David Grudl
78d24a0e74 tests: fixes 2015-11-04 17:40:19 +01:00
David Grudl
5aab1ff023 tests: improved ini quering, removed duplicated tests 2015-11-04 17:29:51 +01:00
David Grudl
6730fb4633 tests: added missing items to databases.sample.ini & etc 2015-11-04 17:29:51 +01:00
David Grudl
ac1ab26e7a removed MsSqlDriver (is not available with PHP 5.3 or later; replaced with SqlsrvDriver) 2015-11-04 03:59:21 +01:00
David Grudl
26a66c92d9 used type callable 2015-11-03 19:01:16 +01:00
David Grudl
2bb99ef3a0 DibiExtension22: bluescreen panel is registered in production mode too 2015-11-03 19:01:16 +01:00
David Grudl
b090ec802b differentiated Type::TIME and Type::DATETIME 2015-11-03 19:01:15 +01:00
David Grudl
89e92d24a2 Connection: added literal() 2015-11-02 18:23:59 +01:00
David Grudl
2627e23701 Fluent: fixed combination of modifier and inner fluent [Closes #192] 2015-11-02 18:00:29 +01:00
David Grudl
65d6f62a5b Translator::translate() can be called only once (BC break) 2015-11-02 18:00:28 +01:00
David Grudl
0c22f3b43f Translator: DateTime can be used only with %d or %t modifiers (BC break?) 2015-11-02 18:00:28 +01:00
David Grudl
b7d922d992 Translator: Literal can be used with %sql or %SQL modifiers 2015-11-02 18:00:27 +01:00
David Grudl
a9a45f0c4c Translator: better error messages 2015-11-02 18:00:27 +01:00
David Grudl
654e345921 added test, whitespace 2015-11-02 18:00:26 +01:00
David Grudl
f2a400084f Reflection\Result: fixed case insensitivity 2015-11-02 18:00:26 +01:00
David Grudl
a3325cac4d added deprecation notices 2015-11-02 18:00:25 +01:00
David Grudl
f19dd9208a Connection::alias() & loadFile() moved to Helpers 2015-10-26 19:20:59 +01:00
David Grudl
fd5cfaa9d3 drivers: applyLimit throws exception for negative values (BC break) 2015-10-26 19:20:58 +01:00
David Grudl
1333d07833 SqlsrvDriver: added support for LIMIT & OFFSET on SQL Server 2012 2015-10-26 19:20:58 +01:00
David Grudl
c26201c75d Fluent: exports limit & offset as %lmt and %ofs [Closes #82]
Also fixes 20f2093 on MSSQL
2015-10-26 19:20:57 +01:00
David Grudl
70c68402ea Fluent: prevents doubled processing 2015-10-26 19:20:57 +01:00
Pavel Zelezny
5fac432272 Connection: option 'driver' can contain driver instance or class name [Closes #153] 2015-10-26 19:20:56 +01:00
David Grudl
b3696f9beb FirebirdDriver: removed $sql from exception in fetch() 2015-10-23 17:24:01 +02:00
David Grudl
11027e2573 MsSql2005 driver renamed to Sqlsrv 2015-10-22 02:05:32 +02:00
David Grudl
d74908402d fixes 2015-10-22 02:05:31 +02:00
David Grudl
31cd9594a1 removed unused code 2015-10-22 02:05:30 +02:00
David Grudl
52f0793991 Result::dump() moved to Helpers 2015-10-13 21:16:49 +02:00
David Grudl
c79f4a1475 MySQL drivers: type TIME is returned as DateInterval (BC break) [Closes #168] 2015-10-13 21:16:49 +02:00
David Grudl
fbb63a9cc3 implemented DriverException descendants:
- ConstraintViolationException
- ForeignKeyConstraintViolationException
- NotNullConstraintViolationException
- UniqueConstraintViolationException
2015-10-13 21:16:48 +02:00
David Grudl
3f44e96353 tests: improved sql dumps, renamed pgsql -> postgre 2015-10-13 20:09:18 +02:00
David Grudl
6994f6d11a Dibi\Exception: code can be string 2015-10-13 20:09:12 +02:00
David Grudl
e849be486f DriverException: removed tryError & catchError (BC break) 2015-10-13 20:08:26 +02:00
David Grudl
8649366b1f PostgreDriver: removed usage of tryError & catchError 2015-10-13 20:04:45 +02:00
David Grudl
1a027c75ab FirebirdDriver: removed usage of tryError & catchError (not tested!) 2015-10-13 20:03:27 +02:00
David Grudl
ee4cd0d6ef Column::detectTypes() moved to Helpers 2015-10-13 15:48:24 +02:00
David Grudl
4630e1818f Result: normalizes invalid date to NULL 2015-10-13 15:04:22 +02:00
David Grudl
c0416bf176 Result: improved normalization of type INT 2015-10-13 15:04:14 +02:00
David Grudl
407a6f7550 Result: fixed normalization of float when ends with "0" [Closes #189] 2015-10-13 15:03:59 +02:00
David Grudl
91c2be2a84 Result: normalize always converts type TEXT to string 2015-10-13 15:03:48 +02:00
David Grudl
6f273ef601 Column::detectType() return NULL when type is unknown instead of TEXT 2015-10-13 15:03:18 +02:00
David Grudl
8bfb39f790 Merge pull request #190 from bckp/patch-1
Updated docs
2015-10-13 11:54:55 +02:00
Radovan Kepák
617e5ca6da Updated docs
Docs updated to new syntax, so people use new and not old deprecated one
2015-10-13 10:36:24 +02:00
castamir
20f2093aa5 Fluent::fetch(): fixed limit clause duplication [Closes #188][Closes #186][Closes #185] 2015-10-09 12:20:15 +02:00
David Grudl
0c4a28935d Fluent: removed keyword AS from SQL [Closes #172] 2015-10-09 12:20:14 +02:00
David Grudl
2e09a559f2 moved to namespace Dibi
added loader for old class names
2015-10-09 12:20:14 +02:00
David Grudl
6222e966c7 typos 2015-10-09 12:20:13 +02:00
David Grudl
8e2feec9fb removed @package 2015-10-09 12:20:12 +02:00
David Grudl
80e2fd6cc3 DibiRow: shows suggestions for missing columns 2015-10-09 12:20:12 +02:00
David Grudl
a119921832 DibiObject: shows suggestions for undeclared members 2015-10-09 12:20:11 +02:00
David Grudl
f42d1b1611 DibiObject replaced with trait DibiStrict 2015-10-09 12:20:11 +02:00
David Grudl
76396ab250 DibiObject: simplified to minimum (BC break)
Removed support for setters, onEvent(), getClass() & getReflection().
Retained support for getters and extension methods.
2015-10-09 12:20:10 +02:00
David Grudl
ae68965710 type constants dibi::* moved to new class Type 2015-10-09 12:20:09 +02:00
David Grudl
785a021b8d dibi::dump() moved to class Helpers 2015-10-09 12:20:09 +02:00
David Grudl
59223d937d removed usage of magic properties 2015-10-09 12:20:08 +02:00
David Grudl
7c1f735f9b used PHP 5.4 syntax 2015-10-09 12:20:08 +02:00
David Grudl
a32e24262f loader.php: uses SPL autoloader 2015-10-09 12:20:07 +02:00
David Grudl
3e010c0f4d removed PHP < 5.4 stuff 2015-10-09 12:20:06 +02:00
David Grudl
96daa02525 Minimal required PHP version changed to 5.4.4 2015-10-09 12:20:06 +02:00
David Grudl
cbebcba37d IDibiDriver: escape() & unescape() replaced with escape*() & unescapeBinary() (BC break!) 2015-10-09 12:20:05 +02:00
David Grudl
7f76a8b2f4 separation of some classes into own files 2015-10-09 12:20:05 +02:00
David Grudl
2522dcd7fe new directory structure, moved to /src 2015-10-09 12:20:04 +02:00
David Grudl
c96271c09b opened 2.4-dev 2015-10-08 22:23:03 +02:00
David Grudl
d708ac2aeb tests: added new, typo 2015-10-06 15:39:37 +02:00
David Grudl
806ee1ccd1 DibiObject: fixed compatibility with PHP 7 2015-10-06 15:35:55 +02:00
David Grudl
0ec544043f removed rarely used @property 2015-10-06 12:10:22 +02:00
David Grudl
6dcdd68d6d removed @author 2015-10-06 12:10:21 +02:00
David Grudl
9ad502887b used https 2015-10-06 12:10:20 +02:00
David Grudl
f06425b9a0 travis: migrating to container-based infrastructure 2015-07-23 18:54:35 +02:00
David Grudl
ca99b0b822 improved coding style 2015-06-19 15:00:23 +02:00
David Grudl
462ef6934b readme.md: added badges 2015-06-15 15:14:45 +02:00
Jan Tvrdik
84c85bc536 travis: run tests on PHP 7 2015-06-15 15:14:44 +02:00
David Grudl
d3151f7c65 DibiTranslator: deprecated support for hex number in strings '0xFF' (BC break)
related to PHP7 and https://wiki.php.net/rfc/remove_hex_support_in_numeric_strings
2015-06-15 14:57:38 +02:00
David Grudl
66afffcddc DibiTranslator: small refactoring 2015-06-15 14:42:48 +02:00
David Grudl
7762da1bbb Released version 2.3.2 2015-04-18 16:26:53 +02:00
David Grudl
6f6a63881a Merge pull request #176 from milo/pull-oracle
Oracle fixes
2015-04-17 15:47:00 +02:00
Miloslav Hůla
999f51a7bd OracleDriver: cast type NUMBER(p, 0) as an INTEGER
In many cases, Oracle returns integers as a NUMBER(8,0). Type NUMBER is casted to (float) which is unnecessary in this case.
2015-04-17 15:22:45 +02:00
Miloslav Hůla
64b3d0c6f4 Tracy panels: Oracle uses EXPLAIN PLAN FOR
Warning 'ORA-00905: missing keyword' is emmited otherwise.
2015-04-17 15:21:21 +02:00
Miloslav Hůla
06440ab6dc OracleDriver: shut-up oci_execute()
The oci_execute() emits warnings e.g. on denied permissions when EXPLAIN.
2015-04-17 15:17:14 +02:00
David Grudl
b341b66d43 Merge pull request #175 from milo/pull-autowired
Nette extensions: added 'autowired' configuration
2015-04-16 16:47:39 +02:00
Miloslav Hůla
aac83ba849 Nette extensions: added 'autowired' configuration 2015-04-16 15:01:00 +02:00
David Grudl
2de32b66e1 Merge pull request #174 from baasha/baasha-patch-1
DibiPdoDriver::escape() added support for dblib
2015-03-27 00:05:09 +01:00
baasha
1829366fc9 DibiPdoDriver::escape() added support for dblib
Fixed escaping for linux version of mssql driver - dblib.
2015-03-26 23:47:06 +01:00
Radovan Kepák
94f34a2a33 DibiPdoDriver: added support for version specified in options
If driver do not support ATTR_SERVER_VERSION (like dblib) fallback to the version from config, or set null as we do not know what is the driver version.

I belive this is better solution then add some creazy switch with queries for all possible versions on all drivers, and becouse it is faster to pass variable then run query asking about version.
2015-03-12 15:11:04 +01:00
David Grudl
a3e5ac86f7 Released version 2.3.1 2015-02-25 15:22:04 +01:00
David Grudl
89d7148b04 removed version.txt 2015-02-25 15:21:48 +01:00
David Grudl
38aa393dc3 dibi: named connections are allowed [Closes #161]
Partially reverts commit a923ce7ecb.
2015-02-25 15:13:52 +01:00
David Grudl
84f9a6fdd8 Merge pull request #164 from bckp/patch-2
Added support for MsSQL2012 ( allow offset )
2015-02-20 12:11:02 +01:00
Radovan Kepák
eb64adeb05 Dibi: Dump now recognize MsSql2012 offset as keyword
Now $connection->test send proper highlighted code
2015-02-20 09:09:37 +01:00
Radovan Kepák
3779a5034a DibiPdoDriver: added support for MsSql2012 Offset
Since MsSql2012 allow using of OFFSET, I added this option to the driver for PDO. Driver will automaticly recognize this is proper version and use the new offset.
2015-02-20 09:04:43 +01:00
David Grudl
090bb2f182 Merge pull request #163 from bckp/patch-1
Tracy\Panel: added vector icon
2015-02-20 00:19:37 +01:00
Radovan Kepák
056c0702a1 Tracy\Panel: added vector icon 2015-02-20 00:16:05 +01:00
David Grudl
020b15c0e2 added contributing.md
inspiration https://github.com/necolas/issue-guidelines
2015-01-27 14:51:42 +01:00
David Grudl
5970db58aa Released version 2.3.0 2015-01-25 17:24:28 +01:00
David Grudl
5ea37c9894 Merge pull request #160 from milo/pull-pglike
Fix DibiPostgreDriver::escapeLike()
2015-01-23 17:26:05 +01:00
Miloslav Hůla
2892e3eae3 Postgre: added test for matching by %like 2015-01-23 09:29:58 +01:00
Miloslav Hůla
91e2d76a0a Postgre: fixed %like escaping [Closes #159] 2015-01-23 09:13:05 +01:00
David Grudl
97b50bd243 Dibi: $defaultDriver changed to mysqli [Closes #156] 2015-01-13 15:45:17 +01:00
David Grudl
97d4c8c35f Released 2.3.0-RC1 2015-01-13 15:35:18 +01:00
David Grudl
f7fd9104e9 removed bridge for Nette 2.0 (BC break) 2015-01-13 15:35:18 +01:00
David Grudl
a923ce7ecb dibi: named connections and activate() are deprecated (BC break) 2015-01-13 15:31:03 +01:00
David Grudl
9a95edf003 Merge pull request #149 from JirkaChadima/oracle-schema
Oracle: adds support for login schema option
2015-01-13 05:25:33 +01:00
MartyIX
23efb97b0c DibiFluent: add leftJoin and on to phpdoc. 2015-01-13 05:24:23 +01:00
Ondrej Brablc
3b96dc7012 DibiFirePhpLogger: save some header operations for sites with hundreds of sql queries. 2015-01-13 05:22:45 +01:00
Ondrej Brablc
39be00e08b DibiFirePhpLogger: Allow user defined size of json stream chunks [Closes #148] 2015-01-13 05:22:34 +01:00
Martin Hradil
d6826d62ed DibiTranslator: respect %if blocks for %lmt and %ofs as well [Closes #145][Closes #87] 2015-01-13 05:14:42 +01:00
Petr BAGR Smrkovský
9189d56c05 DibiResult: float detection locale fix [Closes #154] 2015-01-13 04:40:36 +01:00
David Grudl
26b167fe13 DibiMySqliDriver.php: fixes for HHVM 2015-01-12 11:01:46 +01:00
David Grudl
100f978b9b DibiPdoDriver: missing driver throws DibiNotSupportedException exception 2015-01-12 11:01:12 +01:00
David Grudl
8395abb04f added new tests 2015-01-12 10:41:07 +01:00
David Grudl
f5f4f786f1 tests: improved testing environment 2015-01-12 10:41:06 +01:00
David Grudl
59da4bd66a DibiDatabaseInfo: no table is returned as NULL 2015-01-12 08:58:28 +01:00
David Grudl
50782c037c DibiSqliteReflector: fixed detection of autoincrement 2015-01-12 08:58:27 +01:00
David Grudl
ddbf8c779e DibiOdbcDriver: compatible applyLimit 2015-01-12 04:45:30 +01:00
David Grudl
e2fe4d122e DibiPdoDriver: improved and fixed escaping 2015-01-12 04:45:30 +01:00
David Grudl
2082357f0c * .travis: added code checker 2015-01-10 19:11:30 +01:00
David Grudl
c11a97294a examples: improved Tracy examples 2015-01-10 19:07:29 +01:00
Ing. Andrej Poliak
4f315a0d74 DibiPostgreDriver: added support for pg_ping [Closes #144] 2015-01-10 18:41:56 +01:00
David Grudl
34deb6c04f Merge pull request #158 from paranoiq/patch-1
dump: added bunch of reserved words
2015-01-05 12:49:25 +01:00
Vlasta Neubauer
31122c1969 dump: added bunch of reserved words 2015-01-05 12:40:41 +01:00
David Grudl
f534c15f0e Merge pull request #155 from JirkaChadima/dbliblimitsupport
MSSQL: Adds limit support for PDO dblib driver on unix
2014-11-04 23:47:23 +01:00
Jirka Chadima
985f59a2b2 MSSQL: Adds limit support for PDO dblib driver on unix 2014-11-04 11:43:05 +01:00
David Grudl
6fc99254ab Merge pull request #152 from zeleznypa/master
Oracle does not support any brackets around table name
2014-10-26 14:01:41 +01:00
Pavel Zelezny
dc688f3ee7 Oracle use double quotes for escaping 2014-10-26 13:56:34 +01:00
Jirka Chadima
4e99d7821c Oracle: adds support for login schema option 2014-10-21 17:01:59 +02:00
David Grudl
cde5af7cbe Merge pull request #142 from JanRossler/multi-search-path
PostgreSQL: fixed identifier escaping in reflection.
2014-07-16 17:46:08 +02:00
Rossler Jan
7c35e49a1c PostgreSQL: fixed identifier escaping in reflection. 2014-07-16 14:06:14 +02:00
David Grudl
6b08cf0711 Merge pull request #140 from JanRossler/multi-search-path
PostgreSQL: fixed search path resolution in table and column reflection.
2014-07-16 11:46:38 +02:00
David Grudl
4b0ebc76b0 Merge pull request #141 from JanRossler/php52
DibiDateTime: Restored php 5.2 support.
2014-07-15 12:46:42 +02:00
Rossler Jan
5993ea8aaf DibiDateTime: Restored php 5.2 support. 2014-07-15 12:39:51 +02:00
Rossler Jan
f89a2310cc PostgreSQL: fixed search path resolution in table and column reflection. 2014-07-07 01:51:56 +02:00
David Grudl
a118c2cf96 Released version 2.2.2 2014-06-30 17:08:04 +02:00
castamir
9b0e64220b Tracy loaded from composer instead of a local copy [Closes #139] 2014-06-30 14:52:44 +02:00
David Grudl
1c386d5582 typos 2014-06-30 14:52:43 +02:00
David Grudl
c9944b3886 Partially reverts "DibiTranslator: object is initialized in constructor", fixes lazy connection [Closes #138]
This reverts commit 0071b80938.
2014-06-24 21:40:54 +02:00
David Grudl
d0fd009dda readme.md: buy me a coffee 2014-06-13 17:54:46 +02:00
David Grudl
c32251357d fixed bug 'interface IBarPanel not found' [Closes #137] 2014-06-11 16:16:32 +02:00
David Grudl
c23d9c2866 Released version 2.2.0 2014-06-02 16:35:20 +02:00
David Grudl
60893a1c11 removed some old and deprecated stuff 2014-06-02 16:35:19 +02:00
David Grudl
f31d4a9afa tests: Nette\Debugger replaced with Tracy, examples requires PHP 5.3 2014-06-02 16:03:04 +02:00
David Grudl
abd3e2116c added bridge for Nette 2.2 & Tracy 2014-06-02 16:03:03 +02:00
David Grudl
e4e767048f fixed example 2014-06-02 16:03:03 +02:00
David Grudl
1ebb2deb83 file dibi.php split to Dibi class and loader dibi.php 2014-06-02 16:03:02 +02:00
David Grudl
47f8a6f88d bridges: changed file structure 2014-05-13 17:45:47 +02:00
Rossler Jan
fee5c294d8 PostgreSQL: added support for reflection of materialized views. 2014-05-13 17:45:46 +02:00
David Grudl
b14a4efbbb typos 2014-05-13 17:44:07 +02:00
David Grudl
6949f37a7a removed magic_quotes_runtime checking 2014-05-13 17:44:06 +02:00
David Grudl
e99ce9d053 updated test support files 2014-05-13 02:59:34 +02:00
Emmanuel еΜanwʬĔbdƎv
d4c72bbd4d readme.md: typos 2014-05-13 02:42:36 +02:00
Caspern
c802f9343a .gitattributes: ignoring some paths when downloading from github 2014-05-13 02:34:35 +02:00
David Grudl
771bdbe124 fixed test support files 2014-03-24 19:18:11 +01:00
David Grudl
1a4fca41a7 composer: added branch alias & PHP version 2014-03-24 19:08:18 +01:00
Patrik Votocek
176b1a8895 Add support for DateTimeInterface 2014-03-24 19:03:31 +01:00
David Grudl
0071b80938 DibiTranslator: object is initialized in constructor 2014-03-24 19:03:31 +01:00
David Grudl
4f64bd726b Merge pull request #129 from erikfercak/add_apostrophes_to_dates
Add aposthrophes back to dates
2014-02-22 04:08:22 +01:00
Erik Fercak
7fc3d76072 Add aposthrophes back to dates
Commit 7318658017 removed apostrophes from dates and that caused
dibi to build different queries. Compare:
...WHERE `date_created` < '2014-02-21';
vs.
...WHERE `date_created` < 2014-02-21;
2014-02-21 14:08:07 +01:00
David Grudl
a6cc588d91 Merge pull request #128 from brablc/master
Avoid error handler invocation
2014-02-20 19:38:54 +01:00
Ondrej Brablc
6666d71e5b Avoid error handler invocation 2014-02-20 18:47:35 +01:00
David Grudl
5082282e35 Merge pull request #127 from Ciki/patch-1
fix casting to float
2014-02-11 17:34:17 +01:00
Ciki
7cee7997e2 fix casting to float
Now, when sql returns float from (0,1) interval, e.g. '.842' - the decimal part is missing & it won't get cast to float.
This is fix for that situation
2014-02-11 17:04:19 +01:00
David Grudl
738c0c91ed DibiConnection::loadFile() supports DELIMITER [Closes #119] 2014-02-04 03:09:31 +01:00
David Grudl
2769f1ae0a typos 2014-02-04 03:09:31 +01:00
David Grudl
bf8fb69b9a Merge pull request #118 from emanwebdev/patch-1
Fix minor typos
2013-12-27 02:53:48 -08:00
Emmanuel еΜanwʬĔbdƎv
3780a42971 Fix minor typos 2013-12-27 11:33:16 +01:00
David Grudl
791d001bfd DibiDateTime: fixed buggy constructor 2013-12-19 04:21:45 +01:00
David Grudl
367b115ad2 DibiRow: null time checking consistent with DibiResult 2013-12-12 18:14:18 +01:00
Etienne CHAMPETIER
7318658017 Use DateTime instead of date()
On 32bits systems, date() is affected bug the 2038 bug
DateTime always uses 64bits representation [Closes #110]

Signed-off-by: Etienne CHAMPETIER <etienne.champetier@fiducial.net>
2013-12-12 18:14:17 +01:00
David Grudl
ddf7b74bf0 DibiDateTime: works with UNIX timestamps bigger than 32bits 2013-12-12 18:14:17 +01:00
Rossler Jan
30b5290c9d DibiDateTime: fixed unknown timezone error when serialized date includes the timezone (i. e. 'Y-m-d H:i:sP') [Closes #107] 2013-12-12 06:18:12 +01:00
David Grudl
a36678d3db Merge pull request #114 from JanTvrdik/master_array_typo
typo (array of foo -> foo[]) – master
2013-11-05 12:10:20 -08:00
Jan Tvrdik
530e7d30c9 typo 2013-10-24 21:15:48 +02:00
David Grudl
3b1e9e2632 typos 2013-10-17 01:20:44 +02:00
Rossler Jan
1b38d13422 DibiResult: fixed illegal offset type in fetchPairs. 2013-10-17 01:20:43 +02:00
daliborcaja
f348828223 DibiFluent::execute(dibi::AFFECTED_ROWS) returns number of affected rows 2013-10-17 01:20:42 +02:00
Jiří Pudil
5599dde525 Implemented getForeignKeys() in DibiMySqlReflector 2013-10-17 01:20:42 +02:00
Jan Tvrdik
32518eca54 composer.json: fix compatibility with dg/dibi requirements 2013-10-11 13:05:30 +02:00
David Grudl
a47395d16a Merge pull request #106 from enumag/patch-1
Fixed usage of deprecated parameter
2013-08-29 01:28:25 -07:00
Jáchym Toušek
a1f7413c9f Fixed usage of deprecated parameter 2013-08-29 03:02:11 +02:00
David Grudl
1728437f5d Merge pull request #101 from milo/fix-normalize-time
DibiResult: fixed normalization of time when begins by 00:
2013-08-11 11:59:28 -07:00
Miloslav Hůla
cf942c68ce DibiResult: fixed normalization of time when begins by 00: 2013-07-15 15:22:04 +02:00
David Grudl
e87c112d71 typos & whitespace 2013-07-13 20:23:13 +02:00
David Grudl
9e23730cb0 added examples to readme.md 2013-07-01 12:38:29 +02:00
David Grudl
a388767848 added .travis.yml & other files 2013-06-23 03:36:01 +02:00
David Grudl
bc59eb6a14 updated examples, SQlite3 is used instead of SQLite2 2013-06-23 02:34:15 +02:00
David Grudl
44aba8a986 opened 2.2-dev 2013-06-23 02:34:14 +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
David Grudl
7c47f57e30 released 2.0 stable 2012-02-03 13:48:14 +01:00
David Grudl
0327573085 updated Nette Debugger 2012-02-03 13:48:14 +01:00
David Grudl
cf2e08c20f DibiNettePanel: fixed doubled alias 2012-02-01 21:50:35 +01:00
David Grudl
9b7a80e894 DibiConnection ensures class dibi is loaded 2012-02-01 19:18:24 +01:00
Miloslav Hůla
2ae6535899 Consider value of %n array as identifier 2012-02-01 19:18:23 +01:00
Miloslav Hůla
0b2cb3c6e4 Detection of PostgreSQL array types 2012-01-21 16:58:57 +01:00
David Grudl
0723e8ffc8 typos 2012-01-21 16:58:57 +01:00
David Grudl
5b68657842 DibiResult: row-class can be disabled and fetch() returns array 2012-01-21 16:58:57 +01:00
David Grudl
3cde2c7815 DibiTranslator: supported key%~like~ modifier in array keys 2012-01-21 16:58:57 +01:00
David Grudl
5aed9e7e4f MSSQL2005: used native functions for transaction 2012-01-21 16:58:56 +01:00
David Grudl
c2c63615fd DibiFluent: added setupResult() 2012-01-21 16:58:56 +01:00
David Grudl
e4ed284e77 DibiConnection: added config option "result|formatDate" 2012-01-21 16:58:56 +01:00
David Grudl
0f21b6ca5b DibiEvent: (SELECT ...) UNION (SELECT ...) is classified as SELECT [Closes #35] 2012-01-21 16:58:56 +01:00
David Grudl
b87d3cab81 DibiConnection::test() shows complete error message 2012-01-21 16:58:55 +01:00
David Grudl
3f2e383b47 __toString() do not throw an exception [Closes #19] 2012-01-21 16:58:55 +01:00
David Grudl
bf49cec002 DibiNettePanel: Oracle explains using EXPLAIN PLAN 2012-01-21 16:58:55 +01:00
David Grudl
70fd2368aa DibiNettePanel: explain SQL command can be altered 2012-01-21 16:57:33 +01:00
David Grudl
5d41128752 calling getResultResource() disables auto-free in __destruct() 2012-01-19 04:23:00 +01:00
David Grudl
5efb11d780 DibiMysqlDriver & DibiPostgreSql: escape() checks if resource is alive [Closes #46] 2012-01-19 04:21:09 +01:00
David Grudl
660a9db522 drivers: getResource() and getResultResource() checks if resource is alive 2012-01-19 04:20:57 +01:00
David Grudl
c7b9a91fc2 DibiResult: added getResultDriver() 2012-01-19 00:14:07 +01:00
David Grudl
ea0d6d02ba DibiResult: added setFormat() 2012-01-18 21:15:22 +01:00
David Grudl
b964887f9d released 1.5-rc2 2012-01-12 15:25:19 +01:00
David Grudl
a8f5e09b69 DibiDateTime: added __toString(), modify(), modifyClone() 2012-01-12 15:25:04 +01:00
David Grudl
8c481bc128 DibiRow: asBool(), asDate() and asTimestamp() deprecated 2012-01-12 01:19:15 +01:00
David Grudl
4c85d1d55c DibiNettePanel: works with disabled bar [Closes #43] 2012-01-12 01:06:15 +01:00
David Grudl
2a5934c385 removed IDibiVariable & DibiVariable, replaced with DibiLiteral 2012-01-12 00:46:50 +01:00
David Grudl
a8672bb6ff DibiFluent passed as argument to DibiFluent is converted to string [Closes #44] 2012-01-12 00:46:49 +01:00
Steven Bredenberg
9bc53109a0 Adding reflector code for MSSQL. 2012-01-12 00:16:22 +01:00
Radek Dostál
3288b38b6c Implemented escapeLike() for Oracle driver 2012-01-12 00:06:39 +01:00
David Grudl
8c8b3c3dc1 dibi: new keywords in dump() 2012-01-12 00:03:33 +01:00
David Grudl
2c1950eacf DibiDatabaseInfo::detectTypes: adjusted YEAR, BIGINT 2012-01-12 00:03:33 +01:00
David Grudl
baf08d3c71 DibiConnection: types detection + normalization is always TRUE 2012-01-12 00:03:32 +01:00
David Grudl
e60dc2d2d0 Merge pull request #48 from mil0/master
Implemented getForeignKeys() for PostgreSQL driver
2012-01-11 13:31:15 -08:00
David Grudl
eee105f607 class DibiNettePanel is included in dibi.php [Closes #49] 2012-01-11 00:18:37 +01:00
Miloslav Hůla
c65294075e Merge remote-tracking branch 'upstream/master' 2012-01-08 20:03:30 +01:00
David Grudl
1d63af75f9 Nette: getContainer() renamed to getContainerBuilder() 2012-01-06 04:02:43 +01:00
David Grudl
9be3bd7a53 fix: DibiNettePanel is called only if required interface is available 2012-01-04 18:50:42 +01:00
Miloslav Hůla
96d7236a4a Implemented getForeignKeys() for PostgreSQL driver 2012-01-03 13:57:37 +01:00
David Grudl
9ba0cf62d1 All exceptions are DibiException descendants 2012-01-03 05:46:59 +01:00
David Grudl
d1a63ce757 FireBird driver: implemented getResultColumns() 2012-01-03 05:34:56 +01:00
David Grudl
0a17cc50ae updated Nette\Debugger 2012-01-03 05:15:44 +01:00
David Grudl
74a139974c DibiTranslator: fixed usage of modifier ? 2012-01-03 05:14:44 +01:00
David Grudl
dbb72b769b updated phpDoc @package 2012-01-03 04:50:11 +01:00
David Grudl
dd07d50434 added DibiNetteExtension 2012-01-03 04:34:01 +01:00
David Grudl
53c2ef55d8 changed profiler API; IDibiProfiler replaced with DibiConnection::$onEvent; DibiProfiler split to DibiFileLogger, DibiFirePhpLogger and DibiNettePanel (BC break!) 2012-01-03 04:34:01 +01:00
David Grudl
1d4e86fe2b Updated copyright notices for 2012 2012-01-03 04:17:30 +01:00
David Grudl
183a215fc5 updated DibiProfiler CSS 2011-07-01 08:19:16 +02:00
David Grudl
9c59fee929 updated examples & Debugger 2011-07-01 08:19:15 +02:00
David Grudl
ac1f45b397 updated for Nette 2.0 beta: exceptions 2011-07-01 08:19:15 +02:00
David Grudl
508e8638e8 Merge pull request #34 from mil0/master.
implemented escapeLike() for PostgreSQL driver
2011-05-02 15:35:20 -07:00
David Grudl
0de947883b updated for Nette 2.0 beta 2011-04-21 14:53:22 +02:00
Miloslav Hůla
b979295baa implemented escapeLike() for PostgreSQL driver 2011-03-10 14:33:34 +01:00
David Grudl
8a899c7ddb DibiProfiler logs source files and lines 2011-02-23 02:16:07 +01:00
Lukáš Gavenda
1a4ea39a60 DibiProfiler: iterator fix 2011-02-23 02:12:55 +01:00
David Grudl
acda14ca64 DibiProfiler shows source files and lines 2011-02-17 22:19:06 +01:00
David Grudl
f09e4b9b3e updated Nette\Debug 2011-02-17 22:18:30 +01:00
David Grudl
1103714b9f typos 2011-02-16 19:38:05 +01:00
David Grudl
e37af6f99d added IDibiVariable 2011-02-16 18:01:22 +01:00
David Grudl
b148291ca2 DibiDataSource: removed keyword 'AS' 2011-02-16 17:48:47 +01:00
David Grudl
713918ae3c typos 2011-02-06 15:48:44 +01:00
David Grudl
617cb42e8e fixed PHP bug #53915 2011-02-03 04:13:01 +01:00
David Grudl
4ea5ddae8e DibiResult::convert() correctly handles too big INT [Closes #18] 2011-02-02 22:49:52 +01:00
David Grudl
60b62c50fe MySQLi driver: added support for persistent connection [Closes #27] 2011-02-02 22:39:52 +01:00
David Grudl
568ec80994 DibiProfiler: EXPLAIN is executed at shutdown [Closes #17] 2011-02-02 22:34:13 +01:00
David Grudl
23e3ba6db4 PDO driver: getReflector() is implemented for MySQL and SQLite 2011-02-02 20:36:54 +01:00
David Grudl
bdb5b217c7 License changed to the New BSD License or the GNU General Public License (GPL) version 2 or 3. 2011-02-02 01:20:30 +01:00
David Grudl
faf444567b released 1.5-rc1 2011-01-25 18:26:51 +01:00
David Grudl
018b9da06d used NotSupportedException at appropriate places 2011-01-25 18:23:30 +01:00
David Grudl
9c52b8ea9d renamed DibiLazyStorage to DibiHashMap 2011-01-25 18:00:29 +01:00
David Grudl
1ada6fab97 removed DibiConnection::sql() 2011-01-25 17:50:50 +01:00
David Grudl
0dc9db1d77 some stuff is deprecated and throws E_USER_WARNING: dibi::datetime(), dibi::date(), dibi::addSubst(), dibi::removeSubst(), dibi::setSubstFallback(), DibiResult::rowCount(), DibiResult::getColumnNames(), DibiVariable 2011-01-25 17:49:37 +01:00
David Grudl
08099816d5 DibiDatabaseInfo: removed support for substitutions 2011-01-25 17:42:13 +01:00
David Grudl
26de1aebc0 Substitution moved from class dibi to DibiConnection 2011-01-25 17:41:44 +01:00
David Grudl
88cccc0543 DibiConnection refactoring 2011-01-25 17:37:49 +01:00
David Grudl
0b1547818d DibiDateTime::__construct accepts unix timestamp 2011-01-25 17:37:35 +01:00
David Grudl
e0d110962e MSSQL2005 driver: added alias charset -> options|CharacterSet 2011-01-25 17:37:35 +01:00
David Grudl
ae00fed718 fixed regexp for profiler 2011-01-24 15:20:50 +01:00
Filip Procházka
af715a8044 fixed sql injection vulnerability through conditions and comments [closes #30] 2011-01-24 22:01:51 +08:00
David Grudl
af6352d0af removed czech license 2010-11-10 00:55:22 +01:00
David Grudl
14fee47d54 DibiProfiler: added HTML title for Debug bar 2010-11-07 23:06:21 +01:00
David Grudl
ec82eda864 DibiResult destructor moved to individual IDibiResultDriver drivers 2010-11-02 14:42:15 +01:00
David Grudl
087734fb23 drivers implementing IDibiDriver and IDibiResultDriver together do not use $resultSet in IDibiDriver part 2010-11-02 14:42:14 +01:00
David Grudl
32baabdeac added low-level methods createResultDriver() and DibiConnection::createResultSet() 2010-11-02 13:59:05 +01:00
David Grudl
33ef22b488 fixed compatibility with Nette / RobotLoader 2010-11-02 03:29:19 +01:00
David Grudl
36fe9d42c1 PcreException renamed to DibiPcreException 2010-10-25 16:16:38 +02:00
David Grudl
0c4f343238 Firebird driver: added missing getReflector() 2010-10-06 16:17:29 +02:00
David Grudl
8d6639fa3c DateTime53 renamed to DibiDateTime 2010-10-06 16:16:09 +02:00
David Grudl
90592929ec fixed Nette compatibility [Closes #23] 2010-09-28 17:29:02 +02:00
David Grudl
c052582670 DibiProfiler: the file can be specified in a configuration 2010-09-15 13:25:46 +02:00
David Grudl
e6e7babe22 simplified phpDoc comments 2010-09-14 19:09:56 +02:00
David Grudl
056a680cff DibiProfiler & Debug: compatible with XHTML 2010-09-07 04:05:41 +02:00
David Grudl
6d94afdddd added dibi::setConnection() 2010-09-07 00:16:45 +02:00
David Grudl
b1156e54d8 drivers meta function refactoring 2010-08-27 02:18:07 +02:00
David Grudl
39add9b8a3 dibi::dump() fixed in CLI mode 2010-08-27 01:06:05 +02:00
David Grudl
b8e518f44b implemented escapeLike() and modifiers %~like, %like~, %~like~ 2010-08-27 01:00:53 +02:00
David Grudl
46a3b8a42c now compatible with Debug / NDebug / Nette\Debug 2010-08-25 07:21:49 +02:00
David Grudl
310d43f404 DibiTranslator: temporary removed delimite() cache [Closes #21] 2010-08-25 01:27:05 +02:00
David Grudl
a64c2270d8 Revert "DibiResult: removed destructor"
This reverts commit 6d353c0b5d.
2010-08-25 01:27:05 +02:00
David Grudl
16dd0c7230 dibi::$substs & fall-back provided via DibiLazyStorage 2010-08-25 01:27:04 +02:00
David Grudl
79735e96d1 DibiLazyStorage: allows empty string as property name for reading 2010-08-25 01:27:04 +02:00
David Grudl
325305326b missing substitutions no longer throw exception 2010-08-25 01:27:04 +02:00
David Grudl
ff3ca38504 typos 2010-08-25 01:27:04 +02:00
David Grudl
f651d9f473 Revert "empty substitutions are going to be deprecated" commit e50b1a0b5a. 2010-08-25 01:27:04 +02:00
David Grudl
3568e041c5 MSSQL: delimited name in mssql_select_db 2010-08-25 01:27:04 +02:00
David Grudl
6430573d61 MySQL & MySQLi, SQLite & SQLite3 reflectors moved do external classes DibiMySqlReflector and DibiSqliteReflector 2010-08-25 01:27:04 +02:00
David Grudl
65b5e2eecd added IDibiDriver::getReflector() 2010-08-05 21:03:08 +02:00
David Grudl
9f982cb310 MySQL, MySQLi & PostgreSql drivers: default character set is 'utf8' (BC break) 2010-08-04 15:36:10 +02:00
David Grudl
76783b3872 DibiDatabaseInfo: better IDibiReflector vs. IDibiResultDriver handling 2010-08-04 15:34:49 +02:00
David Grudl
de85d3814e IDibiDriver splitted into IDibiDriver & IDibiResultDriver 2010-08-04 15:34:42 +02:00
David Grudl
5cce595518 DibiConnection::sql() renamed to verb translate() 2010-08-04 12:10:29 +02:00
David Grudl
746a553419 IDibiDriver::getColumnsMeta() renamed to getResultColumns() (BC break!) 2010-08-03 23:33:12 +02:00
David Grudl
0d7b9c32c9 updated phpDoc 2010-08-03 23:27:53 +02:00
David Grudl
9a4f1e6e36 DibiFluent: allowed multiple ->from('table') 2010-08-03 21:54:01 +02:00
David Grudl
204c4cdbd7 DibiConnection: fixed processing of profiler configuration 2010-08-03 21:29:12 +02:00
David Grudl
6b166afffb SQLite & SQLite3: improved primary key detection for ROWID 2010-08-03 21:28:06 +02:00
David Grudl
f3c2c27818 examples: added new 2010-08-03 21:06:56 +02:00
David Grudl
dc62e87629 PostgreSQL: implemented inTransaction() 2010-08-03 20:20:37 +02:00
David Grudl
66e709e846 MySQL & MySQLi drivers: configuration items 'options' renamed to 'flags' (old name is alias); added array 'options' for MySQLi 2010-08-03 19:49:22 +02:00
David Grudl
dc3b1ff399 DibiConnection::getDriver() automatically connects lazy connection; connect() and disconnect() are imperative now! 2010-08-03 18:11:21 +02:00
David Grudl
6bb2bc489d DibiTranslator: removed getDriver() (it is private) 2010-08-03 18:11:21 +02:00
David Grudl
019f6864cf DibiResult::getIterator() - removed optional $offset and $limit parameters (BC break!) 2010-08-03 18:11:20 +02:00
David Grudl
792a25d57b added tests 2010-08-03 17:18:11 +02:00
David Grudl
759b8d4615 removed directory "icon" 2010-08-03 17:18:10 +02:00
David Grudl
3f594756e0 examples: removed unnecessary delimiters [] 2010-08-03 17:18:10 +02:00
David Grudl
beee4ee4b7 examples: files renamed 2010-08-03 17:18:10 +02:00
David Grudl
8f9435b518 examples: better headings and comments 2010-08-03 17:18:02 +02:00
David Grudl
65dba03652 examples: added CSS style 2010-08-03 13:41:06 +02:00
David Grudl
6e35a783c7 examples: data files moved to directory "data" 2010-08-03 13:41:05 +02:00
David Grudl
914f7d3c26 DibiLazyStorage: empty string as property name throws exception; fixed in DibiDatabaseInfo too 2010-08-03 13:41:05 +02:00
David Grudl
e50b1a0b5a empty substitutions are going to be deprecated 2010-08-03 08:20:50 +02:00
David Grudl
8f358ca73d dibi::dump() turns off HTML tags in CLI mode 2010-08-03 08:19:58 +02:00
David Grudl
9d27c7cc4e DibiFluent: speed optimizations 2010-08-03 08:19:57 +02:00
David Grudl
bcee7bba91 DibiFluent::__class() small refactoring 2010-08-03 08:19:57 +02:00
David Grudl
8c5dc153f2 DibiDatabaseInfo: uses DibiLazyStorage for column type detecting 2010-08-03 08:19:34 +02:00
David Grudl
c93137340e DibiTranslator: uses DibiLazyStorage as caching layer over delimite() 2010-08-03 08:19:00 +02:00
David Grudl
84e0f0ecc1 added DibiLazyStorage, simple caching layer 2010-08-03 08:18:42 +02:00
David Grudl
3b87d71a68 MySQLi: fixed columns types detection [Closes #6] 2010-08-03 04:04:59 +02:00
David Grudl
df02cf1e3d dibi::dump highlights keyword OFFSET [Closes #15] 2010-08-03 04:04:58 +02:00
PetrP
e8990c9be6 DibiProfiler: explain query doesn't overwrite dibi::$sql 2010-08-03 04:04:58 +02:00
PetrP
e8de6f21c9 Mysql & Mysqli drivers: fixed bug in detection unsigned columns 2010-08-03 04:04:58 +02:00
PetrP
8082489143 DibiConnection: connect() is public 2010-08-03 04:04:57 +02:00
David Grudl
63163de18b DibiDatabaseInfo: BIGINT is treated as string [Closes #18] 2010-08-03 04:04:53 +02:00
David Grudl
1b623855b7 typos 2010-08-03 04:04:47 +02:00
David Grudl
6288dc8cba DibiConnection: removed old deprecated methods 2010-08-03 01:35:23 +02:00
David Grudl
20d0163316 DibiTranslator: speed optimizations 2010-08-03 01:32:00 +02:00
David Grudl
97da612604 DibiConnection: driver name is case insensitive 2010-08-03 00:45:52 +02:00
David Grudl
2ed67c1944 DibiConnection: uses single DibiTranslator object (per-connection) 2010-08-03 00:44:59 +02:00
David Grudl
a0a12701e9 DibiPdoDriver: speed optimization 2010-08-03 00:42:50 +02:00
David Grudl
739994dac6 MySQLi driver: sets mysqli_report(MYSQLI_REPORT_OFF) 2010-07-21 00:15:16 +02:00
David Grudl
8c99f0c04d Driver's reflection capabilities moved to IDibiReflector 2010-05-26 16:26:21 +02:00
David Grudl
7bac2ef3b3 typos, changed nettephp.com -> nette.org 2010-05-25 02:48:51 +02:00
David Grudl
651c0f8c4a DibiProfiler is configurable via DibiConnection $config 2010-05-19 20:48:35 +02:00
David Grudl
88b1a45e42 DibiResult is configured via items 'detectTypes' and 'formatDateTime' in 'result' subarray; removed RESULT_DETECT_TYPES & RESULT_DATE_TIME 2010-05-19 20:25:17 +02:00
David Grudl
9d803869fa updated Nette\Debug 2010-05-19 19:42:04 +02:00
David Grudl
d19afd5790 Removed inTransaction definitely (BC break!) 2010-05-19 18:33:28 +02:00
David Grudl
8b4cd4e689 DibiTranslator: %f modifier converts value to number 2010-05-19 17:14:12 +02:00
David Grudl
286cd7bacd DibiFluent: implemented clause auto-switch for 'JOIN', 'INNER JOIN', 'LEFT JOIN' 2010-05-19 16:38:51 +02:00
David Grudl
1285d9b30a DibiMsSqlDriver: exception message received from mssql_get_last_message() 2010-05-19 15:54:49 +02:00
David Grudl
0748c693ff DibiMsSql2005Driver: added config aliases 'username', 'password', 'database' 2010-05-19 15:40:32 +02:00
David Grudl
550c477797 DibiConnection::alias() refactoring 2010-05-19 15:33:37 +02:00
David Grudl
27d58bff40 DibiDatabaseInfo: provides substitutions 2010-05-19 15:03:48 +02:00
David Grudl
bec559448c rewritten dibi::IDENTIFIER escaping; added support for [table.*] 2010-05-19 14:59:03 +02:00
David Grudl
27930611de REGEXP optimizations 2010-05-16 22:45:55 +02:00
David Grudl
553f7da5f9 implemented PCRE error checking and PcreException 2010-05-16 22:12:19 +02:00
David Grudl
555e825bb2 DibiResult: fixed compatibility with new DibiRow 2010-04-26 21:20:10 +02:00
David Grudl
5d95f0ba0d added DibiRow::toArray() & Countable 2010-04-26 21:18:46 +02:00
David Grudl
26384626ba ArrayObject -> Traversable & iterator_to_array 2010-04-26 20:43:04 +02:00
David Grudl
f048cc4086 added @method phpDoc 2010-04-23 14:55:29 +02:00
David Grudl
784153e98c DibiRow is not longer ArrayObject descendant 2010-04-22 23:19:33 +02:00
David Grudl
a4c5f327de DibiConnection: $config can be Traversable 2010-04-22 22:14:46 +02:00
David Grudl
90d61002fb added @property phpDoc 2010-04-22 12:12:11 +02:00
Roman Sklenar
ea5e1f052f SQLite driver: implemented database reflection 2010-04-22 17:41:28 +08:00
Roman Sklenar
7412f8bf65 DibiPdoDriver::getColumnsMeta PHP < 5.2.3 compatibility 2010-04-22 17:41:28 +08:00
Jakub Vrana
35b8a4f000 Fix MySQL implementation of inTransaction() 2010-04-22 17:41:04 +08:00
Ondřej Mirtes
e8517b43dc PostgreSQL driver now allows 'database' key in config array instead of 'dbname' 2010-04-22 17:32:36 +08:00
paranoiq
7504a51451 enabled 'unsigned' option on mysql and mysqli column info 2010-04-22 17:32:24 +08:00
David Grudl
550be3b10a Debug Bar fix 2010-04-06 12:58:54 +02:00
David Grudl
52e5d43416 DibiProfiler: added [explain] info 2010-04-04 05:58:57 +02:00
David Grudl
57b68131e6 DibiProfiler: $tickets is now static, profiler sets dibi static variables 2010-04-04 00:08:14 +02:00
David Grudl
52f8128a2f profiler fix 2010-04-03 23:55:16 +02:00
David Grudl
3f6a075251 updated for new Nette Debug Bar 2010-04-01 05:30:32 +02:00
David Grudl
22d41ca3c1 DibiProfiler: json_encode in native in PHP 5.2 2010-03-29 15:46:05 +02:00
David Grudl
0b9562497f typos 2010-02-24 07:50:50 +01:00
David Grudl
dbe79ae57b DibiResult: convert() is protected 2010-02-24 06:51:21 +01:00
David Grudl
92ea9f2c5a DibiResult: default type for datetime changed from timestamp -> object DateTime (BC break) 2010-02-24 06:49:05 +01:00
David Grudl
c01bfd792d added new option 'resultDateTime' - replaces parameter $format in DibiResult::setType() 2010-02-24 06:43:08 +01:00
David Grudl
527863fcce added new option 'resultDetectTypes' - calls automatically detectTypes() 2010-02-24 06:23:55 +01:00
David Grudl
4054bdc231 DibiResult: removed setWithTables & 'resultWithTables' configuration option (BC break!) 2010-02-24 04:59:00 +01:00
David Grudl
a2323271d4 DibiResult: small refactoring 2010-02-24 02:43:15 +01:00
David Grudl
576397319a DibiDataSource: better table name detection in __construct 2010-02-16 19:19:32 +01:00
David Grudl
ec1a1ec5b9 DibiRow::asDateTime() added $format parameter 2010-02-15 21:20:19 +01:00
David Grudl
55cd98e9c1 DibiFluent: fixed support for cloning 2010-01-26 19:55:00 +01:00
David Grudl
a8e83ce93d DibiRow: added asTimestamp() & asDateTime(), therefore asDate() is deprecated 2010-01-26 01:38:47 +01:00
David Grudl
e232bf470c DibiFluent: clause() argument can be in upper-case 2010-01-24 18:58:05 +01:00
David Grudl
65965b0943 DibiFluent: added support for cloning 2010-01-24 18:57:04 +01:00
David Grudl
e035c13437 DibiPostgreDriver: getTables() returns always array 2010-01-23 08:00:52 +01:00
David Grudl
b8600ee704 added DibiFluent::REMOVE const 2010-01-23 06:28:23 +01:00
David Grudl
2395b83b03 DibiTranslator: added modifiers %sN & %iN, replacements for %sn & %in 2010-01-23 06:02:03 +01:00
David Grudl
cb1ed71669 DibiPdoDriver: added rowCount() 2010-01-23 05:39:28 +01:00
David Grudl
fa0b146f67 DibiTranslator: empty arrays DO NOT generate NULL (BC break!) & added array modifier %in 2010-01-23 05:25:17 +01:00
David Grudl
bb40e28eb8 DibiTranslator: %by supports inner arrays 2010-01-23 04:57:49 +01:00
David Grudl
1ecc4ab134 DibiMySqlDriver & MySQLi: sets time_zone in connect() 2010-01-23 04:45:59 +01:00
David Grudl
76c02a65da DibiFluent: added removeClause() 2010-01-23 04:43:36 +01:00
David Grudl
b9ec3047b0 small code refactoring 2010-01-15 22:27:06 +01:00
David Grudl
e177436e38 added DateTime53, fix for crappy DateTime in PHP 5.2 2010-01-14 23:41:37 +01:00
David Grudl
9d4a887e7a typos 2010-01-11 17:03:57 +01:00
David Grudl
d61bd79982 DibiConnection: inTransaction() is back, implemented in drivers 2010-01-11 16:58:37 +01:00
David Grudl
c37475838f - year 2009 -> 2010 2010-01-03 15:32:26 +01:00
David Grudl
7688dd81f9 DibSQLite3Driver: improved by Roman Sklenar 2009-12-18 01:46:51 +01:00
Marek Jelen
686b60fb04 DibiOracleDriver: implemented getInsertId() 2009-12-18 01:44:35 +01:00
David Grudl
ccd20b6f17 added SQLite3 driver 2009-12-18 01:43:50 +01:00
David Grudl
20d22dd81b DibiConnection: deprecated inTransaction (BC break!) 2009-12-17 23:53:45 +01:00
David Grudl
f6d4107116 DibiResult: fixed bug in new-syntax fetchAssoc() 2009-12-09 02:34:58 +01:00
David Grudl
75ede18f94 removed PHP 5.1 support; removed DibiVariable & IDibiVariable 2009-11-26 05:38:20 +01:00
David Grudl
8586eb8e29 changed empty-date detection 2009-11-16 02:00:49 +01:00
David Grudl
5e7774404b code smoothing 2009-11-16 02:00:49 +01:00
Jan Vlcek
4b2a329127 DibiDataSource: removed the final keyword of the __toString() method. 2009-11-03 02:03:05 +08:00
Jan Vlcek
22b62ee9a5 MSSQL driver: Added subselect alias in applyLimit. 2009-11-03 02:03:04 +08:00
David Grudl
b00257c6b0 Updated DibiFirebirdDriver & DibiMsSql2005Driver 2009-10-13 17:02:26 +02:00
David Grudl
4235b3564f DibiResult: rewritten associate descriptor syntax 2009-10-06 18:09:13 +02:00
David Grudl
0337cbdba9 DibiResult: fetchAssoc refactoring 2009-10-06 16:51:27 +02:00
David Grudl
d68e526381 updated version number 2009-09-30 22:50:23 +02:00
David Grudl
3b2ca19d42 Released version 1.2 2009-09-18 07:26:02 +02:00
David Grudl
16f6d537e0 All setters provide a fluent interface now (i.e. return $this) 2009-09-18 03:38:10 +02:00
David Grudl
6d353c0b5d DibiResult: removed destructor 2009-09-09 17:04:20 +02:00
David Grudl
698c12eadc DibiColumnInfo: getType() is implemented lazy 2009-09-09 17:03:40 +02:00
David Grudl
70ba2f065c added DibiResultInfo, available via DibiResult::getInfo() 2009-09-09 17:02:46 +02:00
David Grudl
7e539f8f4f typo changes 2009-09-09 17:01:30 +02:00
David Grudl
532ed3a316 MySQL drivers: getColumns() obtains comments 2009-09-08 21:27:57 +02:00
David Grudl
08e70fda61 DibiTranslator: fixed bug in DateTime object usage 2009-08-26 00:09:05 +02:00
David Grudl
217de42d20 DibiPostgreDriver: added user => username alias (thanks to Milan Matejcek) 2009-08-21 13:48:16 +02:00
David Grudl
fa6d771813 dibi internally uses DateTime object in PHP 5.2 2009-08-21 01:34:07 +02:00
David Grudl
3777bacc02 DibiOracleDriver: supports configuration options 'fmtDate' & 'fmtDateTime' 2009-08-20 22:19:01 +02:00
David Grudl
9850a2f78b opened 1.2-dev 2009-08-17 15:58:08 +02:00
202 changed files with 16125 additions and 12571 deletions

10
.gitattributes vendored Normal file
View File

@@ -0,0 +1,10 @@
.gitattributes export-ignore
.gitignore export-ignore
.github export-ignore
appveyor.yml export-ignore
ncs.* export-ignore
phpstan.neon export-ignore
tests/ export-ignore
*.sh eol=lf
*.php* diff=php linguist-language=PHP

19
.github/ISSUE_TEMPLATE/Bug_report.md vendored Normal file
View File

@@ -0,0 +1,19 @@
---
name: "\U0001F41B Bug Report"
about: "If something isn't working as expected \U0001F914"
---
Version: ?.?.?
### Bug Description
... A clear and concise description of what the bug is. A good bug report shouldn't leave others needing to chase you up for more information.
### Steps To Reproduce
... If possible a minimal demo of the problem ...
### Expected Behavior
... A clear and concise description of what you expected to happen.
### Possible Solution
... Only if you have suggestions on a fix for the bug

View File

@@ -0,0 +1,9 @@
---
name: "\U0001F680 Feature Request"
about: "I have a suggestion (and may want to implement it \U0001F642)"
---
- Is your feature request related to a problem? Please describe.
- Explain your intentions.
- It's up to you to make a strong case to convince the project's developers of the merits of this feature.

17
.github/ISSUE_TEMPLATE/Support_us.md vendored Normal file
View File

@@ -0,0 +1,17 @@
---
name: "❤️ Support us"
about: "If you would like to support our efforts in maintaining this project 🙌"
---
--------------^ Click "Preview" for a nicer view!
Help support Dibi!
We develop Dibi for more than 14 years. In order to make your life more comfortable. Dibi cares about the safety of your sites. Dibi saves you time. Dibi earns you money. And is absolutely free.
To ensure future development and improving the documentation, we need your donation.
**[Please make a donation now](https://nette.org/make-donation?to=dibi)**.
Thank you!

1
.github/funding.yml vendored Normal file
View File

@@ -0,0 +1 @@
github: dg

10
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,10 @@
- bug fix / new feature? <!-- #issue numbers, if any -->
- BC break? yes/no
<!--
Describe your changes here to communicate to the maintainers why we should accept this pull request.
Please add new tests to show the fix or feature works.
Thanks for contributing!
-->

31
.github/workflows/coding-style.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Coding Style
on: [push, pull_request]
jobs:
nette_cc:
name: Nette Code Checker
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: 8.3
coverage: none
- run: composer create-project nette/code-checker temp/code-checker ^3 --no-progress
- run: php temp/code-checker/code-checker --strict-types --no-progress --ignore "tests/*/fixtures"
nette_cs:
name: Nette Coding Standard
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: 8.3
coverage: none
- run: composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress
- run: php temp/coding-standard/ecs check

21
.github/workflows/static-analysis.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Static Analysis (only informative)
on:
push:
branches:
- master
jobs:
phpstan:
name: PHPStan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: 8.2
coverage: none
- run: composer install --no-progress --prefer-dist
- run: composer phpstan -- --no-progress
continue-on-error: true # is only informative

120
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,120 @@
name: Tests
on: [push, pull_request]
env:
php-extensions: mbstring, intl, mysqli, pgsql, sqlsrv-5.12.0, pdo_sqlsrv-5.12.0
php-tools: "composer:v2, pecl"
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
php: ['8.2', '8.3', '8.4', '8.5']
fail-fast: false
name: PHP ${{ matrix.php }} tests
services:
mysql57:
image: mysql:5.7
env:
MYSQL_DATABASE: dibi_test
MYSQL_ROOT_PASSWORD: root
ports:
- 3306:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
mysql80:
image: mysql:8.0
ports:
- 3307:3306
options: >-
--health-cmd="mysqladmin ping -ppass"
--health-interval=10s
--health-timeout=5s
--health-retries=5
-e MYSQL_ROOT_PASSWORD=root
-e MYSQL_DATABASE=dibi_test
postgres96:
image: postgres:9.6
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: dibi_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
postgres13:
image: postgres:13
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: dibi_test
ports:
- 5433:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
mssql:
image: mcr.microsoft.com/mssql/server:latest
env:
ACCEPT_EULA: Y
SA_PASSWORD: YourStrong!Passw0rd
MSSQL_PID: Developer
ports:
- 1433:1433
options: >-
--name=mssql
--health-cmd "/opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -P 'YourStrong!Passw0rd' -Q 'SELECT 1' -N -C"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: ${{ env.php-extensions }}
tools: ${{ env.php-tools }}
coverage: none
- name: Create databases.ini
run: cp ./tests/databases.github.ini ./tests/databases.ini
- name: Create MS SQL Database
run: docker exec -i mssql /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -P 'YourStrong!Passw0rd' -Q 'CREATE DATABASE dibi_test' -N -C
- run: composer install --no-progress --prefer-dist
- run: vendor/bin/tester -p phpdbg tests -s -C --coverage ./coverage.xml --coverage-src ./src
- if: failure()
uses: actions/upload-artifact@v4
with:
name: output-${{ matrix.php }}
path: tests/**/output
- name: Save Code Coverage
if: ${{ matrix.php == '8.2' }}
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar
php php-coveralls.phar --verbose --config tests/.coveralls.yml

2
.gitignore vendored Normal file
View File

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

55
appveyor.yml Normal file
View File

@@ -0,0 +1,55 @@
build: off
cache:
- c:\php -> appveyor.yml
- '%LOCALAPPDATA%\Composer\files -> appveyor.yml'
clone_folder: c:\projects\dibi
environment:
MYSQL_PWD: Password12!
services:
- mssql2012sp1
# - mssql2014
- mysql
init:
- SET PATH=c:\php;c:\Program Files\MySQL\MySQL Server 5.7\bin;%PATH%
- SET ANSICON=121x90 (121x90)
install:
# Install PHP 8.0
- IF EXIST c:\php (SET PHP=0) ELSE (SET PHP=1)
- IF %PHP%==1 mkdir c:\php
- IF %PHP%==1 cd c:\php
- IF %PHP%==1 curl https://windows.php.net/downloads/releases/archives/php-8.0.1-Win32-vs16-x64.zip --output php.zip
- IF %PHP%==1 7z x php.zip >nul
- IF %PHP%==1 echo extension_dir=ext >> php.ini
- IF %PHP%==1 echo extension=php_openssl.dll >> php.ini
- IF %PHP%==1 curl https://github.com/microsoft/msphpsql/releases/download/v5.9.0/Windows-8.0.zip -L --output sqlsrv.zip
- IF %PHP%==1 7z x sqlsrv.zip >nul
- IF %PHP%==1 copy Windows-8.0\x64\php_sqlsrv_80_ts.dll ext\php_sqlsrv_ts.dll
- IF %PHP%==1 del /Q *.zip
# Install Microsoft Access Database Engine x64
- IF %PHP%==1 curl https://download.microsoft.com/download/2/4/3/24375141-E08D-4803-AB0E-10F2E3A07AAA/AccessDatabaseEngine_X64.exe --output AccessDatabaseEngine_X64.exe
- cmd /c start /wait AccessDatabaseEngine_X64.exe /passive
# Install Nette Tester
- cd c:\projects\dibi
- appveyor DownloadFile https://getcomposer.org/composer.phar
- php composer.phar install --prefer-dist --no-interaction --no-progress
# Create databases.ini
- copy tests\databases.appveyor.ini tests\databases.ini
before_test:
# Create MySQL database
- mysql --user=root -e "CREATE DATABASE dibi_test"
test_script:
- vendor\bin\tester tests -s -p c:\php\php -c tests\php-win.ini
on_failure:
# Print *.actual content
- for /r %%x in (*.actual) do ( type "%%x" )

42
composer.json Normal file
View File

@@ -0,0 +1,42 @@
{
"name": "dibi/dibi",
"description": "Dibi is Database Abstraction Library for PHP",
"keywords": ["database", "dbal", "mysql", "postgresql", "sqlite", "mssql", "sqlsrv", "oracle", "access", "pdo", "odbc"],
"homepage": "https://dibiphp.com",
"license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
}
],
"require": {
"php": "8.2 - 8.5"
},
"require-dev": {
"tracy/tracy": "^2.9",
"nette/tester": "^2.5",
"nette/di": "^3.1",
"phpstan/phpstan-nette": "^2.0@stable",
"jetbrains/phpstorm-attributes": "^1.0"
},
"replace": {
"dg/dibi": "*"
},
"autoload": {
"classmap": ["src/"],
"psr-4": {
"Dibi\\": "src/Dibi"
}
},
"minimum-stability": "dev",
"scripts": {
"phpstan": "phpstan analyse",
"tester": "tester tests -s"
},
"extra": {
"branch-alias": {
"dev-master": "6.0-dev"
}
}
}

31
contributing.md Normal file
View File

@@ -0,0 +1,31 @@
How to contribute & use the issue tracker
=========================================
Dibi welcomes your contributions. There are several ways to help out:
* Create an issue on GitHub, if you have found a bug
* Write test cases for open bug issues
* Write fixes for open bug/feature issues, preferably with test cases included
* Contribute to the documentation
Issues
------
Please **do not use the issue tracker to ask questions**. We will be happy to help you
on [Dibi forum](https://forum.dibiphp.com).
A good bug report shouldn't leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report.
**Feature requests** are welcome. But take a moment to find out whether your idea
fits with the scope and aims of the project. It's up to *you* to make a strong
case to convince the project's developers of the merits of this feature.
Contributing
------------
The best way to propose a feature is to discuss your ideas on [Dibi forum](https://forum.dibiphp.com) before implementing them.
Please do not fix whitespace, format code, or make a purely cosmetic patch.
Thanks! :heart:

View File

@@ -1,40 +0,0 @@
<?php
/**
* Nette Framework
*
* Copyright (c) 2004, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "Nette license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://nettephp.com
*
* @copyright Copyright (c) 2004, 2009 David Grudl
* @license http://nettephp.com/license Nette license
* @link http://nettephp.com
* @category Nette
* @package Nette
*/
/*namespace Nette;*/
/**
* Custom output for Nette\Debug.
*
* @author David Grudl
* @copyright Copyright (c) 2004, 2009 David Grudl
* @package Nette
*/
interface IDebuggable
{
/**
* Returns custom panels.
* @return array
*/
function getPanels();
}

View File

@@ -1,754 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* Check PHP configuration.
*/
if (version_compare(PHP_VERSION, '5.1.0', '<')) {
throw new Exception('dibi needs PHP 5.1.0 or newer.');
}
@set_magic_quotes_runtime(FALSE); // intentionally @
/**
* Compatibility with Nette
*/
if (!class_exists('NotImplementedException', FALSE)) {
class NotImplementedException extends LogicException {}
}
if (!class_exists('NotSupportedException', FALSE)) {
class NotSupportedException extends LogicException {}
}
if (!class_exists('MemberAccessException', FALSE)) {
class MemberAccessException extends LogicException {}
}
if (!class_exists('InvalidStateException', FALSE)) {
class InvalidStateException extends RuntimeException {}
}
if (!class_exists('IOException', FALSE)) {
class IOException extends RuntimeException {}
}
if (!class_exists('FileNotFoundException', FALSE)) {
class FileNotFoundException extends IOException {}
}
if (!interface_exists(/*Nette\*/'IDebuggable', FALSE)) {
require_once dirname(__FILE__) . '/Nette/IDebuggable.php';
}
// dibi libraries
require_once dirname(__FILE__) . '/libs/interfaces.php';
require_once dirname(__FILE__) . '/libs/DibiObject.php';
require_once dirname(__FILE__) . '/libs/DibiException.php';
require_once dirname(__FILE__) . '/libs/DibiConnection.php';
require_once dirname(__FILE__) . '/libs/DibiResult.php';
require_once dirname(__FILE__) . '/libs/DibiResultIterator.php';
require_once dirname(__FILE__) . '/libs/DibiRow.php';
require_once dirname(__FILE__) . '/libs/DibiTranslator.php';
require_once dirname(__FILE__) . '/libs/DibiVariable.php';
require_once dirname(__FILE__) . '/libs/DibiDataSource.php';
require_once dirname(__FILE__) . '/libs/DibiFluent.php';
require_once dirname(__FILE__) . '/libs/DibiDatabaseInfo.php';
require_once dirname(__FILE__) . '/libs/DibiProfiler.php';
/**
* Interface for database drivers.
*
* This class is static container class for creating DB objects and
* store connections info.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class dibi
{
/**#@+
* dibi data type
*/
const TEXT = 's'; // as 'string'
const BINARY = 'bin';
const BOOL = 'b';
const INTEGER = 'i';
const FLOAT = 'f';
const DATE = 'd';
const DATETIME = 't';
const TIME = 't';
const IDENTIFIER = 'n';
/**#@-*/
/**#@+
* @deprecated column types
*/
const FIELD_TEXT = self::TEXT;
const FIELD_BINARY = self::BINARY;
const FIELD_BOOL = self::BOOL;
const FIELD_INTEGER = self::INTEGER;
const FIELD_FLOAT = self::FLOAT;
const FIELD_DATE = self::DATE;
const FIELD_DATETIME = self::DATETIME;
const FIELD_TIME = self::TIME;
/**#@-*/
/**#@+
* dibi version
*/
const VERSION = '1.1';
const REVISION = '$WCREV$ released on $WCDATE$';
/**#@-*/
/**#@+
* Configuration options
*/
const RESULT_WITH_TABLES = 'resultWithTables'; // for MySQL
const ROW_CLASS = 'rowClass';
const ASC = 'ASC', DESC = 'DESC';
/**#@-*/
/** @var DibiConnection[] Connection registry storage for DibiConnection objects */
private static $registry = array();
/** @var DibiConnection Current connection */
private static $connection;
/** @var array Substitutions for identifiers */
public static $substs = array();
/** @var callback Substitution fallback */
public static $substFallBack = array(__CLASS__, 'defaultSubstFallback');
/** @var array @see addHandler */
private static $handlers = array();
/** @var string Last SQL command @see dibi::query() */
public static $sql;
/** @var int Elapsed time for last query */
public static $elapsedTime;
/** @var int Elapsed time for all queries */
public static $totalTime;
/** @var int Number or queries */
public static $numOfQueries = 0;
/** @var string Default dibi driver */
public static $defaultDriver = 'mysql';
/**
* Static class - cannot be instantiated.
*/
final public function __construct()
{
throw new LogicException("Cannot instantiate static class " . get_class($this));
}
/********************* connections handling ****************d*g**/
/**
* Creates a new DibiConnection object and connects it to specified database.
* @param array|string|ArrayObject connection parameters
* @param string connection name
* @return DibiConnection
* @throws DibiException
*/
public static function connect($config = array(), $name = 0)
{
return self::$connection = self::$registry[$name] = new DibiConnection($config, $name);
}
/**
* Disconnects from database (doesn't destroy DibiConnection object).
* @return void
*/
public static function disconnect()
{
self::getConnection()->disconnect();
}
/**
* Returns TRUE when connection was established.
* @return bool
*/
public static function isConnected()
{
return (self::$connection !== NULL) && self::$connection->isConnected();
}
/**
* Retrieve active connection.
* @param string connection registy name
* @return DibiConnection
* @throws DibiException
*/
public static function getConnection($name = NULL)
{
if ($name === NULL) {
if (self::$connection === NULL) {
throw new DibiException('Dibi is not connected to database.');
}
return self::$connection;
}
if (!isset(self::$registry[$name])) {
throw new DibiException("There is no connection named '$name'.");
}
return self::$registry[$name];
}
/**
* Change active connection.
* @param string connection registy name
* @return void
* @throws DibiException
*/
public static function activate($name)
{
self::$connection = self::getConnection($name);
}
/**
* Retrieve active connection profiler.
* @return IDibiProfiler
* @throws DibiException
*/
public static function getProfiler()
{
return self::getConnection()->getProfiler();
}
/********************* monostate for active connection ****************d*g**/
/**
* Generates and executes SQL query - Monostate for DibiConnection::query().
* @param array|mixed one or more arguments
* @return DibiResult|int result set object (if any)
* @throws DibiException
*/
public static function query($args)
{
$args = func_get_args();
return self::getConnection()->query($args);
}
/**
* Executes the SQL query - Monostate for DibiConnection::nativeQuery().
* @param string SQL statement.
* @return DibiResult|int result set object (if any)
*/
public static function nativeQuery($sql)
{
return self::getConnection()->nativeQuery($sql);
}
/**
* Generates and prints SQL query - Monostate for DibiConnection::test().
* @param array|mixed one or more arguments
* @return bool
*/
public static function test($args)
{
$args = func_get_args();
return self::getConnection()->test($args);
}
/**
* Generates and returns SQL query as DibiDataSource - Monostate for DibiConnection::test().
* @param array|mixed one or more arguments
* @return DibiDataSource
*/
public static function dataSource($args)
{
$args = func_get_args();
return self::getConnection()->dataSource($args);
}
/**
* Executes SQL query and fetch result - Monostate for DibiConnection::query() & fetch().
* @param array|mixed one or more arguments
* @return DibiRow
* @throws DibiException
*/
public static function fetch($args)
{
$args = func_get_args();
return self::getConnection()->query($args)->fetch();
}
/**
* Executes SQL query and fetch results - Monostate for DibiConnection::query() & fetchAll().
* @param array|mixed one or more arguments
* @return array of DibiRow
* @throws DibiException
*/
public static function fetchAll($args)
{
$args = func_get_args();
return self::getConnection()->query($args)->fetchAll();
}
/**
* Executes SQL query and fetch first column - Monostate for DibiConnection::query() & fetchSingle().
* @param array|mixed one or more arguments
* @return string
* @throws DibiException
*/
public static function fetchSingle($args)
{
$args = func_get_args();
return self::getConnection()->query($args)->fetchSingle();
}
/**
* Executes SQL query and fetch pairs - Monostate for DibiConnection::query() & fetchPairs().
* @param array|mixed one or more arguments
* @return string
* @throws DibiException
*/
public static function fetchPairs($args)
{
$args = func_get_args();
return self::getConnection()->query($args)->fetchPairs();
}
/**
* Gets the number of affected rows.
* Monostate for DibiConnection::getAffectedRows()
* @return int number of rows
* @throws DibiException
*/
public static function getAffectedRows()
{
return self::getConnection()->getAffectedRows();
}
/**
* Gets the number of affected rows. Alias for getAffectedRows().
* @return int number of rows
* @throws DibiException
*/
public static function affectedRows()
{
return self::getConnection()->getAffectedRows();
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* Monostate for DibiConnection::getInsertId()
* @param string optional sequence name
* @return int
* @throws DibiException
*/
public static function getInsertId($sequence=NULL)
{
return self::getConnection()->getInsertId($sequence);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column. Alias for getInsertId().
* @param string optional sequence name
* @return int
* @throws DibiException
*/
public static function insertId($sequence=NULL)
{
return self::getConnection()->getInsertId($sequence);
}
/**
* Begins a transaction - Monostate for DibiConnection::begin().
* @param string optional savepoint name
* @return void
* @throws DibiException
*/
public static function begin($savepoint = NULL)
{
self::getConnection()->begin($savepoint);
}
/**
* Commits statements in a transaction - Monostate for DibiConnection::commit($savepoint = NULL).
* @param string optional savepoint name
* @return void
* @throws DibiException
*/
public static function commit($savepoint = NULL)
{
self::getConnection()->commit($savepoint);
}
/**
* Rollback changes in a transaction - Monostate for DibiConnection::rollback().
* @param string optional savepoint name
* @return void
* @throws DibiException
*/
public static function rollback($savepoint = NULL)
{
self::getConnection()->rollback($savepoint);
}
/**
* Gets a information about the current database - Monostate for DibiConnection::getDatabaseInfo().
* @return DibiDatabaseInfo
*/
public static function getDatabaseInfo()
{
return self::getConnection()->getDatabaseInfo();
}
/**
* Import SQL dump from file - extreme fast!
* @param string filename
* @return int count of sql commands
*/
public static function loadFile($file)
{
return self::getConnection()->loadFile($file);
}
/**
* Replacement for majority of dibi::methods() in future.
*/
public static function __callStatic($name, $args)
{
//if ($name = 'select', 'update', ...') {
// return self::command()->$name($args);
//}
return call_user_func_array(array(self::getConnection(), $name), $args);
}
/********************* fluent SQL builders ****************d*g**/
/**
* @return DibiFluent
*/
public static function command()
{
return self::getConnection()->command();
}
/**
* @param string column name
* @return DibiFluent
*/
public static function select($args)
{
$args = func_get_args();
return call_user_func_array(array(self::getConnection(), 'select'), $args);
}
/**
* @param string table
* @param array
* @return DibiFluent
*/
public static function update($table, $args)
{
return self::getConnection()->update($table, $args);
}
/**
* @param string table
* @param array
* @return DibiFluent
*/
public static function insert($table, $args)
{
return self::getConnection()->insert($table, $args);
}
/**
* @param string table
* @return DibiFluent
*/
public static function delete($table)
{
return self::getConnection()->delete($table);
}
/********************* data types ****************d*g**/
/**
* Pseudotype for timestamp representation.
* @param mixed datetime
* @return DibiVariable
*/
public static function datetime($time = NULL)
{
if ($time === NULL) {
$time = time(); // current time
} elseif (is_numeric($time)) {
$time = (int) $time; // timestamp
} elseif ($time instanceof DateTime) {
$time = $time->format('U');
} else {
$time = strtotime($time); // try convert to timestamp
}
return new DibiVariable($time, dibi::DATETIME);
}
/**
* Pseudotype for date representation.
* @param mixed date
* @return DibiVariable
*/
public static function date($date = NULL)
{
$var = self::datetime($date);
$var->modifier = dibi::DATE;
return $var;
}
/********************* substitutions ****************d*g**/
/**
* Create a new substitution pair for indentifiers.
* @param string from
* @param string to
* @return void
*/
public static function addSubst($expr, $subst)
{
self::$substs[$expr] = $subst;
}
/**
* Remove substitution pair.
* @param mixed from or TRUE
* @return void
*/
public static function removeSubst($expr)
{
if ($expr === TRUE) {
self::$substs = array();
} else {
unset(self::$substs[':'.$expr.':']);
}
}
/**
* Sets substitution fallback handler.
* @param callback
* @return void
*/
public static function setSubstFallback($callback)
{
if (!is_callable($callback)) {
$able = is_callable($callback, TRUE, $textual);
throw new InvalidArgumentException("Handler '$textual' is not " . ($able ? 'callable.' : 'valid PHP callback.'));
}
self::$substFallBack = $callback;
}
/**
* Default substitution fallback handler.
* @param string
* @return mixed
*/
public static function defaultSubstFallback($expr)
{
throw new InvalidStateException("Missing substitution for '$expr' expression.");
}
/********************* misc tools ****************d*g**/
/**
* Prints out a syntax highlighted version of the SQL command or DibiResult.
* @param string|DibiResult
* @param bool return output instead of printing it?
* @return string
*/
public static function dump($sql = NULL, $return = FALSE)
{
ob_start();
if ($sql instanceof DibiResult) {
$sql->dump();
} else {
if ($sql === NULL) $sql = self::$sql;
static $keywords1 = 'SELECT|UPDATE|INSERT(?:\s+INTO)?|REPLACE(?:\s+INTO)?|DELETE|FROM|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|SET|VALUES|LEFT\s+JOIN|INNER\s+JOIN|TRUNCATE';
static $keywords2 = 'ALL|DISTINCT|DISTINCTROW|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|LIKE|TRUE|FALSE';
// insert new lines
$sql = " $sql ";
$sql = preg_replace("#(?<=[\\s,(])($keywords1)(?=[\\s,)])#i", "\n\$1", $sql);
// reduce spaces
$sql = preg_replace('#[ \t]{2,}#', " ", $sql);
$sql = wordwrap($sql, 100);
$sql = htmlSpecialChars($sql);
$sql = preg_replace("#\n{2,}#", "\n", $sql);
// syntax highlight
$sql = preg_replace_callback("#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is", array('dibi', 'highlightCallback'), $sql);
$sql = trim($sql);
echo '<pre class="dump">', $sql, "</pre>\n";
}
if ($return) {
return ob_get_clean();
} else {
ob_end_flush();
}
}
private static function highlightCallback($matches)
{
if (!empty($matches[1])) // comment
return '<em style="color:gray">' . $matches[1] . '</em>';
if (!empty($matches[2])) // error
return '<strong style="color:red">' . $matches[2] . '</strong>';
if (!empty($matches[3])) // most important keywords
return '<strong style="color:blue">' . $matches[3] . '</strong>';
if (!empty($matches[4])) // other keywords
return '<strong style="color:green">' . $matches[4] . '</strong>';
}
/**
* Returns brief descriptions.
* @return string
* @return array
*/
public static function getColophon($sender = NULL)
{
$arr = array(
'Number of SQL queries: ' . dibi::$numOfQueries
. (dibi::$totalTime === NULL ? '' : ', elapsed time: ' . sprintf('%0.3f', dibi::$totalTime * 1000) . ' ms'),
);
if ($sender === 'bluescreen') {
$arr[] = 'dibi ' . dibi::VERSION . ' (revision ' . dibi::REVISION . ')';
}
return $arr;
}
}

View File

@@ -1,834 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* The dibi driver for Firebird/InterBase database.
*
* Connection options:
* - 'database' - the path to database file (server:/path/database.fdb)
* - 'username' (or 'user')
* - 'password' (or 'pass')
* - 'charset' - character encoding to set
* - 'buffers' - buffers is the number of database buffers to allocate for the server-side cache. If 0 or omitted, server chooses its own default.
* - 'lazy' - if TRUE, connection will be established only when required
* - 'resource' - connection resource (optional)
*
* @author Tomáš Kraina, Roman Sklenář
* @copyright Copyright (c) 2009
* @package dibi
*/
class DibiFirebirdDriver extends DibiObject implements IDibiDriver
{
const ERROR_EXCEPTION_THROWN = -836;
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var resource Resultset resource */
private $transaction;
/** @var bool */
private $inTransaction = FALSE;
/**
* @throws DibiException
*/
public function __construct()
{
if (!extension_loaded('interbase')) {
throw new DibiDriverException("PHP extension 'interbase' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array &$config)
{
DibiConnection::alias($config, 'database', 'db');
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} 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;
DibiDriverException::tryError();
if (empty($config['persistent'])) {
$this->connection = ibase_connect($config['database'], $config['username'], $config['password'], $config['charset'], $config['buffers']); // intentionally @
} else {
$this->connection = ibase_pconnect($config['database'], $config['username'], $config['password'], $config['charset'], $config['buffers']); // intentionally @
}
if (DibiDriverException::catchError($msg)) {
throw new DibiDriverException($msg, ibase_errcode());
}
if (!is_resource($this->connection)) {
throw new DibiDriverException(ibase_errmsg(), ibase_errcode());
}
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
ibase_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiDriver|NULL
* @throws DibiDriverException|DibiException
*/
public function query($sql)
{
DibiDriverException::tryError();
$resource = $this->inTransaction ? $this->transaction : $this->connection;
$this->resultSet = ibase_query($resource, $sql);
if (DibiDriverException::catchError($msg)) {
if (ibase_errcode() == self::ERROR_EXCEPTION_THROWN) {
preg_match('/exception (\d+) (\w+) (.*)/i', ibase_errmsg(), $match);
throw new DibiProcedureException($match[3], $match[1], $match[2], dibi::$sql);
} else {
throw new DibiDriverException(ibase_errmsg(), ibase_errcode(), dibi::$sql);
}
}
if ($this->resultSet === FALSE) {
throw new DibiDriverException(ibase_errmsg(), ibase_errcode(), $sql);
}
return is_resource($this->resultSet) ? clone $this : NULL;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return ibase_affected_rows($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @param string generator name
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
return ibase_gen_id($sequence, 0, $this->connection);
//throw new NotSupportedException('Firebird/InterBase does not support autoincrementing.');
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
if ($savepoint !== NULL) {
throw new DibiDriverException('Savepoints are not supported in Firebird/Interbase.');
}
$this->transaction = ibase_trans($this->resource);
$this->inTransaction = TRUE;
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
if ($savepoint !== NULL) {
throw new DibiDriverException('Savepoints are not supported in Firebird/Interbase.');
}
if (!ibase_commit($this->transaction)) {
DibiDriverException('Unable to handle operation - failure when commiting transaction.');
}
$this->inTransaction = FALSE;
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
if ($savepoint !== NULL) {
throw new DibiDriverException('Savepoints are not supported in Firebird/Interbase.');
}
if (!ibase_rollback($this->transaction)) {
DibiDriverException('Unable to handle operation - failure when rolbacking transaction.');
}
$this->inTransaction = FALSE;
}
/**
* Returns the connection resource.
* @return resource
*/
public function getResource()
{
return $this->connection;
}
/********************* SQL ********************/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . str_replace("'", "''", $value) . "'";
case dibi::IDENTIFIER:
return $value;
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
return date("'Y-m-d'", $value);
case dibi::DATETIME:
return date("'Y-m-d H:i:s'", $value);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
public function applyLimit(&$sql, $limit, $offset)
{
if ($limit < 0 && $offset < 1) return;
// see http://scott.yang.id.au/2004/01/limit-in-select-statements-in-firebird/
$sql = 'SELECT FIRST ' . (int) $limit . ($offset > 0 ? ' SKIP ' . (int) $offset : '') . ' * FROM (' . $sql . ')';
}
/********************* result set ********************/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
return ibase_num_fields($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
public function fetch($assoc)
{
DibiDriverException::tryError();
$result = $assoc ? ibase_fetch_assoc($this->resultSet) : ibase_fetch_row($this->resultSet); // intentionally @
if (DibiDriverException::catchError($msg)) {
if (ibase_errcode() == self::ERROR_EXCEPTION_THROWN) {
preg_match('/exception (\d+) (\w+) (.*)/i', ibase_errmsg(), $match);
throw new DibiProcedureException($match[3], $match[1], $match[2], dibi::$sql);
} else {
throw new DibiDriverException($msg, ibase_errcode(), dibi::$sql);
}
}
return $result;
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
public function seek($row)
{
throw new DibiDriverException("Firebird/Interbase do not support seek in result set.");
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
ibase_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns the result set resource.
* @return mysqli_result
*/
public function getResultResource()
{
return $this->resultSet;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getColumnsMeta()
{
throw new NotImplementedException;
}
/********************* reflection ********************/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$this->query("
SELECT TRIM(RDB\$RELATION_NAME),
CASE RDB\$VIEW_BLR WHEN NULL THEN 'TRUE' ELSE 'FALSE' END
FROM RDB\$RELATIONS
WHERE RDB\$SYSTEM_FLAG = 0;"
);
$res = array();
while ($row = $this->fetch(FALSE)) {
$res[] = array(
'name' => $row[0],
'view' => $row[1] === 'TRUE',
);
}
$this->free();
return $res;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$table = strtoupper($table);
$this->query("
SELECT TRIM(r.RDB\$FIELD_NAME) AS FIELD_NAME,
CASE f.RDB\$FIELD_TYPE
WHEN 261 THEN 'BLOB'
WHEN 14 THEN 'CHAR'
WHEN 40 THEN 'CSTRING'
WHEN 11 THEN 'D_FLOAT'
WHEN 27 THEN 'DOUBLE'
WHEN 10 THEN 'FLOAT'
WHEN 16 THEN 'INT64'
WHEN 8 THEN 'INTEGER'
WHEN 9 THEN 'QUAD'
WHEN 7 THEN 'SMALLINT'
WHEN 12 THEN 'DATE'
WHEN 13 THEN 'TIME'
WHEN 35 THEN 'TIMESTAMP'
WHEN 37 THEN 'VARCHAR'
ELSE 'UNKNOWN'
END AS FIELD_TYPE,
f.RDB\$FIELD_LENGTH AS FIELD_LENGTH,
r.RDB\$DEFAULT_VALUE AS DEFAULT_VALUE,
CASE r.RDB\$NULL_FLAG
WHEN 1 THEN 'FALSE' ELSE 'TRUE'
END AS NULLABLE
FROM RDB\$RELATION_FIELDS r
LEFT JOIN RDB\$FIELDS f ON r.RDB\$FIELD_SOURCE = f.RDB\$FIELD_NAME
WHERE r.RDB\$RELATION_NAME = '$table'
ORDER BY r.RDB\$FIELD_POSITION;"
);
$res = array();
while ($row = $this->fetch(TRUE)) {
$key = $row['FIELD_NAME'];
$res[$key] = array(
'name' => $key,
'table' => $table,
'nativetype' => trim($row['FIELD_TYPE']),
'size' => $row['FIELD_LENGTH'],
'nullable' => $row['NULLABLE'] === 'TRUE',
'default' => $row['DEFAULT_VALUE'],
'autoincrement' => FALSE,
);
}
$this->free();
return $res;
}
/**
* Returns metadata for all indexes in a table (the constraints are included).
* @param string
* @return array
*/
public function getIndexes($table)
{
$table = strtoupper($table);
$this->query("
SELECT TRIM(s.RDB\$INDEX_NAME) AS INDEX_NAME,
TRIM(s.RDB\$FIELD_NAME) AS FIELD_NAME,
i.RDB\$UNIQUE_FLAG AS UNIQUE_FLAG,
i.RDB\$FOREIGN_KEY AS FOREIGN_KEY,
TRIM(r.RDB\$CONSTRAINT_TYPE) AS CONSTRAINT_TYPE,
s.RDB\$FIELD_POSITION AS FIELD_POSITION
FROM RDB\$INDEX_SEGMENTS s
LEFT JOIN RDB\$INDICES i ON i.RDB\$INDEX_NAME = s.RDB\$INDEX_NAME
LEFT JOIN RDB\$RELATION_CONSTRAINTS r ON r.RDB\$INDEX_NAME = s.RDB\$INDEX_NAME
WHERE UPPER(i.RDB\$RELATION_NAME) = '$table'
ORDER BY s.RDB\$FIELD_POSITION"
);
$res = array();
while ($row = $this->fetch(TRUE)) {
$key = $row['INDEX_NAME'];
$res[$key]['name'] = $key;
$res[$key]['unique'] = $row['UNIQUE_FLAG'] === 1;
$res[$key]['primary'] = $row['CONSTRAINT_TYPE'] === 'PRIMARY KEY';
$res[$key]['table'] = $table;
$res[$key]['columns'][$row['FIELD_POSITION']] = $row['FIELD_NAME'];
}
$this->free();
return $res;
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
$table = strtoupper($table);
$this->query("
SELECT TRIM(s.RDB\$INDEX_NAME) AS INDEX_NAME,
TRIM(s.RDB\$FIELD_NAME) AS FIELD_NAME,
FROM RDB\$INDEX_SEGMENTS s
LEFT JOIN RDB\$RELATION_CONSTRAINTS r ON r.RDB\$INDEX_NAME = s.RDB\$INDEX_NAME
WHERE UPPER(i.RDB\$RELATION_NAME) = '$table'
AND r.RDB\$CONSTRAINT_TYPE = 'FOREIGN KEY'
ORDER BY s.RDB\$FIELD_POSITION"
);
$res = array();
while ($row = $this->fetch(TRUE)) {
$key = $row['INDEX_NAME'];
$res[$key] = array(
'name' => $key,
'column' => $row['FIELD_NAME'],
'table' => $table,
);
}
$this->free();
return $res;
}
/**
* Returns list of indices in given table (the constraints are not listed).
* @param string
* @return array
*/
public function getIndices($table)
{
$this->query("
SELECT TRIM(RDB\$INDEX_NAME)
FROM RDB\$INDICES
WHERE RDB\$RELATION_NAME = UPPER('$table')
AND RDB\$UNIQUE_FLAG IS NULL
AND RDB\$FOREIGN_KEY IS NULL;"
);
$res = array();
while ($row = $this->fetch(FALSE)) {
$res[] = $row[0];
}
$this->free();
return $res;
}
/**
* Returns list of constraints in given table.
* @param string
* @return array
*/
public function getConstraints($table)
{
$this->query("
SELECT TRIM(RDB\$INDEX_NAME)
FROM RDB\$INDICES
WHERE RDB\$RELATION_NAME = UPPER('$table')
AND (
RDB\$UNIQUE_FLAG IS NOT NULL
OR RDB\$FOREIGN_KEY IS NOT NULL
);"
);
$res = array();
while ($row = $this->fetch(FALSE)) {
$res[] = $row[0];
}
$this->free();
return $res;
}
/**
* Returns metadata for all triggers in a table or database.
* (Only if user has permissions on ALTER TABLE, INSERT/UPDATE/DELETE record in table)
* @param string
* @param string
* @return array
*/
public function getTriggersMeta($table = NULL)
{
$this->query("
SELECT TRIM(RDB\$TRIGGER_NAME) AS TRIGGER_NAME,
TRIM(RDB\$RELATION_NAME) AS TABLE_NAME,
CASE RDB\$TRIGGER_TYPE
WHEN 1 THEN 'BEFORE'
WHEN 2 THEN 'AFTER'
WHEN 3 THEN 'BEFORE'
WHEN 4 THEN 'AFTER'
WHEN 5 THEN 'BEFORE'
WHEN 6 THEN 'AFTER'
END AS TRIGGER_TYPE,
CASE RDB\$TRIGGER_TYPE
WHEN 1 THEN 'INSERT'
WHEN 2 THEN 'INSERT'
WHEN 3 THEN 'UPDATE'
WHEN 4 THEN 'UPDATE'
WHEN 5 THEN 'DELETE'
WHEN 6 THEN 'DELETE'
END AS TRIGGER_EVENT,
CASE RDB\$TRIGGER_INACTIVE
WHEN 1 THEN 'FALSE' ELSE 'TRUE'
END AS TRIGGER_ENABLED
FROM RDB\$TRIGGERS
WHERE RDB\$SYSTEM_FLAG = 0"
. ($table === NULL ? ";" : " AND RDB\$RELATION_NAME = UPPER('$table');")
);
$res = array();
while ($row = $this->fetch(TRUE)) {
$res[$row['TRIGGER_NAME']] = array(
'name' => $row['TRIGGER_NAME'],
'table' => $row['TABLE_NAME'],
'type' => trim($row['TRIGGER_TYPE']),
'event' => trim($row['TRIGGER_EVENT']),
'enabled' => trim($row['TRIGGER_ENABLED']) === 'TRUE',
);
}
$this->free();
return $res;
}
/**
* Returns list of triggers for given table.
* (Only if user has permissions on ALTER TABLE, INSERT/UPDATE/DELETE record in table)
* @param string
* @return array
*/
public function getTriggers($table = NULL)
{
$q = "SELECT TRIM(RDB\$TRIGGER_NAME)
FROM RDB\$TRIGGERS
WHERE RDB\$SYSTEM_FLAG = 0";
$q .= $table === NULL ? ";" : " AND RDB\$RELATION_NAME = UPPER('$table')";
$this->query($q);
$res = array();
while ($row = $this->fetch(FALSE)) {
$res[] = $row[0];
}
$this->free();
return $res;
}
/**
* Returns metadata from stored procedures and their input and output parameters.
* @param string
* @return array
*/
public function getProceduresMeta()
{
$this->query("
SELECT
TRIM(p.RDB\$PARAMETER_NAME) AS PARAMETER_NAME,
TRIM(p.RDB\$PROCEDURE_NAME) AS PROCEDURE_NAME,
CASE p.RDB\$PARAMETER_TYPE
WHEN 0 THEN 'INPUT'
WHEN 1 THEN 'OUTPUT'
ELSE 'UNKNOWN'
END AS PARAMETER_TYPE,
CASE f.RDB\$FIELD_TYPE
WHEN 261 THEN 'BLOB'
WHEN 14 THEN 'CHAR'
WHEN 40 THEN 'CSTRING'
WHEN 11 THEN 'D_FLOAT'
WHEN 27 THEN 'DOUBLE'
WHEN 10 THEN 'FLOAT'
WHEN 16 THEN 'INT64'
WHEN 8 THEN 'INTEGER'
WHEN 9 THEN 'QUAD'
WHEN 7 THEN 'SMALLINT'
WHEN 12 THEN 'DATE'
WHEN 13 THEN 'TIME'
WHEN 35 THEN 'TIMESTAMP'
WHEN 37 THEN 'VARCHAR'
ELSE 'UNKNOWN'
END AS FIELD_TYPE,
f.RDB\$FIELD_LENGTH AS FIELD_LENGTH,
p.RDB\$PARAMETER_NUMBER AS PARAMETER_NUMBER
FROM RDB\$PROCEDURE_PARAMETERS p
LEFT JOIN RDB\$FIELDS f ON f.RDB\$FIELD_NAME = p.RDB\$FIELD_SOURCE
ORDER BY p.RDB\$PARAMETER_TYPE, p.RDB\$PARAMETER_NUMBER;"
);
$res = array();
while ($row = $this->fetch(TRUE)) {
$key = $row['PROCEDURE_NAME'];
$io = trim($row['PARAMETER_TYPE']);
$num = $row['PARAMETER_NUMBER'];
$res[$key]['name'] = $row['PROCEDURE_NAME'];
$res[$key]['params'][$io][$num]['name'] = $row['PARAMETER_NAME'];
$res[$key]['params'][$io][$num]['type'] = trim($row['FIELD_TYPE']);
$res[$key]['params'][$io][$num]['size'] = $row['FIELD_LENGTH'];
}
$this->free();
return $res;
}
/**
* Returns list of stored procedures.
* @return array
*/
public function getProcedures()
{
$this->query("
SELECT TRIM(RDB\$PROCEDURE_NAME)
FROM RDB\$PROCEDURES;"
);
$res = array();
while ($row = $this->fetch(FALSE)) {
$res[] = $row[0];
}
$this->free();
return $res;
}
/**
* Returns list of generators.
* @return array
*/
public function getGenerators()
{
$this->query("
SELECT TRIM(RDB\$GENERATOR_NAME)
FROM RDB\$GENERATORS
WHERE RDB\$SYSTEM_FLAG = 0;"
);
$res = array();
while ($row = $this->fetch(FALSE)) {
$res[] = $row[0];
}
$this->free();
return $res;
}
/**
* Returns list of user defined functions (UDF).
* @return array
*/
public function getFunctions()
{
$this->query("
SELECT TRIM(RDB\$FUNCTION_NAME)
FROM RDB\$FUNCTIONS
WHERE RDB\$SYSTEM_FLAG = 0;"
);
$res = array();
while ($row = $this->fetch(FALSE)) {
$res[] = $row[0];
}
$this->free();
return $res;
}
}
/**
* Database procedure exception.
*
* @author Roman Sklenář
* @copyright Copyright (c) 2009
* @package dibi
*/
class DibiProcedureException extends DibiException
{
/** @var string */
protected $severity;
/**
* Construct the exception.
* @param string Message describing the exception
* @param int Some code
* @param string SQL command
*/
public function __construct($message = NULL, $code = 0, $severity = NULL, $sql = NULL)
{
parent::__construct($message, (int) $code, $sql);
$this->severity = $severity;
}
/**
* Gets the exception severity.
* @return string
*/
public function getSeverity()
{
$this->severity;
}
}

View File

@@ -1,403 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* The dibi driver for MS SQL database.
*
* Connection options:
* - 'host' - the MS SQL server host name. It can also include a port number (hostname:port)
* - 'username' (or 'user')
* - 'password' (or 'pass')
* - 'persistent' - try to find a persistent link?
* - 'database' - the database name to select
* - 'lazy' - if TRUE, connection will be established only when required
* - 'resource' - connection resource (optional)
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiMsSqlDriver extends DibiObject implements IDibiDriver
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/**
* @throws DibiException
*/
public function __construct()
{
if (!extension_loaded('mssql')) {
throw new DibiDriverException("PHP extension 'mssql' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array &$config)
{
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} elseif (empty($config['persistent'])) {
$this->connection = @mssql_connect($config['host'], $config['username'], $config['password'], TRUE); // intentionally @
} else {
$this->connection = @mssql_pconnect($config['host'], $config['username'], $config['password']); // intentionally @
}
if (!is_resource($this->connection)) {
throw new DibiDriverException("Can't connect to DB.");
}
if (isset($config['database']) && !@mssql_select_db($config['database'], $this->connection)) { // intentionally @
throw new DibiDriverException("Can't select DB '$config[database]'.");
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
mssql_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$this->resultSet = @mssql_query($sql, $this->connection); // intentionally @
if ($this->resultSet === FALSE) {
throw new DibiDriverException('Query error', 0, $sql);
}
return is_resource($this->resultSet) ? clone $this : NULL;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return mssql_rows_affected($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
$res = mssql_query('SELECT @@IDENTITY', $this->connection);
if (is_resource($res)) {
$row = mssql_fetch_row($res);
return $row[0];
}
return FALSE;
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query('BEGIN TRANSACTION');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query('COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query('ROLLBACK');
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return $this->connection;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . str_replace("'", "''", $value) . "'";
case dibi::IDENTIFIER:
// @see http://msdn.microsoft.com/en-us/library/ms176027.aspx
$value = str_replace(array('[', ']'), array('[[', ']]'), $value);
return '[' . str_replace('.', '].[', $value) . ']';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
return date("'Y-m-d'", $value);
case dibi::DATETIME:
return date("'Y-m-d H:i:s'", $value);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
public function applyLimit(&$sql, $limit, $offset)
{
// offset support is missing
if ($limit >= 0) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
}
if ($offset) {
throw new NotImplementedException('Offset is not implemented.');
}
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
return mssql_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
public function fetch($assoc)
{
return mssql_fetch_array($this->resultSet, $assoc ? MSSQL_ASSOC : MSSQL_NUM);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
return mssql_data_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
mssql_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getColumnsMeta()
{
$count = mssql_num_fields($this->resultSet);
$res = array();
for ($i = 0; $i < $count; $i++) {
$row = (array) mssql_fetch_field($this->resultSet, $i);
$res[] = array(
'name' => $row['name'],
'fullname' => $row['column_source'] ? $row['column_source'] . '.' . $row['name'] : $row['name'],
'table' => $row['column_source'],
'nativetype' => $row['type'],
);
}
return $res;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
return $this->resultSet;
}
/********************* reflection ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
throw new NotImplementedException;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new NotImplementedException;
}
}

View File

@@ -1,410 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* The dibi driver for MS SQL Driver 2005 database.
*
* Connection options:
* - 'host' - the MS SQL server host name. It can also include a port number (hostname:port)
* - 'options' - connection info array {@link http://msdn.microsoft.com/en-us/library/cc296161(SQL.90).aspx}
* - 'lazy' - if TRUE, connection will be established only when required
* - 'charset' - character encoding to set (default is UTF-8)
* - 'resource' - connection resource (optional)
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiMsSql2005Driver extends DibiObject implements IDibiDriver
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var string character encoding */
private $charset;
/**
* @throws DibiException
*/
public function __construct()
{
if (!extension_loaded('sqlsrv')) {
throw new DibiDriverException("PHP extension 'sqlsrv' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array &$config)
{
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} elseif (isset($config['options'])) {
$this->connection = sqlsrv_connect($config['host'], $config['options']);
} else {
$this->connection = sqlsrv_connect($config['host']);
}
if (!is_resource($this->connection)) {
$info = sqlsrv_errors();
throw new DibiDriverException($info[0]['message'], $info[0]['code']);
}
$this->charset = empty($config['charset']) ? 'UTF-8' : $config['charset'];
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
sqlsrv_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$sql = iconv($this->charset, 'UTF-16LE', $sql);
$this->resultSet = sqlsrv_query($this->connection, $sql);
if ($this->resultSet === FALSE) {
$info = sqlsrv_errors();
throw new DibiDriverException($info[0]['message'], $info[0]['code'], $sql);
}
return is_resource($this->resultSet) ? clone $this : NULL;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return sqlsrv_rows_affected($this->resultSet);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
$res = sqlsrv_query($this->connection, 'SELECT @@IDENTITY');
if (is_resource($res)) {
$row = sqlsrv_fetch_array($res, SQLSRV_FETCH_NUMERIC);
return $row[0];
}
return FALSE;
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query('BEGIN TRANSACTION');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query('COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query('ROLLBACK');
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return $this->connection;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . str_replace("'", "''", $value) . "'";
case dibi::IDENTIFIER:
// @see http://msdn.microsoft.com/en-us/library/ms176027.aspx
$value = str_replace(array('[', ']'), array('[[', ']]'), $value);
return '[' . str_replace('.', '].[', $value) . ']';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
return date("'Y-m-d'", $value);
case dibi::DATETIME:
return date("'Y-m-d H:i:s'", $value);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
public function applyLimit(&$sql, $limit, $offset)
{
// offset support is missing
if ($limit >= 0) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
}
if ($offset) {
throw new NotImplementedException('Offset is not implemented.');
}
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
throw new NotSupportedException('Row count is not available for unbuffered queries.');
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
public function fetch($assoc)
{
$row = sqlsrv_fetch_array($this->resultSet, $assoc ? SQLSRV_FETCH_ASSOC : SQLSRV_FETCH_NUMERIC);
foreach ($row as $k => $v) {
if (is_string($v)) {
$row[$k] = iconv('UTF-16LE', $this->charset, $v);
}
}
return $row;
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
throw new NotSupportedException('Cannot seek an unbuffered result set.');
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
sqlsrv_free_stmt($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getColumnsMeta()
{
$count = sqlsrv_num_fields($this->resultSet);
$res = array();
for ($i = 0; $i < $count; $i++) {
$row = (array) sqlsrv_field_metadata($this->resultSet, $i);
$res[] = array(
'name' => $row['Name'],
'fullname' => $row['Name'],
'nativetype' => $row['Type'],
);
}
return $res;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
return $this->resultSet;
}
/********************* reflection ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
throw new NotImplementedException;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new NotImplementedException;
}
}

View File

@@ -1,521 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* The dibi driver for MySQL database.
*
* Connection options:
* - 'host' - the MySQL server host name
* - 'port' - the port number to attempt to connect to the MySQL server
* - 'socket' - the socket or named pipe
* - 'username' (or 'user')
* - 'password' (or 'pass')
* - 'persistent' - try to find a persistent link?
* - 'database' - the database name to select
* - 'charset' - character encoding to set
* - 'unbuffered' - sends query without fetching and buffering the result rows automatically?
* - 'options' - driver specific constants (MYSQL_*)
* - 'sqlmode' - see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
* - 'lazy' - if TRUE, connection will be established only when required
* - 'resource' - connection resource (optional)
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiMySqlDriver extends DibiObject implements IDibiDriver
{
const ERROR_ACCESS_DENIED = 1045;
const ERROR_DUPLICATE_ENTRY = 1062;
const ERROR_DATA_TRUNCATED = 1265;
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool Is buffered (seekable and countable)? */
private $buffered;
/**
* @throws DibiException
*/
public function __construct()
{
if (!extension_loaded('mysql')) {
throw new DibiDriverException("PHP extension 'mysql' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array &$config)
{
DibiConnection::alias($config, 'options');
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
// default values
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'])) {
$host = ini_get('mysql.default_host');
if ($host) {
$config['host'] = $host;
$config['port'] = ini_get('mysql.default_port');
} else {
if (!isset($config['socket'])) $config['socket'] = ini_get('mysql.default_socket');
$config['host'] = NULL;
}
}
if (empty($config['socket'])) {
$host = $config['host'] . (empty($config['port']) ? '' : ':' . $config['port']);
} else {
$host = ':' . $config['socket'];
}
if (empty($config['persistent'])) {
$this->connection = @mysql_connect($host, $config['username'], $config['password'], TRUE, $config['options']); // intentionally @
} else {
$this->connection = @mysql_pconnect($host, $config['username'], $config['password'], $config['options']); // intentionally @
}
}
if (!is_resource($this->connection)) {
throw new DibiDriverException(mysql_error(), mysql_errno());
}
if (isset($config['charset'])) {
$ok = FALSE;
if (function_exists('mysql_set_charset')) {
// affects the character set used by mysql_real_escape_string() (was added in MySQL 5.0.7 and PHP 5.2.3)
$ok = @mysql_set_charset($config['charset'], $this->connection); // intentionally @
}
if (!$ok) {
$ok = @mysql_query("SET NAMES '$config[charset]'", $this->connection); // intentionally @
if (!$ok) {
throw new DibiDriverException(mysql_error($this->connection), mysql_errno($this->connection));
}
}
}
if (isset($config['database'])) {
if (!@mysql_select_db($config['database'], $this->connection)) { // intentionally @
throw new DibiDriverException(mysql_error($this->connection), mysql_errno($this->connection));
}
}
if (isset($config['sqlmode'])) {
if (!@mysql_query("SET sql_mode='$config[sqlmode]'", $this->connection)) { // intentionally @
throw new DibiDriverException(mysql_error($this->connection), mysql_errno($this->connection));
}
}
$this->buffered = empty($config['unbuffered']);
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
mysql_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
if ($this->buffered) {
$this->resultSet = @mysql_query($sql, $this->connection); // intentionally @
} else {
$this->resultSet = @mysql_unbuffered_query($sql, $this->connection); // intentionally @
}
if (mysql_errno($this->connection)) {
throw new DibiDriverException(mysql_error($this->connection), mysql_errno($this->connection), $sql);
}
return is_resource($this->resultSet) ? clone $this : NULL;
}
/**
* Retrieves information about the most recently executed query.
* @return array
*/
public function getInfo()
{
$res = array();
preg_match_all('#(.+?): +(\d+) *#', mysql_info($this->connection), $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$res[$m[1]] = (int) $m[2];
}
return $res;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return mysql_affected_rows($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
return mysql_insert_id($this->connection);
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return $this->connection;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
return "'" . mysql_real_escape_string($value, $this->connection) . "'";
case dibi::BINARY:
return "_binary'" . mysql_real_escape_string($value, $this->connection) . "'";
case dibi::IDENTIFIER:
// @see http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
$value = str_replace('`', '``', $value);
return '`' . str_replace('.', '`.`', $value) . '`';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
return date("'Y-m-d'", $value);
case dibi::DATETIME:
return date("'Y-m-d H:i:s'", $value);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
public function applyLimit(&$sql, $limit, $offset)
{
if ($limit < 0 && $offset < 1) return;
// see http://dev.mysql.com/doc/refman/5.0/en/select.html
$sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit)
. ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
if (!$this->buffered) {
throw new DibiDriverException('Row count is not available for unbuffered queries.');
}
return mysql_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
public function fetch($assoc)
{
return mysql_fetch_array($this->resultSet, $assoc ? MYSQL_ASSOC : MYSQL_NUM);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
public function seek($row)
{
if (!$this->buffered) {
throw new DibiDriverException('Cannot seek an unbuffered result set.');
}
return mysql_data_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
mysql_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getColumnsMeta()
{
$count = mysql_num_fields($this->resultSet);
$res = array();
for ($i = 0; $i < $count; $i++) {
$row = (array) mysql_fetch_field($this->resultSet, $i);
$res[] = array(
'name' => $row['name'],
'table' => $row['table'],
'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
'nativetype' => strtoupper($row['type']),
'vendor' => $row,
);
}
return $res;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
return $this->resultSet;
}
/********************* reflection ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$this->query("SHOW FULL TABLES");
$res = array();
while ($row = $this->fetch(FALSE)) {
$res[] = array(
'name' => $row[0],
'view' => isset($row[1]) && $row[1] === 'VIEW',
);
}
$this->free();
return $res;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$this->query("SHOW COLUMNS FROM `$table`");
$res = array();
while ($row = $this->fetch(TRUE)) {
$type = explode('(', $row['Type']);
$res[] = array(
'name' => $row['Field'],
'table' => $table,
'nativetype' => strtoupper($type[0]),
'size' => isset($type[1]) ? (int) $type[1] : NULL,
'nullable' => $row['Null'] === 'YES',
'default' => $row['Default'],
'autoincrement' => $row['Extra'] === 'auto_increment',
);
}
$this->free();
return $res;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$this->query("SHOW INDEX FROM `$table`");
$res = array();
while ($row = $this->fetch(TRUE)) {
$res[$row['Key_name']]['name'] = $row['Key_name'];
$res[$row['Key_name']]['unique'] = !$row['Non_unique'];
$res[$row['Key_name']]['primary'] = $row['Key_name'] === 'PRIMARY';
$res[$row['Key_name']]['columns'][$row['Seq_in_index'] - 1] = $row['Column_name'];
}
$this->free();
return array_values($res);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new NotImplementedException;
}
}

View File

@@ -1,531 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* The dibi driver for MySQL database via improved extension.
*
* Connection options:
* - 'host' - the MySQL server host name
* - 'port' - the port number to attempt to connect to the MySQL server
* - 'socket' - the socket or named pipe
* - 'username' (or 'user')
* - 'password' (or 'pass')
* - 'persistent' - try to find a persistent link?
* - 'database' - the database name to select
* - 'charset' - character encoding to set
* - 'unbuffered' - sends query without fetching and buffering the result rows automatically?
* - 'options' - driver specific constants (MYSQLI_*)
* - 'sqlmode' - see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
* - 'lazy' - if TRUE, connection will be established only when required
* - 'resource' - connection resource (optional)
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiMySqliDriver extends DibiObject implements IDibiDriver
{
const ERROR_ACCESS_DENIED = 1045;
const ERROR_DUPLICATE_ENTRY = 1062;
const ERROR_DATA_TRUNCATED = 1265;
/** @var mysqli Connection resource */
private $connection;
/** @var mysqli_result Resultset resource */
private $resultSet;
/** @var bool Is buffered (seekable and countable)? */
private $buffered;
/**
* @throws DibiException
*/
public function __construct()
{
if (!extension_loaded('mysqli')) {
throw new DibiDriverException("PHP extension 'mysqli' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array &$config)
{
DibiConnection::alias($config, 'options');
DibiConnection::alias($config, 'database');
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
// default values
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;
if (!isset($config['host'])) {
$host = ini_get('mysqli.default_host');
if ($host) {
$config['host'] = $host;
$config['port'] = ini_get('mysqli.default_port');
} else {
$config['host'] = NULL;
$config['port'] = NULL;
}
}
$this->connection = mysqli_init();
@mysqli_real_connect($this->connection, $config['host'], $config['username'], $config['password'], $config['database'], $config['port'], $config['socket'], $config['options']); // intentionally @
if ($errno = mysqli_connect_errno()) {
throw new DibiDriverException(mysqli_connect_error(), $errno);
}
}
if (isset($config['charset'])) {
$ok = FALSE;
if (version_compare(PHP_VERSION , '5.1.5', '>=')) {
// affects the character set used by mysql_real_escape_string() (was added in MySQL 5.0.7 and PHP 5.0.5, fixed in PHP 5.1.5)
$ok = @mysqli_set_charset($this->connection, $config['charset']); // intentionally @
}
if (!$ok) {
$ok = @mysqli_query($this->connection, "SET NAMES '$config[charset]'"); // intentionally @
if (!$ok) {
throw new DibiDriverException(mysqli_error($this->connection), mysqli_errno($this->connection));
}
}
}
if (isset($config['sqlmode'])) {
if (!@mysqli_query($this->connection, "SET sql_mode='$config[sqlmode]'")) { // intentionally @
throw new DibiDriverException(mysqli_error($this->connection), mysqli_errno($this->connection));
}
}
$this->buffered = empty($config['unbuffered']);
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
mysqli_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$this->resultSet = @mysqli_query($this->connection, $sql, $this->buffered ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT); // intentionally @
if (mysqli_errno($this->connection)) {
throw new DibiDriverException(mysqli_error($this->connection), mysqli_errno($this->connection), $sql);
}
return is_object($this->resultSet) ? clone $this : NULL;
}
/**
* Retrieves information about the most recently executed query.
* @return array
*/
public function getInfo()
{
$res = array();
preg_match_all('#(.+?): +(\d+) *#', mysqli_info($this->connection), $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$res[$m[1]] = (int) $m[2];
}
return $res;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return mysqli_affected_rows($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
return mysqli_insert_id($this->connection);
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
}
/**
* Returns the connection resource.
* @return mysqli
*/
public function getResource()
{
return $this->connection;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
return "'" . mysqli_real_escape_string($this->connection, $value) . "'";
case dibi::BINARY:
return "_binary'" . mysqli_real_escape_string($this->connection, $value) . "'";
case dibi::IDENTIFIER:
$value = str_replace('`', '``', $value);
return '`' . str_replace('.', '`.`', $value) . '`';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
return date("'Y-m-d'", $value);
case dibi::DATETIME:
return date("'Y-m-d H:i:s'", $value);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
public function applyLimit(&$sql, $limit, $offset)
{
if ($limit < 0 && $offset < 1) return;
// see http://dev.mysql.com/doc/refman/5.0/en/select.html
$sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit)
. ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
if (!$this->buffered) {
throw new DibiDriverException('Row count is not available for unbuffered queries.');
}
return mysqli_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
public function fetch($assoc)
{
return mysqli_fetch_array($this->resultSet, $assoc ? MYSQLI_ASSOC : MYSQLI_NUM);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
public function seek($row)
{
if (!$this->buffered) {
throw new DibiDriverException('Cannot seek an unbuffered result set.');
}
return mysqli_data_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
mysqli_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getColumnsMeta()
{
static $types;
if (empty($types)) {
$consts = get_defined_constants(TRUE);
foreach ($consts['mysqli'] as $key => $value) {
if (strncmp($key, 'MYSQLI_TYPE_', 12) === 0) {
$types[$value] = substr($key, 12);
}
}
}
$count = mysqli_num_fields($this->resultSet);
$res = array();
for ($i = 0; $i < $count; $i++) {
$row = (array) mysqli_fetch_field_direct($this->resultSet, $i);
$res[] = array(
'name' => $row['name'],
'table' => $row['orgtable'],
'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
'nativetype' => $types[$row['type']],
'vendor' => $row,
);
}
return $res;
}
/**
* Returns the result set resource.
* @return mysqli_result
*/
public function getResultResource()
{
return $this->resultSet;
}
/********************* reflection ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
/*$this->query("
SELECT TABLE_NAME as name, TABLE_TYPE = 'VIEW' as view
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE()
");*/
$this->query("SHOW FULL TABLES");
$res = array();
while ($row = $this->fetch(FALSE)) {
$res[] = array(
'name' => $row[0],
'view' => isset($row[1]) && $row[1] === 'VIEW',
);
}
$this->free();
return $res;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
/*$table = $this->escape($table, dibi::TEXT);
$this->query("
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = $table AND TABLE_SCHEMA = DATABASE()
");*/
$this->query("SHOW COLUMNS FROM `$table`");
$res = array();
while ($row = $this->fetch(TRUE)) {
$type = explode('(', $row['Type']);
$res[] = array(
'name' => $row['Field'],
'table' => $table,
'nativetype' => strtoupper($type[0]),
'size' => isset($type[1]) ? (int) $type[1] : NULL,
'nullable' => $row['Null'] === 'YES',
'default' => $row['Default'],
'autoincrement' => $row['Extra'] === 'auto_increment',
);
}
$this->free();
return $res;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
/*$table = $this->escape($table, dibi::TEXT);
$this->query("
SELECT *
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME = $table AND TABLE_SCHEMA = DATABASE()
AND REFERENCED_COLUMN_NAME IS NULL
");*/
$this->query("SHOW INDEX FROM `$table`");
$res = array();
while ($row = $this->fetch(TRUE)) {
$res[$row['Key_name']]['name'] = $row['Key_name'];
$res[$row['Key_name']]['unique'] = !$row['Non_unique'];
$res[$row['Key_name']]['primary'] = $row['Key_name'] === 'PRIMARY';
$res[$row['Key_name']]['columns'][$row['Seq_in_index'] - 1] = $row['Column_name'];
}
$this->free();
return array_values($res);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new NotImplementedException;
}
}

View File

@@ -1,444 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* The dibi driver interacting with databases via ODBC connections.
*
* Connection options:
* - 'dsn' - driver specific DSN
* - 'username' (or 'user')
* - 'password' (or 'pass')
* - 'persistent' - try to find a persistent link?
* - 'lazy' - if TRUE, connection will be established only when required
* - 'resource' - connection resource (optional)
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiOdbcDriver extends DibiObject implements IDibiDriver
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var int Cursor */
private $row = 0;
/**
* @throws DibiException
*/
public function __construct()
{
if (!extension_loaded('odbc')) {
throw new DibiDriverException("PHP extension 'odbc' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array &$config)
{
if (isset($config['resource'])) {
$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');
if (empty($config['persistent'])) {
$this->connection = @odbc_connect($config['dsn'], $config['username'], $config['password']); // intentionally @
} else {
$this->connection = @odbc_pconnect($config['dsn'], $config['username'], $config['password']); // intentionally @
}
}
if (!is_resource($this->connection)) {
throw new DibiDriverException(odbc_errormsg() . ' ' . odbc_error());
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
odbc_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$this->resultSet = @odbc_exec($this->connection, $sql); // intentionally @
if ($this->resultSet === FALSE) {
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection), 0, $sql);
}
return is_resource($this->resultSet) ? clone $this : NULL;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return odbc_num_rows($this->resultSet);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
throw new NotSupportedException('ODBC does not support autoincrementing.');
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
if (!odbc_autocommit($this->connection, FALSE)) {
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
}
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
if (!odbc_commit($this->connection)) {
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
}
odbc_autocommit($this->connection, TRUE);
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
if (!odbc_rollback($this->connection)) {
throw new DibiDriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
}
odbc_autocommit($this->connection, TRUE);
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return $this->connection;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . str_replace("'", "''", $value) . "'";
case dibi::IDENTIFIER:
$value = str_replace(array('[', ']'), array('[[', ']]'), $value);
return '[' . str_replace('.', '].[', $value) . ']';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
return date("#m/d/Y#", $value);
case dibi::DATETIME:
return date("#m/d/Y H:i:s#", $value);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
public function applyLimit(&$sql, $limit, $offset)
{
// offset support is missing
if ($limit >= 0) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
}
if ($offset) throw new InvalidArgumentException('Offset is not implemented in driver odbc.');
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
// will return -1 with many drivers :-(
return odbc_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
public function fetch($assoc)
{
if ($assoc) {
return odbc_fetch_array($this->resultSet, ++$this->row);
} else {
$set = $this->resultSet;
if (!odbc_fetch_row($set, ++$this->row)) return FALSE;
$count = odbc_num_fields($set);
$cols = array();
for ($i = 1; $i <= $count; $i++) $cols[] = odbc_result($set, $i);
return $cols;
}
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
$this->row = $row;
return TRUE;
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
odbc_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getColumnsMeta()
{
$count = odbc_num_fields($this->resultSet);
$res = array();
for ($i = 1; $i <= $count; $i++) {
$res[] = array(
'name' => odbc_field_name($this->resultSet, $i),
'table' => NULL,
'fullname' => odbc_field_name($this->resultSet, $i),
'nativetype'=> odbc_field_type($this->resultSet, $i),
);
}
return $res;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
return $this->resultSet;
}
/********************* reflection ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$result = odbc_tables($this->connection);
$res = array();
while ($row = odbc_fetch_array($result)) {
if ($row['TABLE_TYPE'] === 'TABLE' || $row['TABLE_TYPE'] === 'VIEW') {
$res[] = array(
'name' => $row['TABLE_NAME'],
'view' => $row['TABLE_TYPE'] === 'VIEW',
);
}
}
odbc_free_result($result);
return $res;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$result = odbc_columns($this->connection);
$res = array();
while ($row = odbc_fetch_array($result)) {
if ($row['TABLE_NAME'] === $table) {
$res[] = array(
'name' => $row['COLUMN_NAME'],
'table' => $table,
'nativetype' => $row['TYPE_NAME'],
'size' => $row['COLUMN_SIZE'],
'nullable' => (bool) $row['NULLABLE'],
'default' => $row['COLUMN_DEF'],
);
}
}
odbc_free_result($result);
return $res;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new NotImplementedException;
}
}

View File

@@ -1,420 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* The dibi driver for Oracle database.
*
* Connection options:
* - 'database' (or 'db') - the name of the local Oracle instance or the name of the entry in tnsnames.ora
* - 'username' (or 'user')
* - 'password' (or 'pass')
* - 'charset' - character encoding to set
* - 'lazy' - if TRUE, connection will be established only when required
* - 'resource' - connection resource (optional)
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiOracleDriver extends DibiObject implements IDibiDriver
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool */
private $autocommit = TRUE;
/**
* @throws DibiException
*/
public function __construct()
{
if (!extension_loaded('oci8')) {
throw new DibiDriverException("PHP extension 'oci8' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array &$config)
{
DibiConnection::alias($config, 'charset');
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
$this->connection = @oci_new_connect($config['username'], $config['password'], $config['database'], $config['charset']); // intentionally @
}
if (!$this->connection) {
$err = oci_error();
throw new DibiDriverException($err['message'], $err['code']);
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
oci_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$this->resultSet = oci_parse($this->connection, $sql);
if ($this->resultSet) {
oci_execute($this->resultSet, $this->autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
$err = oci_error($this->resultSet);
if ($err) {
throw new DibiDriverException($err['message'], $err['code'], $sql);
}
} else {
$err = oci_error($this->connection);
throw new DibiDriverException($err['message'], $err['code'], $sql);
}
return is_resource($this->resultSet) ? clone $this : NULL;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
throw new NotImplementedException;
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
throw new NotSupportedException('Oracle does not support autoincrementing.');
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
*/
public function begin($savepoint = NULL)
{
$this->autocommit = FALSE;
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
if (!oci_commit($this->connection)) {
$err = oci_error($this->connection);
throw new DibiDriverException($err['message'], $err['code']);
}
$this->autocommit = TRUE;
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
if (!oci_rollback($this->connection)) {
$err = oci_error($this->connection);
throw new DibiDriverException($err['message'], $err['code']);
}
$this->autocommit = TRUE;
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return $this->connection;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . str_replace("'", "''", $value) . "'"; // TODO: not tested
case dibi::IDENTIFIER:
// @see http://download.oracle.com/docs/cd/B10500_01/server.920/a96540/sql_elements9a.htm
$value = str_replace('"', '""', $value);
return '"' . str_replace('.', '"."', $value) . '"';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
return date("U", $value);
case dibi::DATETIME:
return date("U", $value);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
public function applyLimit(&$sql, $limit, $offset)
{
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;
} elseif ($limit >= 0) {
$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit;
}
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
throw new NotSupportedException('Row count is not available for unbuffered queries.');
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
public function fetch($assoc)
{
return oci_fetch_array($this->resultSet, ($assoc ? OCI_ASSOC : OCI_NUM) | OCI_RETURN_NULLS);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
throw new NotImplementedException;
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
oci_free_statement($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getColumnsMeta()
{
$count = oci_num_fields($this->resultSet);
$res = array();
for ($i = 1; $i <= $count; $i++) {
$res[] = array(
'name' => oci_field_name($this->resultSet, $i),
'table' => NULL,
'fullname' => oci_field_name($this->resultSet, $i),
'nativetype'=> oci_field_type($this->resultSet, $i),
);
}
return $res;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
return $this->resultSet;
}
/********************* reflection ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$this->query('SELECT * FROM cat');
$res = array();
while ($row = $this->fetch(FALSE)) {
if ($row[1] === 'TABLE' || $row[1] === 'VIEW') {
$res[] = array(
'name' => $row[0],
'view' => $row[1] === 'VIEW',
);
}
}
$this->free();
return $res;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new NotImplementedException;
}
}

View File

@@ -1,487 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* The dibi driver for PDO.
*
* Connection options:
* - 'dsn' - driver specific DSN
* - 'username' (or 'user')
* - 'password' (or 'pass')
* - 'options' - driver specific options array
* - 'resource' - PDO object (optional)
* - 'lazy' - if TRUE, connection will be established only when required
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiPdoDriver extends DibiObject implements IDibiDriver
{
/** @var PDO Connection resource */
private $connection;
/** @var PDOStatement Resultset resource */
private $resultSet;
/** @var int|FALSE Affected rows */
private $affectedRows = FALSE;
/**
* @throws DibiException
*/
public function __construct()
{
if (!extension_loaded('pdo')) {
throw new DibiDriverException("PHP extension 'pdo' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array &$config)
{
DibiConnection::alias($config, 'dsn');
DibiConnection::alias($config, 'resource', 'pdo');
DibiConnection::alias($config, 'options');
if ($config['resource'] instanceof PDO) {
$this->connection = $config['resource'];
} else try {
$this->connection = new PDO($config['dsn'], $config['username'], $config['password'], $config['options']);
} catch (PDOException $e) {
throw new DibiDriverException($e->getMessage(), $e->getCode());
}
if (!$this->connection) {
throw new DibiDriverException('Connecting error.');
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
$this->connection = NULL;
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
// must detect if SQL returns result set or num of affected rows
$cmd = strtoupper(substr(ltrim($sql), 0, 6));
$list = array('UPDATE'=>1, 'DELETE'=>1, 'INSERT'=>1, 'REPLAC'=>1);
if (isset($list[$cmd])) {
$this->resultSet = NULL;
$this->affectedRows = $this->connection->exec($sql);
if ($this->affectedRows === FALSE) {
$err = $this->connection->errorInfo();
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1], $sql);
}
return NULL;
} else {
$this->resultSet = $this->connection->query($sql);
$this->affectedRows = FALSE;
if ($this->resultSet === FALSE) {
$err = $this->connection->errorInfo();
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1], $sql);
}
return clone $this;
}
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return $this->affectedRows;
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
return $this->connection->lastInsertId();
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
if (!$this->connection->beginTransaction()) {
$err = $this->connection->errorInfo();
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1]);
}
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
if (!$this->connection->commit()) {
$err = $this->connection->errorInfo();
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1]);
}
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
if (!$this->connection->rollBack()) {
$err = $this->connection->errorInfo();
throw new DibiDriverException("SQLSTATE[$err[0]]: $err[2]", $err[1]);
}
}
/**
* Returns the connection resource.
* @return PDO
*/
public function getResource()
{
return $this->connection;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
return $this->connection->quote($value, PDO::PARAM_STR);
case dibi::BINARY:
return $this->connection->quote($value, PDO::PARAM_LOB);
case dibi::IDENTIFIER:
switch ($this->connection->getAttribute(PDO::ATTR_DRIVER_NAME)) {
case 'mysql':
$value = str_replace('`', '``', $value);
return '`' . str_replace('.', '`.`', $value) . '`';
case 'pgsql':
$a = strrpos($value, '.');
if ($a === FALSE) {
return '"' . str_replace('"', '""', $value) . '"';
} else {
return substr($value, 0, $a) . '."' . str_replace('"', '""', substr($value, $a + 1)) . '"';
}
case 'sqlite':
case 'sqlite2':
$value = strtr($value, '[]', ' ');
case 'odbc':
case 'oci': // TODO: not tested
case 'mssql':
$value = str_replace(array('[', ']'), array('[[', ']]'), $value);
return '[' . str_replace('.', '].[', $value) . ']';
default:
return $value;
}
case dibi::BOOL:
return $this->connection->quote($value, PDO::PARAM_BOOL);
case dibi::DATE:
return date("'Y-m-d'", $value);
case dibi::DATETIME:
return date("'Y-m-d H:i:s'", $value);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
public function applyLimit(&$sql, $limit, $offset)
{
if ($limit < 0 && $offset < 1) return;
switch ($this->connection->getAttribute(PDO::ATTR_DRIVER_NAME)) {
case 'mysql':
$sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit)
. ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
break;
case 'pgsql':
if ($limit >= 0) $sql .= ' LIMIT ' . (int) $limit;
if ($offset > 0) $sql .= ' OFFSET ' . (int) $offset;
break;
case 'sqlite':
case 'sqlite2':
$sql .= ' LIMIT ' . $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
break;
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;
} elseif ($limit >= 0) {
$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit;
}
break;
case 'odbc':
case 'mssql':
if ($offset < 1) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
break;
}
// intentionally break omitted
default:
throw new NotSupportedException('PDO or driver does not support applying limit or offset.');
}
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
throw new NotSupportedException('Row count is not available for unbuffered queries.');
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
public function fetch($assoc)
{
return $this->resultSet->fetch($assoc ? PDO::FETCH_ASSOC : PDO::FETCH_NUM);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
throw new NotSupportedException('Cannot seek an unbuffered result set.');
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
* @throws DibiException
*/
public function getColumnsMeta()
{
$count = $this->resultSet->columnCount();
$res = array();
for ($i = 0; $i < $count; $i++) {
$row = @$this->resultSet->getColumnMeta($i); // intentionally @
if ($row === FALSE) {
throw new DibiDriverException('Driver does not support meta data.');
}
$res[] = array(
'name' => $row['name'],
'table' => $row['table'],
'nativetype' => $row['native_type'],
'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
'vendor' => $row,
);
}
return $res;
}
/**
* Returns the result set resource.
* @return PDOStatement
*/
public function getResultResource()
{
return $this->resultSet;
}
/********************* reflection ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
throw new NotImplementedException;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new NotImplementedException;
}
}

View File

@@ -1,525 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* The dibi driver for PostgreSQL database.
*
* Connection options:
* - 'host','hostaddr','port','dbname','user','password','connect_timeout','options','sslmode','service' - see PostgreSQL API
* - 'string' - or use connection string
* - 'persistent' - try to find a persistent link?
* - 'charset' - character encoding to set
* - 'schema' - the schema search path
* - 'lazy' - if TRUE, connection will be established only when required
* - 'resource' - connection resource (optional)
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiPostgreDriver extends DibiObject implements IDibiDriver
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool Escape method */
private $escMethod = FALSE;
/**
* @throws DibiException
*/
public function __construct()
{
if (!extension_loaded('pgsql')) {
throw new DibiDriverException("PHP extension 'pgsql' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array &$config)
{
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} else {
if (isset($config['string'])) {
$string = $config['string'];
} else {
$string = '';
foreach (array('host','hostaddr','port','dbname','user','password','connect_timeout','options','sslmode','service') as $key) {
if (isset($config[$key])) $string .= $key . '=' . $config[$key] . ' ';
}
}
DibiDriverException::tryError();
if (empty($config['persistent'])) {
$this->connection = pg_connect($string, PGSQL_CONNECT_FORCE_NEW);
} else {
$this->connection = pg_pconnect($string, PGSQL_CONNECT_FORCE_NEW);
}
if (DibiDriverException::catchError($msg)) {
throw new DibiDriverException($msg, 0);
}
}
if (!is_resource($this->connection)) {
throw new DibiDriverException('Connecting error.');
}
if (isset($config['charset'])) {
DibiDriverException::tryError();
pg_set_client_encoding($this->connection, $config['charset']);
if (DibiDriverException::catchError($msg)) {
throw new DibiDriverException($msg, 0);
}
}
if (isset($config['schema'])) {
$this->query('SET search_path TO "' . $config['schema'] . '"');
}
$this->escMethod = version_compare(PHP_VERSION , '5.2.0', '>=');
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
pg_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @param bool update affected rows?
* @return IDibiDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
$this->resultSet = @pg_query($this->connection, $sql); // intentionally @
if ($this->resultSet === FALSE) {
throw new DibiDriverException(pg_last_error($this->connection), 0, $sql);
}
return is_resource($this->resultSet) && pg_num_fields($this->resultSet) ? clone $this : NULL;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return pg_affected_rows($this->resultSet);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
if ($sequence === NULL) {
// PostgreSQL 8.1 is needed
$has = $this->query("SELECT LASTVAL()");
} else {
$has = $this->query("SELECT CURRVAL('$sequence')");
}
if (!$has) return FALSE;
$row = $this->fetch(FALSE);
$this->free();
return is_array($row) ? $row[0] : FALSE;
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return $this->connection;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
if ($this->escMethod) {
return "'" . pg_escape_string($this->connection, $value) . "'";
} else {
return "'" . pg_escape_string($value) . "'";
}
case dibi::BINARY:
if ($this->escMethod) {
return "'" . pg_escape_bytea($this->connection, $value) . "'";
} else {
return "'" . pg_escape_bytea($value) . "'";
}
case dibi::IDENTIFIER:
// @see http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
$a = strrpos($value, '.');
if ($a === FALSE) {
return '"' . str_replace('"', '""', $value) . '"';
} else {
// table.col delimite as table."col"
return substr($value, 0, $a) . '."' . str_replace('"', '""', substr($value, $a + 1)) . '"';
}
case dibi::BOOL:
return $value ? 'TRUE' : 'FALSE';
case dibi::DATE:
return date("'Y-m-d'", $value);
case dibi::DATETIME:
return date("'Y-m-d H:i:s'", $value);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return pg_unescape_bytea($value);
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
public function applyLimit(&$sql, $limit, $offset)
{
if ($limit >= 0)
$sql .= ' LIMIT ' . (int) $limit;
if ($offset > 0)
$sql .= ' OFFSET ' . (int) $offset;
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
return pg_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
public function fetch($assoc)
{
return pg_fetch_array($this->resultSet, NULL, $assoc ? PGSQL_ASSOC : PGSQL_NUM);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
return pg_result_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
pg_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getColumnsMeta()
{
$hasTable = version_compare(PHP_VERSION , '5.2.0', '>=');
$count = pg_num_fields($this->resultSet);
$res = array();
for ($i = 0; $i < $count; $i++) {
$row = array(
'name' => pg_field_name($this->resultSet, $i),
'table' => $hasTable ? pg_field_table($this->resultSet, $i) : NULL,
'nativetype'=> pg_field_type($this->resultSet, $i),
);
$row['fullname'] = $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'];
$res[] = $row;
}
return $res;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
return $this->resultSet;
}
/********************* reflection ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$version = pg_version($this->connection);
if ($version['server'] < 8) {
throw new DibiDriverException('Reflection requires PostgreSQL 8.');
}
$this->query("
SELECT table_name as name, CAST(table_type = 'VIEW' AS INTEGER) as view
FROM information_schema.tables
WHERE table_schema = current_schema()
");
$res = pg_fetch_all($this->resultSet);
$this->free();
return $res;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$_table = $this->escape($table, dibi::TEXT);
$this->query("
SELECT indkey
FROM pg_class
LEFT JOIN pg_index on pg_class.oid = pg_index.indrelid AND pg_index.indisprimary
WHERE pg_class.relname = $_table
");
$primary = (int) pg_fetch_object($this->resultSet)->indkey;
$this->query("
SELECT *
FROM information_schema.columns
WHERE table_name = $_table AND table_schema = current_schema()
ORDER BY ordinal_position
");
$res = array();
while ($row = $this->fetch(TRUE)) {
$size = (int) max($row['character_maximum_length'], $row['numeric_precision']);
$res[] = array(
'name' => $row['column_name'],
'table' => $table,
'nativetype' => strtoupper($row['udt_name']),
'size' => $size ? $size : NULL,
'nullable' => $row['is_nullable'] === 'YES',
'default' => $row['column_default'],
'autoincrement' => (int) $row['ordinal_position'] === $primary && substr($row['column_default'], 0, 7) === 'nextval',
'vendor' => $row,
);
}
$this->free();
return $res;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$_table = $this->escape($table, dibi::TEXT);
$this->query("
SELECT ordinal_position, column_name
FROM information_schema.columns
WHERE table_name = $_table AND table_schema = current_schema()
ORDER BY ordinal_position
");
$columns = array();
while ($row = $this->fetch(TRUE)) {
$columns[$row['ordinal_position']] = $row['column_name'];
}
$this->query("
SELECT pg_class2.relname, indisunique, indisprimary, indkey
FROM pg_class
LEFT JOIN pg_index on pg_class.oid = pg_index.indrelid
INNER JOIN pg_class as pg_class2 on pg_class2.oid = pg_index.indexrelid
WHERE pg_class.relname = $_table
");
$res = array();
while ($row = $this->fetch(TRUE)) {
$res[$row['relname']]['name'] = $row['relname'];
$res[$row['relname']]['unique'] = $row['indisunique'] === 't';
$res[$row['relname']]['primary'] = $row['indisprimary'] === 't';
foreach (explode(' ', $row['indkey']) as $index) {
$res[$row['relname']]['columns'][] = $columns[$index];
}
}
$this->free();
return array_values($res);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new NotImplementedException;
}
}

View File

@@ -1,484 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* The dibi driver for SQLite database.
*
* Connection options:
* - 'database' (or 'file') - the filename of the SQLite database
* - 'persistent' - try to find a persistent link?
* - 'unbuffered' - sends query without fetching and buffering the result rows automatically?
* - 'lazy' - if TRUE, connection will be established only when required
* - 'formatDate' - how to format date in SQL (@see date)
* - 'formatDateTime' - how to format datetime in SQL (@see date)
* - 'dbcharset' - database character encoding (will be converted to 'charset')
* - 'charset' - character encoding to set (default is UTF-8)
* - 'resource' - connection resource (optional)
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiSqliteDriver extends DibiObject implements IDibiDriver
{
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool Is buffered (seekable and countable)? */
private $buffered;
/** @var string Date and datetime format */
private $fmtDate, $fmtDateTime;
/** @var string character encoding */
private $dbcharset, $charset;
/**
* @throws DibiException
*/
public function __construct()
{
if (!extension_loaded('sqlite')) {
throw new DibiDriverException("PHP extension 'sqlite' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws DibiException
*/
public function connect(array &$config)
{
DibiConnection::alias($config, 'database', 'file');
$this->fmtDate = isset($config['formatDate']) ? $config['formatDate'] : 'U';
$this->fmtDateTime = isset($config['formatDateTime']) ? $config['formatDateTime'] : 'U';
$errorMsg = '';
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} elseif (empty($config['persistent'])) {
$this->connection = @sqlite_open($config['database'], 0666, $errorMsg); // intentionally @
} else {
$this->connection = @sqlite_popen($config['database'], 0666, $errorMsg); // intentionally @
}
if (!$this->connection) {
throw new DibiDriverException($errorMsg);
}
$this->buffered = empty($config['unbuffered']);
$this->dbcharset = empty($config['dbcharset']) ? 'UTF-8' : $config['dbcharset'];
$this->charset = empty($config['charset']) ? 'UTF-8' : $config['charset'];
if (strcasecmp($this->dbcharset, $this->charset) === 0) {
$this->dbcharset = $this->charset = NULL;
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
sqlite_close($this->connection);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return IDibiDriver|NULL
* @throws DibiDriverException
*/
public function query($sql)
{
if ($this->dbcharset !== NULL) {
$sql = iconv($this->charset, $this->dbcharset . '//IGNORE', $sql);
}
DibiDriverException::tryError();
if ($this->buffered) {
$this->resultSet = sqlite_query($this->connection, $sql);
} else {
$this->resultSet = sqlite_unbuffered_query($this->connection, $sql);
}
if (DibiDriverException::catchError($msg)) {
throw new DibiDriverException($msg, sqlite_last_error($this->connection), $sql);
}
return is_resource($this->resultSet) ? clone $this : NULL;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return sqlite_changes($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
return sqlite_last_insert_rowid($this->connection);
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function begin($savepoint = NULL)
{
$this->query('BEGIN');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function commit($savepoint = NULL)
{
$this->query('COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
public function rollback($savepoint = NULL)
{
$this->query('ROLLBACK');
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return $this->connection;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
public function escape($value, $type)
{
switch ($type) {
case dibi::TEXT:
case dibi::BINARY:
return "'" . sqlite_escape_string($value) . "'";
/*case dibi::BINARY: // SQLite 3
return "X'" . bin2hex((string) $value) . "'";*/
case dibi::IDENTIFIER:
return '[' . str_replace('.', '].[', strtr($value, '[]', ' ')) . ']';
case dibi::BOOL:
return $value ? 1 : 0;
case dibi::DATE:
return date($this->fmtDate, $value);
case dibi::DATETIME:
return date($this->fmtDateTime, $value);
default:
throw new InvalidArgumentException('Unsupported type.');
}
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
public function unescape($value, $type)
{
if ($type === dibi::BINARY) {
return $value;
}
throw new InvalidArgumentException('Unsupported type.');
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
public function applyLimit(&$sql, $limit, $offset)
{
if ($limit < 0 && $offset < 1) return;
$sql .= ' LIMIT ' . $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
}
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
if (!$this->buffered) {
throw new DibiDriverException('Row count is not available for unbuffered queries.');
}
return sqlite_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
public function fetch($assoc)
{
$row = sqlite_fetch_array($this->resultSet, $assoc ? SQLITE_ASSOC : SQLITE_NUM);
$charset = $this->charset === NULL ? NULL : $this->charset . '//TRANSLIT';
if ($row && ($assoc || $charset)) {
$tmp = array();
foreach ($row as $k => $v) {
if ($charset !== NULL && is_string($v)) {
$v = iconv($this->dbcharset, $charset, $v);
}
$tmp[str_replace(array('[', ']'), '', $k)] = $v;
}
return $tmp;
}
return $row;
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
public function seek($row)
{
if (!$this->buffered) {
throw new DibiDriverException('Cannot seek an unbuffered result set.');
}
return sqlite_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getColumnsMeta()
{
$count = sqlite_num_fields($this->resultSet);
$res = array();
for ($i = 0; $i < $count; $i++) {
$name = str_replace(array('[', ']'), '', sqlite_field_name($this->resultSet, $i));
$pair = explode('.', $name);
$res[] = array(
'name' => isset($pair[1]) ? $pair[1] : $pair[0],
'table' => isset($pair[1]) ? $pair[0] : NULL,
'fullname' => $name,
'nativetype' => NULL,
);
}
return $res;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
return $this->resultSet;
}
/********************* reflection ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$this->query("
SELECT name, type = 'view' as view FROM sqlite_master WHERE type IN ('table', 'view')
UNION ALL
SELECT name, type = 'view' as view FROM sqlite_temp_master WHERE type IN ('table', 'view')
ORDER BY name
");
$res = array();
while ($row = $this->fetch(TRUE)) {
$res[] = $row;
}
$this->free();
return $res;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
throw new NotImplementedException;
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
throw new NotImplementedException;
}
/********************* user defined functions ****************d*g**/
/**
* Registers an user defined function for use in SQL statements.
* @param string function name
* @param mixed callback
* @param int num of arguments
* @return void
*/
public function registerFunction($name, $callback, $numArgs = -1)
{
sqlite_create_function($this->connection, $name, $callback, $numArgs);
}
/**
* Registers an aggregating user defined function for use in SQL statements.
* @param string function name
* @param mixed callback called for each row of the result set
* @param mixed callback called to aggregate the "stepped" data from each row
* @param int num of arguments
* @return void
*/
public function registerAggregateFunction($name, $rowCallback, $agrCallback, $numArgs = -1)
{
sqlite_create_aggregate($this->connection, $name, $rowCallback, $agrCallback, $numArgs);
}
}

View File

@@ -1,778 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* dibi connection.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiConnection extends DibiObject
{
/** @var array Current connection configuration */
private $config;
/** @var IDibiDriver Driver */
private $driver;
/** @var IDibiProfiler Profiler */
private $profiler;
/** @var bool Is connected? */
private $connected = FALSE;
/** @var bool Is in transaction? */
private $inTxn = FALSE;
/**
* Creates object and (optionally) connects to a database.
* @param array|string|ArrayObject connection parameters
* @param string connection name
* @throws DibiException
*/
public function __construct($config, $name = NULL)
{
if (class_exists(/*Nette\*/'Debug', FALSE)) {
/*Nette\*/Debug::addColophon(array('dibi', 'getColophon'));
}
// DSN string
if (is_string($config)) {
parse_str($config, $config);
} elseif ($config instanceof ArrayObject) {
$config = (array) $config;
} elseif (!is_array($config)) {
throw new InvalidArgumentException('Configuration must be array, string or ArrayObject.');
}
self::alias($config, 'username', 'user');
self::alias($config, 'password', 'pass');
self::alias($config, 'host', 'hostname');
if (!isset($config['driver'])) {
$config['driver'] = dibi::$defaultDriver;
}
$driver = preg_replace('#[^a-z0-9_]#', '_', $config['driver']);
$class = "Dibi" . $driver . "Driver";
if (!class_exists($class, FALSE)) {
include_once dirname(__FILE__) . "/../drivers/$driver.php";
if (!class_exists($class, FALSE)) {
throw new DibiException("Unable to create instance of dibi driver '$class'.");
}
}
$config['name'] = $name;
$this->config = $config;
$this->driver = new $class;
if (!empty($config['profiler'])) {
$class = $config['profiler'];
if (is_numeric($class) || is_bool($class)) {
$class = 'DibiProfiler';
}
if (!class_exists($class)) {
throw new DibiException("Unable to create instance of dibi profiler '$class'.");
}
$this->setProfiler(new $class);
}
if (!empty($config['substitutes'])) {
foreach ($config['substitutes'] as $key => $value) {
dibi::addSubst($key, $value);
}
}
if (empty($config['lazy'])) {
$this->connect();
}
}
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
// disconnects and rolls back transaction - do not rely on auto-disconnect and rollback!
$this->disconnect();
}
/**
* Connects to a database.
* @return void
*/
final protected function connect()
{
if (!$this->connected) {
if ($this->profiler !== NULL) {
$ticket = $this->profiler->before($this, IDibiProfiler::CONNECT);
}
$this->driver->connect($this->config);
$this->connected = TRUE;
if (isset($ticket)) {
$this->profiler->after($ticket);
}
}
}
/**
* Disconnects from a database.
* @return void
*/
final public function disconnect()
{
if ($this->connected) {
if ($this->inTxn) {
$this->rollback();
}
$this->driver->disconnect();
$this->connected = FALSE;
}
}
/**
* Returns TRUE when connection was established.
* @return bool
*/
final public function isConnected()
{
return $this->connected;
}
/**
* Returns configuration variable. If no $key is passed, returns the entire array.
* @see self::__construct
* @param string
* @param mixed default value to use if key not found
* @return mixed
*/
final public function getConfig($key = NULL, $default = NULL)
{
if ($key === NULL) {
return $this->config;
} elseif (isset($this->config[$key])) {
return $this->config[$key];
} else {
return $default;
}
}
/**
* Apply configuration alias or default values.
* @param array connect configuration
* @param string key
* @param string alias key
* @return void
*/
public static function alias(&$config, $key, $alias=NULL)
{
if (isset($config[$key])) return;
if ($alias !== NULL && isset($config[$alias])) {
$config[$key] = $config[$alias];
unset($config[$alias]);
} else {
$config[$key] = NULL;
}
}
/**
* Returns the connection resource.
* @return IDibiDriver
*/
final public function getDriver()
{
return $this->driver;
}
/**
* Returns the connection resource.
* @return resource
* @deprecated use getDriver()->getResource()
*/
final public function getResource()
{
trigger_error('Deprecated: use getDriver()->getResource(...) instead.', E_USER_WARNING);
return $this->driver->getResource();
}
/**
* Generates (translates) and executes SQL query.
* @param array|mixed one or more arguments
* @return DibiResult|int result set object (if any)
* @throws DibiException
*/
final public function query($args)
{
$args = func_get_args();
$this->connect();
$translator = new DibiTranslator($this->driver);
return $this->nativeQuery($translator->translate($args));
}
/**
* Generates and returns SQL query.
* @param array|mixed one or more arguments
* @return string
* @throws DibiException
*/
final public function sql($args)
{
$args = func_get_args();
$this->connect();
$translator = new DibiTranslator($this->driver);
return $translator->translate($args);
}
/**
* Generates and prints SQL query.
* @param array|mixed one or more arguments
* @return bool
*/
final public function test($args)
{
$args = func_get_args();
$this->connect();
try {
$translator = new DibiTranslator($this->driver);
dibi::dump($translator->translate($args));
return TRUE;
} catch (DibiException $e) {
dibi::dump($e->getSql());
return FALSE;
}
}
/**
* Generates (translates) and returns SQL query as DibiDataSource.
* @param array|mixed one or more arguments
* @return DibiDataSource
* @throws DibiException
*/
final public function dataSource($args)
{
$args = func_get_args();
$this->connect();
$translator = new DibiTranslator($this->driver);
return new DibiDataSource($translator->translate($args), $this);
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return DibiResult|int result set object (if any)
* @throws DibiException
*/
final public function nativeQuery($sql)
{
$this->connect();
if ($this->profiler !== NULL) {
$event = IDibiProfiler::QUERY;
if (preg_match('#\s*(SELECT|UPDATE|INSERT|DELETE)#i', $sql, $matches)) {
static $events = array(
'SELECT' => IDibiProfiler::SELECT, 'UPDATE' => IDibiProfiler::UPDATE,
'INSERT' => IDibiProfiler::INSERT, 'DELETE' => IDibiProfiler::DELETE,
);
$event = $events[strtoupper($matches[1])];
}
$ticket = $this->profiler->before($this, $event, $sql);
}
// TODO: move to profiler?
dibi::$numOfQueries++;
dibi::$sql = $sql;
dibi::$elapsedTime = FALSE;
$time = -microtime(TRUE);
if ($res = $this->driver->query($sql)) { // intentionally =
$res = new DibiResult($res, $this->config);
} else {
$res = $this->driver->getAffectedRows();
}
$time += microtime(TRUE);
dibi::$elapsedTime = $time;
dibi::$totalTime += $time;
if (isset($ticket)) {
$this->profiler->after($ticket, $res);
}
return $res;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int number of rows
* @throws DibiException
*/
public function getAffectedRows()
{
$rows = $this->driver->getAffectedRows();
if (!is_int($rows) || $rows < 0) throw new DibiException('Cannot retrieve number of affected rows.');
return $rows;
}
/**
* Gets the number of affected rows. Alias for getAffectedRows().
* @return int number of rows
* @throws DibiException
*/
public function affectedRows()
{
return $this->getAffectedRows();
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @param string optional sequence name
* @return int
* @throws DibiException
*/
public function getInsertId($sequence = NULL)
{
$id = $this->driver->getInsertId($sequence);
if ($id < 1) throw new DibiException('Cannot retrieve last generated ID.');
return (int) $id;
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column. Alias for getInsertId().
* @param string optional sequence name
* @return int
* @throws DibiException
*/
public function insertId($sequence = NULL)
{
return $this->getInsertId($sequence);
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
*/
public function begin($savepoint = NULL)
{
$this->connect();
if (!$savepoint && $this->inTxn) {
throw new DibiException('There is already an active transaction.');
}
if ($this->profiler !== NULL) {
$ticket = $this->profiler->before($this, IDibiProfiler::BEGIN, $savepoint);
}
if ($savepoint && !$this->inTxn) {
$this->driver->begin();
}
$this->driver->begin($savepoint);
$this->inTxn = TRUE;
if (isset($ticket)) {
$this->profiler->after($ticket);
}
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
*/
public function commit($savepoint = NULL)
{
if (!$this->inTxn) {
throw new DibiException('There is no active transaction.');
}
if ($this->profiler !== NULL) {
$ticket = $this->profiler->before($this, IDibiProfiler::COMMIT, $savepoint);
}
$this->driver->commit($savepoint);
$this->inTxn = (bool) $savepoint;
if (isset($ticket)) {
$this->profiler->after($ticket);
}
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
*/
public function rollback($savepoint = NULL)
{
if (!$this->inTxn) {
throw new DibiException('There is no active transaction.');
}
if ($this->profiler !== NULL) {
$ticket = $this->profiler->before($this, IDibiProfiler::ROLLBACK, $savepoint);
}
$this->driver->rollback($savepoint);
$this->inTxn = (bool) $savepoint;
if (isset($ticket)) {
$this->profiler->after($ticket);
}
}
/**
* Is in transaction?
* @return bool
*/
public function inTransaction()
{
return $this->inTxn;
}
/**
* Encodes data for use in a SQL statement.
* @param string unescaped string
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string escaped and quoted string
* @deprecated
*/
public function escape($value, $type = dibi::TEXT)
{
trigger_error('Deprecated: use getDriver()->escape(...) instead.', E_USER_WARNING);
$this->connect(); // MySQL & PDO require connection
return $this->driver->escape($value, $type);
}
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @deprecated
*/
public function unescape($value, $type = dibi::BINARY)
{
trigger_error('Deprecated: use getDriver()->unescape(...) instead.', E_USER_WARNING);
return $this->driver->unescape($value, $type);
}
/**
* Delimites identifier (table's or column's name, etc.).
* @param string identifier
* @return string delimited identifier
* @deprecated
*/
public function delimite($value)
{
trigger_error('Deprecated: use getDriver()->escape(...) instead.', E_USER_WARNING);
return $this->driver->escape($value, dibi::IDENTIFIER);
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
* @deprecated
*/
public function applyLimit(&$sql, $limit, $offset)
{
trigger_error('Deprecated: use getDriver()->applyLimit(...) instead.', E_USER_WARNING);
$this->driver->applyLimit($sql, $limit, $offset);
}
/********************* fluent SQL builders ****************d*g**/
/**
* @return DibiFluent
*/
public function command()
{
return new DibiFluent($this);
}
/**
* @param string column name
* @return DibiFluent
*/
public function select($args)
{
$args = func_get_args();
return $this->command()->__call('select', $args);
}
/**
* @param string table
* @param array
* @return DibiFluent
*/
public function update($table, $args)
{
if (!(is_array($args) || $args instanceof ArrayObject)) {
throw new InvalidArgumentException('Arguments must be array or ArrayObject.');
}
return $this->command()->update('%n', $table)->set($args);
}
/**
* @param string table
* @param array
* @return DibiFluent
*/
public function insert($table, $args)
{
if ($args instanceof ArrayObject) {
$args = (array) $args;
} elseif (!is_array($args)) {
throw new InvalidArgumentException('Arguments must be array or ArrayObject.');
}
return $this->command()->insert()
->into('%n', $table, '(%n)', array_keys($args))->values('%l', $args);
}
/**
* @param string table
* @return DibiFluent
*/
public function delete($table)
{
return $this->command()->delete()->from('%n', $table);
}
/********************* profiler ****************d*g**/
/**
* @param IDibiProfiler
* @return void
*/
public function setProfiler(IDibiProfiler $profiler = NULL)
{
$this->profiler = $profiler;
}
/**
* @return IDibiProfiler
*/
public function getProfiler()
{
return $this->profiler;
}
/********************* shortcuts ****************d*g**/
/**
* Executes SQL query and fetch result - shortcut for query() & fetch().
* @param array|mixed one or more arguments
* @return DibiRow
* @throws DibiException
*/
public function fetch($args)
{
$args = func_get_args();
return $this->query($args)->fetch();
}
/**
* Executes SQL query and fetch results - shortcut for query() & fetchAll().
* @param array|mixed one or more arguments
* @return array of DibiRow
* @throws DibiException
*/
public function fetchAll($args)
{
$args = func_get_args();
return $this->query($args)->fetchAll();
}
/**
* Executes SQL query and fetch first column - shortcut for query() & fetchSingle().
* @param array|mixed one or more arguments
* @return string
* @throws DibiException
*/
public function fetchSingle($args)
{
$args = func_get_args();
return $this->query($args)->fetchSingle();
}
/**
* Executes SQL query and fetch pairs - shortcut for query() & fetchPairs().
* @param array|mixed one or more arguments
* @return string
* @throws DibiException
*/
public function fetchPairs($args)
{
$args = func_get_args();
return $this->query($args)->fetchPairs();
}
/********************* misc ****************d*g**/
/**
* Import SQL dump from file - extreme fast!
* @param string filename
* @return int count of sql commands
*/
public function loadFile($file)
{
$this->connect();
@set_time_limit(0); // intentionally @
$handle = @fopen($file, 'r'); // intentionally @
if (!$handle) {
throw new FileNotFoundException("Cannot open file '$file'.");
}
$count = 0;
$sql = '';
while (!feof($handle)) {
$s = fgets($handle);
$sql .= $s;
if (substr(rtrim($s), -1) === ';') {
$this->driver->query($sql);
$sql = '';
$count++;
}
}
fclose($handle);
return $count;
}
/**
* Gets a information about the current database.
* @return DibiDatabaseInfo
*/
public function getDatabaseInfo()
{
$this->connect();
return new DibiDatabaseInfo($this->driver, isset($this->config['database']) ? $this->config['database'] : NULL);
}
/**
* Prevents unserialization.
*/
public function __wakeup()
{
throw new NotSupportedException('You cannot serialize or unserialize ' . $this->getClass() . ' instances.');
}
/**
* Prevents serialization.
*/
public function __sleep()
{
throw new NotSupportedException('You cannot serialize or unserialize ' . $this->getClass() . ' instances.');
}
}

View File

@@ -1,339 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* Default implementation of IDataSource for dibi.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiDataSource extends DibiObject implements IDataSource
{
/** @var DibiConnection */
private $connection;
/** @var string */
private $sql;
/** @var DibiResult */
private $result;
/** @var int */
private $count;
/** @var int */
private $totalCount;
/** @var array */
private $cols = array();
/** @var array */
private $sorting = array();
/** @var array */
private $conds = array();
/** @var int */
private $offset;
/** @var int */
private $limit;
/**
* @param string SQL command or table or view name, as data source
* @param DibiConnection connection
*/
public function __construct($sql, DibiConnection $connection)
{
if (strpos($sql, ' ') === FALSE) {
$this->sql = $connection->getDriver()->escape($sql, dibi::IDENTIFIER); // table name
} else {
$this->sql = '(' . $sql . ') t'; // SQL command
}
$this->connection = $connection;
}
/**
* Selects columns to query.
* @param string|array column name or array of column names
* @param string column alias
* @return DibiDataSource provides a fluent interface
*/
public function select($col, $as = NULL)
{
if (is_array($col)) {
$this->cols = $col;
} else {
$this->cols[$col] = $as;
}
$this->result = NULL;
return $this;
}
/**
* Adds conditions to query.
* @param mixed conditions
* @return DibiDataSource provides a fluent interface
*/
public function where($cond)
{
if (is_array($cond)) {
// TODO: not consistent with select and orderBy
$this->conds[] = $cond;
} else {
$this->conds[] = func_get_args();
}
$this->result = $this->count = NULL;
return $this;
}
/**
* Selects columns to order by.
* @param string|array column name or array of column names
* @param string sorting direction
* @return DibiDataSource provides a fluent interface
*/
public function orderBy($row, $sorting = 'ASC')
{
if (is_array($row)) {
$this->sorting = $row;
} else {
$this->sorting[$row] = $sorting;
}
$this->result = NULL;
return $this;
}
/**
* Limits number of rows.
* @param int limit
* @param int offset
* @return DibiDataSource provides a fluent interface
*/
public function applyLimit($limit, $offset = NULL)
{
$this->limit = $limit;
$this->offset = $offset;
$this->result = $this->count = NULL;
return $this;
}
/**
* Returns the dibi connection.
* @return DibiConnection
*/
final public function getConnection()
{
return $this->connection;
}
/********************* executing ****************d*g**/
/**
* Returns (and queries) DibiResult.
* @return DibiResult
*/
public function getResult()
{
if ($this->result === NULL) {
$this->result = $this->connection->nativeQuery($this->__toString());
}
return $this->result;
}
/**
* @return DibiResultIterator
*/
public function getIterator()
{
return $this->getResult()->getIterator();
}
/**
* Generates, executes SQL query and fetches the single row.
* @return DibiRow|FALSE array on success, FALSE if no next record
*/
public function fetch()
{
return $this->getResult()->fetch();
}
/**
* Like fetch(), but returns only first field.
* @return mixed value on success, FALSE if no next record
*/
public function fetchSingle()
{
return $this->getResult()->fetchSingle();
}
/**
* Fetches all records from table.
* @return array
*/
public function fetchAll()
{
return $this->getResult()->fetchAll();
}
/**
* Fetches all records from table and returns associative tree.
* @param string associative descriptor
* @return array
*/
public function fetchAssoc($assoc)
{
return $this->getResult()->fetchAssoc($assoc);
}
/**
* Fetches all records from table like $key => $value pairs.
* @param string associative key
* @param string value
* @return array
*/
public function fetchPairs($key = NULL, $value = NULL)
{
return $this->getResult()->fetchPairs($key, $value);
}
/**
* Discards the internal cache.
* @return void
*/
public function release()
{
$this->result = $this->count = $this->totalCount = NULL;
}
/********************* exporting ****************d*g**/
/**
* Returns this data source wrapped in DibiFluent object.
* @return DibiFluent
*/
public function toFluent()
{
return $this->connection->select('*')->from('(%SQL) AS t', $this->__toString());
}
/**
* Returns this data source wrapped in DibiDataSource object.
* @return DibiDataSource
*/
public function toDataSource()
{
return new self($this->__toString(), $this->connection);
}
/**
* Returns SQL query.
* @return string
*/
final public function __toString()
{
return $this->connection->sql('
SELECT %n', (empty($this->cols) ? '*' : $this->cols), '
FROM %SQL', $this->sql, '
%ex', $this->conds ? array('WHERE %and', $this->conds) : NULL, '
%ex', $this->sorting ? array('ORDER BY %by', $this->sorting) : NULL, '
%ofs %lmt', $this->offset, $this->limit
);
}
/********************* counting ****************d*g**/
/**
* Returns the number of rows in a given data source.
* @return int
*/
public function count()
{
if ($this->count === NULL) {
$this->count = $this->conds || $this->offset || $this->limit
? (int) $this->connection->nativeQuery(
'SELECT COUNT(*) FROM (' . $this->__toString() . ') AS t'
)->fetchSingle()
: $this->getTotalCount();
}
return $this->count;
}
/**
* Returns the number of rows in a given data source.
* @return int
*/
public function getTotalCount()
{
if ($this->totalCount === NULL) {
$this->totalCount = (int) $this->connection->nativeQuery(
'SELECT COUNT(*) FROM ' . $this->sql
)->fetchSingle();
}
return $this->totalCount;
}
}

View File

@@ -1,611 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* Reflection metadata class for a database.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiDatabaseInfo extends DibiObject
{
/** @var IDibiDriver */
private $driver;
/** @var string */
private $name;
/** @var array */
private $tables;
public function __construct(IDibiDriver $driver, $name)
{
$this->driver = $driver;
$this->name = $name;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return array of DibiTableInfo
*/
public function getTables()
{
$this->init();
return array_values($this->tables);
}
/**
* @return array of string
*/
public function getTableNames()
{
$this->init();
$res = array();
foreach ($this->tables as $table) {
$res[] = $table->getName();
}
return $res;
}
/**
* @param string
* @return DibiTableInfo
*/
public function getTable($name)
{
$this->init();
$l = strtolower($name);
if (isset($this->tables[$l])) {
return $this->tables[$l];
} else {
throw new DibiException("Database '$this->name' has no table '$name'.");
}
}
/**
* @param string
* @return bool
*/
public function hasTable($name)
{
$this->init();
return isset($this->tables[strtolower($name)]);
}
/**
* @return void
*/
protected function init()
{
if ($this->tables === NULL) {
$this->tables = array();
foreach ($this->driver->getTables() as $info) {
$this->tables[strtolower($info['name'])] = new DibiTableInfo($this->driver, $info);
}
}
}
}
/**
* Reflection metadata class for a database table.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiTableInfo extends DibiObject
{
/** @var IDibiDriver */
private $driver;
/** @var string */
private $name;
/** @var bool */
private $view;
/** @var array */
private $columns;
/** @var array */
private $foreignKeys;
/** @var array */
private $indexes;
/** @var DibiIndexInfo */
private $primaryKey;
public function __construct(IDibiDriver $driver, array $info)
{
$this->driver = $driver;
$this->name = $info['name'];
$this->view = !empty($info['view']);
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return bool
*/
public function isView()
{
return $this->view;
}
/**
* @return array of DibiColumnInfo
*/
public function getColumns()
{
$this->initColumns();
return array_values($this->columns);
}
/**
* @return array of string
*/
public function getColumnNames()
{
$this->initColumns();
$res = array();
foreach ($this->columns as $column) {
$res[] = $column->getName();
}
return $res;
}
/**
* @param string
* @return DibiColumnInfo
*/
public function getColumn($name)
{
$this->initColumns();
$l = strtolower($name);
if (isset($this->columns[$l])) {
return $this->columns[$l];
} else {
throw new DibiException("Table '$this->name' has no column '$name'.");
}
}
/**
* @param string
* @return bool
*/
public function hasColumn($name)
{
$this->initColumns();
return isset($this->columns[strtolower($name)]);
}
/**
* @return array of DibiForeignKeyInfo
*/
public function getForeignKeys()
{
$this->initForeignKeys();
return $this->foreignKeys;
}
/**
* @return array of DibiIndexInfo
*/
public function getIndexes()
{
$this->initIndexes();
return $this->indexes;
}
/**
* @return DibiIndexInfo
*/
public function getPrimaryKey()
{
$this->initIndexes();
return $this->primaryKey;
}
/**
* @return void
*/
protected function initColumns()
{
if ($this->columns === NULL) {
$this->columns = array();
foreach ($this->driver->getColumns($this->name) as $info) {
$this->columns[strtolower($info['name'])] = new DibiColumnInfo($this->driver, $info);
}
}
}
/**
* @return void
*/
protected function initIndexes()
{
if ($this->indexes === NULL) {
$this->initColumns();
$this->indexes = array();
foreach ($this->driver->getIndexes($this->name) as $info) {
foreach ($info['columns'] as $key => $name) {
$info['columns'][$key] = $this->columns[strtolower($name)];
}
$this->indexes[strtolower($info['name'])] = new DibiIndexInfo($info);
if (!empty($info['primary'])) {
$this->primaryKey = $this->indexes[strtolower($info['name'])];
}
}
}
}
/**
* @return void
*/
protected function initForeignKeys()
{
throw new NotImplementedException;
}
}
/**
* Reflection metadata class for a table column.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiColumnInfo extends DibiObject
{
/** @var array */
private static $types;
/** @var IDibiDriver */
private $driver;
/** @var array (name, nativetype, [table], [fullname], [size], [nullable], [default], [autoincrement], [vendor]) */
private $info;
/** @var string */
private $type;
public function __construct(IDibiDriver $driver, array $info)
{
$this->driver = $driver;
$this->info = $info;
$this->type = self::detectType($this->info['nativetype']);
}
/**
* @return string
*/
public function getName()
{
return $this->info['name'];
}
/**
* @return bool
*/
public function hasTable()
{
return !empty($this->info['table']);
}
/**
* @return DibiTableInfo
*/
public function getTable()
{
if (empty($this->info['table'])) {
throw new DibiException("Table name is unknown.");
}
return new DibiTableInfo($this->driver, array('name' => $this->info['table']));
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @return mixed
*/
public function getNativeType()
{
return $this->info['nativetype'];
}
/**
* @return int
*/
public function getSize()
{
return isset($this->info['size']) ? (int) $this->info['size'] : NULL;
}
/**
* @return bool
*/
public function isNullable()
{
return isset($this->info['nullable']) ? (bool) $this->info['nullable'] : NULL;
}
/**
* @return bool
*/
public function isAutoIncrement()
{
return isset($this->info['autoincrement']) ? (bool) $this->info['autoincrement'] : NULL;
}
/**
* @return mixed
*/
public function getDefault()
{
return isset($this->info['default']) ? $this->info['default'] : NULL;
}
/**
* @param string
* @return mixed
*/
public function getVendorInfo($key)
{
return isset($this->info['vendor'][$key]) ? $this->info['vendor'][$key] : NULL;
}
/**
* Heuristic type detection.
* @param string
* @return string
*/
public static function detectType($type)
{
static $patterns = array(
'BYTEA|BLOB|BIN' => dibi::BINARY,
'TEXT|CHAR' => dibi::TEXT,
'BYTE|COUNTER|SERIAL|INT|LONG' => dibi::INTEGER,
'CURRENCY|REAL|MONEY|FLOAT|DOUBLE|DECIMAL|NUMERIC|NUMBER' => dibi::FLOAT,
'^TIME$' => dibi::TIME,
'TIME' => dibi::DATETIME, // DATETIME, TIMESTAMP
'YEAR|DATE' => dibi::DATE,
'BOOL|BIT' => dibi::BOOL,
);
if (!isset(self::$types[$type])) {
self::$types[$type] = dibi::TEXT;
foreach ($patterns as $s => $val) {
if (preg_match("#$s#i", $type)) {
return self::$types[$type] = $val;
}
}
}
return self::$types[$type];
}
}
/**
* Reflection metadata class for a foreign key.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
* @todo
*/
class DibiForeignKeyInfo extends DibiObject
{
/** @var string */
private $name;
/** @var array of array(local, foreign, onDelete, onUpdate) */
private $references;
public function __construct($name, array $references)
{
$this->name = $name;
$this->references = $references;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return array
*/
public function getReferences()
{
return $this->references;
}
}
/**
* Reflection metadata class for a index or primary key.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiIndexInfo extends DibiObject
{
/** @var array (name, columns, [unique], [primary]) */
private $info;
public function __construct(array $info)
{
$this->info = $info;
}
/**
* @return string
*/
public function getName()
{
return $this->info['name'];
}
/**
* @return array
*/
public function getColumns()
{
return $this->info['columns'];
}
/**
* @return bool
*/
public function isUnique()
{
return !empty($this->info['unique']);
}
/**
* @return bool
*/
public function isPrimary()
{
return !empty($this->info['primary']);
}
}

View File

@@ -1,156 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* dibi common exception.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiException extends Exception implements /*Nette\*/IDebuggable
{
/** @var string */
private $sql;
/**
* Construct a dibi exception.
* @param string Message describing the exception
* @param int Some code
* @param string SQL command
*/
public function __construct($message = NULL, $code = 0, $sql = NULL)
{
parent::__construct($message, (int) $code);
$this->sql = $sql;
// TODO: add $profiler->exception($this);
}
/**
* @return string The SQL passed to the constructor
*/
final public function getSql()
{
return $this->sql;
}
/**
* @return string string represenation of exception with SQL command
*/
public function __toString()
{
return parent::__toString() . ($this->sql ? "\nSQL: " . $this->sql : '');
}
/********************* interface Nette\IDebuggable ****************d*g**/
/**
* Returns custom panels.
* @return array
*/
public function getPanels()
{
$panels = array();
if ($this->sql !== NULL) {
$panels['SQL'] = array(
'expanded' => TRUE,
'content' => dibi::dump($this->sql, TRUE),
);
}
return $panels;
}
}
/**
* database server exception.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiDriverException extends DibiException
{
/********************* error catching ****************d*g**/
/** @var string */
private static $errorMsg;
/**
* Starts catching potential errors/warnings.
* @return void
*/
public static function tryError()
{
set_error_handler(array(__CLASS__, '_errorHandler'), E_ALL);
self::$errorMsg = NULL;
}
/**
* Returns catched error/warning message.
* @param string catched message
* @return bool
*/
public static function catchError(& $message)
{
restore_error_handler();
$message = self::$errorMsg;
self::$errorMsg = NULL;
return $message !== NULL;
}
/**
* Internal error handler. Do not call directly.
* @internal
*/
public static function _errorHandler($code, $message)
{
restore_error_handler();
if (ini_get('html_errors')) {
$message = strip_tags($message);
$message = html_entity_decode($message);
}
self::$errorMsg = $message;
}
}

View File

@@ -1,457 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* dibi SQL builder via fluent interfaces. EXPERIMENTAL!
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiFluent extends DibiObject implements IDataSource
{
/** @var array */
public static $masks = array(
'SELECT' => array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'GROUP BY',
'HAVING', 'ORDER BY', 'LIMIT', 'OFFSET'),
'UPDATE' => array('UPDATE', 'SET', 'WHERE', 'ORDER BY', 'LIMIT'),
'INSERT' => array('INSERT', 'INTO', 'VALUES', 'SELECT'),
'DELETE' => array('DELETE', 'FROM', 'USING', 'WHERE', 'ORDER BY', 'LIMIT'),
);
/** @var array default modifiers for arrays */
public static $modifiers = array(
'SELECT' => '%n',
'FROM' => '%n',
'IN' => '%l',
'VALUES' => '%l',
'SET' => '%a',
'WHERE' => '%and',
'HAVING' => '%and',
'ORDER BY' => '%by',
'GROUP BY' => '%by',
);
/** @var array clauses separators */
public static $separators = array(
'SELECT' => ',',
'FROM' => FALSE,
'WHERE' => 'AND',
'GROUP BY' => ',',
'HAVING' => 'AND',
'ORDER BY' => ',',
'LIMIT' => FALSE,
'OFFSET' => FALSE,
'SET' => ',',
'VALUES' => ',',
'INTO' => FALSE,
);
/** @var DibiConnection */
private $connection;
/** @var string */
private $command;
/** @var array */
private $clauses = array();
/** @var array */
private $flags = array();
/** @var array */
private $cursor;
/**
* @param DibiConnection
*/
public function __construct(DibiConnection $connection)
{
$this->connection = $connection;
}
/**
* Appends new argument to the clause.
* @param string clause name
* @param array arguments
* @return DibiFluent provides a fluent interface
*/
public function __call($clause, $args)
{
$clause = self::_formatClause($clause);
// lazy initialization
if ($this->command === NULL) {
if (isset(self::$masks[$clause])) {
$this->clauses = array_fill_keys(self::$masks[$clause], NULL);
}
$this->cursor = & $this->clauses[$clause];
$this->cursor = array();
$this->command = $clause;
}
// special types or argument
if (count($args) === 1) {
$arg = $args[0];
// TODO: really ignore TRUE?
if ($arg === TRUE) { // flag
$args = array();
} elseif (is_string($arg) && preg_match('#^[a-z:_][a-z0-9_.:]*$#i', $arg)) { // identifier
$args = array('%n', $arg);
} elseif ($arg instanceof self) {
$args = array_merge(array('('), $arg->_export(), array(')'));
} elseif (is_array($arg) || $arg instanceof ArrayObject) { // any array
if (isset(self::$modifiers[$clause])) {
$args = array(self::$modifiers[$clause], $arg);
} elseif (is_string(key($arg))) { // associative array
$args = array('%a', $arg);
}
} // case $arg === FALSE is handled below
}
if (array_key_exists($clause, $this->clauses)) {
// append to clause
$this->cursor = & $this->clauses[$clause];
// TODO: really delete?
if ($args === array(FALSE)) {
$this->cursor = NULL;
return $this;
}
if (isset(self::$separators[$clause])) {
$sep = self::$separators[$clause];
if ($sep === FALSE) {
$this->cursor = array();
} elseif (!empty($this->cursor)) {
$this->cursor[] = $sep;
}
}
} else {
// append to currect flow
if ($args === array(FALSE)) {
return $this;
}
$this->cursor[] = $clause;
}
if ($this->cursor === NULL) {
$this->cursor = array();
}
array_splice($this->cursor, count($this->cursor), 0, $args);
return $this;
}
/**
* Switch to a clause.
* @param string clause name
* @return DibiFluent provides a fluent interface
*/
public function clause($clause, $remove = FALSE)
{
$this->cursor = & $this->clauses[self::_formatClause($clause)];
if ($remove) {
$this->cursor = NULL;
} elseif ($this->cursor === NULL) {
$this->cursor = array();
}
return $this;
}
/**
* Change a SQL flag.
* @param string flag name
* @param bool value
* @return DibiFluent provides a fluent interface
*/
public function setFlag($flag, $value = TRUE)
{
$flag = strtoupper($flag);
if ($value) {
$this->flags[$flag] = TRUE;
} else {
unset($this->flags[$flag]);
}
return $this;
}
/**
* Is a flag set?
* @param string flag name
* @return bool
*/
final public function getFlag($flag)
{
return isset($this->flags[strtoupper($flag)]);
}
/**
* Returns SQL command.
* @return string
*/
final public function getCommand()
{
return $this->command;
}
/**
* Returns the dibi connection.
* @return DibiConnection
*/
final public function getConnection()
{
return $this->connection;
}
/********************* executing ****************d*g**/
/**
* Generates and executes SQL query.
* @param mixed what to return?
* @return DibiResult|int result set object (if any)
* @throws DibiException
*/
public function execute($return = NULL)
{
$res = $this->connection->query($this->_export());
return $return === dibi::IDENTIFIER ? $this->connection->getInsertId() : $res;
}
/**
* Generates, executes SQL query and fetches the single row.
* @return DibiRow|FALSE array on success, FALSE if no next record
*/
public function fetch()
{
if ($this->command === 'SELECT') {
return $this->connection->query($this->_export(NULL, array('%lmt', 1)))->fetch();
} else {
return $this->connection->query($this->_export())->fetch();
}
}
/**
* Like fetch(), but returns only first field.
* @return mixed value on success, FALSE if no next record
*/
public function fetchSingle()
{
if ($this->command === 'SELECT') {
return $this->connection->query($this->_export(NULL, array('%lmt', 1)))->fetchSingle();
} else {
return $this->connection->query($this->_export())->fetchSingle();
}
}
/**
* Fetches all records from table.
* @param int offset
* @param int limit
* @return array
*/
public function fetchAll($offset = NULL, $limit = NULL)
{
return $this->connection->query($this->_export(NULL, array('%ofs %lmt', $offset, $limit)))->fetchAll();
}
/**
* Fetches all records from table and returns associative tree.
* @param string associative descriptor
* @return array
*/
public function fetchAssoc($assoc)
{
return $this->connection->query($this->_export())->fetchAssoc($assoc);
}
/**
* Fetches all records from table like $key => $value pairs.
* @param string associative key
* @param string value
* @return array
*/
public function fetchPairs($key = NULL, $value = NULL)
{
return $this->connection->query($this->_export())->fetchPairs($key, $value);
}
/**
* Required by the IteratorAggregate interface.
* @param int offset
* @param int limit
* @return DibiResultIterator
*/
public function getIterator($offset = NULL, $limit = NULL)
{
return $this->connection->query($this->_export(NULL, array('%ofs %lmt', $offset, $limit)))->getIterator();
}
/**
* Generates and prints SQL query or it's part.
* @param string clause name
* @return bool
*/
public function test($clause = NULL)
{
return $this->connection->test($this->_export($clause));
}
/**
* @return int
*/
public function count()
{
return (int) $this->connection->query(
'SELECT COUNT(*) FROM (%ex', $this->_export(), ') AS [data]'
)->fetchSingle();
}
/********************* exporting ****************d*g**/
/**
* @return DibiDataSource
*/
public function toDataSource()
{
return new DibiDataSource($this->connection->sql($this->_export()), $this->connection);
}
/**
* Returns SQL query.
* @return string
*/
final public function __toString()
{
return $this->connection->sql($this->_export());
}
/**
* Generates parameters for DibiTranslator.
* @param string clause name
* @return array
*/
protected function _export($clause = NULL, $args = array())
{
if ($clause === NULL) {
$data = $this->clauses;
} else {
$clause = self::_formatClause($clause);
if (array_key_exists($clause, $this->clauses)) {
$data = array($clause => $this->clauses[$clause]);
} else {
return array();
}
}
foreach ($data as $clause => $statement) {
if ($statement !== NULL) {
$args[] = $clause;
if ($clause === $this->command) {
$args[] = implode(' ', array_keys($this->flags));
}
array_splice($args, count($args), 0, $statement);
}
}
return $args;
}
/**
* Format camelCase clause name to UPPER CASE.
* @param string
* @return string
*/
private static function _formatClause($s)
{
if ($s === 'order' || $s === 'group') {
$s .= 'By';
trigger_error("Did you mean '$s'?", E_USER_NOTICE);
}
return strtoupper(preg_replace('#[A-Z]#', ' $0', $s));
}
}
// PHP < 5.2 compatibility
if (!function_exists('array_fill_keys')) {
function array_fill_keys($keys, $value)
{
return array_combine($keys, array_fill(0, count($keys), $value));
}
}

View File

@@ -1,334 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* DibiObject is the ultimate ancestor of all instantiable classes.
*
* DibiObject is copy of Nette\Object from Nette Framework (http://nettephp.com).
*
* It defines some handful methods and enhances object core of PHP:
* - access to undeclared members throws exceptions
* - support for conventional properties with getters and setters
* - support for event raising functionality
* - ability to add new methods to class (extension methods)
*
* Properties is a syntactic sugar which allows access public getter and setter
* methods as normal object variables. A property is defined by a getter method
* and optional setter method (no setter method means read-only property).
* <code>
* $val = $obj->label; // equivalent to $val = $obj->getLabel();
* $obj->label = 'Nette'; // equivalent to $obj->setLabel('Nette');
* </code>
* Property names are case-sensitive, and they are written in the camelCaps
* or PascalCaps.
*
* Event functionality is provided by declaration of property named 'on{Something}'
* Multiple handlers are allowed.
* <code>
* public $onClick; // declaration in class
* $this->onClick[] = 'callback'; // attaching event handler
* if (!empty($this->onClick)) ... // are there any handlers?
* $this->onClick($sender, $arg); // raises the event with arguments
* </code>
*
* Adding method to class (i.e. to all instances) works similar to JavaScript
* prototype property. The syntax for adding a new method is:
* <code>
* MyClass::extensionMethod('newMethod', function(MyClass $obj, $arg, ...) { ... });
* $obj = new MyClass;
* $obj->newMethod($x);
* </code>
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
abstract class DibiObject
{
/** @var array (method => array(type => callback)) */
private static $extMethods;
/**
* Returns the name of the class of this object.
* @return string
*/
final public /*static*/ function getClass()
{
return /*get_called_class()*/ /**/get_class($this)/**/;
}
/**
* Access to reflection.
* @return \ReflectionObject
*/
final public function getReflection()
{
return new /*\*/ReflectionObject($this);
}
/**
* Call to undefined method.
* @param string method name
* @param array arguments
* @return mixed
* @throws \MemberAccessException
*/
public function __call($name, $args)
{
$class = get_class($this);
if ($name === '') {
throw new /*\*/MemberAccessException("Call to class '$class' method without name.");
}
// event functionality
if (preg_match('#^on[A-Z]#', $name)) {
$rp = new /*\*/ReflectionProperty($class, $name);
if ($rp->isPublic() && !$rp->isStatic()) {
$list = $this->$name;
if (is_array($list) || $list instanceof /*\*/Traversable) {
foreach ($list as $handler) {
/**/if (is_object($handler)) {
call_user_func_array(array($handler, '__invoke'), $args);
} else /**/{
call_user_func_array($handler, $args);
}
}
}
return NULL;
}
}
// extension methods
if ($cb = self::extensionMethod("$class::$name")) {
array_unshift($args, $this);
return call_user_func_array($cb, $args);
}
throw new /*\*/MemberAccessException("Call to undefined method $class::$name().");
}
/**
* Call to undefined static method.
* @param string method name (in lower case!)
* @param array arguments
* @return mixed
* @throws \MemberAccessException
*/
public static function __callStatic($name, $args)
{
$class = get_called_class();
throw new /*\*/MemberAccessException("Call to undefined static method $class::$name().");
}
/**
* Adding method to class.
* @param string method name
* @param mixed callback or closure
* @return mixed
*/
public static function extensionMethod($name, $callback = NULL)
{
if (self::$extMethods === NULL || $name === NULL) { // for backwards compatibility
$list = get_defined_functions();
foreach ($list['user'] as $fce) {
$pair = explode('_prototype_', $fce);
if (count($pair) === 2) {
self::$extMethods[$pair[1]][$pair[0]] = $fce;
self::$extMethods[$pair[1]][''] = NULL;
}
}
if ($name === NULL) return NULL;
}
$name = strtolower($name);
$a = strrpos($name, ':'); // search ::
if ($a === FALSE) {
$class = strtolower(get_called_class());
$l = & self::$extMethods[$name];
} else {
$class = substr($name, 0, $a - 1);
$l = & self::$extMethods[substr($name, $a + 1)];
}
if ($callback !== NULL) { // works as setter
$l[$class] = $callback;
$l[''] = NULL;
return NULL;
}
// works as getter
if (empty($l)) {
return FALSE;
} elseif (isset($l[''][$class])) { // cached value
return $l[''][$class];
}
$cl = $class;
do {
$cl = strtolower($cl);
if (isset($l[$cl])) {
return $l[''][$class] = $l[$cl];
}
} while (($cl = get_parent_class($cl)) !== FALSE);
foreach (class_implements($class) as $cl) {
$cl = strtolower($cl);
if (isset($l[$cl])) {
return $l[''][$class] = $l[$cl];
}
}
return $l[''][$class] = FALSE;
}
/**
* Returns property value. Do not call directly.
* @param string property name
* @return mixed property value
* @throws \MemberAccessException if the property is not defined.
*/
public function &__get($name)
{
$class = get_class($this);
if ($name === '') {
throw new /*\*/MemberAccessException("Cannot read a class '$class' property without name.");
}
// property getter support
$name[0] = $name[0] & "\xDF"; // case-sensitive checking, capitalize first character
$m = 'get' . $name;
if (self::hasAccessor($class, $m)) {
// ampersands:
// - uses &__get() because declaration should be forward compatible (e.g. with Nette\Web\Html)
// - doesn't call &$this->$m because user could bypass property setter by: $x = & $obj->property; $x = 'new value';
$val = $this->$m();
return $val;
}
$m = 'is' . $name;
if (self::hasAccessor($class, $m)) {
$val = $this->$m();
return $val;
}
$name = func_get_arg(0);
throw new /*\*/MemberAccessException("Cannot read an undeclared property $class::\$$name.");
}
/**
* Sets value of a property. Do not call directly.
* @param string property name
* @param mixed property value
* @return void
* @throws \MemberAccessException if the property is not defined or is read-only
*/
public function __set($name, $value)
{
$class = get_class($this);
if ($name === '') {
throw new /*\*/MemberAccessException("Cannot assign to a class '$class' property without name.");
}
// property setter support
$name[0] = $name[0] & "\xDF"; // case-sensitive checking, capitalize first character
if (self::hasAccessor($class, 'get' . $name) || self::hasAccessor($class, 'is' . $name)) {
$m = 'set' . $name;
if (self::hasAccessor($class, $m)) {
$this->$m($value);
return;
} else {
$name = func_get_arg(0);
throw new /*\*/MemberAccessException("Cannot assign to a read-only property $class::\$$name.");
}
}
$name = func_get_arg(0);
throw new /*\*/MemberAccessException("Cannot assign to an undeclared property $class::\$$name.");
}
/**
* Is property defined?
* @param string property name
* @return bool
*/
public function __isset($name)
{
$name[0] = $name[0] & "\xDF";
return $name !== '' && self::hasAccessor(get_class($this), 'get' . $name);
}
/**
* Access to undeclared property.
* @param string property name
* @return void
* @throws \MemberAccessException
*/
public function __unset($name)
{
$class = get_class($this);
throw new /*\*/MemberAccessException("Cannot unset the property $class::\$$name.");
}
/**
* Has property an accessor?
* @param string class name
* @param string method name
* @return bool
*/
private static function hasAccessor($c, $m)
{
static $cache;
if (!isset($cache[$c])) {
// get_class_methods returns private, protected and public methods of Object (doesn't matter)
// and ONLY PUBLIC methods of descendants (perfect!)
// but returns static methods too (nothing doing...)
// and is much faster than reflection
// (works good since 5.0.4)
$cache[$c] = array_flip(get_class_methods($c));
}
return isset($cache[$c][$m]);
}
}

View File

@@ -1,242 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* dibi basic logger & profiler (experimental).
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiProfiler extends DibiObject implements IDibiProfiler
{
/** maximum number of rows */
const FIREBUG_MAX_ROWS = 30;
/** maximum SQL length */
const FIREBUG_MAX_LENGTH = 500;
/** @var string Name of the file where SQL errors should be logged */
private $file;
/** @var bool log to firebug? */
public $useFirebug;
/** @var int */
private $filter = self::ALL;
/** @var array */
public $tickets = array();
/** @var array */
public static $table = array(array('Time', 'SQL Statement', 'Rows', 'Connection'));
public function __construct()
{
$this->useFirebug = isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'FirePHP/');
}
/**
* @param string filename
* @return void
*/
public function setFile($file)
{
$this->file = $file;
}
/**
* @param int
* @return void
*/
public function setFilter($filter)
{
$this->filter = (int) $filter;
}
/**
* Before event notification.
* @param DibiConnection
* @param int event name
* @param string sql
* @return int
*/
public function before(DibiConnection $connection, $event, $sql = NULL)
{
$this->tickets[] = array($connection, $event, $sql);
end($this->tickets);
return key($this->tickets);
}
/**
* After event notification.
* @param int
* @param DibiResult
* @return void
*/
public function after($ticket, $res = NULL)
{
if (!isset($this->tickets[$ticket])) {
throw new InvalidArgumentException('Bad ticket number.');
}
list($connection, $event, $sql) = $this->tickets[$ticket];
$sql = trim($sql);
if (($event & $this->filter) === 0) return;
if ($event & self::QUERY) {
try {
$count = $res instanceof DibiResult ? count($res) : '-';
} catch (Exception $e) {
$count = '?';
}
if ($this->useFirebug && !headers_sent()) {
if (count(self::$table) < self::FIREBUG_MAX_ROWS) {
self::$table[] = array(
sprintf('%0.3f', dibi::$elapsedTime * 1000),
strlen($sql) > self::FIREBUG_MAX_LENGTH ? substr($sql, 0, self::FIREBUG_MAX_LENGTH) . '...' : $sql,
$count,
$connection->getConfig('driver') . '/' . $connection->getConfig('name')
);
}
header('X-Wf-Protocol-dibi: http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
header('X-Wf-dibi-Plugin-1: http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0');
header('X-Wf-dibi-Structure-1: http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
$payload = array(
array(
'Type' => 'TABLE',
'Label' => 'dibi profiler (' . dibi::$numOfQueries . ' SQL queries took ' . sprintf('%0.3f', dibi::$totalTime * 1000) . ' ms)',
),
self::$table,
);
$payload = function_exists('json_encode') ? json_encode($payload) : self::json_encode($payload);
foreach (str_split($payload, 4990) as $num => $s) {
$num++;
header("X-Wf-dibi-1-1-d$num: |$s|\\"); // protocol-, structure-, plugin-, message-index
}
header("X-Wf-dibi-1-1-d$num: |$s|");
}
if ($this->file) {
$this->writeFile(
"OK: " . $sql
. ($res instanceof DibiResult ? ";\n-- rows: " . $count : '')
. "\n-- takes: " . sprintf('%0.3f', dibi::$elapsedTime * 1000) . ' ms'
. "\n-- driver: " . $connection->getConfig('driver') . '/' . $connection->getConfig('name')
. "\n-- " . date('Y-m-d H:i:s')
. "\n\n"
);
}
}
}
/**
* After exception notification.
* @param DibiDriverException
* @return void
*/
public function exception(DibiDriverException $exception)
{
if ((self::EXCEPTION & $this->filter) === 0) return;
if ($this->useFirebug) {
// TODO: implement
}
if ($this->file) {
$message = $exception->getMessage();
$code = $exception->getCode();
if ($code) {
$message = "[$code] $message";
}
$this->writeFile(
"ERROR: $message"
. "\n-- SQL: " . dibi::$sql
. "\n-- driver: " //. $connection->getConfig('driver')
. ";\n-- " . date('Y-m-d H:i:s')
. "\n\n"
);
}
}
private function writeFile($message)
{
$handle = fopen($this->file, 'a');
if (!$handle) return; // or throw exception?
flock($handle, LOCK_EX);
fwrite($handle, $message);
fclose($handle);
}
public static function json_encode($val)
{
// indexed array
if (is_array($val) && (!$val
|| array_keys($val) === range(0, count($val) - 1))) {
return '[' . implode(',', array_map(array(__CLASS__, 'json_encode'), $val)) . ']';
}
// associative array
if (is_array($val) || is_object($val)) {
$tmp = array();
foreach ($val as $k => $v) {
$tmp[] = self::json_encode((string) $k) . ':' . self::json_encode($v);
}
return '{' . implode(',', $tmp) . '}';
}
if (is_string($val)) {
$val = str_replace(array("\\", "\x00"), array("\\\\", "\\u0000"), $val); // due to bug #40915
return '"' . addcslashes($val, "\x8\x9\xA\xC\xD/\"") . '"';
}
if (is_int($val) || is_float($val)) {
return rtrim(rtrim(number_format($val, 5, '.', ''), '0'), '.');
}
if (is_bool($val)) {
return $val ? 'true' : 'false';
}
return 'null';
}
}

View File

@@ -1,656 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* dibi result-set.
*
* <code>
* $result = dibi::query('SELECT * FROM [table]');
*
* $row = $result->fetch();
* $value = $result->fetchSingle();
* $table = $result->fetchAll();
* $pairs = $result->fetchPairs();
* $assoc = $result->fetchAssoc('id');
* $assoc = $result->fetchAssoc('active,#,id');
*
* unset($result);
* </code>
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiResult extends DibiObject implements IDataSource
{
/** @var array IDibiDriver */
private $driver;
/** @var array Translate table */
private $xlat;
/** @var array Cache for $driver->getColumnsMeta() */
private $meta;
/** @var bool Already fetched? Used for allowance for first seek(0) */
private $fetched = FALSE;
/** @var array|FALSE Qualifiy each column name with the table name? */
private $withTables = FALSE;
/** @var string returned object class */
private $class = 'DibiRow';
/**
* @param IDibiDriver
* @param array
*/
public function __construct($driver, $config)
{
$this->driver = $driver;
if (!empty($config[dibi::RESULT_WITH_TABLES])) {
$this->setWithTables(TRUE);
}
}
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
@$this->free(); // intentionally @
}
/**
* Returns the result set resource.
* @return mixed
*/
final public function getResource()
{
return $this->getDriver()->getResultResource();
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
final public function seek($row)
{
return ($row !== 0 || $this->fetched) ? (bool) $this->getDriver()->seek($row) : TRUE;
}
/**
* Returns the number of rows in a result set.
* @return int
*/
final public function getRowCount()
{
return $this->getDriver()->getRowCount();
}
/**
* Returns the number of rows in a result set. Alias for getRowCount().
* @return int
*/
final public function rowCount()
{
return $this->getDriver()->getRowCount();
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
final public function free()
{
if ($this->driver !== NULL) {
$this->driver->free();
$this->driver = NULL;
}
}
/**
* Qualifiy each column name with the table name?
* @param bool
* @return DibiResult provides a fluent interface
* @throws DibiException
*/
final public function setWithTables($val)
{
if ($val) {
$cols = array();
foreach ($this->getMeta() as $info) {
$name = $info['fullname'];
if (isset($cols[$name])) {
$fix = 1;
while (isset($cols[$name . '#' . $fix])) $fix++;
$name .= '#' . $fix;
}
$cols[$name] = TRUE;
}
$this->withTables = array_keys($cols);
} else {
$this->withTables = FALSE;
}
return $this;
}
/**
* Qualifiy each key with the table name?
* @return bool
*/
final public function getWithTables()
{
return (bool) $this->withTables;
}
/**
* Set fetched object class. This class should extend the DibiRow class.
* @param string
* @return DibiResult provides a fluent interface
*/
public function setRowClass($class)
{
$this->class = $class;
return $this;
}
/**
* Returns fetched object class name.
* @return string
*/
public function getRowClass()
{
return $this->class;
}
/**
* Fetches the row at current position, process optional type conversion.
* and moves the internal cursor to the next position
* @return DibiRow|FALSE array on success, FALSE if no next record
*/
final public function fetch()
{
if ($this->withTables === FALSE) {
$row = $this->getDriver()->fetch(TRUE);
if (!is_array($row)) return FALSE;
} else {
$row = $this->getDriver()->fetch(FALSE);
if (!is_array($row)) return FALSE;
$row = array_combine($this->withTables, $row);
}
$this->fetched = TRUE;
// types-converting?
if ($this->xlat !== NULL) {
foreach ($this->xlat as $col => $type) {
if (isset($row[$col])) {
$row[$col] = $this->convert($row[$col], $type['type'], $type['format']);
}
}
}
return new $this->class($row);
}
/**
* Like fetch(), but returns only first field.
* @return mixed value on success, FALSE if no next record
*/
final public function fetchSingle()
{
$row = $this->getDriver()->fetch(TRUE);
if (!is_array($row)) return FALSE;
$this->fetched = TRUE;
$value = reset($row);
// types-converting?
$key = key($row);
if (isset($this->xlat[$key])) {
$type = $this->xlat[$key];
return $this->convert($value, $type['type'], $type['format']);
}
return $value;
}
/**
* Fetches all records from table.
* @param int offset
* @param int limit
* @return array of DibiRow
*/
final public function fetchAll($offset = NULL, $limit = NULL)
{
$limit = $limit === NULL ? -1 : (int) $limit;
$this->seek((int) $offset);
$row = $this->fetch();
if (!$row) return array(); // empty result set
$data = array();
do {
if ($limit === 0) break;
$limit--;
$data[] = $row;
} while ($row = $this->fetch());
return $data;
}
/**
* Fetches all records from table and returns associative tree.
* Associative descriptor: assoc1,#,assoc2,=,assoc3,@
* builds a tree: $data[assoc1][index][assoc2]['assoc3']->value = {record}
* @param string associative descriptor
* @return DibiRow
* @throws InvalidArgumentException
*/
final public function fetchAssoc($assoc)
{
$this->seek(0);
$row = $this->fetch();
if (!$row) return array(); // empty result set
$data = NULL;
$assoc = explode(',', $assoc);
// check columns
foreach ($assoc as $as) {
// offsetExists ignores NULL in PHP 5.2.1, isset() surprisingly NULL accepts
if ($as !== '#' && $as !== '=' && $as !== '@' && !isset($row[$as])) {
throw new InvalidArgumentException("Unknown column '$as' in associative descriptor.");
}
}
// strip leading = and @
$leaf = '@'; // gap
$last = count($assoc) - 1;
while ($assoc[$last] === '=' || $assoc[$last] === '@') {
$leaf = $assoc[$last];
unset($assoc[$last]);
$last--;
if ($last < 0) {
$assoc[] = '#';
break;
}
}
// make associative tree
do {
$arr = (array) $row;
$x = & $data;
// iterative deepening
foreach ($assoc as $i => $as) {
if ($as === '#') { // indexed-array node
$x = & $x[];
} elseif ($as === '=') { // "record" node
if ($x === NULL) {
$x = $arr;
$x = & $x[ $assoc[$i+1] ];
$x = NULL; // prepare child node
} else {
$x = & $x[ $assoc[$i+1] ];
}
} elseif ($as === '@') { // "object" node
if ($x === NULL) {
$x = clone $row;
$x = & $x->{$assoc[$i+1]};
$x = NULL; // prepare child node
} else {
$x = & $x->{$assoc[$i+1]};
}
} else { // associative-array node
$x = & $x[ $arr[ $as ] ];
}
}
if ($x === NULL) { // build leaf
if ($leaf === '=') {
$x = $arr;
} else {
$x = $row;
}
}
} while ($row = $this->fetch());
unset($x);
return $data;
}
/**
* Fetches all records from table like $key => $value pairs.
* @param string associative key
* @param string value
* @return array
* @throws InvalidArgumentException
*/
final public function fetchPairs($key = NULL, $value = NULL)
{
$this->seek(0);
$row = $this->fetch();
if (!$row) return array(); // empty result set
$data = array();
if ($value === NULL) {
if ($key !== NULL) {
throw new InvalidArgumentException("Either none or both columns must be specified.");
}
// autodetect
$tmp = array_keys((array) $row);
$key = $tmp[0];
if (count($row) < 2) { // indexed-array
do {
$data[] = $row[$key];
} while ($row = $this->fetch());
return $data;
}
$value = $tmp[1];
} else {
if (!isset($row[$value])) {
throw new InvalidArgumentException("Unknown value column '$value'.");
}
if ($key === NULL) { // indexed-array
do {
$data[] = $row[$value];
} while ($row = $this->fetch());
return $data;
}
if (!isset($row[$key])) {
throw new InvalidArgumentException("Unknown key column '$key'.");
}
}
do {
$data[ $row[$key] ] = $row[$value];
} while ($row = $this->fetch());
return $data;
}
/**
* Define column type.
* @param string column
* @param string type (use constant Dibi::*)
* @param string optional format
* @return void
*/
final public function setType($col, $type, $format = NULL)
{
$this->xlat[$col] = array('type' => $type, 'format' => $format);
}
/**
* Autodetect column types.
* @return void
*/
final public function detectTypes()
{
foreach ($this->getMeta() as $info) {
$this->xlat[$info['name']] = array('type' => $info['type'], 'format' => NULL);
}
}
/**
* Define multiple columns types.
* @param array
* @return void
* @internal
*/
final public function setTypes(array $types)
{
$this->xlat = $types;
}
/**
* Returns column type.
* @return array ($type, $format)
*/
final public function getType($col)
{
return isset($this->xlat[$col]) ? $this->xlat[$col] : NULL;
}
/**
* Converts value to specified type and format.
* @param mixed value
* @param int type
* @param string format
* @return mixed
*/
final public function convert($value, $type, $format = NULL)
{
if ($value === NULL || $value === FALSE) {
return $value;
}
switch ($type) {
case dibi::TEXT:
return (string) $value;
case dibi::BINARY:
return $this->getDriver()->unescape($value, $type);
case dibi::INTEGER:
return (int) $value;
case dibi::FLOAT:
return (float) $value;
case dibi::DATE:
case dibi::DATETIME:
$value = is_numeric($value) ? (int) $value : strtotime($value);
return $format === NULL ? $value : date($format, $value);
case dibi::BOOL:
return ((bool) $value) && $value !== 'f' && $value !== 'F';
default:
return $value;
}
}
/**
* Gets an array of meta informations about columns.
* @return array of DibiColumnInfo
*/
final public function getColumns()
{
$cols = array();
foreach ($this->getMeta() as $info) {
$cols[] = new DibiColumnInfo($this->getDriver(), $info);
}
return $cols;
}
/**
* @param bool
* @return array of string
*/
public function getColumnNames($withTables = FALSE)
{
$cols = array();
foreach ($this->getMeta() as $info) {
$cols[] = $info[$withTables ? 'fullname' : 'name'];
}
return $cols;
}
/**
* Displays complete result-set as HTML 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";
}
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";
}
}
/**
* Required by the IteratorAggregate interface.
* @param int offset
* @param int limit
* @return DibiResultIterator
*/
final public function getIterator($offset = NULL, $limit = NULL)
{
return new DibiResultIterator($this, $offset, $limit);
}
/**
* Required by the Countable interface.
* @return int
*/
final public function count()
{
return $this->getRowCount();
}
/**
* Safe access to property $driver.
* @return IDibiDriver
* @throws InvalidStateException
*/
private function getDriver()
{
if ($this->driver === NULL) {
throw new InvalidStateException('Result-set was released from memory.');
}
return $this->driver;
}
/**
* Meta lazy initialization.
* @return array
*/
private function getMeta()
{
if ($this->meta === NULL) {
$this->meta = $this->getDriver()->getColumnsMeta();
foreach ($this->meta as & $row) {
$row['type'] = DibiColumnInfo::detectType($row['nativetype']);
}
}
return $this->meta;
}
}

View File

@@ -1,145 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* External result set iterator.
*
* This can be returned by DibiResult::getIterator() method or using foreach
* <code>
* $result = dibi::query('SELECT * FROM table');
* foreach ($result as $row) {
* print_r($row);
* }
* unset($result);
* </code>
*
* Optionally you can specify offset and limit:
* <code>
* foreach ($result->getIterator(2, 3) as $row) {
* print_r($row);
* }
* </code>
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiResultIterator implements Iterator, Countable
{
/** @var DibiResult */
private $result;
/** @var int */
private $offset;
/** @var int */
private $limit;
/** @var int */
private $row;
/** @var int */
private $pointer;
/**
* @param DibiResult
* @param int offset
* @param int limit
*/
public function __construct(DibiResult $result, $offset = NULL, $limit = NULL)
{
$this->result = $result;
$this->offset = (int) $offset;
$this->limit = $limit === NULL ? -1 : (int) $limit;
}
/**
* Rewinds the iterator to the first element.
* @return void
*/
public function rewind()
{
$this->pointer = 0;
$this->result->seek($this->offset);
$this->row = $this->result->fetch();
}
/**
* Returns the key of the current element.
* @return mixed
*/
public function key()
{
return $this->pointer;
}
/**
* Returns the current element.
* @return mixed
*/
public function current()
{
return $this->row;
}
/**
* Moves forward to next element.
* @return void
*/
public function next()
{
//$this->result->seek($this->offset + $this->pointer + 1);
$this->row = $this->result->fetch();
$this->pointer++;
}
/**
* Checks if there is a current element after calls to rewind() or next().
* @return bool
*/
public function valid()
{
return !empty($this->row) && ($this->limit < 0 || $this->pointer < $this->limit);
}
/**
* Required by the Countable interface.
* @return int
*/
public function count()
{
return $this->result->getRowCount();
}
}

View File

@@ -1,89 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* Result-set single row.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
class DibiRow extends ArrayObject
{
/**
* @param array
*/
public function __construct($arr)
{
parent::__construct($arr, 2);
}
/**
* Converts value to date-time format.
* @param string key
* @param string format
* @return mixed
*/
public function asDate($key, $format = NULL)
{
$value = $this[$key];
if ($value === NULL || $value === FALSE) {
return $value;
} else {
$value = is_numeric($value) ? (int) $value : strtotime($value);
return $format === NULL ? $value : date($format, $value);
}
}
/**
* Converts value to boolean.
* @param string key
* @return mixed
*/
public function asBool($key)
{
$value = $this[$key];
if ($value === NULL || $value === FALSE) {
return $value;
} else {
return ((bool) $value) && $value !== 'f' && $value !== 'F';
}
}
/**
* PHP < 5.3 workaround
* @return void
*/
public function __wakeup()
{
$this->setFlags(2);
}
}

View File

@@ -1,594 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* dibi SQL translator.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
final class DibiTranslator extends DibiObject
{
/** @var IDibiDriver */
private $driver;
/** @var int */
private $cursor;
/** @var array */
private $args;
/** @var bool */
private $hasError;
/** @var bool */
private $comment;
/** @var int */
private $ifLevel;
/** @var int */
private $ifLevelStart;
/** @var int */
private $limit;
/** @var int */
private $offset;
public function __construct(IDibiDriver $driver)
{
$this->driver = $driver;
}
/**
* return IDibiDriver.
*/
public function getDriver()
{
return $this->driver;
}
/**
* Generates SQL.
* @param array
* @return string
* @throws DibiException
*/
public function translate(array $args)
{
$this->limit = -1;
$this->offset = 0;
$this->hasError = FALSE;
$commandIns = NULL;
$lastArr = NULL;
// shortcuts
$cursor = & $this->cursor;
$cursor = 0;
$this->args = array_values($args);
$args = & $this->args;
// conditional sql
$this->ifLevel = $this->ifLevelStart = 0;
$comment = & $this->comment;
$comment = FALSE;
// iterate
$sql = array();
while ($cursor < count($args))
{
$arg = $args[$cursor];
$cursor++;
// simple string means SQL
if (is_string($arg)) {
// speed-up - is regexp required?
$toSkip = strcspn($arg, '`[\'":%');
if (strlen($arg) === $toSkip) { // needn't be translated
$sql[] = $arg;
} else {
$sql[] = substr($arg, 0, $toSkip)
/*
preg_replace_callback('/
(?=[`[\'":%?]) ## speed-up
(?:
`(.+?)`| ## 1) `identifier`
\[(.+?)\]| ## 2) [identifier]
(\')((?:\'\'|[^\'])*)\'| ## 3,4) 'string'
(")((?:""|[^"])*)"| ## 5,6) "string"
(\'|")| ## 7) lone quote
:(\S*?:)([a-zA-Z0-9._]?)| ## 8,9) substitution
%([a-zA-Z]{1,4})(?![a-zA-Z]) ## 10) modifier
(\?) ## 11) placeholder
)/xs',
*/ // note: this can change $this->args & $this->cursor & ...
. preg_replace_callback('/(?=[`[\'":%?])(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|:(\S*?:)([a-zA-Z0-9._]?)|%([a-zA-Z]{1,4})(?![a-zA-Z])|(\?))/s',
array($this, 'cb'),
substr($arg, $toSkip)
);
}
continue;
}
if ($comment) {
$sql[] = '...';
continue;
}
if ($arg instanceof ArrayObject) {
$arg = (array) $arg;
}
if (is_array($arg)) {
if (is_string(key($arg))) {
// associative array -> autoselect between SET or VALUES & LIST
if ($commandIns === NULL) {
$commandIns = strtoupper(substr(ltrim($args[0]), 0, 6));
$commandIns = $commandIns === 'INSERT' || $commandIns === 'REPLAC';
$sql[] = $this->formatValue($arg, $commandIns ? 'v' : 'a');
} else {
if ($lastArr === $cursor - 1) $sql[] = ',';
$sql[] = $this->formatValue($arg, $commandIns ? 'l' : 'a');
}
$lastArr = $cursor;
continue;
} elseif ($cursor === 1) {
// implicit array expansion
$cursor = 0;
array_splice($args, 0, 1, $arg);
continue;
}
}
// default processing
$sql[] = $this->formatValue($arg, FALSE);
} // while
if ($comment) $sql[] = "*/";
$sql = implode(' ', $sql);
if ($this->hasError) {
throw new DibiException('SQL translate error', 0, $sql);
}
// apply limit
if ($this->limit > -1 || $this->offset > 0) {
$this->driver->applyLimit($sql, $this->limit, $this->offset);
}
return $sql;
}
/**
* Apply modifier to single value.
* @param mixed
* @param string
* @return string
*/
public function formatValue($value, $modifier)
{
// array processing (with or without modifier)
if ($value instanceof ArrayObject) {
$value = (array) $value;
}
if (is_array($value)) {
$vx = $kx = array();
switch ($modifier) {
case 'and':
case 'or': // key=val AND key IS NULL AND ...
if (empty($value)) {
return '1=1';
}
foreach ($value as $k => $v) {
if (is_string($k)) {
$pair = explode('%', $k, 2); // split into identifier & modifier
$k = $this->delimite($pair[0]) . ' ';
if (!isset($pair[1])) {
$v = $this->formatValue($v, FALSE);
$vx[] = $k . ($v === 'NULL' ? 'IS ' : '= ') . $v;
} elseif ($pair[1] === 'ex') { // TODO: this will be removed
$vx[] = $k . $this->formatValue($v, 'ex');
} else {
$v = $this->formatValue($v, $pair[1]);
$vx[] = $k . ($pair[1] === 'l' ? 'IN ' : ($v === 'NULL' ? 'IS ' : '= ')) . $v;
}
} else {
$vx[] = $this->formatValue($v, 'ex');
}
}
return '(' . implode(') ' . strtoupper($modifier) . ' (', $vx) . ')';
case 'n': // key, key, ... identifier names
foreach ($value as $k => $v) {
if (is_string($k)) {
$vx[] = $this->delimite($k) . (empty($v) ? '' : ' AS ' . $v);
} else {
$pair = explode('%', $v, 2); // split into identifier & modifier
$vx[] = $this->delimite($pair[0]);
}
}
return implode(', ', $vx);
case 'a': // key=val, key=val, ...
foreach ($value as $k => $v) {
$pair = explode('%', $k, 2); // split into identifier & modifier
$vx[] = $this->delimite($pair[0]) . '='
. $this->formatValue($v, isset($pair[1]) ? $pair[1] : (is_array($v) ? 'ex' : FALSE));
}
return implode(', ', $vx);
case 'l': // (val, val, ...)
foreach ($value as $k => $v) {
$pair = explode('%', $k, 2); // split into identifier & modifier
$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : (is_array($v) ? 'ex' : FALSE));
}
return '(' . ($vx ? implode(', ', $vx) : 'NULL') . ')';
case 'v': // (key, key, ...) VALUES (val, val, ...)
foreach ($value as $k => $v) {
$pair = explode('%', $k, 2); // split into identifier & modifier
$kx[] = $this->delimite($pair[0]);
$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : (is_array($v) ? 'ex' : FALSE));
}
return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
case 'm': // (key, key, ...) VALUES (val, val, ...), (val, val, ...), ...
foreach ($value as $k => $v) {
if (is_array($v)) {
if (isset($proto)) {
if ($proto !== array_keys($v)) {
$this->hasError = TRUE;
return '**Multi-insert array "' . $k . '" is different.**';
}
} else {
$proto = array_keys($v);
}
} else {
$this->hasError = TRUE;
return '**Unexpected type ' . gettype($v) . '**';
}
$pair = explode('%', $k, 2); // split into identifier & modifier
$kx[] = $this->delimite($pair[0]);
foreach ($v as $k2 => $v2) {
$vx[$k2][] = $this->formatValue($v2, isset($pair[1]) ? $pair[1] : (is_array($v2) ? 'ex' : FALSE));
}
}
foreach ($vx as $k => $v) {
$vx[$k] = '(' . ($v ? implode(', ', $v) : 'NULL') . ')';
}
return '(' . implode(', ', $kx) . ') VALUES ' . implode(', ', $vx);
case 'by': // key ASC, key DESC
foreach ($value as $k => $v) {
if (is_string($k)) {
$v = (is_string($v) && strncasecmp($v, 'd', 1)) || $v > 0 ? 'ASC' : 'DESC';
$vx[] = $this->delimite($k) . ' ' . $v;
} else {
$vx[] = $this->delimite($v);
}
}
return implode(', ', $vx);
case 'ex':
case 'sql':
$translator = new self($this->driver);
return $translator->translate($value);
default: // value, value, value - all with the same modifier
foreach ($value as $v) {
$vx[] = $this->formatValue($v, $modifier);
}
return $vx ? implode(', ', $vx) : 'NULL';
}
}
// with modifier procession
if ($modifier) {
if ($value instanceof IDibiVariable) {
return $value->toSql($this, $modifier);
} elseif ($value instanceof DateTime) {
$value = $value->format('U');
} elseif ($value !== NULL && !is_scalar($value)) { // array is already processed
$this->hasError = TRUE;
return '**Unexpected type ' . gettype($value) . '**';
}
switch ($modifier) {
case 's': // string
case 'bin':// binary
case 'b': // boolean
return $value === NULL ? 'NULL' : $this->driver->escape($value, $modifier);
case 'sn': // string or NULL
return $value == '' ? 'NULL' : $this->driver->escape($value, dibi::TEXT); // notice two equal signs
case 'in': // signed int or NULL
if ($value == '') $value = NULL;
// intentionally break omitted
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)) {
return $value;
} else {
return $value === NULL ? 'NULL' : (string) (int) ($value + 0);
}
case 'f': // float
// support for extreme numbers - keep them unchanged
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, 5, '.', ''), '0'), '.');
}
case 'd': // date
case 't': // datetime
if ($value === NULL) {
return 'NULL';
} else {
return $this->driver->escape(is_numeric($value) ? (int) $value : strtotime($value), $modifier);
}
case 'by':
case 'n': // identifier name
return $this->delimite($value);
case 'ex':
case 'sql': // preserve as dibi-SQL (TODO: leave only %ex)
$value = (string) $value;
// speed-up - is regexp required?
$toSkip = strcspn($value, '`[\'":');
if (strlen($value) === $toSkip) { // needn't be translated
return $value;
} else {
return substr($value, 0, $toSkip)
. preg_replace_callback(
'/(?=[`[\'":])(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|:(\S*?:)([a-zA-Z0-9._]?))/s',
array($this, 'cb'),
substr($value, $toSkip)
);
}
case 'SQL': // preserve as real SQL (TODO: rename to %sql)
return (string) $value;
case 'and':
case 'or':
case 'a':
case 'l':
case 'v':
$this->hasError = TRUE;
return '**Unexpected type ' . gettype($value) . '**';
default:
$this->hasError = TRUE;
return "**Unknown or invalid modifier %$modifier**";
}
}
// without modifier procession
if (is_string($value))
return $this->driver->escape($value, dibi::TEXT);
if (is_int($value) || is_float($value))
return rtrim(rtrim(number_format($value, 5, '.', ''), '0'), '.');
if (is_bool($value))
return $this->driver->escape($value, dibi::BOOL);
if ($value === NULL)
return 'NULL';
if ($value instanceof IDibiVariable)
return $value->toSql($this, NULL);
if ($value instanceof DateTime)
return $value = $value->format('U');
$this->hasError = TRUE;
return '**Unexpected ' . gettype($value) . '**';
}
/**
* PREG callback from translate() or formatValue().
* @param array
* @return string
*/
private function cb($matches)
{
// [1] => `ident`
// [2] => [ident]
// [3] => '
// [4] => string
// [5] => "
// [6] => string
// [7] => lone-quote
// [8] => substitution
// [9] => substitution flag
// [10] => modifier (when called from self::translate())
// [11] => placeholder (when called from self::translate())
if (!empty($matches[11])) { // placeholder
$cursor = & $this->cursor;
if ($cursor >= count($this->args)) {
$this->hasError = TRUE;
return "**Extra placeholder**";
}
$cursor++;
return $this->formatValue($this->args[$cursor - 1], FALSE);
}
if (!empty($matches[10])) { // modifier
$mod = $matches[10];
$cursor = & $this->cursor;
if ($cursor >= count($this->args) && $mod !== 'else' && $mod !== 'end') {
$this->hasError = TRUE;
return "**Extra modifier %$mod**";
}
if ($mod === 'if') {
$this->ifLevel++;
$cursor++;
if (!$this->comment && !$this->args[$cursor - 1]) {
// open comment
$this->ifLevelStart = $this->ifLevel;
$this->comment = TRUE;
return "/*";
}
return '';
} elseif ($mod === 'else') {
if ($this->ifLevelStart === $this->ifLevel) {
$this->ifLevelStart = 0;
$this->comment = FALSE;
return "*/";
} elseif (!$this->comment) {
$this->ifLevelStart = $this->ifLevel;
$this->comment = TRUE;
return "/*";
}
} elseif ($mod === 'end') {
$this->ifLevel--;
if ($this->ifLevelStart === $this->ifLevel + 1) {
// close comment
$this->ifLevelStart = 0;
$this->comment = FALSE;
return "*/";
}
return '';
} elseif ($mod === 'ex') { // array expansion
array_splice($this->args, $cursor, 1, $this->args[$cursor]);
return '';
} elseif ($mod === 'lmt') { // apply limit
if ($this->args[$cursor] !== NULL) $this->limit = (int) $this->args[$cursor];
$cursor++;
return '';
} elseif ($mod === 'ofs') { // apply offset
if ($this->args[$cursor] !== NULL) $this->offset = (int) $this->args[$cursor];
$cursor++;
return '';
} else { // default processing
$cursor++;
return $this->formatValue($this->args[$cursor - 1], $mod);
}
}
if ($this->comment) return '...';
if ($matches[1]) // SQL identifiers: `ident`
return $this->delimite($matches[1]);
if ($matches[2]) // SQL identifiers: [ident]
return $this->delimite($matches[2]);
if ($matches[3]) // SQL strings: '...'
return $this->driver->escape( str_replace("''", "'", $matches[4]), dibi::TEXT);
if ($matches[5]) // SQL strings: "..."
return $this->driver->escape( str_replace('""', '"', $matches[6]), dibi::TEXT);
if ($matches[7]) { // string quote
$this->hasError = TRUE;
return '**Alone quote**';
}
if ($matches[8]) { // SQL identifier substitution
$m = substr($matches[8], 0, -1);
$m = isset(dibi::$substs[$m]) ? dibi::$substs[$m] : call_user_func(dibi::$substFallBack, $m);
return $matches[9] == '' ? $this->formatValue($m, FALSE) : $m . $matches[9]; // value or identifier
}
die('this should be never executed');
}
/**
* Apply substitutions to indentifier and delimites it.
* @param string indentifier
* @return string
*/
private function delimite($value)
{
if ($value === '*') {
return '*';
} elseif (strpos($value, ':') !== FALSE) { // provide substitution
$value = preg_replace_callback('#:(.*):#U', array(__CLASS__, 'subCb'), $value);
}
return $this->driver->escape($value, dibi::IDENTIFIER);
}
/**
* Substitution callback.
* @param array
* @return string
*/
private static function subCb($m)
{
$m = $m[1];
return isset(dibi::$substs[$m]) ? dibi::$substs[$m] : call_user_func(dibi::$substFallBack, $m);
}
}

View File

@@ -1,48 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* Default implemenation of IDibiVariable.
* @package dibi
*/
class DibiVariable extends DibiObject implements IDibiVariable
{
/** @var mixed */
public $value;
/** @var string */
public $modifier;
public function __construct($value, $modifier)
{
$this->value = $value;
$this->modifier = $modifier;
}
public function toSql(DibiTranslator $translator, $modifier)
{
return $translator->formatValue($this->value, $this->modifier);
}
}

View File

@@ -1,295 +0,0 @@
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://dibiphp.com
*
* @copyright Copyright (c) 2005, 2009 David Grudl
* @license http://dibiphp.com/license dibi license
* @link http://dibiphp.com
* @package dibi
*/
/**
* Interface for user variable, used for generating SQL.
* @package dibi
*/
interface IDibiVariable
{
/**
* Format for SQL.
* @param DibiTranslator
* @param string optional modifier
* @return string SQL code
*/
function toSql(DibiTranslator $translator, $modifier);
}
/**
* Provides an interface between a dataset and data-aware components.
* @package dibi
*/
interface IDataSource extends Countable, IteratorAggregate
{
//function IteratorAggregate::getIterator();
//function Countable::count();
}
/**
* Defines method that must profiler implement.
* @package dibi
*/
interface IDibiProfiler
{
/**#@+ event type */
const CONNECT = 1;
const SELECT = 4;
const INSERT = 8;
const DELETE = 16;
const UPDATE = 32;
const QUERY = 60;
const BEGIN = 64;
const COMMIT = 128;
const ROLLBACK = 256;
const TRANSACTION = 448;
const EXCEPTION = 512;
const ALL = 1023;
/**#@-*/
/**
* Before event notification.
* @param DibiConnection
* @param int event name
* @param string sql
* @return int
*/
function before(DibiConnection $connection, $event, $sql = NULL);
/**
* After event notification.
* @param int
* @param DibiResult
* @return void
*/
function after($ticket, $result = NULL);
/**
* After exception notification.
* @param DibiDriverException
* @return void
*/
function exception(DibiDriverException $exception);
}
/**
* dibi driver interface.
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2009 David Grudl
* @package dibi
*/
interface IDibiDriver
{
/**
* Connects to a database.
* @param array
* @return void
* @throws DibiException
*/
function connect(array &$config);
/**
* Disconnects from a database.
* @return void
* @throws DibiException
*/
function disconnect();
/**
* Internal: Executes the SQL query.
* @param string SQL statement.
* @return IDibiDriver|NULL
* @throws DibiDriverException
*/
function query($sql);
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
function getAffectedRows();
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
function getInsertId($sequence);
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
function begin($savepoint = NULL);
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
function commit($savepoint = NULL);
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws DibiDriverException
*/
function rollback($savepoint = NULL);
/**
* Returns the connection resource.
* @return mixed
*/
function getResource();
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param string value
* @param string type (dibi::TEXT, dibi::BOOL, ...)
* @return string encoded value
* @throws InvalidArgumentException
*/
function escape($value, $type);
/**
* Decodes data from result set.
* @param string value
* @param string type (dibi::BINARY)
* @return string decoded value
* @throws InvalidArgumentException
*/
function unescape($value, $type);
/**
* Injects LIMIT/OFFSET to the SQL query.
* @param string &$sql The SQL query that will be modified.
* @param int $limit
* @param int $offset
* @return void
*/
function applyLimit(&$sql, $limit, $offset);
/********************* result set ****************d*g**/
/**
* Returns the number of rows in a result set.
* @return int
*/
function getRowCount();
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
* @throws DibiException
*/
function seek($row);
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
* @internal
*/
function fetch($type);
/**
* Frees the resources allocated for this result set.
* @param resource result set resource
* @return void
*/
function free();
/**
* Returns metadata for all columns in a result set.
* @return array
* @throws DibiException
*/
function getColumnsMeta();
/**
* Returns the result set resource.
* @return mixed
*/
function getResultResource();
/********************* reflection ****************d*g**/
/**
* Returns list of tables.
* @return array
*/
function getTables();
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
function getColumns($table);
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
function getIndexes($table);
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
function getForeignKeys($table);
}

View File

@@ -1,2 +0,0 @@
Disallow: /drivers
Disallow: /Nette

1
examples/.gitignore vendored
View File

@@ -1,3 +1,4 @@
_test.bat
ref
output
log

View File

@@ -1,917 +0,0 @@
<?php
/**
* Nette Framework
*
* Copyright (c) 2004, 2009 David Grudl (http://davidgrudl.com)
*
* This source file is subject to the "Nette license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://nettephp.com
*
* @copyright Copyright (c) 2004, 2009 David Grudl
* @license http://nettephp.com/license Nette license
* @link http://nettephp.com
* @category Nette
* @package Nette
*/
if(version_compare(PHP_VERSION,'5.2.0','<')){throw
new
Exception('Nette Framework requires PHP 5.2.0 or newer.');}@set_magic_quotes_runtime(FALSE);if(version_compare(PHP_VERSION,'5.2.2','<')){function
fixCallback(&$callback){if(is_object($callback)){$callback=array($callback,'__invoke');return;}if(is_string($callback)&&strpos($callback,':')){$callback=explode('::',$callback);}if(is_array($callback)&&is_string($callback[0])&&$a=strrpos($callback[0],'\\')){$callback[0]=substr($callback[0],$a+1);}}}else{function
fixCallback(&$callback){if(is_object($callback)){$callback=array($callback,'__invoke');}elseif(is_string($callback)&&$a=strrpos($callback,'\\')){$callback=substr($callback,$a+1);}elseif(is_array($callback)&&is_string($callback[0])&&$a=strrpos($callback[0],'\\')){$callback[0]=substr($callback[0],$a+1);}}}function
fixNamespace(&$class){if($a=strrpos($class,'\\')){$class=substr($class,$a+1);}}class
ArgumentOutOfRangeException
extends
InvalidArgumentException{}class
InvalidStateException
extends
RuntimeException{function
__construct($message='',$code=0,Exception$previous=NULL){if(version_compare(PHP_VERSION,'5.3','<')){$this->previous=$previous;parent::__construct($message,$code);}else{parent::__construct($message,$code,$previous);}}}class
NotImplementedException
extends
LogicException{}class
NotSupportedException
extends
LogicException{}class
DeprecatedException
extends
NotSupportedException{}class
MemberAccessException
extends
LogicException{}class
IOException
extends
RuntimeException{}class
FileNotFoundException
extends
IOException{}class
DirectoryNotFoundException
extends
IOException{}class
FatalErrorException
extends
Exception{private$severity;public
function
__construct($message,$code,$severity,$file,$line,$context){parent::__construct($message,$code);$this->severity=$severity;$this->file=$file;$this->line=$line;$this->context=$context;}public
function
getSeverity(){return$this->severity;}}final
class
Framework{const
NAME='Nette Framework';const
VERSION='0.9';const
REVISION='424 released on 2009/07/15 12:03:47';const
PACKAGE='PHP 5.2';final
public
function
__construct(){throw
new
LogicException("Cannot instantiate static class ".get_class($this));}public
static
function
compareVersion($version){return
version_compare($version,self::VERSION);}public
static
function
promo($xhtml=TRUE){echo'<a href="http://nettephp.com/" title="Nette Framework - The Most Innovative PHP Framework"><img ','src="http://nettephp.com/images/nette-powered.gif" alt="Powered by Nette Framework" width="80" height="15"',($xhtml?' />':'>'),'</a>';}}final
class
Debug{public
static$productionMode;public
static$consoleMode;public
static$time;private
static$firebugDetected;private
static$ajaxDetected;private
static$consoleData;public
static$maxDepth=3;public
static$maxLen=150;public
static$showLocation=FALSE;const
DEVELOPMENT=FALSE;const
PRODUCTION=TRUE;const
DETECT=NULL;public
static$strictMode=FALSE;public
static$onFatalError=array();public
static$mailer=array(__CLASS__,'defaultMailer');private
static$enabled=FALSE;private
static$logFile;private
static$logHandle;private
static$sendEmails;private
static$emailHeaders=array('To'=>'','From'=>'noreply@%host%','X-Mailer'=>'Nette Framework','Subject'=>'PHP: An error occurred on the server %host%','Body'=>'[%date%] %message%');private
static$colophons=array(array(__CLASS__,'getDefaultColophons'));private
static$enabledProfiler=FALSE;public
static$counters=array();const
LOG='LOG';const
INFO='INFO';const
WARN='WARN';const
ERROR='ERROR';const
TRACE='TRACE';const
EXCEPTION='EXCEPTION';const
GROUP_START='GROUP_START';const
GROUP_END='GROUP_END';final
public
function
__construct(){throw
new
LogicException("Cannot instantiate static class ".get_class($this));}public
static
function
init(){self::$time=microtime(TRUE);self::$consoleMode=PHP_SAPI==='cli';self::$productionMode=self::DETECT;self::$firebugDetected=isset($_SERVER['HTTP_USER_AGENT'])&&strpos($_SERVER['HTTP_USER_AGENT'],'FirePHP/');self::$ajaxDetected=isset($_SERVER['HTTP_X_REQUESTED_WITH'])&&$_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest';register_shutdown_function(array(__CLASS__,'shutdownHandler'));}public
static
function
shutdownHandler(){static$types=array(E_ERROR=>1,E_CORE_ERROR=>1,E_COMPILE_ERROR=>1,E_PARSE=>1);$error=error_get_last();if(isset($types[$error['type']])){if(!headers_sent()){header('HTTP/1.1 500 Internal Server Error');}if(ini_get('html_errors')){$error['message']=html_entity_decode(strip_tags($error['message']));}self::processException(new
FatalErrorException($error['message'],0,$error['type'],$error['file'],$error['line'],NULL),TRUE);}if(self::$productionMode){return;}foreach(headers_list()as$header){if(strncasecmp($header,'Content-Type:',13)===0){if(substr($header,14,9)==='text/html'){break;}return;}}if(self::$enabledProfiler){if(self::$firebugDetected){self::fireLog('Nette profiler',self::GROUP_START);foreach(self::$colophons
as$callback){foreach((array)call_user_func($callback,'profiler')as$line)self::fireLog(strip_tags($line));}self::fireLog(NULL,self::GROUP_END);}if(!self::$ajaxDetected){$colophons=self::$colophons;?>
<style type="text/css">
/* <![CDATA[ */
#netteProfilerContainer {
position: fixed;
_position: absolute;
right: 5px;
bottom: 5px;
z-index: 23178;
}
#netteProfiler {
font: normal normal 11px/1.4 Consolas, Arial;
position: relative;
padding: 1px;
color: black;
background: #EEE;
border: 1px dotted gray;
cursor: move;
opacity: .70;
=filter: alpha(opacity=70);
}
#netteProfiler * {
color: inherit;
background: inherit;
text-align: inherit;
}
#netteProfilerIcon {
position: absolute;
right: 0;
top: 0;
line-height: 1;
padding: 4px;
color: black;
text-decoration: none;
}
#netteProfiler:hover {
opacity: 1;
=filter: none;
}
#netteProfiler ul {
margin: 0;
padding: 0;
width: 350px;
}
#netteProfiler li {
margin: 0;
padding: 1px;
text-align: left;
list-style: none;
}
#netteProfiler span[title] {
border-bottom: 1px dotted gray;
cursor: help;
}
#netteProfiler strong {
color: red;
}
/* ]]> */
</style>
<div id="netteProfilerContainer">
<div id="netteProfiler">
<a id="netteProfilerIcon" href="#"><abbr>&#x25bc;</abbr></a
><ul>
<?php foreach($colophons
as$callback):?>
<?php foreach((array)call_user_func($callback,'profiler')as$line):?><li><?php echo$line,"\n"?></li><?php endforeach?>
<?php endforeach?>
</ul>
</div>
</div>
<script type="text/javascript">
/* <![CDATA[ */
document.getElementById('netteProfiler').onmousedown = function(e) {
e = e || event;
this.posX = parseInt(this.style.left + '0');
this.posY = parseInt(this.style.top + '0');
this.mouseX = e.clientX;
this.mouseY = e.clientY;
var thisObj = this;
document.documentElement.onmousemove = function(e) {
e = e || event;
thisObj.style.left = (e.clientX - thisObj.mouseX + thisObj.posX) + "px";
thisObj.style.top = (e.clientY - thisObj.mouseY + thisObj.posY) + "px";
return false;
};
document.documentElement.onmouseup = function(e) {
document.documentElement.onmousemove = null;
document.documentElement.onmouseup = null;
return false;
};
};
document.getElementById('netteProfilerIcon').onclick = function(e) {
var arrow = this.getElementsByTagName('abbr')[0];
var panel = this.nextSibling;
var collapsed = panel.currentStyle ? panel.currentStyle.display == 'none' : getComputedStyle(panel, null).display == 'none';
arrow.innerHTML = collapsed ? String.fromCharCode(0x25bc) : 'Profiler ' + String.fromCharCode(0x25ba);
panel.style.display = collapsed ? 'block' : 'none';
arrow.parentNode.style.position = collapsed ? 'absolute' : 'static';
return false;
}
document.body.appendChild(document.getElementById('netteProfilerContainer'));
/* ]]> */
</script>
<?php }}if(self::$consoleData){$payload=self::$consoleData;if(!function_exists('_netteDumpCb2')){function
_netteDumpCb2($m){return"$m[1]<a href='#' onclick='return !netteToggle(this)'>$m[2]($m[3]) ".($m[3]<7?'<abbr>&#x25bc;</abbr> </a><code>':'<abbr>&#x25ba;</abbr> </a><code class="collapsed">');}}ob_start();?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="robots" content="noindex,noarchive">
<meta name="generator" content="Nette Framework">
<title>Nette Debug Console</title>
<style type="text/css">
/* <![CDATA[ */
body {
margin: 0;
padding: 0;
font: 9pt/1.5 Verdana, sans-serif;
background: white;
color: #333;
}
h1 {
font-size: 13pt;
margin: 0;
padding: 2px 8px;
background: black;
color: white;
border-bottom: 1px solid black;
}
h2 {
font: 11pt/1.5 sans-serif;
margin: 0;
padding: 2px 8px;
background: #3484d2;
color: white;
}
a {
text-decoration: none;
color: #4197E3;
}
a abbr {
font-family: sans-serif;
color: #999;
}
p {
margin: .8em 0
}
pre, code, table {
font: 9pt/1.5 Consolas, monospace;
}
pre, table {
background: #fffbcc;
padding: .4em .7em;
border: 1px dotted silver;
}
table pre {
padding: 0;
margin: 0;
border: none;
}
pre.dump span {
color: #c16549;
}
pre.dump a {
color: #333;
}
table {
border-collapse: collapse;
width: 100%;
}
td, th {
vertical-align: top;
text-align: left;
border: 1px solid #eeeebb;
}
th {
width: 10;
padding: 2px 3px 2px 8px;
font-weight: bold;
}
td {
padding: 2px 8px 2px 3px;
}
.odd, .odd pre {
background: #faf5c3;
}
/* ]]> */
</style>
<script type="text/javascript">
/* <![CDATA[ */
document.write('<style> .collapsed { display: none; } <\/style>');
function netteToggle(link, panelId)
{
var arrow = link.getElementsByTagName('abbr')[0];
var panel = panelId ? document.getElementById(panelId) : link.nextSibling;
while (panel.nodeType !== 1) panel = panel.nextSibling;
var collapsed = panel.currentStyle ? panel.currentStyle.display == 'none' : getComputedStyle(panel, null).display == 'none';
arrow.innerHTML = String.fromCharCode(collapsed ? 0x25bc : 0x25ba);
panel.style.display = collapsed ? (panel.tagName.toLowerCase() === 'code' ? 'inline' : 'block') : 'none';
return true;
}
/* ]]> */
</script>
</head>
<body>
<h1>Nette Debug Console</h1>
</body>
</html>
<?php $document=ob_get_clean()?>
<?php ob_start()?>
<?php foreach($payload
as$item):?>
<?php if($item['title']):?>
<h2><?php echo
htmlspecialchars($item['title'])?></h2>
<?php endif?>
<table>
<?php $i=0?>
<?php foreach((is_array($item['var'])?$item['var']:array(''=>$item['var']))as$key=>$val):?>
<tr class="<?php echo$i++%
2?'odd':'even'?>">
<th><?php echo
htmlspecialchars($key)?></th>
<td><?php echo
preg_replace_callback('#(<pre class="dump">|\s+)?(.*)\((\d+)\) <code>#','_netteDumpCb2',Debug::dump($val,TRUE))?></td>
</tr>
<?php endforeach?>
</table>
<?php endforeach?>
<?php $body=ob_get_clean()?>
<script type="text/javascript">
/* <![CDATA[ */
if (typeof _netteConsole === 'undefined') {
_netteConsole = window.open('','_netteConsole','width=700,height=700,resizable,scrollbars=yes');
_netteConsole.document.write(<?php echo
json_encode(preg_replace('#\s+#',' ',$document))?>);
_netteConsole.document.close();
_netteConsole.document.onkeyup = function(e) {
e = e || _netteConsole.event;
if (e.keyCode == 27) _netteConsole.close();
}
_netteConsole.document.body.focus();
}
_netteConsole.document.body.innerHTML = _netteConsole.document.body.innerHTML + <?php echo
json_encode($body)?>;
/* ]]> */
</script>
<?php }}public
static
function
dump($var,$return=FALSE){if(!$return&&self::$productionMode){return$var;}$output="<pre class=\"dump\">".self::_dump($var,0)."</pre>\n";if(self::$showLocation){$trace=debug_backtrace();if(isset($trace[0]['file'],$trace[0]['line'])){$output=substr_replace($output,' <small>'.htmlspecialchars("in file {$trace[0]['file']} on line {$trace[0]['line']}",ENT_NOQUOTES).'</small>',-8,0);}}if(self::$consoleMode){$output=htmlspecialchars_decode(strip_tags($output),ENT_NOQUOTES);}if($return){return$output;}else{echo$output;return$var;}}public
static
function
consoleDump($var,$title=NULL){if(!self::$productionMode){self::$consoleData[]=array('title'=>$title,'var'=>$var);}return$var;}private
static
function
_dump(&$var,$level){if(is_bool($var)){return"<span>bool</span>(".($var?'TRUE':'FALSE').")\n";}elseif($var===NULL){return"<span>NULL</span>\n";}elseif(is_int($var)){return"<span>int</span>($var)\n";}elseif(is_float($var)){return"<span>float</span>($var)\n";}elseif(is_string($var)){if(self::$maxLen&&strlen($var)>self::$maxLen){$s=htmlSpecialChars(substr($var,0,self::$maxLen),ENT_NOQUOTES).' ... ';}else{$s=htmlSpecialChars($var,ENT_NOQUOTES);}return"<span>string</span>(".strlen($var).") \"$s\"\n";}elseif(is_array($var)){$s="<span>array</span>(".count($var).") ";$space=str_repeat($space1=' ',$level);static$marker;if($marker===NULL)$marker=uniqid("\x00",TRUE);if(empty($var)){}elseif(isset($var[$marker])){$s.="{\n$space$space1*RECURSION*\n$space}";}elseif($level<self::$maxDepth||!self::$maxDepth){$s.="<code>{\n";$var[$marker]=0;foreach($var
as$k=>&$v){if($k===$marker)continue;$s.="$space$space1".(is_int($k)?$k:"\"$k\"")." => ".self::_dump($v,$level+1);}unset($var[$marker]);$s.="$space}</code>";}else{$s.="{\n$space$space1...\n$space}";}return$s."\n";}elseif(is_object($var)){$arr=(array)$var;$s="<span>object</span>(".get_class($var).") (".count($arr).") ";$space=str_repeat($space1=' ',$level);static$list=array();if(empty($arr)){$s.="{}";}elseif(in_array($var,$list,TRUE)){$s.="{\n$space$space1*RECURSION*\n$space}";}elseif($level<self::$maxDepth||!self::$maxDepth){$s.="<code>{\n";$list[]=$var;foreach($arr
as$k=>&$v){$m='';if($k[0]==="\x00"){$m=$k[1]==='*'?' <span>protected</span>':' <span>private</span>';$k=substr($k,strrpos($k,"\x00")+1);}$s.="$space$space1\"$k\"$m => ".self::_dump($v,$level+1);}array_pop($list);$s.="$space}</code>";}else{$s.="{\n$space$space1...\n$space}";}return$s."\n";}elseif(is_resource($var)){return"<span>resource of type</span>(".get_resource_type($var).")\n";}else{return"<span>unknown type</span>\n";}}public
static
function
timer($name=NULL){static$time=array();$now=microtime(TRUE);$delta=isset($time[$name])?$now-$time[$name]:0;$time[$name]=$now;return$delta;}public
static
function
enable($mode=NULL,$logFile=NULL,$email=NULL){error_reporting(E_ALL|E_STRICT);if(is_bool($mode)){self::$productionMode=$mode;}if(self::$productionMode===self::DETECT){if(class_exists('Environment')){self::$productionMode=Environment::isProduction();}elseif(isset($_SERVER['SERVER_ADDR'])||isset($_SERVER['LOCAL_ADDR'])){$addr=isset($_SERVER['SERVER_ADDR'])?$_SERVER['SERVER_ADDR']:$_SERVER['LOCAL_ADDR'];$oct=explode('.',$addr);self::$productionMode=$addr!=='::1'&&(count($oct)!==4||($oct[0]!=='10'&&$oct[0]!=='127'&&($oct[0]!=='172'||$oct[1]<16||$oct[1]>31)&&($oct[0]!=='169'||$oct[1]!=='254')&&($oct[0]!=='192'||$oct[1]!=='168')));}else{self::$productionMode=!self::$consoleMode;}}if(self::$productionMode&&$logFile!==FALSE){self::$logFile='log/php_error.log';if(class_exists('Environment')){if(is_string($logFile)){self::$logFile=Environment::expand($logFile);}else
try{self::$logFile=Environment::expand('%logDir%/php_error.log');}catch(InvalidStateException$e){}}elseif(is_string($logFile)){self::$logFile=$logFile;}ini_set('error_log',self::$logFile);}if(function_exists('ini_set')){ini_set('display_errors',!self::$productionMode);ini_set('html_errors',!self::$logFile&&!self::$consoleMode);ini_set('log_errors',(bool)self::$logFile);}elseif(ini_get('log_errors')!=(bool)self::$logFile||(ini_get('display_errors')!=!self::$productionMode&&ini_get('display_errors')!==(self::$productionMode?'stderr':'stdout'))){throw
new
NotSupportedException('Function ini_set() must be enabled.');}self::$sendEmails=self::$logFile&&$email;if(self::$sendEmails){if(is_string($email)){self::$emailHeaders['To']=$email;}elseif(is_array($email)){self::$emailHeaders=$email+self::$emailHeaders;}}if(!defined('E_DEPRECATED')){define('E_DEPRECATED',8192);}if(!defined('E_USER_DEPRECATED')){define('E_USER_DEPRECATED',16384);}set_exception_handler(array(__CLASS__,'exceptionHandler'));set_error_handler(array(__CLASS__,'errorHandler'));self::$enabled=TRUE;}public
static
function
isEnabled(){return
self::$enabled;}public
static
function
exceptionHandler(Exception$exception){if(!headers_sent()){header('HTTP/1.1 500 Internal Server Error');}self::processException($exception,TRUE);exit;}public
static
function
errorHandler($severity,$message,$file,$line,$context){if($severity===E_RECOVERABLE_ERROR||$severity===E_USER_ERROR){throw
new
FatalErrorException($message,0,$severity,$file,$line,$context);}elseif(($severity&error_reporting())!==$severity){return
NULL;}elseif(self::$strictMode){self::processException(new
FatalErrorException($message,0,$severity,$file,$line,$context),TRUE);exit;}static$types=array(E_WARNING=>'Warning',E_USER_WARNING=>'Warning',E_NOTICE=>'Notice',E_USER_NOTICE=>'Notice',E_STRICT=>'Strict standards',E_DEPRECATED=>'Deprecated',E_USER_DEPRECATED=>'Deprecated');$type=isset($types[$severity])?$types[$severity]:'Unknown error';if(self::$logFile){if(self::$sendEmails){self::sendEmail("$type: $message in $file on line $line");}return
FALSE;}elseif(!self::$productionMode&&self::$firebugDetected&&!headers_sent()){$message=strip_tags($message);self::fireLog("$type: $message in $file on line $line",self::ERROR);return
NULL;}return
FALSE;}public
static
function
processException(Exception$exception,$outputAllowed=FALSE){if(self::$logFile){error_log("PHP Fatal error: Uncaught $exception");$file=@strftime('%d-%b-%Y %H-%M-%S ',Debug::$time).strstr(number_format(Debug::$time,4,'~',''),'~');$file=dirname(self::$logFile)."/exception $file.html";self::$logHandle=@fopen($file,'x');if(self::$logHandle){ob_start(array(__CLASS__,'writeFile'),1);self::paintBlueScreen($exception);ob_end_flush();fclose(self::$logHandle);}if(self::$sendEmails){self::sendEmail((string)$exception);}}elseif(self::$productionMode){}elseif(self::$consoleMode){if($outputAllowed){echo"$exception\n";foreach(self::$colophons
as$callback){foreach((array)call_user_func($callback,'bluescreen')as$line)echo
strip_tags($line)."\n";}}}elseif(self::$firebugDetected&&self::$ajaxDetected&&!headers_sent()){self::fireLog($exception,self::EXCEPTION);}elseif($outputAllowed){if(!headers_sent()){@ob_end_clean();while(ob_get_level()&&@ob_end_clean());header('Content-Encoding:',TRUE);}self::paintBlueScreen($exception);}elseif(self::$firebugDetected&&!headers_sent()){self::fireLog($exception,self::EXCEPTION);}foreach(self::$onFatalError
as$handler){fixCallback($handler);call_user_func($handler,$exception);}}public
static
function
paintBlueScreen(Exception$exception){$internals=array();foreach(array('Object','ObjectMixin')as$class){if(class_exists($class,FALSE)){$rc=new
ReflectionClass($class);$internals[$rc->getFileName()]=TRUE;}}$colophons=self::$colophons;if(!function_exists('_netteDebugPrintCode')){function
_netteDebugPrintCode($file,$line,$count=15){if(function_exists('ini_set')){ini_set('highlight.comment','#999; font-style: italic');ini_set('highlight.default','#000');ini_set('highlight.html','#06b');ini_set('highlight.keyword','#d24; font-weight: bold');ini_set('highlight.string','#080');}$start=max(1,$line-floor($count/2));$source=@file_get_contents($file);if(!$source)return;$source=explode("\n",highlight_string($source,TRUE));$spans=1;echo$source[0];$source=explode('<br />',$source[1]);array_unshift($source,NULL);$i=$start;while(--$i>=1){if(preg_match('#.*(</?span[^>]*>)#',$source[$i],$m)){if($m[1]!=='</span>'){$spans++;echo$m[1];}break;}}$source=array_slice($source,$start,$count,TRUE);end($source);$numWidth=strlen((string)key($source));foreach($source
as$n=>$s){$spans+=substr_count($s,'<span')-substr_count($s,'</span');$s=str_replace(array("\r","\n"),array('',''),$s);if($n===$line){printf("<span class='highlight'>Line %{$numWidth}s: %s\n</span>%s",$n,strip_tags($s),preg_replace('#[^>]*(<[^>]+>)[^<]*#','$1',$s));}else{printf("<span class='line'>Line %{$numWidth}s:</span> %s\n",$n,$s);}}echo
str_repeat('</span>',$spans),'</code>';}function
_netteDump($var){return
preg_replace_callback('#(<pre class="dump">|\s+)?(.*)\((\d+)\) <code>#','_netteDumpCb',Debug::dump($var,TRUE));}function
_netteDumpCb($m){return"$m[1]<a href='#' onclick='return !netteToggle(this)'>$m[2]($m[3]) ".(trim($m[1])||$m[3]<7?'<abbr>&#x25bc;</abbr> </a><code>':'<abbr>&#x25ba;</abbr> </a><code class="collapsed">');}function
_netteOpenPanel($name,$collapsed){static$id;$id++;?>
<div class="panel">
<h2><a href="#" onclick="return !netteToggle(this, 'pnl<?php echo$id?>')"><?php echo
htmlSpecialChars($name)?> <abbr><?php echo$collapsed?'&#x25ba;':'&#x25bc;'?></abbr></a></h2>
<div id="pnl<?php echo$id?>" class="<?php echo$collapsed?'collapsed ':''?>inner">
<?php
}function
_netteClosePanel(){?>
</div>
</div>
<?php
}}static$errorTypes=array(E_ERROR=>'Fatal Error',E_USER_ERROR=>'User Error',E_RECOVERABLE_ERROR=>'Recoverable Error',E_CORE_ERROR=>'Core Error',E_COMPILE_ERROR=>'Compile Error',E_PARSE=>'Parse Error',E_WARNING=>'Warning',E_CORE_WARNING=>'Core Warning',E_COMPILE_WARNING=>'Compile Warning',E_USER_WARNING=>'User Warning',E_NOTICE=>'Notice',E_USER_NOTICE=>'User Notice',E_STRICT=>'Strict',E_DEPRECATED=>'Deprecated',E_USER_DEPRECATED=>'User Deprecated');$title=($exception
instanceof
FatalErrorException&&isset($errorTypes[$exception->getSeverity()]))?$errorTypes[$exception->getSeverity()]:get_class($exception);$rn=0;if(headers_sent()){echo'</pre></xmp></table>';}?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="robots" content="noindex,noarchive">
<meta name="generator" content="Nette Framework">
<title><?php echo
htmlspecialchars($title)?></title>
<style type="text/css">
/* <![CDATA[ */
body {
margin: 0 0 2em;
padding: 0;
}
#netteBluescreen {
font: 9pt/1.5 Verdana, sans-serif;
background: white;
color: #333;
position: absolute;
left: 0;
top: 0;
width: 100%;
z-index: 23178;
text-align: left;
}
#netteBluescreen * {
color: inherit;
background: inherit;
text-align: inherit;
}
#netteBluescreenIcon {
position: absolute;
right: .5em;
top: .5em;
z-index: 23179;
text-decoration: none;
background: red;
padding: 3px;
}
#netteBluescreenIcon abbr {
color: black !important;
}
#netteBluescreen h1 {
font: 18pt/1.5 Verdana, sans-serif !important;
margin: .6em 0;
}
#netteBluescreen h2 {
font: 14pt/1.5 sans-serif !important;
color: #888;
margin: .6em 0;
}
#netteBluescreen a {
text-decoration: none;
color: #4197E3;
}
#netteBluescreen a abbr {
font-family: sans-serif;
color: #999;
}
#netteBluescreen h3 {
font: bold 10pt/1.5 Verdana, sans-serif !important;
margin: 1em 0;
padding: 0;
}
#netteBluescreen p {
margin: .8em 0
}
#netteBluescreen pre, #netteBluescreen code, #netteBluescreen table {
font: 9pt/1.5 Consolas, monospace !important;
}
#netteBluescreen pre, #netteBluescreen table {
background: #fffbcc;
padding: .4em .7em;
border: 1px dotted silver;
}
#netteBluescreen table pre {
padding: 0;
margin: 0;
border: none;
}
#netteBluescreen pre.dump span {
color: #c16549;
}
#netteBluescreen pre.dump a {
color: #333;
}
#netteBluescreen div.panel {
border-bottom: 1px solid #eee;
padding: 1px 2em;
}
#netteBluescreen div.inner {
padding: 0.1em 1em 1em;
background: #f5f5f5;
}
#netteBluescreen table {
border-collapse: collapse;
width: 100%;
}
#netteBluescreen td, #netteBluescreen th {
vertical-align: top;
text-align: left;
padding: 2px 3px;
border: 1px solid #eeeebb;
}
#netteBluescreen th {
width: 10%;
font-weight: bold;
}
#netteBluescreen .odd, #netteBluescreen .odd pre {
background-color: #faf5c3;
}
#netteBluescreen ul {
font: 7pt/1.5 Verdana, sans-serif !important;
padding: 1em 2em 50px;
}
#netteBluescreen .highlight, #netteBluescreenError {
background: red;
color: white;
font-weight: bold;
font-style: normal;
display: block;
}
#netteBluescreen .line {
color: #9e9e7e;
font-weight: normal;
font-style: normal;
}
/* ]]> */
</style>
<script type="text/javascript">
/* <![CDATA[ */
document.write('<style> .collapsed { display: none; } <\/style>');
function netteToggle(link, panelId)
{
var arrow = link.getElementsByTagName('abbr')[0];
var panel = panelId ? document.getElementById(panelId) : link.nextSibling;
while (panel.nodeType !== 1) panel = panel.nextSibling;
var collapsed = panel.currentStyle ? panel.currentStyle.display == 'none' : getComputedStyle(panel, null).display == 'none';
arrow.innerHTML = String.fromCharCode(collapsed ? 0x25bc : 0x25ba);
panel.style.display = collapsed ? (panel.tagName.toLowerCase() === 'code' ? 'inline' : 'block') : 'none';
return true;
}
/* ]]> */
</script>
</head>
<body>
<div id="netteBluescreen">
<a id="netteBluescreenIcon" href="#" onclick="return !netteToggle(this)"><abbr>&#x25bc;</abbr></a
><div>
<div id="netteBluescreenError" class="panel">
<h1><?php echo
htmlspecialchars($title),($exception->getCode()?' #'.$exception->getCode():'')?></h1>
<p><?php echo
htmlspecialchars($exception->getMessage())?></p>
</div>
<?php $ex=$exception;$level=0;?>
<?php do{?>
<?php if($level++):?>
<?php _netteOpenPanel('Caused by',TRUE)?>
<div class="panel">
<h1><?php echo
htmlspecialchars(get_class($ex)),($ex->getCode()?' #'.$ex->getCode():'')?></h1>
<p><?php echo
htmlspecialchars($ex->getMessage())?></p>
</div>
<?php endif?>
<?php $collapsed=isset($internals[$ex->getFile()]);?>
<?php if(is_file($ex->getFile())):?>
<?php _netteOpenPanel('Source file',$collapsed)?>
<p><strong>File:</strong> <?php echo
htmlspecialchars($ex->getFile())?> &nbsp; <strong>Line:</strong> <?php echo$ex->getLine()?></p>
<pre><?php _netteDebugPrintCode($ex->getFile(),$ex->getLine())?></pre>
<?php _netteClosePanel()?>
<?php endif?>
<?php _netteOpenPanel('Call stack',FALSE)?>
<ol>
<?php foreach($ex->getTrace()as$key=>$row):?>
<li><p>
<?php if(isset($row['file'])):?>
<span title="<?php echo
htmlSpecialChars($row['file'])?>"><?php echo
htmlSpecialChars(basename(dirname($row['file']))),'/<b>',htmlSpecialChars(basename($row['file'])),'</b></span> (',$row['line'],')'?>
<?php else:?>
&lt;PHP inner-code&gt;
<?php endif?>
<?php if(isset($row['file'])&&is_file($row['file'])):?><a href="#" onclick="return !netteToggle(this, 'src<?php echo"$level-$key"?>')">source <abbr>&#x25ba;</abbr></a>&nbsp; <?php endif?>
<?php if(isset($row['class']))echo$row['class'].$row['type']?>
<?php echo$row['function']?>
(<?php if(!empty($row['args'])):?><a href="#" onclick="return !netteToggle(this, 'args<?php echo"$level-$key"?>')">arguments <abbr>&#x25ba;</abbr></a><?php endif?>)
</p>
<?php if(!empty($row['args'])):?>
<div class="collapsed" id="args<?php echo"$level-$key"?>">
<table>
<?php
try{$r=isset($row['class'])?new
ReflectionMethod($row['class'],$row['function']):new
ReflectionFunction($row['function']);$params=$r->getParameters();}catch(Exception$e){$params=array();}foreach($row['args']as$k=>$v){echo'<tr><th>',(isset($params[$k])?'$'.$params[$k]->name:"#$k"),'</th><td>';echo
_netteDump($v);echo"</td></tr>\n";}?>
</table>
</div>
<?php endif?>
<?php if(isset($row['file'])&&is_file($row['file'])):?>
<pre <?php if(!$collapsed||isset($internals[$row['file']]))echo'class="collapsed"';else$collapsed=FALSE?> id="src<?php echo"$level-$key"?>"><?php _netteDebugPrintCode($row['file'],$row['line'])?></pre>
<?php endif?>
</li>
<?php endforeach?>
<?php if(!isset($row)):?>
<li><i>empty</i></li>
<?php endif?>
</ol>
<?php _netteClosePanel()?>
<?php if($ex
instanceof
IDebuggable):?>
<?php foreach($ex->getPanels()as$name=>$panel):?>
<?php _netteOpenPanel($name,empty($panel['expanded']))?>
<?php echo$panel['content']?>
<?php _netteClosePanel()?>
<?php endforeach?>
<?php endif?>
<?php if(isset($ex->context)&&is_array($ex->context)):?>
<?php _netteOpenPanel('Variables',TRUE)?>
<table>
<?php
foreach($ex->context
as$k=>$v){echo'<tr><th>$',htmlspecialchars($k),'</th><td>',_netteDump($v),"</td></tr>\n";}?>
</table>
<?php _netteClosePanel()?>
<?php endif?>
<?php }while((method_exists($ex,'getPrevious')&&$ex=$ex->getPrevious())||(isset($ex->previous)&&$ex=$ex->previous));?>
<?php while(--$level)_netteClosePanel()?>
<?php _netteOpenPanel('Environment',TRUE)?>
<?php
$list=get_defined_constants(TRUE);if(!empty($list['user'])):?>
<h3><a href="#" onclick="return !netteToggle(this, 'pnl-env-const')">Constants <abbr>&#x25bc;</abbr></a></h3>
<table id="pnl-env-const">
<?php
foreach($list['user']as$k=>$v){echo'<tr'.($rn++%2?' class="odd"':'').'><th>',htmlspecialchars($k),'</th>';echo'<td>',_netteDump($v),"</td></tr>\n";}?>
</table>
<?php endif?>
<h3><a href="#" onclick="return !netteToggle(this, 'pnl-env-files')">Included files <abbr>&#x25ba;</abbr></a>(<?php echo
count(get_included_files())?>)</h3>
<table id="pnl-env-files" class="collapsed">
<?php
foreach(get_included_files()as$v){echo'<tr'.($rn++%2?' class="odd"':'').'><td>',htmlspecialchars($v),"</td></tr>\n";}?>
</table>
<h3>$_SERVER</h3>
<?php if(empty($_SERVER)):?>
<p><i>empty</i></p>
<?php else:?>
<table>
<?php
foreach($_SERVER
as$k=>$v)echo'<tr'.($rn++%2?' class="odd"':'').'><th>',htmlspecialchars($k),'</th><td>',_netteDump($v),"</td></tr>\n";?>
</table>
<?php endif?>
<?php _netteClosePanel()?>
<?php _netteOpenPanel('HTTP request',TRUE)?>
<?php if(function_exists('apache_request_headers')):?>
<h3>Headers</h3>
<table>
<?php
foreach(apache_request_headers()as$k=>$v)echo'<tr'.($rn++%2?' class="odd"':'').'><th>',htmlspecialchars($k),'</th><td>',htmlspecialchars($v),"</td></tr>\n";?>
</table>
<?php endif?>
<?php foreach(array('_GET','_POST','_COOKIE')as$name):?>
<h3>$<?php echo$name?></h3>
<?php if(empty($GLOBALS[$name])):?>
<p><i>empty</i></p>
<?php else:?>
<table>
<?php
foreach($GLOBALS[$name]as$k=>$v)echo'<tr'.($rn++%2?' class="odd"':'').'><th>',htmlspecialchars($k),'</th><td>',_netteDump($v),"</td></tr>\n";?>
</table>
<?php endif?>
<?php endforeach?>
<?php _netteClosePanel()?>
<?php _netteOpenPanel('HTTP response',TRUE)?>
<h3>Headers</h3>
<?php if(headers_list()):?>
<pre><?php
foreach(headers_list()as$s)echo
htmlspecialchars($s),'<br>';?></pre>
<?php else:?>
<p><i>no headers</i></p>
<?php endif?>
<?php _netteClosePanel()?>
<ul>
<?php foreach($colophons
as$callback):?>
<?php foreach((array)call_user_func($callback,'bluescreen')as$line):?><li><?php echo$line,"\n"?></li><?php endforeach?>
<?php endforeach?>
</ul>
</div>
</div>
<script type="text/javascript">
document.body.appendChild(document.getElementById('netteBluescreen'));
</script>
</body>
</html><?php }public
static
function
writeFile($buffer){fwrite(self::$logHandle,$buffer);}private
static
function
sendEmail($message){$monitorFile=self::$logFile.'.monitor';if(!is_file($monitorFile)){if(@file_put_contents($monitorFile,'e-mail has been sent')){call_user_func(self::$mailer,$message);}}}private
static
function
defaultMailer($message){$host=isset($_SERVER['HTTP_HOST'])?$_SERVER['HTTP_HOST']:(isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:'');$headers=str_replace(array('%host%','%date%','%message%'),array($host,@date('Y-m-d H:i:s',Debug::$time),$message),self::$emailHeaders);$subject=$headers['Subject'];$to=$headers['To'];$body=$headers['Body'];unset($headers['Subject'],$headers['To'],$headers['Body']);$header='';foreach($headers
as$key=>$value){$header.="$key: $value\r\n";}$body=str_replace("\r\n","\n",$body);if(PHP_OS!='Linux')$body=str_replace("\n","\r\n",$body);mail($to,$subject,$body,$header);}public
static
function
enableProfiler(){self::$enabledProfiler=TRUE;}public
static
function
disableProfiler(){self::$enabledProfiler=FALSE;}public
static
function
addColophon($callback){fixCallback($callback);if(!is_callable($callback)){$able=is_callable($callback,TRUE,$textual);throw
new
InvalidArgumentException("Colophon handler '$textual' is not ".($able?'callable.':'valid PHP callback.'));}if(!in_array($callback,self::$colophons,TRUE)){self::$colophons[]=$callback;}}public
static
function
getDefaultColophons($sender){if($sender==='profiler'){$arr[]='Elapsed time: <b>'.number_format((microtime(TRUE)-Debug::$time)*1000,1,'.',' ').'</b> ms | Allocated memory: <b>'.number_format(memory_get_peak_usage()/1000,1,'.',' ').'</b> kB';foreach((array)self::$counters
as$name=>$value){if(is_array($value))$value=implode(', ',$value);$arr[]=htmlSpecialChars($name).' = <strong>'.htmlSpecialChars($value).'</strong>';}$autoloaded=class_exists('AutoLoader',FALSE)?AutoLoader::$count:0;$s='<span>'.count(get_included_files()).'/'.$autoloaded.' files</span>, ';$exclude=array('stdClass','Exception','ErrorException','Traversable','IteratorAggregate','Iterator','ArrayAccess','Serializable','Closure');foreach(get_loaded_extensions()as$ext){$ref=new
ReflectionExtension($ext);$exclude=array_merge($exclude,$ref->getClassNames());}$classes=array_diff(get_declared_classes(),$exclude);$intf=array_diff(get_declared_interfaces(),$exclude);$func=get_defined_functions();$func=(array)@$func['user'];$consts=get_defined_constants(TRUE);$consts=array_keys((array)@$consts['user']);foreach(array('classes','intf','func','consts')as$item){$s.='<span '.($$item?'title="'.implode(", ",$$item).'"':'').'>'.count($$item).' '.$item.'</span>, ';}$arr[]=$s;}if($sender==='bluescreen'){$arr[]='Report generated at '.@date('Y/m/d H:i:s',Debug::$time);if(isset($_SERVER['HTTP_HOST'],$_SERVER['REQUEST_URI'])){$url=(isset($_SERVER['HTTPS'])&&strcasecmp($_SERVER['HTTPS'],'off')?'https://':'http://').htmlSpecialChars($_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);$arr[]='<a href="'.$url.'">'.$url.'</a>';}$arr[]='PHP '.htmlSpecialChars(PHP_VERSION);if(isset($_SERVER['SERVER_SOFTWARE']))$arr[]=htmlSpecialChars($_SERVER['SERVER_SOFTWARE']);$arr[]=htmlSpecialChars(Framework::NAME.' '.Framework::VERSION).' <i>(revision '.htmlSpecialChars(Framework::REVISION).')</i>';}return$arr;}public
static
function
fireDump($var,$key){self::fireSend(2,array((string)$key=>$var));return$var;}public
static
function
fireLog($message,$priority=self::LOG,$label=NULL){if($message
instanceof
Exception){if($priority!==self::EXCEPTION&&$priority!==self::TRACE){$priority=self::TRACE;}$message=array('Class'=>get_class($message),'Message'=>$message->getMessage(),'File'=>$message->getFile(),'Line'=>$message->getLine(),'Trace'=>$message->getTrace(),'Type'=>'','Function'=>'');foreach($message['Trace']as&$row){if(empty($row['file']))$row['file']='?';if(empty($row['line']))$row['line']='?';}}elseif($priority===self::GROUP_START){$label=$message;$message=NULL;}return
self::fireSend(1,self::replaceObjects(array(array('Type'=>$priority,'Label'=>$label),$message)));}private
static
function
fireSend($index,$payload){if(self::$productionMode)return
NULL;if(headers_sent())return
FALSE;header('X-Wf-Protocol-nette: http://meta.wildfirehq.org/Protocol/JsonStream/0.2');header('X-Wf-nette-Plugin-1: http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0');if($index===1){header('X-Wf-nette-Structure-1: http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');}elseif($index===2){header('X-Wf-nette-Structure-2: http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1');}$payload=json_encode($payload);static$counter;foreach(str_split($payload,4990)as$s){$num=++$counter;header("X-Wf-nette-$index-1-n$num: |$s|\\");}header("X-Wf-nette-$index-1-n$num: |$s|");return
TRUE;}static
private
function
replaceObjects($val){if(is_object($val)){return'object '.get_class($val).'';}elseif(is_string($val)){return@iconv('UTF-16','UTF-8//IGNORE',iconv('UTF-8','UTF-16//IGNORE',$val));}elseif(is_array($val)){foreach($val
as$k=>$v){unset($val[$k]);$k=@iconv('UTF-16','UTF-8//IGNORE',iconv('UTF-8','UTF-16//IGNORE',$k));$val[$k]=self::replaceObjects($v);}}return$val;}}Debug::init();

View File

@@ -1,62 +0,0 @@
The Nette License, Version 1
============================
Copyright (c) 2004, 2008 David Grudl (http://davidgrudl.com)
All rights reserved.
This license is a legal agreement between you and David Grudl (the "Author")
for the use of Nette Framework (the "Software"). By obtaining, using and/or
copying the Software, you agree that you have read, understood, and will
comply with the terms and conditions of this license.
PERMITTED USE
-------------
You are permitted to use, copy, modify, and distribute the Software and its
documentation, with or without modification, for any purpose, provided that
the following conditions are met:
1. A copy of this license agreement must be included with the distribution.
2. Redistributions of source code must retain the above copyright notice in
all source code files.
3. Redistributions in binary form must reproduce the above copyright notice
in the documentation and/or other materials provided with the distribution.
4. Products derived from the Software must include an acknowledgment that
they are derived from Nette Framework in their documentation and/or other
materials provided with the distribution.
5. The name "Nette Framework" must not be used to endorse or promote products
derived from the Software without prior written permission from Author.
6. Products derived from the Software may not be called "Nette Framework",
nor may "Nette" appear in their name, without prior written
permission from Author.
INDEMNITY
---------
You agree to indemnify and hold harmless the Author and any contributors
for any direct, indirect, incidental, or consequential third-party claims,
actions or suits, as well as any related expenses, liabilities, damages,
settlements or fees arising from your use or misuse of the Software,
or a violation of any terms of this license.
DISCLAIMER OF WARRANTY
----------------------
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "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 HOLDER 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.

View File

@@ -1 +0,0 @@
Disallow: /

View File

@@ -1,3 +0,0 @@
This file is part of Nette Framework
For more information please see http://nettephp.com

View File

@@ -1,31 +0,0 @@
<h1>dibi apply limit/offset example</h1>
<pre>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
// no limit
dibi::test('SELECT * FROM [products]');
// -> SELECT * FROM [products]
echo '<hr>';
// with limit = 2
dibi::test('SELECT * FROM [products] %lmt', 2);
// -> SELECT * FROM [products] LIMIT 2
echo '<hr>';
// with limit = 2, offset = 1
dibi::test('SELECT * FROM [products] %lmt %ofs', 2, 1);
// -> SELECT * FROM [products] LIMIT 2 OFFSET 1

View File

@@ -1,145 +0,0 @@
<h1>dibi::connect() example</h1>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
// connects to SQlite
echo '<p>Connecting to Sqlite: ';
try {
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to MySQL using DSN
echo '<p>Connecting to MySQL: ';
try {
dibi::connect('driver=mysql&host=localhost&username=root&password=xxx&database=test&charset=utf8');
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to MySQLi using array
echo '<p>Connecting to MySQL: ';
try {
dibi::connect(array(
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => 'xxx',
'database' => 'dibi',
'charset' => 'utf8',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to ODBC
echo '<p>Connecting to ODBC: ';
try {
dibi::connect(array(
'driver' => 'odbc',
'username' => 'root',
'password' => '***',
'dsn' => 'Driver={Microsoft Access Driver (*.mdb)};Dbq='.dirname(__FILE__).'/sample.mdb',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to PostgreSql
echo '<p>Connecting to PostgreSql: ';
try {
dibi::connect(array(
'driver' => 'postgre',
'string' => 'host=localhost port=5432 dbname=mary',
'persistent' => TRUE,
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to PDO
echo '<p>Connecting to Sqlite via PDO: ';
try {
dibi::connect(array(
'driver' => 'pdo',
'dsn' => 'sqlite2::memory:',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to MS SQL
echo '<p>Connecting to MS SQL: ';
try {
dibi::connect(array(
'driver' => 'mssql',
'host' => 'localhost',
'username' => 'root',
'password' => 'xxx',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to Oracle
echo '<p>Connecting to Oracle: ';
try {
dibi::connect(array(
'driver' => 'oracle',
'username' => 'root',
'password' => 'xxx',
'database' => 'db',
));
echo 'OK';
} catch (DibiException $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";

View File

@@ -0,0 +1,139 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Connecting to Databases | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
// connects to SQlite using Dibi class
echo '<p>Connecting to Sqlite: ';
try {
dibi::connect([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
echo 'OK';
} catch (Dibi\Exception $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to SQlite using Dibi\Connection object
echo '<p>Connecting to Sqlite: ';
try {
$connection = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
echo 'OK';
} catch (Dibi\Exception $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to MySQLi
echo '<p>Connecting to MySQLi: ';
try {
dibi::connect([
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => 'xxx',
'database' => 'dibi',
'options' => [
MYSQLI_OPT_CONNECT_TIMEOUT => 30,
],
'flags' => MYSQLI_CLIENT_COMPRESS,
]);
echo 'OK';
} catch (Dibi\Exception $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to ODBC
echo '<p>Connecting to ODBC: ';
try {
dibi::connect([
'driver' => 'odbc',
'username' => 'root',
'password' => '***',
'dsn' => 'Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=' . __DIR__ . '/data/sample.mdb',
]);
echo 'OK';
} catch (Dibi\Exception $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to PostgreSql
echo '<p>Connecting to PostgreSql: ';
try {
dibi::connect([
'driver' => 'postgre',
'string' => 'host=localhost port=5432 dbname=mary',
'persistent' => true,
]);
echo 'OK';
} catch (Dibi\Exception $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to PDO
echo '<p>Connecting to Sqlite via PDO: ';
try {
dibi::connect([
'driver' => 'pdo',
'dsn' => 'sqlite::memory:',
]);
echo 'OK';
} catch (Dibi\Exception $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to SQLSRV
echo '<p>Connecting to Microsoft SQL Server: ';
try {
dibi::connect([
'driver' => 'sqlsrv',
'host' => '(local)',
'username' => 'Administrator',
'password' => 'xxx',
'database' => 'main',
]);
echo 'OK';
} catch (Dibi\Exception $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to Oracle
echo '<p>Connecting to Oracle: ';
try {
dibi::connect([
'driver' => 'oracle',
'username' => 'root',
'password' => 'xxx',
'database' => 'db',
]);
echo 'OK';
} catch (Dibi\Exception $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";

BIN
examples/data/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 300 B

64
examples/data/style.css Normal file
View File

@@ -0,0 +1,64 @@
body {
font: 15px/1.5 Tahoma, Verdana, Myriad Web, Syntax, sans-serif;
color: #333;
background: #fff url('dibi-powered.gif') no-repeat 99% 1em;
margin: 1.6em;
padding: 0;
}
h1, h2 {
font-size: 210%;
font-weight: normal;
color: #036;
}
h2 {
font-size: 150%;
}
a {
color: #000080;
}
table.dump {
padding: 0;
margin: 0;
border-collapse:collapse;
}
table.dump td, table.dump th {
color: #505767;
background: #fff;
border: 1px solid #d1cdab;
padding: 6px 6px 6px 12px;
text-align: left;
}
table.dump th {
font-size: 80%;
color: #525b37;
background: #e3e9ba;
}
/* dump() */
pre.tracy-dump, pre.dump {
color: #444; background: white;
border: 1px solid silver;
padding: 1em;
margin: 1em 0;
}
pre.tracy-dump .php-array, pre.tracy-dump .php-object {
color: #C22;
}
pre.tracy-dump .php-string {
color: #080;
}
pre.tracy-dump .php-int, pre.tracy-dump .php-float {
color: #37D;
}
pre.tracy-dump .php-null, pre.tracy-dump .php-bool {
color: black;
}
pre.tracy-dump .php-visibility {
font-size: 85%; color: #999;
}

View File

@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Database Reflection | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
// retrieve database reflection
$database = $dibi->getDatabaseInfo();
echo "<h2>Database '{$database->getName()}'</h2>\n";
echo "<ul>\n";
foreach ($database->getTables() as $table) {
echo '<li>', ($table->isView() ? 'view' : 'table') . " {$table->getName()}</li>\n";
}
echo "</ul>\n";
// table reflection
$table = $database->getTable('products');
echo "<h2>Table '{$table->getName()}'</h2>\n";
echo "Columns\n";
echo "<ul>\n";
foreach ($table->getColumns() as $column) {
echo "<li>{$column->getName()} <i>{$column->getNativeType()}</i> <code>{$column->getDefault()}</code></li>\n";
}
echo "</ul>\n";
echo 'Indexes';
echo "<ul>\n";
foreach ($table->getIndexes() as $index) {
echo "<li>{$index->getName()} " . ($index->isPrimary() ? 'primary ' : '') . ($index->isUnique() ? 'unique' : '') . ' (';
foreach ($index->getColumns() as $column) {
echo $column->getName(), ', ';
}
echo ")</li>\n";
}
echo "</ul>\n";

View File

@@ -1,28 +0,0 @@
<h1>IDibiVariable example</h1>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
// CHANGE TO REAL PARAMETERS!
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
'formatDate' => "'Y-m-d'",
'formatDateTime' => "'Y-m-d H-i-s'",
));
// generate and dump SQL
dibi::test("
INSERT INTO [mytable]", array(
'id' => 123,
'date' => dibi::date('12.3.2007'),
'stamp' => dibi::dateTime('23.1.2007 10:23'),
));
// -> INSERT INTO [mytable] ([id], [date], [stamp]) VALUES (123, '2007-03-12', '2007-01-23 10-23-00')

View File

@@ -1,33 +0,0 @@
<h1>dibi dump example</h1>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
$res = dibi::query('
SELECT * FROM [products]
INNER JOIN [orders] USING ([product_id])
INNER JOIN [customers] USING ([customer_id])
');
echo '<h2>dibi::dump()</h2>';
// dump last query (dibi::$sql)
dibi::dump();
// -> SELECT * FROM [products] INNER JOIN [orders] USING ([product_id]) INNER JOIN [customers] USING ([customer_id])
// dump result table
echo '<h2>DibiResult::dump()</h2>';
$res->dump();
// -> [table]

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Dumping SQL and Result Set | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
$res = $dibi->query('
SELECT * FROM products
INNER JOIN orders USING (product_id)
INNER JOIN customers USING (customer_id)
');
echo '<h2>dibi::dump()</h2>';
// dump last query (dibi::$sql)
dibi::dump();
// dump result table
echo '<h2>Dibi\Result::dump()</h2>';
$res->dump();

View File

@@ -1,28 +0,0 @@
<h1>dibi extension method example</h1>
<pre>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
// using the "prototype" to add custom method to class DibiResult
function DibiResult_prototype_fetchShuffle(DibiResult $obj)
{
$all = $obj->fetchAll();
shuffle($all);
return $all;
}
// fetch complete result set shuffled
$res = dibi::query('SELECT * FROM [customers]');
$all = $res->fetchShuffle();
Debug::dump($all);

View File

@@ -1,94 +0,0 @@
<h1>dibi fetch example</h1>
<pre>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
/*
TABLE products
product_id | title
-----------+----------
1 | Chair
2 | Table
3 | Computer
*/
// fetch a single row
$row = dibi::fetch('SELECT title FROM [products]');
Debug::dump($row); // Chair
echo '<hr>';
// fetch a single value
$value = dibi::fetchSingle('SELECT [title] FROM [products]');
Debug::dump($value); // Chair
echo '<hr>';
// fetch complete result set
$all = dibi::fetchAll('SELECT * FROM [products]');
Debug::dump($all);
echo '<hr>';
// fetch complete result set like association array
$res = dibi::query('SELECT * FROM [products]');
$assoc = $res->fetchAssoc('title'); // key
Debug::dump($assoc);
echo '<hr>';
// fetch complete result set like pairs key => value
$pairs = $res->fetchPairs('product_id', 'title');
Debug::dump($pairs);
echo '<hr>';
// fetch row by row
foreach ($res as $n => $row) {
Debug::dump($row);
}
echo '<hr>';
// fetch row by row with defined offset
foreach ($res->getIterator(2) as $n => $row) {
Debug::dump($row);
}
// fetch row by row with defined offset and limit
foreach ($res->getIterator(2, 1) as $n => $row) {
Debug::dump($row);
}
// more complex association array
$res = dibi::query('
SELECT *
FROM [products]
INNER JOIN [orders] USING ([product_id])
INNER JOIN [customers] USING ([customer_id])
');
$assoc = $res->fetchAssoc('customers.name,products.title'); // key
Debug::dump($assoc);
echo '<hr>';
$assoc = $res->fetchAssoc('customers.name,#,products.title'); // key
Debug::dump($assoc);
echo '<hr>';
$assoc = $res->fetchAssoc('customers.name,=,products.title'); // key
Debug::dump($assoc);
echo '<hr>';

View File

@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install dependencies using `composer install --dev`');
}
Tracy\Debugger::enable();
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Fetching Examples | Dibi</h1>
<?php
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
/*
TABLE products
product_id | title
-----------+----------
1 | Chair
2 | Table
3 | Computer
*/
// fetch a single row
echo "<h2>fetch()</h2>\n";
$row = $dibi->fetch('SELECT title FROM products');
Tracy\Dumper::dump($row); // Chair
// fetch a single value
echo "<h2>fetchSingle()</h2>\n";
$value = $dibi->fetchSingle('SELECT title FROM products');
Tracy\Dumper::dump($value); // Chair
// fetch complete result set
echo "<h2>fetchAll()</h2>\n";
$all = $dibi->fetchAll('SELECT * FROM products');
Tracy\Dumper::dump($all);
// fetch complete result set like association array
echo "<h2>fetchAssoc('title')</h2>\n";
$res = $dibi->query('SELECT * FROM products');
$assoc = $res->fetchAssoc('title'); // key
Tracy\Dumper::dump($assoc);
// fetch complete result set like pairs key => value
echo "<h2>fetchPairs('product_id', 'title')</h2>\n";
$res = $dibi->query('SELECT * FROM products');
$pairs = $res->fetchPairs('product_id', 'title');
Tracy\Dumper::dump($pairs);
// fetch row by row
echo "<h2>using foreach</h2>\n";
$res = $dibi->query('SELECT * FROM products');
foreach ($res as $n => $row) {
Tracy\Dumper::dump($row);
}
// more complex association array
$res = $dibi->query('
SELECT *
FROM products
INNER JOIN orders USING (product_id)
INNER JOIN customers USING (customer_id)
');
echo "<h2>fetchAssoc('name|title')</h2>\n";
$assoc = $res->fetchAssoc('name|title'); // key
Tracy\Dumper::dump($assoc);
echo "<h2>fetchAssoc('name[]title')</h2>\n";
$res = $dibi->query('SELECT * FROM products INNER JOIN orders USING (product_id) INNER JOIN customers USING (customer_id)');
$assoc = $res->fetchAssoc('name[]title'); // key
Tracy\Dumper::dump($assoc);
echo "<h2>fetchAssoc('name->title')</h2>\n";
$res = $dibi->query('SELECT * FROM products INNER JOIN orders USING (product_id) INNER JOIN customers USING (customer_id)');
$assoc = $res->fetchAssoc('name->title'); // key
Tracy\Dumper::dump($assoc);

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Importing SQL Dump from File | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
$count = $dibi->loadFile('compress.zlib://data/sample.dump.sql.gz');
echo 'Number of SQL commands:', $count;

View File

@@ -1,17 +0,0 @@
<h1>dibi import SQL dump example</h1>
<pre>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
$count = dibi::loadFile('compress.zlib://sample.dump.sql.gz');
echo 'Number of SQL commands:', $count;

View File

@@ -1,36 +0,0 @@
<h1>dibi logger example</h1>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
'profiler' => TRUE,
));
// enable log to this file
dibi::getProfiler()->setFile('log.sql');
try {
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] = %i', 1);
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] < %i', 5);
$res = dibi::query('SELECT FROM [customers] WHERE [customer_id] < %i', 38);
} catch (DibiException $e) {
echo '<p>', get_class($e), ': ', $e->getMessage(), '</p>';
}
echo "<h2>File log.sql:</h2>";
echo '<pre>', file_get_contents('log.sql'), '</pre>';

View File

@@ -1,30 +0,0 @@
<h1>dibi metatypes example</h1>
<pre>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
$res = dibi::query('SELECT * FROM [customers]');
// auto-converts this column to integer
$res->setType('customer_id', Dibi::INTEGER);
$res->setType('added', Dibi::DATETIME, 'H:i j.n.Y');
$row = $res->fetch();
Debug::dump($row);
// outputs:
// object(DibiRow)#3 (3) {
// customer_id => int(1)
// name => string(11) "Dave Lister"
// added => string(15) "17:20 11.3.2007"
// }

View File

@@ -1,28 +0,0 @@
<h1>Nette\Debug & dibi example</h1>
<p>Dibi can display and log exceptions via Nette\Debug, part of Nette Framework.</p>
<ul>
<li>Nette Framework: http://nettephp.com
</ul>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
// enable Nette\Debug
Debug::enable();
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
// throws error
dibi::query('SELECT FROM [customers] WHERE [customer_id] < %i', 38);

View File

@@ -1,28 +0,0 @@
<h1>Nette\Debug & dibi example 2</h1>
<p>Dibi can dump variables via Nette\Debug, part of Nette Framework.</p>
<ul>
<li>Nette Framework: http://nettephp.com
</ul>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
// enable Nette\Debug
Debug::enable();
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
// throws error
Debug::consoleDump( dibi::fetchAll('SELECT * FROM [customers] WHERE [customer_id] < %i', 38), '[customers]' );

View File

@@ -1,36 +0,0 @@
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
'profiler' => TRUE,
));
for ($i=0; $i<20; $i++) {
$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] < %i', $i);
}
?>
<h1>Dibi profiler example</h1>
<p>Last query: <strong><?php echo dibi::$sql; ?></strong></p>
<p>Number of queries: <strong><?php echo dibi::$numOfQueries; ?></strong></p>
<p>Elapsed time for last query: <strong><?php echo sprintf('%0.3f', dibi::$elapsedTime * 1000); ?> ms</strong></p>
<p>Total elapsed time: <strong><?php echo sprintf('%0.3f', dibi::$totalTime * 1000); ?> ms</strong></p>
<br>
<p>Dibi can log to your Firebug Console. You first need to install the Firefox, Firebug and FirePHP extensions. You can install them from here:</p>
<ul>
<li>Firebug: https://addons.mozilla.org/en-US/firefox/addon/1843
<li>FirePHP: http://www.firephp.org/
</ul>

View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Query Language & Conditions | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
// some variables
$cond1 = true;
$cond2 = false;
$foo = -1;
$bar = 2;
// conditional variable
$name = $cond1 ? 'K%' : null;
// if & end
$dibi->test('
SELECT *
FROM customers
%if', isset($name), 'WHERE name LIKE ?', $name, '%end',
);
// -> SELECT * FROM customers WHERE name LIKE 'K%'
// if & else & (optional) end
$dibi->test('
SELECT *
FROM people
WHERE id > 0
%if', ($foo > 0), 'AND foo=?', $foo, '
%else %if', ($bar > 0), 'AND bar=?', $bar, '
');
// -> SELECT * FROM people WHERE id > 0 AND bar=2
// nested condition
$dibi->test('
SELECT *
FROM customers
WHERE
%if', isset($name), 'name LIKE ?', $name, '
%if', $cond2, 'AND admin=1 %end
%else 1 LIMIT 10 %end',
);
// -> SELECT * FROM customers WHERE LIMIT 10
// IF()
$dibi->test('UPDATE products SET', [
'price' => $dibi->expression('IF(price_fixed, price, ?)', 123),
]);
// -> SELECT * FROM customers WHERE LIMIT 10

View File

@@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Query Language Basic Examples | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
date_default_timezone_set('Europe/Prague');
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
// SELECT
$ipMask = '192.168.%';
$timestamp = mktime(0, 0, 0, 10, 13, 1997);
$dibi->test('
SELECT COUNT(*) as [count]
FROM [comments]
WHERE [ip] LIKE ?', $ipMask, '
AND [date] > ', new Dibi\DateTime($timestamp),
);
// -> SELECT COUNT(*) as [count] FROM [comments] WHERE [ip] LIKE '192.168.%' AND [date] > 876693600
// dibi detects INSERT or REPLACE command
$dibi->test('
REPLACE INTO products', [
'title' => 'Super product',
'price' => 318,
'active' => true,
]);
// -> REPLACE INTO products ([title], [price], [active]) VALUES ('Super product', 318, 1)
// multiple INSERT command
$array = [
'title' => 'Super Product',
'price' => 12,
'brand' => null,
'created' => new DateTime,
];
$dibi->test('INSERT INTO products', $array, $array, $array);
// -> INSERT INTO products ([title], [price], [brand], [created]) VALUES ('Super Product', ...) , (...) , (...)
// dibi detects UPDATE command
$dibi->test('
UPDATE colors SET', [
'color' => 'blue',
'order' => 12,
], '
WHERE id=?', 123);
// -> UPDATE colors SET [color]='blue', [order]=12 WHERE id=123
// modifier applied to array
$array = [1, 2, 3];
$dibi->test('
SELECT *
FROM people
WHERE id IN (?)', $array,
);
// -> SELECT * FROM people WHERE id IN ( 1, 2, 3 )
// modifier %by for ORDER BY
$order = [
'field1' => 'asc',
'field2' => 'desc',
];
$dibi->test('
SELECT *
FROM people
ORDER BY %by', $order, '
');
// -> SELECT * FROM people ORDER BY [field1] ASC, [field2] DESC
// indentifiers and strings syntax mix
$dibi->test('UPDATE [table] SET `item` = "5 1/4"" diskette"');
// -> UPDATE [table] SET [item] = '5 1/4" diskette'

View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
use Dibi\Type;
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install dependencies using `composer install --dev`');
}
Tracy\Debugger::enable();
date_default_timezone_set('Europe/Prague');
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Result Set Data Types | Dibi</h1>
<?php
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
// using manual hints
$res = $dibi->query('SELECT * FROM [customers]');
$res->setType('customer_id', Type::Integer)
->setType('added', Type::DateTime)
->setFormat(Type::DateTime, 'Y-m-d H:i:s');
Tracy\Dumper::dump($res->fetch());
// outputs:
// Dibi\Row(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)
$res = $dibi->query('SELECT * FROM [customers]');
Tracy\Dumper::dump($res->fetch());
// outputs:
// Dibi\Row(3) {
// customer_id => 1
// name => "Dave Lister" (11)
// added => "2007-03-11 17:20:03" (19)

View File

@@ -1,89 +0,0 @@
<style>
pre.dibi { padding-bottom: 10px; }
</style>
<h1>dibi SQL builder example</h1>
<pre>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
date_default_timezone_set('Europe/Prague');
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
// dibi detects INSERT or REPLACE command
dibi::test('
REPLACE INTO [products]', array(
'title' => 'Super product',
'price' => 318,
'active' => TRUE,
));
// -> REPLACE INTO [products] ([title], [price], [active]) VALUES ('Super product', 318, 1)
// multiple INSERT command
$array = array(
'title' => 'Super Product',
'price' => 12,
'brand' => NULL,
'created' => dibi::datetime(),
);
dibi::test("INSERT INTO [products]", $array, $array, $array);
// -> INSERT INTO [products] ([title], [price], [brand], [created]) VALUES ('Super Product', ...) , (...) , (...)
// dibi detects UPDATE command
dibi::test("
UPDATE [colors] SET", array(
'color' => 'blue',
'order' => 12,
), "
WHERE [id]=%i", 123);
// -> UPDATE [colors] SET [color]='blue', [order]=12 WHERE [id]=123
// SELECT
$ipMask = '192.168.%';
$timestamp = mktime(0, 0, 0, 10, 13, 1997);
dibi::test('
SELECT COUNT(*) as [count]
FROM [comments]
WHERE [ip] LIKE %s', $ipMask, '
AND [date] > ', dibi::date($timestamp)
);
// -> SELECT COUNT(*) as [count] FROM [comments] WHERE [ip] LIKE '192.168.%' AND [date] > 876693600
// IN array
$array = array(1, 2, 3);
dibi::test("
SELECT *
FROM [people]
WHERE [id] IN (", $array, ")
");
// -> SELECT * FROM [people] WHERE [id] IN ( 1, 2, 3 )
// ORDER BY array
$order = array(
'field1' => 'asc',
'field2' => 'desc',
);
dibi::test("
SELECT *
FROM [people]
ORDER BY %by", $order, "
");
// -> SELECT * FROM [people] ORDER BY [field1] ASC, [field2] DESC

View File

@@ -1,58 +0,0 @@
<style>
pre.dibi { padding-bottom: 10px; }
</style>
<h1>dibi conditional SQL example</h1>
<pre>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
$cond1 = TRUE;
$cond2 = FALSE;
$foo = -1;
$bar = 2;
$name = $cond1 ? 'K%' : NULL;
// if & end
dibi::test('
SELECT *
FROM [customers]
%if', isset($name), 'WHERE [name] LIKE %s', $name, '%end'
);
// -> SELECT * FROM [customers] WHERE [name] LIKE 'K%'
// if & else & (optional) end
dibi::test("
SELECT *
FROM [people]
WHERE [id] > 0
%if", ($foo > 0), "AND [foo]=%i", $foo, "
%else %if", ($bar > 0), "AND [bar]=%i", $bar, "
");
// -> SELECT * FROM [people] WHERE [id] > 0 AND [bar]=2
// nested condition
dibi::test('
SELECT *
FROM [customers]
WHERE
%if', isset($name), '[name] LIKE %s', $name, '
%if', $cond2, 'AND [admin]=1 %end
%else 1 LIMIT 10 %end'
);
// -> SELECT * FROM [customers] WHERE LIMIT 10

View File

@@ -1,49 +0,0 @@
<h1>dibi prefix & substitute example</h1>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
// create new substitution :blog: ==> wp_
dibi::addSubst('blog', 'wp_');
dibi::test("UPDATE :blog:items SET [text]='Hello World'");
// -> UPDATE wp_items SET [text]='Hello World'
// create new substitution :: (empty) ==> my_
dibi::addSubst('', 'my_');
dibi::test("UPDATE [database.::table] SET [text]='Hello World'");
// -> UPDATE [database].[my_table] SET [text]='Hello World'
// create substitution fallback
function substFallBack($expr)
{
if (defined($expr)) {
return constant($expr);
} else {
return 'the_' . $expr;
}
}
dibi::setSubstFallBack('substFallBack');
dibi::test("UPDATE [:account:user] SET [name]='John Doe', [active]=:true:");
// -> UPDATE [the_accountuser] SET [name]='John Doe', [active]=1

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install dependencies using `composer install --dev`');
}
// enable Tracy
Tracy\Debugger::enable();
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
// add panel to debug bar
$panel = new Dibi\Bridges\Tracy\Panel;
$panel->register($dibi);
// throws error because SQL is bad
$dibi->query('SELECT FROM customers WHERE customer_id < ?', 38);
?><!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Tracy & SQL Exceptions | dibi</h1>
<p>Dibi can display and log exceptions via <a href="https://tracy.nette.org">Tracy</a>.</p>

38
examples/tracy.php Normal file
View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install dependencies using `composer install --dev`');
}
// enable Tracy
Tracy\Debugger::enable();
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
// add panel to debug bar
$panel = new Dibi\Bridges\Tracy\Panel;
$panel->register($dibi);
// query will be logged
$dibi->query('SELECT 123');
// result set will be dumped
Tracy\Debugger::barDump($dibi->fetchAll('SELECT * FROM customers WHERE customer_id < ?', 38), '[customers]');
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<style> html { background: url(data/arrow.png) no-repeat bottom right; height: 100%; } </style>
<h1>Tracy | dibi</h1>
<p>Dibi can log queries and dump variables to the <a href="https://tracy.nette.org">Tracy</a>.</p>

View File

@@ -1,30 +0,0 @@
<h1>dibi transaction example</h1>
<pre>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
echo "<h2>Before:</h2>\n";
dibi::query('SELECT * FROM [products]')->dump();
// -> 3 rows
dibi::begin();
dibi::query('INSERT INTO [products]', array(
'title' => 'Test product',
));
dibi::rollback(); // or dibi::commit();
echo "<h2>After:</h2>\n";
dibi::query('SELECT * FROM [products]')->dump();
// -> 3 rows

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using DateTime | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
date_default_timezone_set('Europe/Prague');
// CHANGE TO REAL PARAMETERS!
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
'formatDate' => "'Y-m-d'",
'formatDateTime' => "'Y-m-d H-i-s'",
]);
// generate and dump SQL
$dibi->test('
INSERT INTO [mytable]', [
'id' => 123,
'date' => new DateTime('12.3.2007'),
'stamp' => new DateTime('23.1.2007 10:23'),
],
);
// -> INSERT INTO [mytable] ([id], [date], [stamp]) VALUES (123, '2007-03-12', '2007-01-23 10-23-00')

View File

@@ -1,27 +1,34 @@
<h1>dibi dump example</h1>
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Fluent Syntax | Dibi</h1>
<?php
require_once 'Nette/Debug.php';
require_once '../dibi/dibi.php';
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
date_default_timezone_set('Europe/Prague');
dibi::connect(array(
'driver' => 'sqlite',
'database' => 'sample.sdb',
));
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
$id = 10;
$record = array(
'title' => 'Super product',
'price' => 318,
'active' => TRUE,
);
$record = [
'title' => 'Super product',
'price' => 318,
'active' => true,
];
// SELECT ...
dibi::select('product_id')->as('id')
$dibi->select('product_id')->as('id')
->select('title')
->from('products')
->innerJoin('orders')->using('(product_id)')
@@ -32,62 +39,44 @@ dibi::select('product_id')->as('id')
// USING (product_id) INNER JOIN customers USING (customer_id) ORDER BY [title]
echo "\n";
// SELECT ...
echo dibi::select('title')->as('id')
echo $dibi->select('title')->as('id')
->from('products')
->fetchSingle();
// -> Chair (as result of query: SELECT [title] AS [id] FROM [products])
echo "\n";
// INSERT ...
dibi::insert('products', $record)
$dibi->insert('products', $record)
->setFlag('IGNORE')
->test();
// -> INSERT IGNORE INTO [products] ([title], [price], [active]) VALUES ('Super product', 318, 1)
echo "\n";
// UPDATE ...
dibi::update('products', $record)
->where('product_id = %d', $id)
$dibi->update('products', $record)
->where('product_id = ?', $id)
->test();
// -> UPDATE [products] SET [title]='Super product', [price]=318, [active]=1 WHERE product_id = 10
echo "\n";
// DELETE ...
dibi::delete('products')
->where('product_id = %d', $id)
$dibi->delete('products')
->where('product_id = ?', $id)
->test();
// -> DELETE FROM [products] WHERE product_id = 10
echo "\n";
// custom commands
dibi::command()
$dibi->command()
->update('products')
->where('product_id = %d', $id)
->where('product_id = ?', $id)
->set($record)
->test();
// -> UPDATE [products] SET [title]='Super product', [price]=318, [active]=1 WHERE product_id = 10
echo "\n";
dibi::command()
$dibi->command()
->truncate('products')
->test();
// -> TRUNCATE [products]

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Limit & Offset | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
// no limit
$dibi->test('SELECT * FROM [products]');
// -> SELECT * FROM [products]
// with limit = 2
$dibi->test('SELECT * FROM [products] %lmt', 2);
// -> SELECT * FROM [products] LIMIT 2
// with limit = 2, offset = 1
$dibi->test('SELECT * FROM [products] %lmt %ofs', 2, 1);
// -> SELECT * FROM [products] LIMIT 2 OFFSET 1

42
examples/using-logger.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Logger | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
date_default_timezone_set('Europe/Prague');
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
// enable query logging to this file
'profiler' => [
'file' => 'log/log.sql',
'errorsOnly' => false,
],
]);
try {
$res = $dibi->query('SELECT * FROM [customers] WHERE [customer_id] = ?', 1);
$res = $dibi->query('SELECT * FROM [customers] WHERE [customer_id] < ?', 5);
$res = $dibi->query('SELECT FROM [customers] WHERE [customer_id] < ?', 38);
} catch (Dibi\Exception $e) {
echo '<p>', get_class($e), ': ', $e->getMessage(), '</p>';
}
// outputs a log file
echo '<h2>File log/log.sql:</h2>';
echo '<pre>', file_get_contents('log/log.sql'), '</pre>';

View File

@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Substitutions | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
// create new substitution :blog: ==> wp_
$dibi->getSubstitutes()->blog = 'wp_';
$dibi->test('SELECT * FROM [:blog:items]');
// -> SELECT * FROM [wp_items]
// create new substitution :: (empty) ==> my_
$dibi->getSubstitutes()->{''} = 'my_';
$dibi->test("UPDATE ::table SET [text]='Hello World'");
// -> UPDATE my_table SET [text]='Hello World'
// create substitutions using fallback callback
function substFallBack($expr)
{
$const = 'SUBST_' . strtoupper($expr);
if (defined($const)) {
return constant($const);
} else {
throw new Exception("Undefined substitution :$expr:");
}
}
// define callback
$dibi->getSubstitutes()->setCallback(substFallBack(...));
// define substitutes as constants
define('SUBST_ACCOUNT', 'eshop_');
define('SUBST_ACTIVE', 7);
$dibi->test("
UPDATE :account:user
SET name='John Doe', status=:active:
WHERE id=", 7,
);
// -> UPDATE eshop_user SET name='John Doe', status=7 WHERE id= 7

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
?>
<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
<h1>Using Transactions | Dibi</h1>
<?php
if (@!include __DIR__ . '/../vendor/autoload.php') {
die('Install packages using `composer install`');
}
$dibi = new Dibi\Connection([
'driver' => 'sqlite',
'database' => 'data/sample.s3db',
]);
echo "<h2>Before</h2>\n";
$dibi->query('SELECT * FROM [products]')->dump();
// -> 3 rows
$dibi->begin();
$dibi->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
echo "<h2>After INSERT</h2>\n";
$dibi->query('SELECT * FROM [products]')->dump();
$dibi->rollback(); // or $dibi->commit();
echo "<h2>After rollback</h2>\n";
$dibi->query('SELECT * FROM [products]')->dump();
// -> 3 rows again

View File

@@ -1,16 +0,0 @@
<style>
h1 {
font-family: Trebuchet MS,"Geneva CE", lucida, sans-serif;
color: #1e5eb6;
}
img {
border: none;
}
</style>
<h1>Icon for your website</h1>
<a href="http://dibiphp.com" title="dibi - tiny 'n' smart database abstraction layer"
><img src="dibi-powered.gif" width="80" height="15" alt="dibi powered" /></a>

View File

@@ -1,69 +0,0 @@
----------------------------------------------------------------------------------
Tento text je NEOFICI<43>LN<4C>M p<>ekladem "Dibi license". Nevyjad<61>uje pr<70>vn<76> podstatu
podm<EFBFBD>nek pro <20><><EFBFBD>en<65> tohoto softwaru - k tomuto <20><>elu slou<6F><75> v<>hradn<64> p<>vodn<64>
anglick<EFBFBD> verze licence.
----------------------------------------------------------------------------------
Dibi Licence, verze 1
======================
Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
V<EFBFBD>echna pr<70>va vyhrazena.
Tato licence je pr<70>vn<76> ujedn<64>n<EFBFBD> mezi v<>mi a Davidem Grudlem (d<>le Author)
pro pot<6F>eby pou<6F>it<69> "dibi" (d<>le "Software"). Z<>sk<73>n<EFBFBD>m, pou<6F>it<69>m
a/nebo zkop<6F>rov<6F>n<EFBFBD>m Software projevujete souhlas s t<>m, <20>e jste p<>e<EFBFBD>etli,
porozum<EFBFBD>li a budete jednat v souladu s podm<64>nkami t<>to licence.
POVOLEN<EFBFBD> POU<4F>IT<49>
----------------
Je povoleno pou<6F><75>vat, kop<6F>rovat, modifikovat a distribuovat Software
a jeho dokumentaci, v p<>vodn<64>m i upravovan<61>m tvaru, pro jak<61>koliv <20><>el,
za p<>edpokladu, <20>e jsou spln<6C>ny tyto podm<64>nky:
1. Kopie t<>to licen<65>n<EFBFBD> smlouvy mus<75> b<>t sou<6F><75>st<73> distribuce.
2. <20><><EFBFBD>en<65> zdrojov<6F> k<>d mus<75> zachovat v<><76>e uvedenou informaci o autorsk<73>ch
pr<70>vech ve v<>ech souborech zdrojov<6F>ho k<>du.
3. <20><><EFBFBD>en<65> bin<69>rn<72> tvar mus<75> reprodukovat v<><76>e uvedenou informaci o autorsk<73>ch
pr<70>vech v dokumentaci a/nebo jin<69>ch materi<72>lech poskytovan<61>ch s distribuc<75>.
4. Produkty odvozen<65> od Software mus<75> obsahovat potvrzen<65>, <20>e jsou odvozen<65>
od "dibi", ve sv<73> dokumentaci a/nebo jin<69>ch materi<72>lech
poskytovan<61>ch s distribuc<75>.
5. N<>zev "dibi" nesm<73> b<>t pou<6F>it p<>i podpo<70>e nebo propagaci produkt<6B>
odvozen<65>mi ze Software bez p<>edchoz<6F>ho p<>semn<6D>ho souhlasu Autora.
6. Produkty odvozen<65> od Software nesm<73> b<>t nazv<7A>ny "dibi",
ani se nesm<73> "dibi" objevit v jejich n<>zvu bez p<>edchoz<6F>ho
p<>semn<6D>ho souhlasu Autora.
ZBAVEN<EFBFBD> ZODPOV<4F>DNOSTI
---------------------
Souhlas<EFBFBD>te se zbaven<65>m zodpov<6F>dnosti a kryt<79>m Autora a p<>isp<73>vatel<65> v<><76>i
jak<EFBFBD>mkoliv p<><70>m<EFBFBD>m, nep<65><70>m<EFBFBD>m, n<>hodn<64>m nebo n<>sledn<64>m odjinud poch<63>zej<65>c<EFBFBD>m <20>kod<6F>m,
<EFBFBD>alob<EFBFBD>m nebo spor<6F>m, jako<6B> i p<>ed v<>emi souvisej<65>c<EFBFBD>mi n<>klady, z<>vazky,
od<EFBFBD>kodn<EFBFBD>n<EFBFBD>mi, <20>hradami nebo poplatky vypl<70>vaj<61>c<EFBFBD>ch z pou<6F><75>v<EFBFBD>n<EFBFBD> nebo
nespr<EFBFBD>vn<EFBFBD>ho u<>it<69> Software, nebo z poru<72>en<65> podm<64>nek t<>to licence.
Z<EFBFBD>RUKA SE NEPOSKYTUJE
---------------------
TENTO SOFTWARE JE POSKYTOV<4F>N DR<44>ITELEM LICENCE A JEHO P<>ISP<53>VATELI "JAK STOJ<4F> A LE<4C><45>"
A JAK<41>KOLIV V<>SLOVN<56> NEBO P<>EDPOKL<4B>DAN<41> Z<>RUKY V<>ETN<54>, ALE NEJEN, P<>EDPOKL<4B>DAN<41>CH
OBCHODN<EFBFBD>CH Z<>RUK A Z<>RUKY VHODNOSTI PRO JAK<41>KOLIV <20><>EL JSOU POP<4F>ENY.
DR<EFBFBD>ITEL, ANI P<>ISP<53>VATEL<45> NEBUDOU V <20><>DN<44>M P<><50>PAD<41> ODPOV<4F>DNI ZA JAK<41>KOLIV P<><50>M<EFBFBD>,
NEP<EFBFBD><EFBFBD>M<EFBFBD>, N<>HODN<44>, ZVL<56><4C>TN<54>, P<><50>KLADN<44> NEBO VYPL<50>VAJ<41>C<EFBFBD> <20>KODY (V<>ETN<54>, ALE NEJEN,
<EFBFBD>KOD VZNIKL<4B>CH NARU<52>EN<45>M DOD<4F>VEK ZBO<42><4F> NEBO SLU<4C>EB; ZTR<54>TOU POU<4F>ITELNOSTI,
DAT NEBO ZISK<53>; NEBO P<>ERU<52>EN<45>M OBCHODN<44> <20>INNOSTI) JAKKOLIV ZP<5A>SOBEN<45> NA Z<>KLAD<41>
JAK<EFBFBD>KOLIV TEORIE O ZODPOV<4F>DNOSTI, A<> U<> PLYNOUC<55> Z JIN<49>HO SMLUVN<56>HO VZTAHU,
UR<EFBFBD>IT<EFBFBD> ZODPOV<4F>DNOSTI NEBO P<>E<EFBFBD>INU (V<>ETN<54> NEDBALOSTI) NA JAK<41>MKOLIV ZP<5A>SOBU POU<4F>IT<49>
TOHOTO SOFTWARE, I V P<><50>PAD<41>, <20>E DR<44>ITEL PR<50>V BYL UPOZORN<52>N NA MO<4D>NOST TAKOV<4F>CH <20>KOD.

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, 2014 David Grudl (https://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,62 +0,0 @@
The Dibi License, Version 1
============================
Copyright (c) 2005, 2008 David Grudl (http://davidgrudl.com)
All rights reserved.
This license is a legal agreement between you and David Grudl (the "Author")
for the use of "dibi" (the "Software"). By obtaining, using and/or
copying the Software, you agree that you have read, understood, and will
comply with the terms and conditions of this license.
PERMITTED USE
-------------
You are permitted to use, copy, modify, and distribute the Software and its
documentation, with or without modification, for any purpose, provided that
the following conditions are met:
1. A copy of this license agreement must be included with the distribution.
2. Redistributions of source code must retain the above copyright notice in
all source code files.
3. Redistributions in binary form must reproduce the above copyright notice
in the documentation and/or other materials provided with the distribution.
4. Products derived from the Software must include an acknowledgment that
they are derived from "dibi" in their documentation and/or other
materials provided with the distribution.
5. The name "dibi" must not be used to endorse or promote products
derived from the Software without prior written permission from Author.
6. Products derived from the Software may not be called "dibi",
nor may "dibi" appear in their name, without prior written
permission from Author.
INDEMNITY
---------
You agree to indemnify and hold harmless the Author and any contributors
for any direct, indirect, incidental, or consequential third-party claims,
actions or suits, as well as any related expenses, liabilities, damages,
settlements or fees arising from your use or misuse of the Software,
or a violation of any terms of this license.
DISCLAIMER OF WARRANTY
----------------------
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "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 HOLDER 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.

9
phpstan.neon Normal file
View File

@@ -0,0 +1,9 @@
parameters:
level: 5
paths:
- src
ignoreErrors:
# The namespace is referenced, not the class.
- '#Class dibi referenced with incorrect case: Dibi#'

664
readme.md Normal file
View File

@@ -0,0 +1,664 @@
[Dibi](https://dibiphp.com) - smart database layer for PHP [![Buy me a coffee](https://files.nette.org/images/coffee1s.png)](https://nette.org/make-donation?to=dibi)
=========================================================
[![Downloads this Month](https://img.shields.io/packagist/dm/dibi/dibi.svg)](https://packagist.org/packages/dibi/dibi)
[![Tests](https://github.com/dg/dibi/workflows/Tests/badge.svg?branch=master)](https://github.com/dg/dibi/actions)
[![Build Status Windows](https://ci.appveyor.com/api/projects/status/github/dg/dibi?branch=master&svg=true)](https://ci.appveyor.com/project/dg/dibi/branch/master)
[![Latest Stable Version](https://poser.pugx.org/dibi/dibi/v/stable)](https://github.com/dg/dibi/releases)
[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/dg/dibi/blob/master/license.md)
Introduction
------------
Database access functions in PHP are not standardised. This library
hides the differences between them, and above all, it gives you a very handy interface.
Support Me
----------
Do you like Dibi? Are you looking forward to the new features?
[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)
Thank you!
Installation
------------
Install Dibi via Composer:
```bash
composer require dibi/dibi
```
The Dibi 6.0 requires PHP version 8.2 and supports PHP up to 8.5.
Usage
-----
Refer to the `examples` directory for examples. Dibi documentation is
available on the [homepage](https://dibiphp.com).
### Connecting to database
The database connection is represented by the object `Dibi\Connection`:
```php
$database = new Dibi\Connection([
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'table',
]);
$result = $database->query('SELECT * FROM users');
```
Alternatively, you can use the `dibi` static register, which maintains a connection object in a globally available storage and calls all the functions above it:
```php
dibi::connect([
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'test',
'charset' => 'utf8',
]);
$result = dibi::query('SELECT * FROM users');
```
In the event of a connection error, it throws `Dibi\Exception`.
### Queries
We query the database queries by the method `query()` which returns `Dibi\Result`. Rows are objects `Dibi\Row`.
You can try all the examples [online at the playground](https://repl.it/@DavidGrudl/dibi-playground).
```php
$result = $database->query('SELECT * FROM users');
foreach ($result as $row) {
echo $row->id;
echo $row->name;
}
// array of all rows
$all = $result->fetchAll();
// array of all rows, key is 'id'
$all = $result->fetchAssoc('id');
// associative pairs id => name
$pairs = $result->fetchPairs('id', 'name');
// the number of rows of the result, if known, or number of affected rows
$count = $result->getRowCount();
```
Method fetchAssoc() can return a more complex associative array.
You can easily add parameters to the query, note the question mark:
```php
$result = $database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active);
// or
$result = $database->query('SELECT * FROM users WHERE name = ?', $name, 'AND active = ?', $active););
$ids = [10, 20, 30];
$result = $database->query('SELECT * FROM users WHERE id IN (?)', $ids);
```
**WARNING: Never concatenate parameters to SQL. It would create a [SQL injection](https://en.wikipedia.org/wiki/SQL_injection)** vulnerability.
```
$result = $database->query('SELECT * FROM users WHERE id = ' . $id); // BAD!!!
```
Instead of a question mark, so-called modifiers can be used.
```php
$result = $database->query('SELECT * FROM users WHERE name = %s', $name);
```
In case of failure `query()` throws `Dibi\Exception`, or one of the descendants:
- `ConstraintViolationException` - violation of a table constraint
- `ForeignKeyConstraintViolationException` - invalid foreign key
- `NotNullConstraintViolationException` - violation of the NOT NULL condition
- `UniqueConstraintViolationException` - collides unique index
You can use also shortcuts:
```php
// returns associative pairs id => name, shortcut for query(...)->fetchPairs()
$pairs = $database->fetchPairs('SELECT id, name FROM users');
// returns array of all rows, shortcut for query(...)->fetchAll()
$rows = $database->fetchAll('SELECT * FROM users');
// returns row, shortcut for query(...)->fetch()
$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id);
// returns field, shortcut for query(...)->fetchSingle()
$name = $database->fetchSingle('SELECT name FROM users WHERE id = ?', $id);
```
### Modifiers
In addition to the `?` wildcard char, we can also use modifiers:
| modifier | description
|----------|-----
| %s | string
| %sN | string, but '' translates as NULL
| %bin | binary data
| %b | boolean
| %i | integer
| %iN | integer, but 0 is translates as NULL
| %f | float
| %d | date (accepts DateTime, string or UNIX timestamp)
| %dt | datetime (accepts DateTime, string or UNIX timestamp)
| %n | identifier, ie the name of the table or column
| %N | identifier, treats period as a common character, ie alias or a database name (`%n AS %N` or `DROP DATABASE %N`)
| %SQL | SQL - directly inserts into SQL (the alternative is Dibi\Literal)
| %ex | SQL expression or array of expressions
| %lmt | special - adds LIMIT to the query
| %ofs | special - adds OFFSET to the query
Example:
```php
$result = $database->query('SELECT * FROM users WHERE name = %s', $name);
```
If $name is null, the NULL is inserted into the SQL statement.
If the variable is an array, the modifier is applied to all of its elements and they are inserted into SQL separated by commas:
```php
$ids = [10, '20', 30];
$result = $database->query('SELECT * FROM users WHERE id IN (%i)', $ids);
// SELECT * FROM users WHERE id IN (10, 20, 30)
```
The modifier `%n` is used if the table or column name is a variable. (Beware, do not allow the user to manipulate the content of such a variable):
```php
$table = 'blog.users';
$column = 'name';
$result = $database->query('SELECT * FROM %n WHERE %n = ?', $table, $column, $value);
// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim'
```
Three special modifiers are available for LIKE:
| modifier | description
|----------|-----
| `%like~` | the expression starts with a string
| `%~like` | the expression ends with a string
| `%~like~` | the expression contains a string
| `%like` | the expression matches a string
Search for names beginning with a string:
```php
$result = $database->query('SELECT * FROM table WHERE name LIKE %like~', $query);
```
### Modifiers for arrays
The parameter entered in the SQL query can also be an array. These modifiers determine how to compile the SQL statement:
| modifier | | result
|----------|---|-----
| %and | | `key1 = value1 AND key2 = value2 AND ...`
| %or | | `key1 = value1 OR key2 = value2 OR ...`
| %a | assoc | `key1 = value1, key2 = value2, ...`
| %l %in | list | `(val1, val2, ...)`
| %v | values | `(key1, key2, ...) VALUES (value1, value2, ...)`
| %m | multi | `(key1, key2, ...) VALUES (value1, value2, ...), (value1, value2, ...), ...`
| %by | ordering | `key1 ASC, key2 DESC ...`
| %n | names | `key1, key2 AS alias, ...`
Example:
```php
$arr = [
'a' => 'hello',
'b' => true,
];
$database->query('INSERT INTO table %v', $arr);
// INSERT INTO `table` (`a`, `b`) VALUES ('hello', 1)
$database->query('UPDATE `table` SET %a', $arr);
// UPDATE `table` SET `a`='hello', `b`=1
```
In the WHERE clause modifiers `%and` nebo `%or` can be used:
```php
$result = $database->query('SELECT * FROM users WHERE %and', [
'name' => $name,
'year' => $year,
]);
// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978
```
The modifier `%by` is used to sort, the keys show the columns, and the boolean value will determine whether to sort in ascending order:
```php
$result = $database->query('SELECT id FROM author ORDER BY %by', [
'id' => true, // ascending
'name' => false, // descending
]);
// SELECT id FROM author ORDER BY `id`, `name` DESC
```
### Insert, Update & Delete
We insert the data into an SQL query as an associative array. Modifiers and wildcards `?` are not required in these cases.
```php
$database->query('INSERT INTO users', [
'name' => $name,
'year' => $year,
]);
// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978)
$id = $database->getInsertId(); // returns the auto-increment of the inserted record
$id = $database->getInsertId($sequence); // or sequence value
```
Multiple INSERT:
```php
$database->query('INSERT INTO users', [
'name' => 'Jim',
'year' => 1978,
], [
'name' => 'Jack',
'year' => 1987,
]);
// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987)
```
Deleting:
```php
$database->query('DELETE FROM users WHERE id = ?', $id);
// returns the number of deleted rows
$affectedRows = $database->getAffectedRows();
```
Update:
```php
$database->query('UPDATE users SET', [
'name' => $name,
'year' => $year,
], 'WHERE id = ?', $id);
// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123
// returns the number of updated rows
$affectedRows = $database->getAffectedRows();
```
Insert an entry or update if it already exists:
```php
$database->query('INSERT INTO users', [
'id' => $id,
'name' => $name,
'year' => $year,
], 'ON DUPLICATE KEY UPDATE %a', [ // here the modifier %a must be used
'name' => $name,
'year' => $year,
]);
// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978)
// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978
```
### Transaction
There are three methods for dealing with transactions:
```php
$database->begin();
$database->commit();
$database->rollback();
```
### Testing
In order to play with Dibi a little, there is a `test()` method that you pass parameters like to `query()`, but instead of executing the SQL statement, it is echoed on the screen.
The query results can be echoed as a table using `$result->dump()`.
These variables are also available:
```php
dibi::$sql; // the latest SQL query
dibi::$elapsedTime; // its duration in sec
dibi::$numOfQueries;
dibi::$totalTime;
```
### Complex queries
The parameter may also be an object `DateTime`.
```php
$result = $database->query('SELECT * FROM users WHERE created < ?', new DateTime);
$database->query('INSERT INTO users', [
'created' => new DateTime,
]);
```
Or SQL literal:
```php
$database->query('UPDATE table SET', [
'date' => $database->literal('NOW()'),
]);
// UPDATE table SET `date` = NOW()
```
Or an expression in which you can use `?` or modifiers:
```php
$database->query('UPDATE `table` SET', [
'title' => $database::expression('SHA1(?)', 'secret'),
]);
// UPDATE `table` SET `title` = SHA1('secret')
```
When updating, modifiers can be placed directly in the keys:
```php
$database->query('UPDATE table SET', [
'date%SQL' => 'NOW()', // %SQL means SQL ;)
]);
// UPDATE table SET `date` = NOW()
```
In conditions (ie, for `%and` and `%or` modifiers), it is not necessary to specify the keys:
```php
$result = $database->query('SELECT * FROM `table` WHERE %and', [
'number > 10',
'number < 100',
]);
// SELECT * FROM `table` WHERE (number > 10) AND (number < 100)
```
Modifiers or wildcards can also be used in expressions:
```php
$result = $database->query('SELECT * FROM `table` WHERE %and', [
['number > ?', 10], // or $database::expression('number > ?', 10)
['number < ?', 100],
['%or', [
'left' => 1,
'top' => 2,
]],
]);
// SELECT * FROM `table` WHERE (number > 10) AND (number < 100) AND (`left` = 1 OR `top` = 2)
```
The `%ex` modifier inserts all items of the array into SQL:
```php
$result = $database->query('SELECT * FROM `table` WHERE %ex', [
$database::expression('left = ?', 1),
'AND',
'top IS NULL',
]);
// SELECT * FROM `table` WHERE left = 1 AND top IS NULL
```
### Conditions in the SQL
Conditional SQL commands are controlled by three modifiers `%if`, `%else`, and `%end`. The `%if` must be at the end of the string representing SQL and is followed by the variable:
```php
$user = ???
$result = $database->query('
SELECT *
FROM table
%if', isset($user), 'WHERE user=%s', $user, '%end
ORDER BY name
');
```
The condition can be supplemented by the section `%else`:
```php
$result = $database->query('
SELECT *
FROM %if', $cond, 'one_table %else second_table
');
```
Conditions can nest together.
### Identifiers and strings in SQL
SQL itself goes through processing to meet the conventions of the database. The identifiers (names of tables and columns) can be entered into square brackets or backticks, strings are quoted with single or double quotation marks, but the server always sends what the database asks for. Example:
```php
$database->query("UPDATE `table` SET [status]='I''m fine'");
// MySQL: UPDATE `table` SET `status`='I\'m fine'
// ODBC: UPDATE [table] SET [status]='I''m fine'
```
The quotation marks are duplicated inside the string in SQL.
### Result as associative array
Example: returns results as an associative field, where the key will be the value of the `id` field:
```php
$assoc = $result->fetchAssoc('id');
```
The greatest power of `fetchAssoc()` is reflected in a SQL query joining several tables with different types of joins. The database will make a flat table, fetchAssoc returns the shape.
Example: Let's take a customer and order table (N:M binding) and query:
```php
$result = $database->query('
SELECT customer_id, customers.name, order_id, orders.number, ...
FROM customers
INNER JOIN orders USING (customer_id)
WHERE ...
');
```
And we'd like to get a nested associative array by Customer ID and then Order ID:
```php
$all = $result->fetchAssoc('customer_id|order_id');
// we will iterate like this:
foreach ($all as $customerId => $orders) {
foreach ($orders as $orderId => $order) {
...
}
}
```
An associative descriptor has a similar syntax as when you type the array by assigning it to PHP. Thus `'customer_id|order_id'` represents the assignment series `$all[$customerId][$orderId] = $row;` sequentially for all rows.
Sometimes it would be useful to associate by the customer's name instead of his ID:
```php
$all = $result->fetchAssoc('name|order_id');
// the elements then proceeds like this:
$order = $all['Arnold Rimmer'][$orderId];
```
But what if there are more customers with the same name? The table should be in the form of:
```php
$row = $all['Arnold Rimmer'][0][$orderId];
$row = $all['Arnold Rimmer'][1][$orderId];
...
```
So we can distinguish between multiple possible Rimmers using an array. The associative descriptor has a format similar to the assignment, with the sequence array representing `[]`:
```php
$all = $result->fetchAssoc('name[]order_id');
// we get all the Arnolds in the results
foreach ($all['Arnold Rimmer'] as $arnoldOrders) {
foreach ($arnoldOrders as $orderId => $order) {
...
}
}
```
Returning to the example with the `customer_id|order_id` descriptor, we will try to list the orders of each customer:
```php
$all = $result->fetchAssoc('customer_id|order_id');
foreach ($all as $customerId => $orders) {
echo "Customer $customerId":
foreach ($orders as $orderId => $order) {
echo "ID number: $order->number";
// customer name is in $order->name
}
}
```
It would be a nice to echo customer name too. But we would have to look for it in the `$orders` array. So let's adjust the results to such a shape:
```php
$all[$customerId]->name = 'John Doe';
$all[$customerId]->order_id[$orderId] = $row;
$all[$customerId]->order_id[$orderId2] = $row2;
```
So, between `$clientId` and `$orderId`, we will also insert an intermediate item. This time not the numbered indexes as we used to distinguish between individual Rimmers, but a database row. The solution is very similar, just remember that the row symbolizes the arrow:
```php
$all = $result->fetchAssoc('customer_id->order_id');
foreach ($all as $customerId => $row) {
echo "Customer $row->name":
foreach ($row->order_id as $orderId => $order) {
echo "ID number: $order->number";
}
}
```
### Prefixes & substitutions
Table and column names can contain variable parts. You will first define:
```php
// create new substitution :blog: ==> wp_
$database->substitute('blog', 'wp_');
```
and then use it in SQL. Note that in SQL they are quoted by the colon:
```php
$database->query("UPDATE [:blog:items] SET [text]='Hello World'");
// UPDATE `wp_items` SET `text`='Hello World'
```
### Field data types
Dibi automatically detects the types of query columns and converts fields them to native PHP types. We can also specify the type manually. You can find the possible types in the `Dibi\Type` class.
```php
$result->setType('id', Dibi\Type::Integer); // id will be integer
$row = $result->fetch();
is_int($row->id) // true
```
### Logger
Dibi has a built-in logger that lets you track all SQL statements executed and measure the length of their duration. Activating the logger:
```php
$database->connect([
'driver' => 'sqlite',
'database' => 'sample.sdb',
'profiler' => [
'file' => 'file.log',
],
]);
```
A more versatile profiler is a Tracy panel that is activated when connected to Nette.
### Connect to [Nette](https://nette.org)
In the configuration file, we will register the DI extensions and add the `dibi` section to create the required objects and also the database panel in the [Tracy](https://tracy.nette.org) debugger bar.
```neon
extensions:
dibi: Dibi\Bridges\Nette\DibiExtension3
dibi:
host: localhost
username: root
password: ***
database: foo
lazy: true
```
Then the object of connection can be [obtained as a service from the container DI](https://doc.nette.org/di-usage), eg:
```php
class Model
{
private $database;
public function __construct(Dibi\Connection $database)
{
$this->database = $database;
}
}
```

View File

@@ -1,41 +0,0 @@
Dibi (c) David Grudl, 2005-2009 (http://davidgrudl.com)
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.
The files in this archive are released under the Dibi license.
See license.txt in this directory for a copy of the license.
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

@@ -0,0 +1,75 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi\Bridges\Nette;
use Dibi;
use Nette;
use Tracy;
/**
* Dibi extension for Nette Framework 2.2. Creates 'connection' & 'panel' services.
*/
class DibiExtension22 extends Nette\DI\CompilerExtension
{
public function __construct(
private ?bool $debugMode = null,
private ?bool $cliMode = null,
) {
}
public function loadConfiguration()
{
$container = $this->getContainerBuilder();
$config = $this->getConfig();
if ($this->debugMode === null) {
$this->debugMode = $container->parameters['debugMode'];
}
if ($this->cliMode === null) {
$this->cliMode = $container->parameters['consoleMode'];
}
$useProfiler = $config['profiler'] ?? (class_exists(Tracy\Debugger::class) && $this->debugMode && !$this->cliMode);
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'))
->setFactory(Dibi\Connection::class, [$config])
->setAutowired($config['autowired'] ?? true);
if (class_exists(Tracy\Debugger::class)) {
$connection->addSetup(
[new Nette\DI\Statement('Tracy\Debugger::getBlueScreen'), 'addPanel'],
[[Dibi\Bridges\Tracy\Panel::class, 'renderException']],
);
}
if ($useProfiler) {
$panel = $container->addDefinition($this->prefix('panel'))
->setFactory(Dibi\Bridges\Tracy\Panel::class, [
$config['explain'] ?? true,
isset($config['filter']) && $config['filter'] === false ? Dibi\Event::ALL : Dibi\Event::QUERY,
]);
$connection->addSetup([$panel, 'register'], [$connection]);
}
}
}

View File

@@ -0,0 +1,93 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi\Bridges\Nette;
use Dibi;
use Nette;
use Nette\Schema\Expect;
use Tracy;
use function is_array;
/**
* Dibi extension for Nette Framework 3. Creates 'connection' & 'panel' services.
*/
class DibiExtension3 extends Nette\DI\CompilerExtension
{
public function __construct(
private ?bool $debugMode = null,
private ?bool $cliMode = null,
) {
}
public function getConfigSchema(): Nette\Schema\Schema
{
return Expect::structure([
'autowired' => Expect::bool(true),
'flags' => Expect::anyOf(Expect::arrayOf('string'), Expect::type('dynamic')),
'profiler' => Expect::bool(),
'explain' => Expect::bool(true),
'filter' => Expect::bool(true),
'driver' => Expect::string()->dynamic(),
'name' => Expect::string()->dynamic(),
'lazy' => Expect::bool(false)->dynamic(),
'onConnect' => Expect::array()->dynamic(),
'substitutes' => Expect::arrayOf('string')->dynamic(),
'result' => Expect::structure([
'normalize' => Expect::bool(true),
'formatDateTime' => Expect::string(),
'formatTimeInterval' => Expect::string(),
'formatJson' => Expect::string(),
])->castTo('array'),
])->otherItems(Expect::type('mixed'))
->castTo('array');
}
public function loadConfiguration()
{
$container = $this->getContainerBuilder();
$config = $this->getConfig();
$this->debugMode ??= $container->parameters['debugMode'];
$this->cliMode ??= $container->parameters['consoleMode'];
$useProfiler = $config['profiler'] ?? (class_exists(Tracy\Debugger::class) && $this->debugMode && !$this->cliMode);
unset($config['profiler']);
if (is_array($config['flags'])) {
$flags = 0;
foreach ((array) $config['flags'] as $flag) {
$flags |= constant($flag);
}
$config['flags'] = $flags;
}
$connection = $container->addDefinition($this->prefix('connection'))
->setCreator(Dibi\Connection::class, [$config])
->setAutowired($config['autowired']);
if (class_exists(Tracy\Debugger::class)) {
$connection->addSetup(
[new Nette\DI\Definitions\Statement('Tracy\Debugger::getBlueScreen'), 'addPanel'],
[[Dibi\Bridges\Tracy\Panel::class, 'renderException']],
);
}
if ($useProfiler) {
$panel = $container->addDefinition($this->prefix('panel'))
->setCreator(Dibi\Bridges\Tracy\Panel::class, [
$config['explain'],
$config['filter'] ? Dibi\Event::QUERY : Dibi\Event::ALL,
]);
$connection->addSetup([$panel, 'register'], [$connection]);
}
}
}

View File

@@ -0,0 +1,12 @@
# This will create service named 'dibi.connection'.
# Requires Nette Framework 3 or later
extensions:
dibi: Dibi\Bridges\Nette\DibiExtension3
dibi:
host: localhost
username: root
password: ***
database: foo
lazy: true

View File

@@ -0,0 +1,172 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi\Bridges\Tracy;
use Dibi;
use Dibi\Event;
use Dibi\Helpers;
use Tracy;
use function count, is_string, strlen;
/**
* Dibi panel for Tracy.
*/
class Panel implements Tracy\IBarPanel
{
public static int $maxLength = 1000;
private array $events = [];
public function __construct(
public bool|string $explain = true,
public int $filter = Event::QUERY,
) {
}
public function register(Dibi\Connection $connection): void
{
Tracy\Debugger::getBar()->addPanel($this);
Tracy\Debugger::getBlueScreen()->addPanel(self::renderException(...));
$connection->onEvent[] = $this->logEvent(...);
}
/**
* After event notification.
*/
public function logEvent(Event $event): void
{
if (($event->type & $this->filter) === 0) {
return;
}
$this->events[] = $event;
}
/**
* Returns blue-screen custom tab.
*/
public static function renderException(?\Throwable $e): ?array
{
if ($e instanceof Dibi\Exception && $e->getSql()) {
return [
'tab' => 'SQL',
'panel' => Helpers::dump($e->getSql(), return: true),
];
}
return null;
}
/**
* Returns HTML code for custom tab. (Tracy\IBarPanel)
*/
public function getTab(): string
{
$totalTime = 0;
$count = count($this->events);
foreach ($this->events as $event) {
$totalTime += $event->time;
}
return '<span title="dibi"><svg viewBox="0 0 2048 2048" style="vertical-align: bottom; width:1.23em; height:1.55em"><path fill="' . ($count ? '#b079d6' : '#aaa') . '" d="M1024 896q237 0 443-43t325-127v170q0 69-103 128t-280 93.5-385 34.5-385-34.5-280-93.5-103-128v-170q119 84 325 127t443 43zm0 768q237 0 443-43t325-127v170q0 69-103 128t-280 93.5-385 34.5-385-34.5-280-93.5-103-128v-170q119 84 325 127t443 43zm0-384q237 0 443-43t325-127v170q0 69-103 128t-280 93.5-385 34.5-385-34.5-280-93.5-103-128v-170q119 84 325 127t443 43zm0-1152q208 0 385 34.5t280 93.5 103 128v128q0 69-103 128t-280 93.5-385 34.5-385-34.5-280-93.5-103-128v-128q0-69 103-128t280-93.5 385-34.5z"/></svg><span class="tracy-label">'
. $count . "\u{a0}queries"
. ($totalTime ? ' / ' . number_format($totalTime * 1000, 1, '.', "\u{202f}") . "\u{202f}ms" : '')
. '</span></span>';
}
/**
* Returns HTML code for custom panel. (Tracy\IBarPanel)
*/
public function getPanel(): ?string
{
if (!$this->events) {
return null;
}
$totalTime = $s = null;
$singleConnection = reset($this->events)->connection;
foreach ($this->events as $event) {
if ($event->connection !== $singleConnection) {
$singleConnection = null;
break;
}
}
foreach ($this->events as $event) {
$totalTime += $event->time;
$connection = $event->connection;
$explain = null; // EXPLAIN is called here to work SELECT FOUND_ROWS()
if ($this->explain && $event->type === Event::SELECT) {
$backup = [$connection->onEvent, \dibi::$numOfQueries, \dibi::$totalTime];
$connection->onEvent = null;
$cmd = is_string($this->explain)
? $this->explain
: ($connection->getConfig('driver') === 'oracle' ? 'EXPLAIN PLAN FOR' : 'EXPLAIN');
try {
$explain = @Helpers::dump($connection->nativeQuery("$cmd $event->sql"), return: true);
} catch (Dibi\Exception $e) {
}
[$connection->onEvent, \dibi::$numOfQueries, \dibi::$totalTime] = $backup;
}
$s .= '<tr><td data-order="' . $event->time . '">' . number_format($event->time * 1000, 3, '.', "\u{202f}");
if ($explain) {
static $counter;
$counter++;
$s .= "<br /><a href='#tracy-debug-DibiProfiler-row-$counter' class='tracy-toggle tracy-collapsed' rel='#tracy-debug-DibiProfiler-row-$counter'>explain</a>";
}
$s .= '</td><td class="tracy-DibiProfiler-sql">' . Helpers::dump(strlen($event->sql) > self::$maxLength ? substr($event->sql, 0, self::$maxLength) . '...' : $event->sql, return: true);
if ($explain) {
$s .= "<div id='tracy-debug-DibiProfiler-row-$counter' class='tracy-collapsed'>{$explain}</div>";
}
if ($event->source) {
$s .= Tracy\Helpers::editorLink($event->source[0], $event->source[1]); //->class('tracy-DibiProfiler-source');
}
$s .= "</td><td>{$event->count}</td>";
if (!$singleConnection) {
$s .= '<td>' . htmlspecialchars($this->getConnectionName($connection)) . '</td></tr>';
}
}
return '<style> #tracy-debug td.tracy-DibiProfiler-sql { background: white !important }
#tracy-debug .tracy-DibiProfiler-source { color: #999 !important }
#tracy-debug tracy-DibiProfiler tr table { margin: 8px 0; max-height: 150px; overflow:auto } </style>
<h1>Queries:' . "\u{a0}" . count($this->events)
. ($totalTime === null ? '' : ", time:\u{a0}" . number_format($totalTime * 1000, 1, '.', "\u{202f}") . "\u{202f}ms")
. ($singleConnection === null ? '' : ', ' . htmlspecialchars($this->getConnectionName($singleConnection))) . '</h1>
<div class="tracy-inner tracy-DibiProfiler">
<table class="tracy-sortable">
<tr><th>Time&nbsp;ms</th><th>SQL Statement</th><th>Rows</th>' . (!$singleConnection ? '<th>Connection</th>' : '') . '</tr>
' . $s . '
</table>
</div>';
}
private function getConnectionName(Dibi\Connection $connection): string
{
$driver = $connection->getConfig('driver');
return get_debug_type($driver)
. ($connection->getConfig('name') ? '/' . $connection->getConfig('name') : '')
. ($connection->getConfig('host') ? "\u{202f}@\u{202f}" . $connection->getConfig('host') : '');
}
}

720
src/Dibi/Connection.php Normal file
View File

@@ -0,0 +1,720 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi;
use JetBrains\PhpStorm\Language;
use Traversable;
use function array_key_exists, is_array, sprintf;
use const PHP_SAPI;
/**
* Dibi connection.
*
* @property-read int $affectedRows
* @property-read int $insertId
*/
class Connection
{
private const Drivers = [
'firebird' => Drivers\Ibase\Connection::class,
'mysqli' => Drivers\MySQLi\Connection::class,
'odbc' => Drivers\ODBC\Connection::class,
'oracle' => Drivers\OCI8\Connection::class,
'pdo' => Drivers\PDO\Connection::class,
'postgre' => Drivers\PgSQL\Connection::class,
'sqlite3' => Drivers\SQLite3\Connection::class,
'sqlite' => Drivers\SQLite3\Connection::class,
'sqlsrv' => Drivers\SQLSrv\Connection::class,
];
/** function (Event $event); Occurs after query is executed */
public ?array $onEvent = [];
private array $config;
/** @var string[] resultset formats */
private array $formats;
private ?Drivers\Connection $driver = null;
private Drivers\Engine $engine;
private ?Translator $translator = null;
/** @var array<string, callable(object): Expression | null> */
private array $translators = [];
private bool $sortTranslators = false;
private HashMap $substitutes;
private int $transactionDepth = 0;
/**
* Connection options: (see driver-specific options too)
* - lazy (bool) => if true, connection will be established only when required
* - result (array) => result set options
* - normalize => normalizes result fields (default: true)
* - formatDateTime => date-time format
* empty for decoding as Dibi\DateTime (default)
* "..." formatted according to given format, see https://www.php.net/manual/en/datetime.format.php
* "native" for leaving value as is
* - formatTimeInterval => time-interval format
* empty for decoding as DateInterval (default)
* "..." formatted according to given format, see https://www.php.net/manual/en/dateinterval.format.php
* "native" for leaving value as is
* - formatJson => json format
* "array" for decoding json as an array (default)
* "object" for decoding json as \stdClass
* "native" for leaving value as is
* - profiler (array)
* - run (bool) => enable profiler?
* - file => file to log
* - errorsOnly (bool) => log only errors
* - substitutes (array) => map of driver specific substitutes (under development)
* - onConnect (array) => list of SQL queries to execute (by Connection::query()) after connection is established
* @throws Exception
*/
public function __construct(array $config, ?string $name = null)
{
Helpers::alias($config, 'username', 'user');
Helpers::alias($config, 'password', 'pass');
Helpers::alias($config, 'host', 'hostname');
Helpers::alias($config, 'result|formatDate', 'resultDate');
Helpers::alias($config, 'result|formatDateTime', 'resultDateTime');
$config['driver'] ??= 'mysqli';
$config['name'] = $name;
$this->config = $config;
$this->formats = [
Type::Date => $this->config['result']['formatDate'],
Type::DateTime => $this->config['result']['formatDateTime'],
Type::JSON => $this->config['result']['formatJson'] ?? 'array',
Type::TimeInterval => $this->config['result']['formatTimeInterval'] ?? null,
];
// profiler
if (isset($config['profiler']['file']) && (!isset($config['profiler']['run']) || $config['profiler']['run'])) {
$filter = $config['profiler']['filter'] ?? Event::QUERY;
$errorsOnly = $config['profiler']['errorsOnly'] ?? false;
$this->onEvent[] = [new Loggers\FileLogger($config['profiler']['file'], $filter, $errorsOnly), 'logEvent'];
}
$this->substitutes = new HashMap(fn(string $expr) => ":$expr:");
if (!empty($config['substitutes'])) {
foreach ($config['substitutes'] as $key => $value) {
$this->substitutes->$key = $value;
}
}
if (isset($config['onConnect']) && !is_array($config['onConnect'])) {
throw new \InvalidArgumentException("Configuration option 'onConnect' must be array.");
}
if (empty($config['lazy'])) {
$this->connect();
}
}
/**
* Automatically frees the resources allocated for this result set.
*/
public function __destruct()
{
if ($this->driver && $this->driver->getResource()) {
$this->disconnect();
}
}
/**
* Connects to a database.
*/
final public function connect(): void
{
if ($this->config['driver'] instanceof Drivers\Connection) {
$this->driver = $this->config['driver'];
$this->translator = new Translator($this);
return;
} elseif (is_subclass_of($this->config['driver'], Drivers\Connection::class)) {
$class = $this->config['driver'];
} else {
$class = self::Drivers[strtolower($this->config['driver'])] ?? throw new Exception("Unknown driver '{$this->config['driver']}'.");
if (!class_exists($class)) {
throw new Exception("Unable to create instance of Dibi driver '$class'.");
}
}
$event = $this->onEvent ? new Event($this, Event::CONNECT) : null;
try {
$this->driver = new $class($this->config);
$this->translator = new Translator($this);
if ($event) {
$this->onEvent($event->done());
}
if (isset($this->config['onConnect'])) {
foreach ($this->config['onConnect'] as $sql) {
$this->query($sql);
}
}
} catch (DriverException $e) {
if ($event) {
$this->onEvent($event->done($e));
}
throw $e;
}
}
/**
* Disconnects from a database.
*/
final public function disconnect(): void
{
if ($this->driver) {
$this->driver->disconnect();
$this->driver = $this->translator = null;
}
}
/**
* Returns true when connection was established.
*/
final public function isConnected(): bool
{
return (bool) $this->driver;
}
/**
* Returns configuration variable. If no $key is passed, returns the entire array.
* @see self::__construct
*/
final public function getConfig(?string $key = null, $default = null): mixed
{
return $key === null
? $this->config
: ($this->config[$key] ?? $default);
}
/**
* Returns the driver and connects to a database in lazy mode.
*/
final public function getDriver(): Drivers\Connection
{
if (!$this->driver) {
$this->connect();
}
return $this->driver;
}
/**
* Generates (translates) and executes SQL query.
* @throws Exception
*/
final public function query(#[Language('GenericSQL')] mixed ...$args): Result
{
return $this->nativeQuery($this->translate(...$args));
}
/**
* Generates SQL query.
* @throws Exception
*/
final public function translate(#[Language('GenericSQL')] mixed ...$args): string
{
if (!$this->driver) {
$this->connect();
}
return (clone $this->translator)->translate($args);
}
/**
* Generates and prints SQL query.
*/
final public function test(#[Language('GenericSQL')] mixed ...$args): bool
{
try {
Helpers::dump($this->translate(...$args));
return true;
} catch (Exception $e) {
if ($e->getSql()) {
Helpers::dump($e->getSql());
} else {
echo $e::class . ': ' . $e->getMessage() . (PHP_SAPI === 'cli' ? "\n" : '<br>');
}
return false;
}
}
/**
* Generates (translates) and returns SQL query as DataSource.
* @throws Exception
*/
final public function dataSource(#[Language('GenericSQL')] mixed ...$args): DataSource
{
return new DataSource($this->translate(...$args), $this);
}
/**
* Executes the SQL query.
* @throws Exception
*/
final public function nativeQuery(#[Language('SQL')] string $sql): Result
{
if (!$this->driver) {
$this->connect();
}
\dibi::$sql = $sql;
$event = $this->onEvent ? new Event($this, Event::QUERY, $sql) : null;
try {
$res = $this->driver->query($sql);
} catch (DriverException $e) {
if ($event) {
$this->onEvent($event->done($e));
}
throw $e;
}
$res = $this->createResultSet($res ?: new Drivers\Dummy\Result(max(0, $this->driver->getAffectedRows())));
if ($event) {
$this->onEvent($event->done($res));
}
return $res;
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @throws Exception
*/
public function getAffectedRows(): int
{
if (!$this->driver) {
$this->connect();
}
$rows = $this->driver->getAffectedRows();
if ($rows === null || $rows < 0) {
throw new Exception('Cannot retrieve number of affected rows.');
}
return $rows;
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @throws Exception
*/
public function getInsertId(?string $sequence = null): int
{
if (!$this->driver) {
$this->connect();
}
$id = $this->driver->getInsertId($sequence);
if ($id === null) {
throw new Exception('Cannot retrieve last generated ID.');
}
return $id;
}
/**
* Begins a transaction (if supported).
*/
public function begin(?string $savepoint = null): void
{
if ($this->transactionDepth !== 0) {
throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
}
if (!$this->driver) {
$this->connect();
}
$event = $this->onEvent ? new Event($this, Event::BEGIN, $savepoint) : null;
try {
$this->driver->begin($savepoint);
if ($event) {
$this->onEvent($event->done());
}
} catch (DriverException $e) {
if ($event) {
$this->onEvent($event->done($e));
}
throw $e;
}
}
/**
* Commits statements in a transaction.
*/
public function commit(?string $savepoint = null): void
{
if ($this->transactionDepth !== 0) {
throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
}
if (!$this->driver) {
$this->connect();
}
$event = $this->onEvent ? new Event($this, Event::COMMIT, $savepoint) : null;
try {
$this->driver->commit($savepoint);
if ($event) {
$this->onEvent($event->done());
}
} catch (DriverException $e) {
if ($event) {
$this->onEvent($event->done($e));
}
throw $e;
}
}
/**
* Rollback changes in a transaction.
*/
public function rollback(?string $savepoint = null): void
{
if ($this->transactionDepth !== 0) {
throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
}
if (!$this->driver) {
$this->connect();
}
$event = $this->onEvent ? new Event($this, Event::ROLLBACK, $savepoint) : null;
try {
$this->driver->rollback($savepoint);
if ($event) {
$this->onEvent($event->done());
}
} catch (DriverException $e) {
if ($event) {
$this->onEvent($event->done($e));
}
throw $e;
}
}
public function transaction(callable $callback): mixed
{
if ($this->transactionDepth === 0) {
$this->begin();
}
$this->transactionDepth++;
try {
$res = $callback($this);
} catch (\Throwable $e) {
$this->transactionDepth--;
if ($this->transactionDepth === 0) {
$this->rollback();
}
throw $e;
}
$this->transactionDepth--;
if ($this->transactionDepth === 0) {
$this->commit();
}
return $res;
}
/**
* Result set factory.
*/
public function createResultSet(Drivers\Result $resultDriver): Result
{
return (new Result($resultDriver, $this->config['result']['normalize'] ?? true))
->setFormats($this->formats);
}
/********************* fluent SQL builders ****************d*g**/
public function command(): Fluent
{
return new Fluent($this);
}
public function select(...$args): Fluent
{
return $this->command()->select(...$args);
}
/**
* @param string|string[] $table
*/
public function update($table, iterable $args): Fluent
{
return $this->command()->update('%n', $table)->set($args);
}
public function insert(string $table, iterable $args): Fluent
{
if ($args instanceof Traversable) {
$args = iterator_to_array($args);
}
return $this->command()->insert()
->into('%n', $table, '(%n)', array_keys($args))->values('%l', $args);
}
public function delete(string $table): Fluent
{
return $this->command()->delete()->from('%n', $table);
}
/********************* substitutions ****************d*g**/
/**
* Returns substitution hashmap.
*/
public function getSubstitutes(): HashMap
{
return $this->substitutes;
}
/**
* Provides substitution.
*/
public function substitute(string $value): string
{
return str_contains($value, ':')
? preg_replace_callback('#:([^:\s]*):#', fn(array $m) => $this->substitutes->{$m[1]}, $value)
: $value;
}
/********************* value objects translation ****************d*g**/
/**
* @param callable(object): Expression $translator
*/
public function setObjectTranslator(callable $translator): void
{
if (!$translator instanceof \Closure) {
$translator = \Closure::fromCallable($translator);
}
$param = (new \ReflectionFunction($translator))->getParameters()[0] ?? null;
$type = $param?->getType();
$types = match (true) {
$type instanceof \ReflectionNamedType => [$type],
$type instanceof \ReflectionUnionType => $type->getTypes(),
default => throw new Exception('Object translator must have exactly one parameter with class typehint.'),
};
foreach ($types as $type) {
if ($type->isBuiltin() || $type->allowsNull()) {
throw new Exception("Object translator must have exactly one parameter with non-nullable class typehint, got '$type'.");
}
$this->translators[$type->getName()] = $translator;
}
$this->sortTranslators = true;
}
public function translateObject(object $object): ?Expression
{
if ($this->sortTranslators) {
$this->translators = array_filter($this->translators);
uksort($this->translators, fn($a, $b) => is_subclass_of($a, $b) ? -1 : 1);
$this->sortTranslators = false;
}
if (!array_key_exists($object::class, $this->translators)) {
$translator = null;
foreach ($this->translators as $class => $t) {
if ($object instanceof $class) {
$translator = $t;
break;
}
}
$this->translators[$object::class] = $translator;
}
$translator = $this->translators[$object::class];
if ($translator === null) {
return null;
}
$result = $translator($object);
if (!$result instanceof Expression) {
throw new Exception(sprintf(
"Object translator for class '%s' returned '%s' but %s expected.",
$object::class,
get_debug_type($result),
Expression::class,
));
}
return $result;
}
/********************* shortcuts ****************d*g**/
/**
* Executes SQL query and fetch result - shortcut for query() & fetch().
* @throws Exception
*/
public function fetch(#[Language('GenericSQL')] mixed ...$args): ?Row
{
return $this->query($args)->fetch();
}
/**
* Executes SQL query and fetch results - shortcut for query() & fetchAll().
* @return Row[]|array[]
* @throws Exception
*/
public function fetchAll(#[Language('GenericSQL')] mixed ...$args): array
{
return $this->query($args)->fetchAll();
}
/**
* Executes SQL query and fetch first column - shortcut for query() & fetchSingle().
* @throws Exception
*/
public function fetchSingle(#[Language('GenericSQL')] mixed ...$args): mixed
{
return $this->query($args)->fetchSingle();
}
/**
* Executes SQL query and fetch pairs - shortcut for query() & fetchPairs().
* @throws Exception
*/
public function fetchPairs(#[Language('GenericSQL')] mixed ...$args): array
{
return $this->query($args)->fetchPairs();
}
public static function literal(string $value): Literal
{
return new Literal($value);
}
public static function expression(...$args): Expression
{
return new Expression(...$args);
}
/********************* misc ****************d*g**/
/**
* Import SQL dump from file.
* @param callable $onProgress function (int $count, ?float $percent): void
* @return int count of sql commands
*/
public function loadFile(string $file, ?callable $onProgress = null): int
{
return Helpers::loadFromFile($this, $file, $onProgress);
}
public function getDatabaseEngine(): Drivers\Engine
{
if (!$this->driver) { // TODO
$this->connect();
}
return $this->engine ??= $this->driver->getReflector();
}
/**
* Gets a information about the current database.
*/
public function getDatabaseInfo(): Reflection\Database
{
if (!$this->driver) {
$this->connect();
}
return new Reflection\Database($this->getDatabaseEngine(), $this->config['database'] ?? null);
}
/**
* Prevents unserialization.
*/
public function __unserialize($_)
{
throw new NotSupportedException('You cannot serialize or unserialize ' . static::class . ' instances.');
}
/**
* Prevents serialization.
*/
public function __serialize()
{
throw new NotSupportedException('You cannot serialize or unserialize ' . static::class . ' instances.');
}
protected function onEvent($arg): void
{
foreach ($this->onEvent as $handler) {
$handler($arg);
}
}
}

262
src/Dibi/DataSource.php Normal file
View File

@@ -0,0 +1,262 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi;
use function func_get_args, is_array, strpbrk;
/**
* Default implementation of IDataSource.
*/
class DataSource implements IDataSource
{
private readonly Connection $connection;
private readonly string $sql;
private ?Result $result = null;
private ?int $count = null;
private ?int $totalCount = null;
private array $cols = [];
private array $sorting = [];
private array $conds = [];
private ?int $offset = null;
private ?int $limit = null;
/**
* @param string $sql command or table or view name, as data source
*/
public function __construct(string $sql, Connection $connection)
{
$this->sql = strpbrk($sql, " \t\r\n") === false
? $connection->getDatabaseEngine()->escapeIdentifier($sql) // table name
: '(' . $sql . ') t'; // SQL command
$this->connection = $connection;
}
/**
* Selects columns to query.
* @param string|array $col column name or array of column names
* @param string $as column alias
*/
public function select(string|array $col, ?string $as = null): static
{
if (is_array($col)) {
$this->cols = $col;
} else {
$this->cols[$col] = $as;
}
$this->result = null;
return $this;
}
/**
* Adds conditions to query.
*/
public function where($cond): static
{
$this->conds[] = is_array($cond)
? $cond // TODO: not consistent with select and orderBy
: func_get_args();
$this->result = $this->count = null;
return $this;
}
/**
* Selects columns to order by.
* @param string|array $row column name or array of column names
*/
public function orderBy(string|array $row, string $direction = 'ASC'): static
{
if (is_array($row)) {
$this->sorting = $row;
} else {
$this->sorting[$row] = $direction;
}
$this->result = null;
return $this;
}
/**
* Limits number of rows.
*/
public function applyLimit(int $limit, ?int $offset = null): static
{
$this->limit = $limit;
$this->offset = $offset;
$this->result = $this->count = null;
return $this;
}
final public function getConnection(): Connection
{
return $this->connection;
}
/********************* executing ****************d*g**/
/**
* Returns (and queries) Result.
*/
public function getResult(): Result
{
if ($this->result === null) {
$this->result = $this->connection->nativeQuery($this->__toString());
}
return $this->result;
}
public function getIterator(): ResultIterator
{
return $this->getResult()->getIterator();
}
/**
* Generates, executes SQL query and fetches the single row.
*/
public function fetch(): ?Row
{
return $this->getResult()->fetch();
}
/**
* Like fetch(), but returns only first field.
* @return mixed value on success, null if no next record
*/
public function fetchSingle(): mixed
{
return $this->getResult()->fetchSingle();
}
/**
* Fetches all records from table.
*/
public function fetchAll(): array
{
return $this->getResult()->fetchAll();
}
/**
* Fetches all records from table and returns associative tree.
*/
public function fetchAssoc(string $assoc): array
{
return $this->getResult()->fetchAssoc($assoc);
}
/**
* Fetches all records from table like $key => $value pairs.
*/
public function fetchPairs(?string $key = null, ?string $value = null): array
{
return $this->getResult()->fetchPairs($key, $value);
}
/**
* Discards the internal cache.
*/
public function release(): void
{
$this->result = $this->count = $this->totalCount = null;
}
/********************* exporting ****************d*g**/
/**
* Returns this data source wrapped in Fluent object.
*/
public function toFluent(): Fluent
{
return $this->connection->select('*')->from('(%SQL) t', $this->__toString());
}
/**
* Returns this data source wrapped in DataSource object.
*/
public function toDataSource(): self
{
return new self($this->__toString(), $this->connection);
}
/**
* Returns SQL query.
*/
public function __toString(): string
{
return $this->connection->translate(
"\nSELECT %n",
(empty($this->cols) ? '*' : $this->cols),
"\nFROM %SQL",
$this->sql,
"\n%ex",
$this->conds ? ['WHERE %and', $this->conds] : null,
"\n%ex",
$this->sorting ? ['ORDER BY %by', $this->sorting] : null,
"\n%ofs %lmt",
$this->offset,
$this->limit,
);
}
/********************* counting ****************d*g**/
/**
* Returns the number of rows in a given data source.
*/
public function count(): int
{
if ($this->count === null) {
$this->count = $this->conds || $this->offset || $this->limit
? Helpers::intVal($this->connection->nativeQuery(
'SELECT COUNT(*) FROM (' . $this->__toString() . ') t',
)->fetchSingle())
: $this->getTotalCount();
}
return $this->count;
}
/**
* Returns the number of rows in a given data source.
*/
public function getTotalCount(): int
{
if ($this->totalCount === null) {
$this->totalCount = Helpers::intVal($this->connection->nativeQuery(
'SELECT COUNT(*) FROM ' . $this->sql,
)->fetchSingle());
}
return $this->totalCount;
}
}

34
src/Dibi/DateTime.php Normal file
View File

@@ -0,0 +1,34 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi;
/**
* DateTime.
*/
class DateTime extends \DateTimeImmutable
{
public function __construct(string|int $time = 'now', ?\DateTimeZone $timezone = null)
{
$timezone = $timezone ?: new \DateTimeZone(date_default_timezone_get());
if (is_numeric($time)) {
$tmp = (new self('@' . $time))->setTimezone($timezone);
parent::__construct($tmp->format('Y-m-d H:i:s.u'), $tmp->getTimezone());
} else {
parent::__construct($time, $timezone);
}
}
public function __toString(): string
{
return $this->format('Y-m-d H:i:s.u');
}
}

View File

@@ -0,0 +1,77 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi\Drivers;
use Dibi\DriverException;
use Dibi\Exception;
/**
* Database connection driver.
*/
interface Connection
{
/**
* Disconnects from a database.
* @throws Exception
*/
function disconnect(): void;
/**
* Internal: Executes the SQL query.
* @throws DriverException
*/
function query(string $sql): ?Result;
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
*/
function getAffectedRows(): ?int;
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
*/
function getInsertId(?string $sequence): ?int;
/**
* Begins a transaction (if supported).
* @throws DriverException
*/
function begin(?string $savepoint = null): void;
/**
* Commits statements in a transaction.
* @throws DriverException
*/
function commit(?string $savepoint = null): void;
/**
* Rollback changes in a transaction.
* @throws DriverException
*/
function rollback(?string $savepoint = null): void;
/**
* Returns the connection resource.
*/
function getResource(): mixed;
/**
* Returns the connection reflector.
*/
function getReflector(): Engine;
/**
* Encodes data for use in a SQL statement.
*/
function escapeText(string $value): string;
function escapeBinary(string $value): string;
}

View File

@@ -0,0 +1,219 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi\Drivers\Dummy;
use Dibi;
use Dibi\Drivers;
/**
* The dummy driver for testing purposes.
*/
class Connection implements Drivers\Connection, Drivers\Result, Drivers\Engine
{
public function disconnect(): void
{
}
public function query(string $sql): ?Result
{
return null;
}
public function getAffectedRows(): ?int
{
return null;
}
public function getInsertId(?string $sequence): ?int
{
return null;
}
public function begin(?string $savepoint = null): void
{
}
public function commit(?string $savepoint = null): void
{
}
public function rollback(?string $savepoint = null): void
{
}
public function getResource(): mixed
{
return null;
}
/**
* Returns the connection reflector.
*/
public function getReflector(): Drivers\Engine
{
return $this;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
*/
public function escapeText(string $value): string
{
return "'" . str_replace("'", "''", $value) . "'";
}
public function escapeBinary(string $value): string
{
return "N'" . str_replace("'", "''", $value) . "'";
}
public function escapeIdentifier(string $value): string
{
return '[' . strtr($value, '[]', ' ') . ']';
}
public function escapeBool(bool $value): string
{
return $value ? '1' : '0';
}
public function escapeDate(\DateTimeInterface $value): string
{
return $value->format("'Y-m-d'");
}
public function escapeDateTime(\DateTimeInterface $value): string
{
return $value->format("'Y-m-d H:i:s.u'");
}
public function escapeDateInterval(\DateInterval $value): string
{
throw new Dibi\NotImplementedException;
}
/**
* Encodes string for use in a LIKE statement.
*/
public function escapeLike(string $value, int $pos): string
{
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
}
/**
* Injects LIMIT/OFFSET to the SQL query.
*/
public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
{
if ($limit < 0 || $offset < 0) {
throw new Dibi\NotSupportedException('Negative offset or limit.');
} elseif ($limit !== null || $offset) {
$sql .= ' LIMIT ' . ($limit ?? '-1')
. ($offset ? ' OFFSET ' . $offset : '');
}
}
/********************* Result ****************d*g**/
public function getRowCount(): int
{
return 0;
}
public function fetch(bool $assoc): ?array
{
return null;
}
public function seek(int $row): bool
{
return false;
}
public function free(): void
{
}
public function getResultResource(): mixed
{
return null;
}
public function getResultColumns(): array
{
return [];
}
/**
* Decodes data from result set.
*/
public function unescapeBinary(string $value): string
{
return $value;
}
/********************* Reflector ****************d*g**/
public function getTables(): array
{
return [];
}
public function getColumns(string $table): array
{
return [];
}
public function getIndexes(string $table): array
{
return [];
}
public function getForeignKeys(string $table): array
{
return [];
}
}

View File

@@ -0,0 +1,68 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi\Drivers\Dummy;
use Dibi\Drivers;
/**
* The driver for no result set.
*/
class Result implements Drivers\Result
{
public function __construct(
private readonly int $rows,
) {
}
/**
* Returns the number of affected rows.
*/
public function getRowCount(): int
{
return $this->rows;
}
public function fetch(bool $assoc): ?array
{
return null;
}
public function seek(int $row): bool
{
return false;
}
public function free(): void
{
}
public function getResultColumns(): array
{
return [];
}
public function getResultResource(): mixed
{
return null;
}
public function unescapeBinary(string $value): string
{
return $value;
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi\Drivers;
/**
* Engine-specific behaviors.
*/
interface Engine
{
function escapeIdentifier(string $value): string;
function escapeBool(bool $value): string;
function escapeDate(\DateTimeInterface $value): string;
function escapeDateTime(\DateTimeInterface $value): string;
function escapeDateInterval(\DateInterval $value): string;
/**
* Encodes string for use in a LIKE statement.
*/
function escapeLike(string $value, int $pos): string;
/**
* Injects LIMIT/OFFSET to the SQL query.
*/
function applyLimit(string &$sql, ?int $limit, ?int $offset): void;
/**
* Returns list of tables.
* @return array of {name [, (bool) view ]}
*/
function getTables(): array;
/**
* Returns metadata for all columns in a table.
* @return array of {name, nativetype [, table, fullname, (int) size, (bool) nullable, (mixed) default, (bool) autoincrement, (array) vendor ]}
*/
function getColumns(string $table): array;
/**
* Returns metadata for all indexes in a table.
* @return array of {name, (array of names) columns [, (bool) unique, (bool) primary ]}
*/
function getIndexes(string $table): array;
/**
* Returns metadata for all foreign keys in a table.
*/
function getForeignKeys(string $table): array;
}

Some files were not shown because too many files have changed in this diff Show More