Przeglądaj źródła

updated Dibi to 4.0.1

causefx 7 lat temu
rodzic
commit
0283f8f261
84 zmienionych plików z 4316 dodań i 5831 usunięć
  1. 12 12
      api/composer.json
  2. 9 12
      api/composer.lock
  3. 16 4
      api/vendor/composer/autoload_classmap.php
  4. 0 1
      api/vendor/composer/autoload_files.php
  5. 16 5
      api/vendor/composer/autoload_static.php
  6. 66 69
      api/vendor/composer/installed.json
  7. 4 5
      api/vendor/dibi/dibi/composer.json
  8. 12 34
      api/vendor/dibi/dibi/examples/connecting-to-databases.php
  9. BIN
      api/vendor/dibi/dibi/examples/data/sample.s3db
  10. 10 5
      api/vendor/dibi/dibi/examples/database-reflection.php
  11. 10 5
      api/vendor/dibi/dibi/examples/dumping-sql-and-result-set.php
  12. 13 12
      api/vendor/dibi/dibi/examples/fetching-examples.php
  13. 10 5
      api/vendor/dibi/dibi/examples/importing-dump-from-file.php
  14. 14 9
      api/vendor/dibi/dibi/examples/query-language-and-conditions.php
  15. 16 11
      api/vendor/dibi/dibi/examples/query-language-basic-examples.php
  16. 6 5
      api/vendor/dibi/dibi/examples/result-set-data-types.php
  17. 5 7
      api/vendor/dibi/dibi/examples/tracy-and-exceptions.php
  18. 6 8
      api/vendor/dibi/dibi/examples/tracy.php
  19. 10 5
      api/vendor/dibi/dibi/examples/using-datetime.php
  20. 0 33
      api/vendor/dibi/dibi/examples/using-extension-methods.php
  21. 16 11
      api/vendor/dibi/dibi/examples/using-fluent-syntax.php
  22. 12 7
      api/vendor/dibi/dibi/examples/using-limit-and-offset.php
  23. 15 11
      api/vendor/dibi/dibi/examples/using-logger.php
  24. 0 43
      api/vendor/dibi/dibi/examples/using-profiler.php
  25. 15 10
      api/vendor/dibi/dibi/examples/using-substitutions.php
  26. 15 10
      api/vendor/dibi/dibi/examples/using-transactions.php
  27. 586 67
      api/vendor/dibi/dibi/readme.md
  28. 13 12
      api/vendor/dibi/dibi/src/Dibi/Bridges/Nette/DibiExtension22.php
  29. 176 220
      api/vendor/dibi/dibi/src/Dibi/Connection.php
  30. 32 60
      api/vendor/dibi/dibi/src/Dibi/DataSource.php
  31. 61 27
      api/vendor/dibi/dibi/src/Dibi/DateTime.php
  32. 41 586
      api/vendor/dibi/dibi/src/Dibi/Drivers/FirebirdDriver.php
  33. 377 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/FirebirdReflector.php
  34. 138 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/FirebirdResult.php
  35. 0 409
      api/vendor/dibi/dibi/src/Dibi/Drivers/MsSqlDriver.php
  36. 0 215
      api/vendor/dibi/dibi/src/Dibi/Drivers/MsSqlReflector.php
  37. 0 502
      api/vendor/dibi/dibi/src/Dibi/Drivers/MySqlDriver.php
  38. 8 14
      api/vendor/dibi/dibi/src/Dibi/Drivers/MySqlReflector.php
  39. 62 237
      api/vendor/dibi/dibi/src/Dibi/Drivers/MySqliDriver.php
  40. 147 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/MySqliResult.php
  41. 74 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/NoDataResult.php
  42. 49 290
      api/vendor/dibi/dibi/src/Dibi/Drivers/OdbcDriver.php
  43. 92 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/OdbcReflector.php
  44. 141 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/OdbcResult.php
  45. 50 285
      api/vendor/dibi/dibi/src/Dibi/Drivers/OracleDriver.php
  46. 89 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/OracleReflector.php
  47. 124 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/OracleResult.php
  48. 80 221
      api/vendor/dibi/dibi/src/Dibi/Drivers/PdoDriver.php
  49. 122 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/PdoResult.php
  50. 48 445
      api/vendor/dibi/dibi/src/Dibi/Drivers/PostgreDriver.php
  51. 259 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/PostgreReflector.php
  52. 125 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/PostgreResult.php
  53. 5 484
      api/vendor/dibi/dibi/src/Dibi/Drivers/Sqlite3Driver.php
  54. 18 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/Sqlite3Result.php
  55. 301 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/SqliteDriver.php
  56. 8 14
      api/vendor/dibi/dibi/src/Dibi/Drivers/SqliteReflector.php
  57. 123 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/SqliteResult.php
  58. 38 197
      api/vendor/dibi/dibi/src/Dibi/Drivers/SqlsrvDriver.php
  59. 9 16
      api/vendor/dibi/dibi/src/Dibi/Drivers/SqlsrvReflector.php
  60. 121 0
      api/vendor/dibi/dibi/src/Dibi/Drivers/SqlsrvResult.php
  61. 16 11
      api/vendor/dibi/dibi/src/Dibi/Event.php
  62. 6 4
      api/vendor/dibi/dibi/src/Dibi/Expression.php
  63. 38 82
      api/vendor/dibi/dibi/src/Dibi/Fluent.php
  64. 12 10
      api/vendor/dibi/dibi/src/Dibi/HashMap.php
  65. 34 29
      api/vendor/dibi/dibi/src/Dibi/Helpers.php
  66. 4 5
      api/vendor/dibi/dibi/src/Dibi/Literal.php
  67. 7 6
      api/vendor/dibi/dibi/src/Dibi/Loggers/FileLogger.php
  68. 0 94
      api/vendor/dibi/dibi/src/Dibi/Loggers/FirePhpLogger.php
  69. 21 61
      api/vendor/dibi/dibi/src/Dibi/Reflection/Column.php
  70. 12 24
      api/vendor/dibi/dibi/src/Dibi/Reflection/Database.php
  71. 6 10
      api/vendor/dibi/dibi/src/Dibi/Reflection/ForeignKey.php
  72. 7 17
      api/vendor/dibi/dibi/src/Dibi/Reflection/Index.php
  73. 10 20
      api/vendor/dibi/dibi/src/Dibi/Reflection/Result.php
  74. 19 43
      api/vendor/dibi/dibi/src/Dibi/Reflection/Table.php
  75. 62 106
      api/vendor/dibi/dibi/src/Dibi/Result.php
  76. 8 22
      api/vendor/dibi/dibi/src/Dibi/ResultIterator.php
  77. 8 8
      api/vendor/dibi/dibi/src/Dibi/Row.php
  78. 17 28
      api/vendor/dibi/dibi/src/Dibi/Strict.php
  79. 34 38
      api/vendor/dibi/dibi/src/Dibi/Translator.php
  80. 5 2
      api/vendor/dibi/dibi/src/Dibi/Type.php
  81. 54 314
      api/vendor/dibi/dibi/src/Dibi/dibi.php
  82. 15 26
      api/vendor/dibi/dibi/src/Dibi/exceptions.php
  83. 96 91
      api/vendor/dibi/dibi/src/Dibi/interfaces.php
  84. 0 140
      api/vendor/dibi/dibi/src/loader.php

+ 12 - 12
api/composer.json

@@ -1,14 +1,14 @@
 {
-    "require": {
-        "dibi/dibi": "^3.1",
-        "lcobucci/jwt": "^3.2",
-        "composer/semver": "^1.4",
-        "phpmailer/phpmailer": "^6.0",
-        "rmccue/requests": "^1.7",
-        "kryptonit3/sonarr": "1.0.6.1",
-        "kryptonit3/couchpotato": "^1.0",
-        "kryptonit3/sickrage": "^1.0",
-        "pusher/pusher-php-server": "^3.2",
-        "pragmarx/google2fa": "^3.0"
-    }
+  "require": {
+    "dibi/dibi": "^4.0",
+    "lcobucci/jwt": "^3.2",
+    "composer/semver": "^1.4",
+    "phpmailer/phpmailer": "^6.0",
+    "rmccue/requests": "^1.7",
+    "kryptonit3/sonarr": "1.0.6.1",
+    "kryptonit3/couchpotato": "^1.0",
+    "kryptonit3/sickrage": "^1.0",
+    "pusher/pusher-php-server": "^3.2",
+    "pragmarx/google2fa": "^3.0"
+  }
 }

+ 9 - 12
api/composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "content-hash": "0e5ee280433e4a8e418c7b3a14dc39ff",
+    "content-hash": "4a53496f136ee22d88ec83f8ce65ab7d",
     "packages": [
         {
             "name": "composer/semver",
@@ -70,40 +70,37 @@
         },
         {
             "name": "dibi/dibi",
-            "version": "v3.1.0",
+            "version": "v4.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/dg/dibi.git",
-                "reference": "fa35c0cf7de1286ce1cf9fbdba058c1d54c849f8"
+                "reference": "811974139eb2b8f16fd0aa6ff104de1d416b8b35"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/dg/dibi/zipball/fa35c0cf7de1286ce1cf9fbdba058c1d54c849f8",
-                "reference": "fa35c0cf7de1286ce1cf9fbdba058c1d54c849f8",
+                "url": "https://api.github.com/repos/dg/dibi/zipball/811974139eb2b8f16fd0aa6ff104de1d416b8b35",
+                "reference": "811974139eb2b8f16fd0aa6ff104de1d416b8b35",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.4.4"
+                "php": ">=7.1"
             },
             "replace": {
                 "dg/dibi": "*"
             },
             "require-dev": {
-                "nette/tester": "~1.7",
+                "nette/tester": "~2.0",
                 "tracy/tracy": "~2.2"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-master": "4.0-dev"
                 }
             },
             "autoload": {
                 "classmap": [
                     "src/"
-                ],
-                "files": [
-                    "src/loader.php"
                 ]
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -133,7 +130,7 @@
                 "sqlite",
                 "sqlsrv"
             ],
-            "time": "2017-09-25T15:57:54+00:00"
+            "time": "2018-09-17T11:50:54+00:00"
         },
         {
             "name": "guzzlehttp/guzzle",

+ 16 - 4
api/vendor/composer/autoload_classmap.php

@@ -15,19 +15,31 @@ return array(
     'Dibi\\Driver' => $vendorDir . '/dibi/dibi/src/Dibi/interfaces.php',
     'Dibi\\DriverException' => $vendorDir . '/dibi/dibi/src/Dibi/exceptions.php',
     'Dibi\\Drivers\\FirebirdDriver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/FirebirdDriver.php',
-    'Dibi\\Drivers\\MsSqlDriver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/MsSqlDriver.php',
-    'Dibi\\Drivers\\MsSqlReflector' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/MsSqlReflector.php',
-    'Dibi\\Drivers\\MySqlDriver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/MySqlDriver.php',
+    'Dibi\\Drivers\\FirebirdReflector' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/FirebirdReflector.php',
+    'Dibi\\Drivers\\FirebirdResult' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/FirebirdResult.php',
     'Dibi\\Drivers\\MySqlReflector' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/MySqlReflector.php',
     'Dibi\\Drivers\\MySqliDriver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/MySqliDriver.php',
+    'Dibi\\Drivers\\MySqliResult' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/MySqliResult.php',
+    'Dibi\\Drivers\\NoDataResult' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/NoDataResult.php',
     'Dibi\\Drivers\\OdbcDriver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/OdbcDriver.php',
+    'Dibi\\Drivers\\OdbcReflector' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/OdbcReflector.php',
+    'Dibi\\Drivers\\OdbcResult' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/OdbcResult.php',
     'Dibi\\Drivers\\OracleDriver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/OracleDriver.php',
+    'Dibi\\Drivers\\OracleReflector' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/OracleReflector.php',
+    'Dibi\\Drivers\\OracleResult' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/OracleResult.php',
     'Dibi\\Drivers\\PdoDriver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/PdoDriver.php',
+    'Dibi\\Drivers\\PdoResult' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/PdoResult.php',
     'Dibi\\Drivers\\PostgreDriver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/PostgreDriver.php',
+    'Dibi\\Drivers\\PostgreReflector' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/PostgreReflector.php',
+    'Dibi\\Drivers\\PostgreResult' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/PostgreResult.php',
     'Dibi\\Drivers\\Sqlite3Driver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/Sqlite3Driver.php',
+    'Dibi\\Drivers\\Sqlite3Result' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/Sqlite3Result.php',
+    'Dibi\\Drivers\\SqliteDriver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/SqliteDriver.php',
     'Dibi\\Drivers\\SqliteReflector' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/SqliteReflector.php',
+    'Dibi\\Drivers\\SqliteResult' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/SqliteResult.php',
     'Dibi\\Drivers\\SqlsrvDriver' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/SqlsrvDriver.php',
     'Dibi\\Drivers\\SqlsrvReflector' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/SqlsrvReflector.php',
+    'Dibi\\Drivers\\SqlsrvResult' => $vendorDir . '/dibi/dibi/src/Dibi/Drivers/SqlsrvResult.php',
     'Dibi\\Event' => $vendorDir . '/dibi/dibi/src/Dibi/Event.php',
     'Dibi\\Exception' => $vendorDir . '/dibi/dibi/src/Dibi/exceptions.php',
     'Dibi\\Expression' => $vendorDir . '/dibi/dibi/src/Dibi/Expression.php',
@@ -36,10 +48,10 @@ return array(
     'Dibi\\HashMap' => $vendorDir . '/dibi/dibi/src/Dibi/HashMap.php',
     'Dibi\\HashMapBase' => $vendorDir . '/dibi/dibi/src/Dibi/HashMap.php',
     'Dibi\\Helpers' => $vendorDir . '/dibi/dibi/src/Dibi/Helpers.php',
+    'Dibi\\IConnection' => $vendorDir . '/dibi/dibi/src/Dibi/interfaces.php',
     'Dibi\\IDataSource' => $vendorDir . '/dibi/dibi/src/Dibi/interfaces.php',
     'Dibi\\Literal' => $vendorDir . '/dibi/dibi/src/Dibi/Literal.php',
     'Dibi\\Loggers\\FileLogger' => $vendorDir . '/dibi/dibi/src/Dibi/Loggers/FileLogger.php',
-    'Dibi\\Loggers\\FirePhpLogger' => $vendorDir . '/dibi/dibi/src/Dibi/Loggers/FirePhpLogger.php',
     'Dibi\\NotImplementedException' => $vendorDir . '/dibi/dibi/src/Dibi/exceptions.php',
     'Dibi\\NotNullConstraintViolationException' => $vendorDir . '/dibi/dibi/src/Dibi/exceptions.php',
     'Dibi\\NotSupportedException' => $vendorDir . '/dibi/dibi/src/Dibi/exceptions.php',

+ 0 - 1
api/vendor/composer/autoload_files.php

@@ -11,5 +11,4 @@ return array(
     '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
     '3109cb1a231dcd04bee1f9f620d46975' => $vendorDir . '/paragonie/sodium_compat/autoload.php',
     'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php',
-    '0097ca414fcb37c7130ac24b05f485f8' => $vendorDir . '/dibi/dibi/src/loader.php',
 );

+ 16 - 5
api/vendor/composer/autoload_static.php

@@ -12,7 +12,6 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
         '3109cb1a231dcd04bee1f9f620d46975' => __DIR__ . '/..' . '/paragonie/sodium_compat/autoload.php',
         'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php',
-        '0097ca414fcb37c7130ac24b05f485f8' => __DIR__ . '/..' . '/dibi/dibi/src/loader.php',
     );
 
     public static $prefixLengthsPsr4 = array (
@@ -144,19 +143,31 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         'Dibi\\Driver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/interfaces.php',
         'Dibi\\DriverException' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/exceptions.php',
         'Dibi\\Drivers\\FirebirdDriver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/FirebirdDriver.php',
-        'Dibi\\Drivers\\MsSqlDriver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/MsSqlDriver.php',
-        'Dibi\\Drivers\\MsSqlReflector' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/MsSqlReflector.php',
-        'Dibi\\Drivers\\MySqlDriver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/MySqlDriver.php',
+        'Dibi\\Drivers\\FirebirdReflector' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/FirebirdReflector.php',
+        'Dibi\\Drivers\\FirebirdResult' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/FirebirdResult.php',
         'Dibi\\Drivers\\MySqlReflector' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/MySqlReflector.php',
         'Dibi\\Drivers\\MySqliDriver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/MySqliDriver.php',
+        'Dibi\\Drivers\\MySqliResult' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/MySqliResult.php',
+        'Dibi\\Drivers\\NoDataResult' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/NoDataResult.php',
         'Dibi\\Drivers\\OdbcDriver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/OdbcDriver.php',
+        'Dibi\\Drivers\\OdbcReflector' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/OdbcReflector.php',
+        'Dibi\\Drivers\\OdbcResult' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/OdbcResult.php',
         'Dibi\\Drivers\\OracleDriver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/OracleDriver.php',
+        'Dibi\\Drivers\\OracleReflector' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/OracleReflector.php',
+        'Dibi\\Drivers\\OracleResult' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/OracleResult.php',
         'Dibi\\Drivers\\PdoDriver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/PdoDriver.php',
+        'Dibi\\Drivers\\PdoResult' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/PdoResult.php',
         'Dibi\\Drivers\\PostgreDriver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/PostgreDriver.php',
+        'Dibi\\Drivers\\PostgreReflector' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/PostgreReflector.php',
+        'Dibi\\Drivers\\PostgreResult' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/PostgreResult.php',
         'Dibi\\Drivers\\Sqlite3Driver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/Sqlite3Driver.php',
+        'Dibi\\Drivers\\Sqlite3Result' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/Sqlite3Result.php',
+        'Dibi\\Drivers\\SqliteDriver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/SqliteDriver.php',
         'Dibi\\Drivers\\SqliteReflector' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/SqliteReflector.php',
+        'Dibi\\Drivers\\SqliteResult' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/SqliteResult.php',
         'Dibi\\Drivers\\SqlsrvDriver' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/SqlsrvDriver.php',
         'Dibi\\Drivers\\SqlsrvReflector' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/SqlsrvReflector.php',
+        'Dibi\\Drivers\\SqlsrvResult' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Drivers/SqlsrvResult.php',
         'Dibi\\Event' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Event.php',
         'Dibi\\Exception' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/exceptions.php',
         'Dibi\\Expression' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Expression.php',
@@ -165,10 +176,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         'Dibi\\HashMap' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/HashMap.php',
         'Dibi\\HashMapBase' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/HashMap.php',
         'Dibi\\Helpers' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Helpers.php',
+        'Dibi\\IConnection' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/interfaces.php',
         'Dibi\\IDataSource' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/interfaces.php',
         'Dibi\\Literal' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Literal.php',
         'Dibi\\Loggers\\FileLogger' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Loggers/FileLogger.php',
-        'Dibi\\Loggers\\FirePhpLogger' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Loggers/FirePhpLogger.php',
         'Dibi\\NotImplementedException' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/exceptions.php',
         'Dibi\\NotNullConstraintViolationException' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/exceptions.php',
         'Dibi\\NotSupportedException' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/exceptions.php',

+ 66 - 69
api/vendor/composer/installed.json

@@ -1,73 +1,4 @@
 [
-    {
-        "name": "dibi/dibi",
-        "version": "v3.1.0",
-        "version_normalized": "3.1.0.0",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/dg/dibi.git",
-            "reference": "fa35c0cf7de1286ce1cf9fbdba058c1d54c849f8"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/dg/dibi/zipball/fa35c0cf7de1286ce1cf9fbdba058c1d54c849f8",
-            "reference": "fa35c0cf7de1286ce1cf9fbdba058c1d54c849f8",
-            "shasum": ""
-        },
-        "require": {
-            "php": ">=5.4.4"
-        },
-        "replace": {
-            "dg/dibi": "*"
-        },
-        "require-dev": {
-            "nette/tester": "~1.7",
-            "tracy/tracy": "~2.2"
-        },
-        "time": "2017-09-25T15:57:54+00:00",
-        "type": "library",
-        "extra": {
-            "branch-alias": {
-                "dev-master": "3.1-dev"
-            }
-        },
-        "installation-source": "dist",
-        "autoload": {
-            "classmap": [
-                "src/"
-            ],
-            "files": [
-                "src/loader.php"
-            ]
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "BSD-3-Clause",
-            "GPL-2.0",
-            "GPL-3.0"
-        ],
-        "authors": [
-            {
-                "name": "David Grudl",
-                "homepage": "https://davidgrudl.com"
-            }
-        ],
-        "description": "Dibi is Database Abstraction Library for PHP",
-        "homepage": "https://dibiphp.com",
-        "keywords": [
-            "access",
-            "database",
-            "dbal",
-            "mssql",
-            "mysql",
-            "odbc",
-            "oracle",
-            "pdo",
-            "postgresql",
-            "sqlite",
-            "sqlsrv"
-        ]
-    },
     {
         "name": "lcobucci/jwt",
         "version": "3.2.2",
@@ -1138,5 +1069,71 @@
             "rest",
             "web service"
         ]
+    },
+    {
+        "name": "dibi/dibi",
+        "version": "v4.0.1",
+        "version_normalized": "4.0.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/dg/dibi.git",
+            "reference": "811974139eb2b8f16fd0aa6ff104de1d416b8b35"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/dg/dibi/zipball/811974139eb2b8f16fd0aa6ff104de1d416b8b35",
+            "reference": "811974139eb2b8f16fd0aa6ff104de1d416b8b35",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.1"
+        },
+        "replace": {
+            "dg/dibi": "*"
+        },
+        "require-dev": {
+            "nette/tester": "~2.0",
+            "tracy/tracy": "~2.2"
+        },
+        "time": "2018-09-17T11:50:54+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "4.0-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "classmap": [
+                "src/"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "BSD-3-Clause",
+            "GPL-2.0",
+            "GPL-3.0"
+        ],
+        "authors": [
+            {
+                "name": "David Grudl",
+                "homepage": "https://davidgrudl.com"
+            }
+        ],
+        "description": "Dibi is Database Abstraction Library for PHP",
+        "homepage": "https://dibiphp.com",
+        "keywords": [
+            "access",
+            "database",
+            "dbal",
+            "mssql",
+            "mysql",
+            "odbc",
+            "oracle",
+            "pdo",
+            "postgresql",
+            "sqlite",
+            "sqlsrv"
+        ]
     }
 ]

+ 4 - 5
api/vendor/dibi/dibi/composer.json

@@ -11,22 +11,21 @@
 		}
 	],
 	"require": {
-		"php": ">=5.4.4"
+		"php": ">=7.1"
 	},
 	"require-dev": {
 		"tracy/tracy": "~2.2",
-		"nette/tester": "~1.7"
+		"nette/tester": "~2.0"
 	},
 	"replace": {
 		"dg/dibi": "*"
 	},
 	"autoload": {
-		"classmap": ["src/"],
-		"files": ["src/loader.php"]
+		"classmap": ["src/"]
 	},
 	"extra": {
 		"branch-alias": {
-			"dev-master": "3.1-dev"
+			"dev-master": "4.0-dev"
 		}
 	}
 }

+ 12 - 34
api/vendor/dibi/dibi/examples/connecting-to-databases.php

@@ -1,17 +1,22 @@
+<?php
+declare(strict_types=1);
+?>
 <!DOCTYPE html><link rel="stylesheet" href="data/style.css">
 
-<h1>Connecting to Databases | dibi</h1>
+<h1>Connecting to Databases | Dibi</h1>
 
 <?php
 
-require __DIR__ . '/../src/loader.php';
+if (@!include __DIR__ . '/../vendor/autoload.php') {
+	die('Install packages using `composer install`');
+}
 
 
-// connects to SQlite using dibi class
+// connects to SQlite using Dibi class
 echo '<p>Connecting to Sqlite: ';
 try {
 	dibi::connect([
-		'driver' => 'sqlite3',
+		'driver' => 'sqlite',
 		'database' => 'data/sample.s3db',
 	]);
 	echo 'OK';
@@ -25,7 +30,7 @@ echo "</p>\n";
 echo '<p>Connecting to Sqlite: ';
 try {
 	$connection = new Dibi\Connection([
-		'driver' => 'sqlite3',
+		'driver' => 'sqlite',
 		'database' => 'data/sample.s3db',
 	]);
 	echo 'OK';
@@ -35,18 +40,7 @@ try {
 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=cp1250');
-	echo 'OK';
-} catch (Dibi\Exception $e) {
-	echo get_class($e), ': ', $e->getMessage(), "\n";
-}
-echo "</p>\n";
-
-
-// connects to MySQLi using array
+// connects to MySQLi
 echo '<p>Connecting to MySQLi: ';
 try {
 	dibi::connect([
@@ -74,7 +68,7 @@ try {
 		'driver' => 'odbc',
 		'username' => 'root',
 		'password' => '***',
-		'dsn' => 'Driver={Microsoft Access Driver (*.mdb)};Dbq=' . __DIR__ . '/data/sample.mdb',
+		'dsn' => 'Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=' . __DIR__ . '/data/sample.mdb',
 	]);
 	echo 'OK';
 } catch (Dibi\Exception $e) {
@@ -112,22 +106,6 @@ try {
 echo "</p>\n";
 
 
-// connects to MS SQL
-echo '<p>Connecting to MS SQL: ';
-try {
-	dibi::connect([
-		'driver' => 'mssql',
-		'host' => 'localhost',
-		'username' => 'root',
-		'password' => 'xxx',
-	]);
-	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 {

BIN
api/vendor/dibi/dibi/examples/data/sample.s3db


+ 10 - 5
api/vendor/dibi/dibi/examples/database-reflection.php

@@ -1,20 +1,25 @@
+<?php
+declare(strict_types=1);
+?>
 <!DOCTYPE html><link rel="stylesheet" href="data/style.css">
 
-<h1>Database Reflection | dibi</h1>
+<h1>Database Reflection | Dibi</h1>
 
 <?php
 
-require __DIR__ . '/../src/loader.php';
+if (@!include __DIR__ . '/../vendor/autoload.php') {
+	die('Install packages using `composer install`');
+}
 
 
-dibi::connect([
-	'driver' => 'sqlite3',
+$dibi = new Dibi\Connection([
+	'driver' => 'sqlite',
 	'database' => 'data/sample.s3db',
 ]);
 
 
 // retrieve database reflection
-$database = dibi::getDatabaseInfo();
+$database = $dibi->getDatabaseInfo();
 
 echo "<h2>Database '{$database->getName()}'</h2>\n";
 echo "<ul>\n";

+ 10 - 5
api/vendor/dibi/dibi/examples/dumping-sql-and-result-set.php

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

+ 13 - 12
api/vendor/dibi/dibi/examples/fetching-examples.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 if (@!include __DIR__ . '/../vendor/autoload.php') {
 	die('Install dependencies using `composer install --dev`');
@@ -9,12 +10,12 @@ Tracy\Debugger::enable();
 ?>
 <!DOCTYPE html><link rel="stylesheet" href="data/style.css">
 
-<h1>Fetching Examples | dibi</h1>
+<h1>Fetching Examples | Dibi</h1>
 
 <?php
 
-dibi::connect([
-	'driver' => 'sqlite3',
+$dibi = new Dibi\Connection([
+	'driver' => 'sqlite',
 	'database' => 'data/sample.s3db',
 ]);
 
@@ -33,46 +34,46 @@ product_id | title
 
 // fetch a single row
 echo "<h2>fetch()</h2>\n";
-$row = dibi::fetch('SELECT title FROM products');
+$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');
+$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');
+$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');
+$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');
+$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');
+$res = $dibi->query('SELECT * FROM products');
 foreach ($res as $n => $row) {
 	Tracy\Dumper::dump($row);
 }
 
 
 // more complex association array
-$res = dibi::query('
+$res = $dibi->query('
 	SELECT *
 	FROM products
 	INNER JOIN orders USING (product_id)
@@ -84,11 +85,11 @@ $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)');
+$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)');
+$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);

+ 10 - 5
api/vendor/dibi/dibi/examples/importing-dump-from-file.php

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

+ 14 - 9
api/vendor/dibi/dibi/examples/query-language-and-conditions.php

@@ -1,14 +1,19 @@
+<?php
+declare(strict_types=1);
+?>
 <!DOCTYPE html><link rel="stylesheet" href="data/style.css">
 
-<h1>Query Language & Conditions | dibi</h1>
+<h1>Query Language & Conditions | Dibi</h1>
 
 <?php
 
-require __DIR__ . '/../src/loader.php';
+if (@!include __DIR__ . '/../vendor/autoload.php') {
+	die('Install packages using `composer install`');
+}
 
 
-dibi::connect([
-	'driver' => 'sqlite3',
+$dibi = new Dibi\Connection([
+	'driver' => 'sqlite',
 	'database' => 'data/sample.s3db',
 ]);
 
@@ -23,7 +28,7 @@ $bar = 2;
 $name = $cond1 ? 'K%' : null;
 
 // if & end
-dibi::test('
+$dibi->test('
 	SELECT *
 	FROM customers
 	%if', isset($name), 'WHERE name LIKE ?', $name, '%end'
@@ -32,7 +37,7 @@ dibi::test('
 
 
 // if & else & (optional) end
-dibi::test('
+$dibi->test('
 	SELECT *
 	FROM people
 	WHERE id > 0
@@ -43,7 +48,7 @@ dibi::test('
 
 
 // nested condition
-dibi::test('
+$dibi->test('
 	SELECT *
 	FROM customers
 	WHERE
@@ -55,7 +60,7 @@ dibi::test('
 
 
 // IF()
-dibi::test('UPDATE products SET', [
-	'price' => ['IF(price_fixed, price, ?)', 123],
+$dibi->test('UPDATE products SET', [
+	'price' => $dibi->expression('IF(price_fixed, price, ?)', 123),
 ]);
 // -> SELECT * FROM customers WHERE LIMIT 10

+ 16 - 11
api/vendor/dibi/dibi/examples/query-language-basic-examples.php

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

+ 6 - 5
api/vendor/dibi/dibi/examples/result-set-data-types.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 use Dibi\Type;
 
@@ -13,18 +14,18 @@ date_default_timezone_set('Europe/Prague');
 ?>
 <!DOCTYPE html><link rel="stylesheet" href="data/style.css">
 
-<h1>Result Set Data Types | dibi</h1>
+<h1>Result Set Data Types | Dibi</h1>
 
 <?php
 
-dibi::connect([
-	'driver' => 'sqlite3',
+$dibi = new Dibi\Connection([
+	'driver' => 'sqlite',
 	'database' => 'data/sample.s3db',
 ]);
 
 
 // using manual hints
-$res = dibi::query('SELECT * FROM [customers]');
+$res = $dibi->query('SELECT * FROM [customers]');
 
 $res->setType('customer_id', Type::INTEGER)
 	->setType('added', Type::DATETIME)
@@ -40,7 +41,7 @@ Tracy\Dumper::dump($res->fetch());
 
 
 // using auto-detection (works well with MySQL or other strictly typed databases)
-$res = dibi::query('SELECT * FROM [customers]');
+$res = $dibi->query('SELECT * FROM [customers]');
 
 Tracy\Dumper::dump($res->fetch());
 // outputs:

+ 5 - 7
api/vendor/dibi/dibi/examples/tracy-and-exceptions.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 if (@!include __DIR__ . '/../vendor/autoload.php') {
 	die('Install dependencies using `composer install --dev`');
@@ -9,22 +10,19 @@ if (@!include __DIR__ . '/../vendor/autoload.php') {
 Tracy\Debugger::enable();
 
 
-$connection = dibi::connect([
-	'driver' => 'sqlite3',
+$dibi = new Dibi\Connection([
+	'driver' => 'sqlite',
 	'database' => 'data/sample.s3db',
-	'profiler' => [
-		'run' => true,
-	],
 ]);
 
 
 // add panel to debug bar
 $panel = new Dibi\Bridges\Tracy\Panel;
-$panel->register($connection);
+$panel->register($dibi);
 
 
 // throws error because SQL is bad
-dibi::query('SELECT FROM customers WHERE customer_id < ?', 38);
+$dibi->query('SELECT FROM customers WHERE customer_id < ?', 38);
 
 ?><!DOCTYPE html><link rel="stylesheet" href="data/style.css">
 

+ 6 - 8
api/vendor/dibi/dibi/examples/tracy.php

@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 
 if (@!include __DIR__ . '/../vendor/autoload.php') {
 	die('Install dependencies using `composer install --dev`');
@@ -9,25 +10,22 @@ if (@!include __DIR__ . '/../vendor/autoload.php') {
 Tracy\Debugger::enable();
 
 
-$connection = dibi::connect([
-	'driver' => 'sqlite3',
+$dibi = new Dibi\Connection([
+	'driver' => 'sqlite',
 	'database' => 'data/sample.s3db',
-	'profiler' => [
-		'run' => true,
-	],
 ]);
 
 
 // add panel to debug bar
 $panel = new Dibi\Bridges\Tracy\Panel;
-$panel->register($connection);
+$panel->register($dibi);
 
 
 // query will be logged
-dibi::query('SELECT 123');
+$dibi->query('SELECT 123');
 
 // result set will be dumped
-Tracy\Debugger::barDump(dibi::fetchAll('SELECT * FROM customers WHERE customer_id < ?', 38), '[customers]');
+Tracy\Debugger::barDump($dibi->fetchAll('SELECT * FROM customers WHERE customer_id < ?', 38), '[customers]');
 
 
 ?>

+ 10 - 5
api/vendor/dibi/dibi/examples/using-datetime.php

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

+ 0 - 33
api/vendor/dibi/dibi/examples/using-extension-methods.php

@@ -1,33 +0,0 @@
-<?php
-
-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>Using Extension Methods | dibi</h1>
-
-<?php
-
-dibi::connect([
-	'driver' => 'sqlite3',
-	'database' => 'data/sample.s3db',
-]);
-
-
-// using the "prototype" to add custom method to class Dibi\Result
-Dibi\Result::extensionMethod('fetchShuffle', function (Dibi\Result $obj) {
-	$all = $obj->fetchAll();
-	shuffle($all);
-	return $all;
-});
-
-
-// fetch complete result set shuffled
-$res = dibi::query('SELECT * FROM [customers]');
-$all = $res->fetchShuffle();
-Tracy\Dumper::dump($all);

+ 16 - 11
api/vendor/dibi/dibi/examples/using-fluent-syntax.php

@@ -1,16 +1,21 @@
+<?php
+declare(strict_types=1);
+?>
 <!DOCTYPE html><link rel="stylesheet" href="data/style.css">
 
-<h1>Using Fluent Syntax | dibi</h1>
+<h1>Using Fluent Syntax | Dibi</h1>
 
 <?php
 
-require __DIR__ . '/../src/loader.php';
+if (@!include __DIR__ . '/../vendor/autoload.php') {
+	die('Install packages using `composer install`');
+}
 
 date_default_timezone_set('Europe/Prague');
 
 
-dibi::connect([
-	'driver' => 'sqlite3',
+$dibi = new Dibi\Connection([
+	'driver' => 'sqlite',
 	'database' => 'data/sample.s3db',
 ]);
 
@@ -23,7 +28,7 @@ $record = [
 ];
 
 // SELECT ...
-dibi::select('product_id')->as('id')
+$dibi->select('product_id')->as('id')
 	->select('title')
 	->from('products')
 	->innerJoin('orders')->using('(product_id)')
@@ -35,35 +40,35 @@ dibi::select('product_id')->as('id')
 
 
 // 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])
 
 
 // INSERT ...
-dibi::insert('products', $record)
+$dibi->insert('products', $record)
 	->setFlag('IGNORE')
 	->test();
 // -> INSERT IGNORE INTO [products] ([title], [price], [active]) VALUES ('Super product', 318, 1)
 
 
 // UPDATE ...
-dibi::update('products', $record)
+$dibi->update('products', $record)
 	->where('product_id = ?', $id)
 	->test();
 // -> UPDATE [products] SET [title]='Super product', [price]=318, [active]=1 WHERE product_id = 10
 
 
 // DELETE ...
-dibi::delete('products')
+$dibi->delete('products')
 	->where('product_id = ?', $id)
 	->test();
 // -> DELETE FROM [products] WHERE product_id = 10
 
 
 // custom commands
-dibi::command()
+$dibi->command()
 	->update('products')
 	->where('product_id = ?', $id)
 	->set($record)
@@ -71,7 +76,7 @@ dibi::command()
 // -> UPDATE [products] SET [title]='Super product', [price]=318, [active]=1 WHERE product_id = 10
 
 
-dibi::command()
+$dibi->command()
 	->truncate('products')
 	->test();
 // -> TRUNCATE [products]

+ 12 - 7
api/vendor/dibi/dibi/examples/using-limit-and-offset.php

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

+ 15 - 11
api/vendor/dibi/dibi/examples/using-logger.php

@@ -1,37 +1,41 @@
+<?php
+declare(strict_types=1);
+?>
 <!DOCTYPE html><link rel="stylesheet" href="data/style.css">
 
-<h1>Using Logger | dibi</h1>
+<h1>Using Logger | Dibi</h1>
 
 <?php
 
-require __DIR__ . '/../src/loader.php';
+if (@!include __DIR__ . '/../vendor/autoload.php') {
+	die('Install packages using `composer install`');
+}
 
 date_default_timezone_set('Europe/Prague');
 
 
-dibi::connect([
-	'driver' => 'sqlite3',
+$dibi = new Dibi\Connection([
+	'driver' => 'sqlite',
 	'database' => 'data/sample.s3db',
 	// enable query logging to this file
 	'profiler' => [
-		'run' => true,
-		'file' => 'data/log.sql',
+		'file' => 'log/log.sql',
 	],
 ]);
 
 
 try {
-	$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] = ?', 1);
+	$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] < ?', 5);
 
-	$res = dibi::query('SELECT FROM [customers] WHERE [customer_id] < ?', 38);
+	$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 data/log.sql:</h2>';
+echo '<h2>File log/log.sql:</h2>';
 
-echo '<pre>', file_get_contents('data/log.sql'), '</pre>';
+echo '<pre>', file_get_contents('log/log.sql'), '</pre>';

+ 0 - 43
api/vendor/dibi/dibi/examples/using-profiler.php

@@ -1,43 +0,0 @@
-<?php ob_start() // needed by FirePHP ?>
-
-<!DOCTYPE html><link rel="stylesheet" href="data/style.css">
-
-<h1>Using Profiler | dibi</h1>
-
-<?php
-
-require __DIR__ . '/../src/loader.php';
-
-
-dibi::connect([
-	'driver' => 'sqlite3',
-	'database' => 'data/sample.s3db',
-	'profiler' => [
-		'run' => true,
-	],
-]);
-
-
-// execute some queries...
-for ($i = 0; $i < 20; $i++) {
-	$res = dibi::query('SELECT * FROM [customers] WHERE [customer_id] < ?', $i);
-}
-
-// display output
-?>
-<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>

+ 15 - 10
api/vendor/dibi/dibi/examples/using-substitutions.php

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

+ 15 - 10
api/vendor/dibi/dibi/examples/using-transactions.php

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

+ 586 - 67
api/vendor/dibi/dibi/readme.md

@@ -1,4 +1,4 @@
-[Dibi](https://dibiphp.com) - smart database layer for PHP  [![Buy me a coffee](https://files.nette.org/images/coffee1s.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9XXL5ZJHAYQUN)
+[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)
@@ -7,127 +7,646 @@
 [![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.
 
-The best way to install Dibi is to use a [Composer](https://getcomposer.org/download):
+If you like Dibi, **[please make a donation now](https://nette.org/make-donation?to=dibi)**. Thank you!
+
+
+Installation
+------------
 
-    php composer.phar require dibi/dibi
+Install Dibi via Composer:
 
-Or you can download the latest package from https://dibiphp.com. In this
-package is also `Dibi.minified`, shrinked single-file version of whole Dibi,
-useful when you don't want to modify the library, but just use it.
+```bash
+composer require dibi/dibi
+```
 
-Dibi requires PHP 5.4.4 or later. It has been tested with PHP 7 too.
+The Dibi 4.0 requires PHP version 7.1 and supports PHP up to 7.2. Older Dibi 3.x requires PHP 5.4 and supports PHP up to 7.2.
 
 
-Examples
---------
+Usage
+-----
 
 Refer to the `examples` directory for examples. Dibi documentation is
 available on the [homepage](https://dibiphp.com).
 
-Connect to database:
+
+### 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
-// connect to database (static way)
 dibi::connect([
-    'driver'   => 'mysql',
+    'driver'   => 'mysqli',
     'host'     => 'localhost',
     'username' => 'root',
     'password' => '***',
+    'database' => 'test',
+    'charset'  => 'utf8',
 ]);
 
-// or object way; in all other examples use $connection-> instead of dibi::
-$connection = new DibiConnection($options);
+$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`.
+
+```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 concencate parameters to SQL, the vulnerability would arise [SQL injection](https://en.wikipedia.org/wiki/SQL_injection)**
+```
+$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 `?` wild 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
+| %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);
 ```
 
-SELECT, INSERT, UPDATE
+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
-dibi::query('SELECT * FROM users WHERE id = ?', $id);
+$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
+
+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 = [
-    'name' => 'John',
-    'is_admin'  => true,
+    'a' => 'hello',
+    'b'  => true,
 ];
-dibi::query('INSERT INTO users', $arr);
-// INSERT INTO users (`name`, `is_admin`) VALUES ('John', 1)
 
-dibi::query('UPDATE users SET', $arr, 'WHERE `id`=?', $x);
-// UPDATE users SET `name`='John', `is_admin`=1 WHERE `id` = 123
+$database->query('INSERT INTO table %v', $arr);
+// INSERT INTO `table` (`a`, `b`) VALUES ('hello', 1)
 
-dibi::query('UPDATE users SET', [
-	'title' => array('SHA1(?)', 'tajneheslo'),
+$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,
 ]);
-// UPDATE users SET 'title' = SHA1('tajneheslo')
+// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978
 ```
 
-Getting results
+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 = dibi::query('SELECT * FROM users');
+$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
+```
 
-$value = $result->fetchSingle(); // single value
-$all = $result->fetchAll(); // all rows
-$assoc = $result->fetchAssoc('id'); // all rows as associative array
-$pairs = $result->fetchPairs('customerID', 'name'); // all rows as key => value pairs
 
-// iterating
-foreach ($result as $n => $row) {
-    print_r($row);
-}
+### 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->beginTransaction();
+
+$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()
 ```
 
-Modifiers for arrays:
+Or an expression in which you can use `?` or modifiers:
 
 ```php
-dibi::query('SELECT * FROM users WHERE %and', [
-	array('number > ?', 10),
-	array('number < ?', 100),
+$database->query('UPDATE `table` SET', [
+	'title' => $database::expression('SHA1(?)', 'secret'),
 ]);
-// SELECT * FROM users WHERE (number > 10) AND (number < 100)
+// UPDATE `table` SET `title` = SHA1('secret')
 ```
 
-<table>
-<tr><td> %and </td><td>  </td><td> `[key]=val AND [key2]="val2" AND ...` </td></tr>
-<tr><td> %or </td><td>  </td><td> `[key]=val OR [key2]="val2" OR ...` </td></tr>
-<tr><td> %a </td><td> assoc </td><td> `[key]=val, [key2]="val2", ...` </td></tr>
-<tr><td> %l %in </td><td> list </td><td> `(val, "val2", ...)` </td></tr>
-<tr><td> %v </td><td> values </td><td> `([key], [key2], ...) VALUES (val, "val2", ...)` </td></tr>
-<tr><td> %m </td><td> multivalues </td><td> `([key], [key2], ...) VALUES (val, "val2", ...), (val, "val2", ...), ...` </td></tr>
-<tr><td> %by </td><td> ordering </td><td> `[key] ASC, [key2] DESC ...` </td></tr>
-<tr><td> %n </td><td> identifiers </td><td> `[key], [key2] AS alias, ...` </td></tr>
-<tr><td> other  </td><td> - </td><td> `val, val2, ...` </td></tr>
-</table>
+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()
+```
 
-Modifiers for LIKE
+In conditions (ie, for `%and` and `%or` modifiers), it is not necessary to specify the keys:
 
 ```php
-dibi::query("SELECT * FROM table WHERE name LIKE %like~", $query);
+$result = $database->query('SELECT * FROM `table` WHERE %and', [
+	'number > 10',
+	'number < 100',
+]);
+// SELECT * FROM `table` WHERE (number > 10) AND (number < 100)
 ```
 
-<table>
-<tr><td> %like~	</td><td> begins with </td></tr>
-<tr><td> %~like	</td><td> ends with </td></tr>
-<tr><td> %~like~ </td><td> contains </td></tr>
-</table>
+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)
+```
 
-DateTime:
+The `%ex` modifier inserts all items of the array into SQL:
 
 ```php
-dibi::query('UPDATE users SET', [
-    'time' => new DateTime,
+$result = $database->query('SELECT * FROM `table` WHERE %ex', [
+	$database::expression('left = ?', 1),
+	'AND',
+	'top IS NULL',
 ]);
-// UPDATE users SET ('2008-01-01 01:08:10')
+// 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');
 ```
 
-Testing:
+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
-echo dibi::$sql; // last SQL query
-echo dibi::$elapsedTime;
-echo dibi::$numOfQueries;
-echo dibi::$totalTime;
+$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\DibiExtension22
+
+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;
+	}
+}
 ```

+ 13 - 12
api/vendor/dibi/dibi/src/Dibi/Bridges/Nette/DibiExtension22.php

@@ -1,14 +1,17 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
@@ -16,11 +19,11 @@ use Nette;
  */
 class DibiExtension22 extends Nette\DI\CompilerExtension
 {
-	/** @var bool */
+	/** @var bool|null */
 	private $debugMode;
 
 
-	public function __construct($debugMode = null)
+	public function __construct(bool $debugMode = null)
 	{
 		$this->debugMode = $debugMode;
 	}
@@ -35,9 +38,7 @@ class DibiExtension22 extends Nette\DI\CompilerExtension
 			$this->debugMode = $container->parameters['debugMode'];
 		}
 
-		$useProfiler = isset($config['profiler'])
-			? $config['profiler']
-			: class_exists('Tracy\Debugger') && $this->debugMode;
+		$useProfiler = $config['profiler'] ?? (class_exists(Tracy\Debugger::class) && $this->debugMode);
 
 		unset($config['profiler']);
 
@@ -50,19 +51,19 @@ class DibiExtension22 extends Nette\DI\CompilerExtension
 		}
 
 		$connection = $container->addDefinition($this->prefix('connection'))
-			->setClass('Dibi\Connection', [$config])
-			->setAutowired(isset($config['autowired']) ? $config['autowired'] : true);
+			->setFactory(Dibi\Connection::class, [$config])
+			->setAutowired($config['autowired'] ?? true);
 
-		if (class_exists('Tracy\Debugger')) {
+		if (class_exists(Tracy\Debugger::class)) {
 			$connection->addSetup(
 				[new Nette\DI\Statement('Tracy\Debugger::getBlueScreen'), 'addPanel'],
-				[['Dibi\Bridges\Tracy\Panel', 'renderException']]
+				[[Dibi\Bridges\Tracy\Panel::class, 'renderException']]
 			);
 		}
 		if ($useProfiler) {
 			$panel = $container->addDefinition($this->prefix('panel'))
-				->setClass('Dibi\Bridges\Tracy\Panel', [
-					isset($config['explain']) ? $config['explain'] : true,
+				->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]);

+ 176 - 220
api/vendor/dibi/dibi/src/Dibi/Connection.php

@@ -1,40 +1,39 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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 Traversable;
 
 
 /**
- * dibi connection.
+ * Dibi connection.
  *
  * @property-read int $affectedRows
  * @property-read int $insertId
  */
-class Connection
+class Connection implements IConnection
 {
 	use Strict;
 
 	/** @var array of function (Event $event); Occurs after query is executed */
-	public $onEvent;
+	public $onEvent = [];
 
 	/** @var array  Current connection configuration */
 	private $config;
 
-	/** @var Driver */
+	/** @var Driver|null */
 	private $driver;
 
-	/** @var Translator */
+	/** @var Translator|null */
 	private $translator;
 
-	/** @var bool  Is connected? */
-	private $connected = false;
-
 	/** @var HashMap Substitutes for identifiers */
 	private $substitutes;
 
@@ -44,20 +43,22 @@ class Connection
 	 *   - lazy (bool) => if true, connection will be established only when required
 	 *   - result (array) => result set options
 	 *       - formatDateTime => date-time format (if empty, DateTime objects will be returned)
-	 *   - profiler (array or bool)
+	 *   - profiler (array)
 	 *       - run (bool) => enable profiler?
 	 *       - file => file to log
 	 *   - substitutes (array) => map of driver specific substitutes (under development)
-	 * @param  mixed   connection parameters
-	 * @param  string  connection name
+	 *   - onConnect (array) => list of SQL queries to execute (by Connection::query()) after connection is established
+	 * @param  array   $config  connection parameters
 	 * @throws Exception
 	 */
-	public function __construct($config, $name = null)
+	public function __construct($config, string $name = null)
 	{
 		if (is_string($config)) {
+			trigger_error(__METHOD__ . '() Configuration should be array.', E_USER_DEPRECATED);
 			parse_str($config, $config);
 
 		} elseif ($config instanceof Traversable) {
+			trigger_error(__METHOD__ . '() Configuration should be array.', E_USER_DEPRECATED);
 			$tmp = [];
 			foreach ($config as $key => $val) {
 				$tmp[$key] = $val instanceof Traversable ? iterator_to_array($val) : $val;
@@ -65,7 +66,7 @@ class Connection
 			$config = $tmp;
 
 		} elseif (!is_array($config)) {
-			throw new \InvalidArgumentException('Configuration must be array, string or object.');
+			throw new \InvalidArgumentException('Configuration must be array.');
 		}
 
 		Helpers::alias($config, 'username', 'user');
@@ -73,52 +74,27 @@ class Connection
 		Helpers::alias($config, 'host', 'hostname');
 		Helpers::alias($config, 'result|formatDate', 'resultDate');
 		Helpers::alias($config, 'result|formatDateTime', 'resultDateTime');
-
-		if (!isset($config['driver'])) {
-			$config['driver'] = \dibi::$defaultDriver;
-		}
-
-		if ($config['driver'] instanceof Driver) {
-			$this->driver = $config['driver'];
-			$config['driver'] = get_class($this->driver);
-		} elseif (is_subclass_of($config['driver'], 'Dibi\Driver')) {
-			$this->driver = new $config['driver'];
-		} else {
-			$class = preg_replace(['#\W#', '#sql#'], ['_', 'Sql'], ucfirst(strtolower($config['driver'])));
-			$class = "Dibi\\Drivers\\{$class}Driver";
-			if (!class_exists($class)) {
-				throw new Exception("Unable to create instance of dibi driver '$class'.");
-			}
-			$this->driver = new $class;
-		}
-
+		$config['driver'] = $config['driver'] ?? 'mysqli';
 		$config['name'] = $name;
 		$this->config = $config;
 
 		// profiler
-		$profilerCfg = &$config['profiler'];
-		if (is_scalar($profilerCfg)) {
-			$profilerCfg = ['run' => (bool) $profilerCfg];
+		if (isset($config['profiler']['file']) && (!isset($config['profiler']['run']) || $config['profiler']['run'])) {
+			$filter = $config['profiler']['filter'] ?? Event::QUERY;
+			$this->onEvent[] = [new Loggers\FileLogger($config['profiler']['file'], $filter), 'logEvent'];
 		}
-		if (!empty($profilerCfg['run'])) {
-			$filter = isset($profilerCfg['filter']) ? $profilerCfg['filter'] : Event::QUERY;
 
-			if (isset($profilerCfg['file'])) {
-				$this->onEvent[] = [new Loggers\FileLogger($profilerCfg['file'], $filter), 'logEvent'];
-			}
-
-			if (Loggers\FirePhpLogger::isAvailable()) {
-				$this->onEvent[] = [new Loggers\FirePhpLogger($filter), 'logEvent'];
-			}
-		}
-
-		$this->substitutes = new HashMap(function ($expr) { return ":$expr:"; });
+		$this->substitutes = new HashMap(function (string $expr) { return ":$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();
 		}
@@ -127,29 +103,51 @@ class Connection
 
 	/**
 	 * 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->connected && $this->driver->getResource() && $this->disconnect();
+		if ($this->driver && $this->driver->getResource()) {
+			$this->disconnect();
+		}
 	}
 
 
 	/**
 	 * Connects to a database.
-	 * @return void
 	 */
-	final public function connect()
+	final public function connect(): void
 	{
+		if ($this->config['driver'] instanceof Driver) {
+			$this->driver = $this->config['driver'];
+			return;
+
+		} elseif (is_subclass_of($this->config['driver'], Driver::class)) {
+			$class = $this->config['driver'];
+
+		} else {
+			$class = preg_replace(['#\W#', '#sql#'], ['_', 'Sql'], ucfirst(strtolower($this->config['driver'])));
+			$class = "Dibi\\Drivers\\{$class}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->connect($this->config);
-			$this->connected = true;
-			$event && $this->onEvent($event->done());
+			$this->driver = new $class($this->config);
+			if ($event) {
+				$this->onEvent($event->done());
+			}
+			if (isset($this->config['onConnect'])) {
+				foreach ($this->config['onConnect'] as $sql) {
+					$this->query($sql);
+				}
+			}
 
-		} catch (Exception $e) {
-			$event && $this->onEvent($event->done($e));
+		} catch (DriverException $e) {
+			if ($event) {
+				$this->onEvent($event->done($e));
+			}
 			throw $e;
 		}
 	}
@@ -157,99 +155,78 @@ class Connection
 
 	/**
 	 * Disconnects from a database.
-	 * @return void
 	 */
-	final public function disconnect()
+	final public function disconnect(): void
 	{
-		$this->driver->disconnect();
-		$this->connected = false;
+		if ($this->driver) {
+			$this->driver->disconnect();
+			$this->driver = null;
+		}
 	}
 
 
 	/**
 	 * Returns true when connection was established.
-	 * @return bool
 	 */
-	final public function isConnected()
+	final public function isConnected(): bool
 	{
-		return $this->connected;
+		return (bool) $this->driver;
 	}
 
 
 	/**
 	 * 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)
+	final public function getConfig(string $key = null, $default = null)
 	{
-		if ($key === null) {
-			return $this->config;
-
-		} elseif (isset($this->config[$key])) {
-			return $this->config[$key];
-
-		} else {
-			return $default;
-		}
-	}
-
-
-	/** @deprecated */
-	public static function alias(&$config, $key, $alias)
-	{
-		trigger_error(__METHOD__ . '() is deprecated, use Helpers::alias().', E_USER_DEPRECATED);
-		Helpers::alias($config, $key, $alias);
+		return $key === null
+			? $this->config
+			: ($this->config[$key] ?? $default);
 	}
 
 
 	/**
 	 * Returns the driver and connects to a database in lazy mode.
-	 * @return Driver
 	 */
-	final public function getDriver()
+	final public function getDriver(): Driver
 	{
-		$this->connected || $this->connect();
+		if (!$this->driver) {
+			$this->connect();
+		}
 		return $this->driver;
 	}
 
 
 	/**
 	 * Generates (translates) and executes SQL query.
-	 * @param  array|mixed      one or more arguments
-	 * @return Result|int   result set or number of affected rows
+	 * @param  mixed  ...$args
 	 * @throws Exception
 	 */
-	final public function query($args)
+	final public function query(...$args): Result
 	{
-		$args = func_get_args();
 		return $this->nativeQuery($this->translateArgs($args));
 	}
 
 
 	/**
 	 * Generates SQL query.
-	 * @param  array|mixed      one or more arguments
-	 * @return string
+	 * @param  mixed  ...$args
 	 * @throws Exception
 	 */
-	final public function translate($args)
+	final public function translate(...$args): string
 	{
-		$args = func_get_args();
 		return $this->translateArgs($args);
 	}
 
 
 	/**
 	 * Generates and prints SQL query.
-	 * @param  array|mixed  one or more arguments
-	 * @return bool
+	 * @param  mixed  ...$args
 	 */
-	final public function test($args)
+	final public function test(...$args): bool
 	{
-		$args = func_get_args();
 		try {
 			Helpers::dump($this->translateArgs($args));
 			return true;
@@ -267,25 +244,23 @@ class Connection
 
 	/**
 	 * Generates (translates) and returns SQL query as DataSource.
-	 * @param  array|mixed      one or more arguments
-	 * @return DataSource
+	 * @param  mixed  ...$args
 	 * @throws Exception
 	 */
-	final public function dataSource($args)
+	final public function dataSource(...$args): DataSource
 	{
-		$args = func_get_args();
 		return new DataSource($this->translateArgs($args), $this);
 	}
 
 
 	/**
 	 * Generates SQL query.
-	 * @param  array
-	 * @return string
 	 */
-	protected function translateArgs($args)
+	protected function translateArgs(array $args): string
 	{
-		$this->connected || $this->connect();
+		if (!$this->driver) {
+			$this->connect();
+		}
 		if (!$this->translator) {
 			$this->translator = new Translator($this);
 		}
@@ -296,45 +271,45 @@ class Connection
 
 	/**
 	 * Executes the SQL query.
-	 * @param  string           SQL statement.
-	 * @return Result|int   result set or number of affected rows
 	 * @throws Exception
 	 */
-	final public function nativeQuery($sql)
+	final public function nativeQuery(string $sql): Result
 	{
-		$this->connected || $this->connect();
+		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 (Exception $e) {
-			$event && $this->onEvent($event->done($e));
+		} catch (DriverException $e) {
+			if ($event) {
+				$this->onEvent($event->done($e));
+			}
 			throw $e;
 		}
 
-		if ($res) {
-			$res = $this->createResultSet($res);
-		} else {
-			$res = $this->driver->getAffectedRows();
+		$res = $this->createResultSet($res ?: new Drivers\NoDataResult(max(0, $this->driver->getAffectedRows())));
+		if ($event) {
+			$this->onEvent($event->done($res));
 		}
-
-		$event && $this->onEvent($event->done($res));
 		return $res;
 	}
 
 
 	/**
 	 * Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
-	 * @return int  number of rows
 	 * @throws Exception
 	 */
-	public function getAffectedRows()
+	public function getAffectedRows(): int
 	{
-		$this->connected || $this->connect();
+		if (!$this->driver) {
+			$this->connect();
+		}
 		$rows = $this->driver->getAffectedRows();
-		if (!is_int($rows) || $rows < 0) {
+		if ($rows === null || $rows < 0) {
 			throw new Exception('Cannot retrieve number of affected rows.');
 		}
 		return $rows;
@@ -344,7 +319,7 @@ class Connection
 	/**
 	 * @deprecated
 	 */
-	public function affectedRows()
+	public function affectedRows(): int
 	{
 		trigger_error(__METHOD__ . '() is deprecated, use getAffectedRows()', E_USER_DEPRECATED);
 		return $this->getAffectedRows();
@@ -353,25 +328,25 @@ class Connection
 
 	/**
 	 * Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
-	 * @param  string     optional sequence name
-	 * @return int
 	 * @throws Exception
 	 */
-	public function getInsertId($sequence = null)
+	public function getInsertId(string $sequence = null): int
 	{
-		$this->connected || $this->connect();
+		if (!$this->driver) {
+			$this->connect();
+		}
 		$id = $this->driver->getInsertId($sequence);
 		if ($id < 1) {
 			throw new Exception('Cannot retrieve last generated ID.');
 		}
-		return Helpers::intVal($id);
+		return $id;
 	}
 
 
 	/**
 	 * @deprecated
 	 */
-	public function insertId($sequence = null)
+	public function insertId(string $sequence = null): int
 	{
 		trigger_error(__METHOD__ . '() is deprecated, use getInsertId()', E_USER_DEPRECATED);
 		return $this->getInsertId($sequence);
@@ -380,19 +355,23 @@ class Connection
 
 	/**
 	 * Begins a transaction (if supported).
-	 * @param  string  optional savepoint name
-	 * @return void
 	 */
-	public function begin($savepoint = null)
+	public function begin(string $savepoint = null): void
 	{
-		$this->connected || $this->connect();
+		if (!$this->driver) {
+			$this->connect();
+		}
 		$event = $this->onEvent ? new Event($this, Event::BEGIN, $savepoint) : null;
 		try {
 			$this->driver->begin($savepoint);
-			$event && $this->onEvent($event->done());
+			if ($event) {
+				$this->onEvent($event->done());
+			}
 
-		} catch (Exception $e) {
-			$event && $this->onEvent($event->done($e));
+		} catch (DriverException $e) {
+			if ($event) {
+				$this->onEvent($event->done($e));
+			}
 			throw $e;
 		}
 	}
@@ -400,19 +379,23 @@ class Connection
 
 	/**
 	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 */
-	public function commit($savepoint = null)
+	public function commit(string $savepoint = null): void
 	{
-		$this->connected || $this->connect();
+		if (!$this->driver) {
+			$this->connect();
+		}
 		$event = $this->onEvent ? new Event($this, Event::COMMIT, $savepoint) : null;
 		try {
 			$this->driver->commit($savepoint);
-			$event && $this->onEvent($event->done());
+			if ($event) {
+				$this->onEvent($event->done());
+			}
 
-		} catch (Exception $e) {
-			$event && $this->onEvent($event->done($e));
+		} catch (DriverException $e) {
+			if ($event) {
+				$this->onEvent($event->done($e));
+			}
 			throw $e;
 		}
 	}
@@ -420,19 +403,23 @@ class Connection
 
 	/**
 	 * Rollback changes in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 */
-	public function rollback($savepoint = null)
+	public function rollback(string $savepoint = null): void
 	{
-		$this->connected || $this->connect();
+		if (!$this->driver) {
+			$this->connect();
+		}
 		$event = $this->onEvent ? new Event($this, Event::ROLLBACK, $savepoint) : null;
 		try {
 			$this->driver->rollback($savepoint);
-			$event && $this->onEvent($event->done());
+			if ($event) {
+				$this->onEvent($event->done());
+			}
 
-		} catch (Exception $e) {
-			$event && $this->onEvent($event->done($e));
+		} catch (DriverException $e) {
+			if ($event) {
+				$this->onEvent($event->done($e));
+			}
 			throw $e;
 		}
 	}
@@ -440,10 +427,8 @@ class Connection
 
 	/**
 	 * Result set factory.
-	 * @param  ResultDriver
-	 * @return Result
 	 */
-	public function createResultSet(ResultDriver $resultDriver)
+	public function createResultSet(ResultDriver $resultDriver): Result
 	{
 		$res = new Result($resultDriver);
 		return $res->setFormat(Type::DATE, $this->config['result']['formatDate'])
@@ -454,62 +439,38 @@ class Connection
 	/********************* fluent SQL builders ****************d*g**/
 
 
-	/**
-	 * @return Fluent
-	 */
-	public function command()
+	public function command(): Fluent
 	{
 		return new Fluent($this);
 	}
 
 
-	/**
-	 * @param  mixed    column name
-	 * @return Fluent
-	 */
-	public function select($args)
+	public function select(...$args): Fluent
 	{
-		$args = func_get_args();
-		return $this->command()->__call('select', $args);
+		return $this->command()->select(...$args);
 	}
 
 
 	/**
-	 * @param  string   table
-	 * @param  array
-	 * @return Fluent
+	 * @param  string|string[]  $table
 	 */
-	public function update($table, $args)
+	public function update($table, iterable $args): Fluent
 	{
-		if (!(is_array($args) || $args instanceof Traversable)) {
-			throw new \InvalidArgumentException('Arguments must be array or Traversable.');
-		}
 		return $this->command()->update('%n', $table)->set($args);
 	}
 
 
-	/**
-	 * @param  string   table
-	 * @param  array
-	 * @return Fluent
-	 */
-	public function insert($table, $args)
+	public function insert(string $table, iterable $args): Fluent
 	{
 		if ($args instanceof Traversable) {
 			$args = iterator_to_array($args);
-		} elseif (!is_array($args)) {
-			throw new \InvalidArgumentException('Arguments must be array or Traversable.');
 		}
 		return $this->command()->insert()
 			->into('%n', $table, '(%n)', array_keys($args))->values('%l', $args);
 	}
 
 
-	/**
-	 * @param  string   table
-	 * @return Fluent
-	 */
-	public function delete($table)
+	public function delete(string $table): Fluent
 	{
 		return $this->command()->delete()->from('%n', $table);
 	}
@@ -520,9 +481,8 @@ class Connection
 
 	/**
 	 * Returns substitution hashmap.
-	 * @return HashMap
 	 */
-	public function getSubstitutes()
+	public function getSubstitutes(): HashMap
 	{
 		return $this->substitutes;
 	}
@@ -530,13 +490,12 @@ class Connection
 
 	/**
 	 * Provides substitution.
-	 * @return string
 	 */
-	public function substitute($value)
+	public function substitute(string $value): string
 	{
 		return strpos($value, ':') === false
 			? $value
-			: preg_replace_callback('#:([^:\s]*):#', function ($m) { return $this->substitutes->{$m[1]}; }, $value);
+			: preg_replace_callback('#:([^:\s]*):#', function (array $m) { return $this->substitutes->{$m[1]}; }, $value);
 	}
 
 
@@ -545,75 +504,71 @@ class Connection
 
 	/**
 	 * Executes SQL query and fetch result - shortcut for query() & fetch().
-	 * @param  array|mixed    one or more arguments
-	 * @return Row|false
+	 * @param  mixed  ...$args
 	 * @throws Exception
 	 */
-	public function fetch($args)
+	public function fetch(...$args): ?Row
 	{
-		$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 Row[]
+	 * @param  mixed  ...$args
+	 * @return Row[]|array[]
 	 * @throws Exception
 	 */
-	public function fetchAll($args)
+	public function fetchAll(...$args): array
 	{
-		$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
+	 * @param  mixed  ...$args
 	 * @return mixed
 	 * @throws Exception
 	 */
-	public function fetchSingle($args)
+	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 array
+	 * @param  mixed  ...$args
 	 * @throws Exception
 	 */
-	public function fetchPairs($args)
+	public function fetchPairs(...$args): array
 	{
-		$args = func_get_args();
 		return $this->query($args)->fetchPairs();
 	}
 
 
-	/**
-	 * @return Literal
-	 */
-	public static function literal($value)
+	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  string  filename
-	 * @param  callable  function (int $count, ?float $percent): void
+	 * @param  callable  $onProgress  function (int $count, ?float $percent): void
 	 * @return int  count of sql commands
 	 */
-	public function loadFile($file, callable $onProgress = null)
+	public function loadFile(string $file, callable $onProgress = null): int
 	{
 		return Helpers::loadFromFile($this, $file, $onProgress);
 	}
@@ -621,12 +576,13 @@ class Connection
 
 	/**
 	 * Gets a information about the current database.
-	 * @return Reflection\Database
 	 */
-	public function getDatabaseInfo()
+	public function getDatabaseInfo(): Reflection\Database
 	{
-		$this->connected || $this->connect();
-		return new Reflection\Database($this->driver->getReflector(), isset($this->config['database']) ? $this->config['database'] : null);
+		if (!$this->driver) {
+			$this->connect();
+		}
+		return new Reflection\Database($this->driver->getReflector(), $this->config['database'] ?? null);
 	}
 
 
@@ -648,10 +604,10 @@ class Connection
 	}
 
 
-	protected function onEvent($arg)
+	protected function onEvent($arg): void
 	{
-		foreach ($this->onEvent ?: [] as $handler) {
-			call_user_func($handler, $arg);
+		foreach ($this->onEvent as $handler) {
+			$handler($arg);
 		}
 	}
 }

+ 32 - 60
api/vendor/dibi/dibi/src/Dibi/DataSource.php

@@ -1,15 +1,17 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * Default implementation of IDataSource for dibi.
+ * Default implementation of IDataSource.
  */
 class DataSource implements IDataSource
 {
@@ -21,13 +23,13 @@ class DataSource implements IDataSource
 	/** @var string */
 	private $sql;
 
-	/** @var Result */
+	/** @var Result|null */
 	private $result;
 
-	/** @var int */
+	/** @var int|null */
 	private $count;
 
-	/** @var int */
+	/** @var int|null */
 	private $totalCount;
 
 	/** @var array */
@@ -47,10 +49,9 @@ class DataSource implements IDataSource
 
 
 	/**
-	 * @param  string  SQL command or table or view name, as data source
-	 * @param  Connection  connection
+	 * @param  string  $sql  command or table or view name, as data source
 	 */
-	public function __construct($sql, Connection $connection)
+	public function __construct(string $sql, Connection $connection)
 	{
 		if (strpbrk($sql, " \t\r\n") === false) {
 			$this->sql = $connection->getDriver()->escapeIdentifier($sql); // table name
@@ -63,11 +64,10 @@ class DataSource implements IDataSource
 
 	/**
 	 * Selects columns to query.
-	 * @param  string|array  column name or array of column names
-	 * @param  string        column alias
-	 * @return self
+	 * @param  string|array  $col  column name or array of column names
+	 * @param  string  $as        column alias
 	 */
-	public function select($col, $as = null)
+	public function select($col, string $as = null): self
 	{
 		if (is_array($col)) {
 			$this->cols = $col;
@@ -81,10 +81,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * Adds conditions to query.
-	 * @param  mixed  conditions
-	 * @return self
 	 */
-	public function where($cond)
+	public function where($cond): self
 	{
 		if (is_array($cond)) {
 			// TODO: not consistent with select and orderBy
@@ -99,16 +97,14 @@ class DataSource implements IDataSource
 
 	/**
 	 * Selects columns to order by.
-	 * @param  string|array  column name or array of column names
-	 * @param  string        sorting direction
-	 * @return self
+	 * @param  string|array  $row  column name or array of column names
 	 */
-	public function orderBy($row, $sorting = 'ASC')
+	public function orderBy($row, string $direction = 'ASC'): self
 	{
 		if (is_array($row)) {
 			$this->sorting = $row;
 		} else {
-			$this->sorting[$row] = $sorting;
+			$this->sorting[$row] = $direction;
 		}
 		$this->result = null;
 		return $this;
@@ -117,11 +113,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * Limits number of rows.
-	 * @param  int|null limit
-	 * @param  int offset
-	 * @return self
 	 */
-	public function applyLimit($limit, $offset = null)
+	public function applyLimit(int $limit, int $offset = null): self
 	{
 		$this->limit = $limit;
 		$this->offset = $offset;
@@ -130,11 +123,7 @@ class DataSource implements IDataSource
 	}
 
 
-	/**
-	 * Returns the dibi connection.
-	 * @return Connection
-	 */
-	final public function getConnection()
+	final public function getConnection(): Connection
 	{
 		return $this->connection;
 	}
@@ -145,9 +134,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * Returns (and queries) Result.
-	 * @return Result
 	 */
-	public function getResult()
+	public function getResult(): Result
 	{
 		if ($this->result === null) {
 			$this->result = $this->connection->nativeQuery($this->__toString());
@@ -156,10 +144,7 @@ class DataSource implements IDataSource
 	}
 
 
-	/**
-	 * @return ResultIterator
-	 */
-	public function getIterator()
+	public function getIterator(): ResultIterator
 	{
 		return $this->getResult()->getIterator();
 	}
@@ -167,9 +152,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * Generates, executes SQL query and fetches the single row.
-	 * @return Row|false
 	 */
-	public function fetch()
+	public function fetch(): ?Row
 	{
 		return $this->getResult()->fetch();
 	}
@@ -177,7 +161,7 @@ class DataSource implements IDataSource
 
 	/**
 	 * Like fetch(), but returns only first field.
-	 * @return mixed  value on success, false if no next record
+	 * @return mixed  value on success, null if no next record
 	 */
 	public function fetchSingle()
 	{
@@ -187,9 +171,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * Fetches all records from table.
-	 * @return array
 	 */
-	public function fetchAll()
+	public function fetchAll(): array
 	{
 		return $this->getResult()->fetchAll();
 	}
@@ -197,10 +180,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * Fetches all records from table and returns associative tree.
-	 * @param  string  associative descriptor
-	 * @return array
 	 */
-	public function fetchAssoc($assoc)
+	public function fetchAssoc(string $assoc): array
 	{
 		return $this->getResult()->fetchAssoc($assoc);
 	}
@@ -208,11 +189,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * 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)
+	public function fetchPairs(string $key = null, string $value = null): array
 	{
 		return $this->getResult()->fetchPairs($key, $value);
 	}
@@ -220,9 +198,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * Discards the internal cache.
-	 * @return void
 	 */
-	public function release()
+	public function release(): void
 	{
 		$this->result = $this->count = $this->totalCount = null;
 	}
@@ -233,9 +210,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * Returns this data source wrapped in Fluent object.
-	 * @return Fluent
 	 */
-	public function toFluent()
+	public function toFluent(): Fluent
 	{
 		return $this->connection->select('*')->from('(%SQL) t', $this->__toString());
 	}
@@ -243,9 +219,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * Returns this data source wrapped in DataSource object.
-	 * @return DataSource
 	 */
-	public function toDataSource()
+	public function toDataSource(): self
 	{
 		return new self($this->__toString(), $this->connection);
 	}
@@ -253,9 +228,8 @@ class DataSource implements IDataSource
 
 	/**
 	 * Returns SQL query.
-	 * @return string
 	 */
-	public function __toString()
+	public function __toString(): string
 	{
 		try {
 			return $this->connection->translate('
@@ -265,7 +239,7 @@ FROM %SQL', $this->sql, '
 %ex', $this->sorting ? ['ORDER BY %by', $this->sorting] : null, '
 %ofs %lmt', $this->offset, $this->limit
 			);
-		} catch (\Exception $e) {
+		} catch (\Throwable $e) {
 			trigger_error($e->getMessage(), E_USER_ERROR);
 			return '';
 		}
@@ -277,9 +251,8 @@ FROM %SQL', $this->sql, '
 
 	/**
 	 * Returns the number of rows in a given data source.
-	 * @return int
 	 */
-	public function count()
+	public function count(): int
 	{
 		if ($this->count === null) {
 			$this->count = $this->conds || $this->offset || $this->limit
@@ -294,9 +267,8 @@ FROM %SQL', $this->sql, '
 
 	/**
 	 * Returns the number of rows in a given data source.
-	 * @return int
 	 */
-	public function getTotalCount()
+	public function getTotalCount(): int
 	{
 		if ($this->totalCount === null) {
 			$this->totalCount = Helpers::intVal($this->connection->nativeQuery(

+ 61 - 27
api/vendor/dibi/dibi/src/Dibi/DateTime.php

@@ -1,74 +1,108 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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 \DateTime
+class DateTime extends \DateTimeImmutable
 {
 	use Strict;
 
 	/**
-	 * @param  string|int
+	 * @param  string|int  $time
 	 */
 	public function __construct($time = 'now', \DateTimeZone $timezone = null)
 	{
+		$timezone = $timezone ?: new \DateTimeZone(date_default_timezone_get());
 		if (is_numeric($time)) {
-			parent::__construct('@' . $time);
-			$this->setTimeZone($timezone ? $timezone : new \DateTimeZone(date_default_timezone_get()));
-		} elseif ($timezone === null) {
-			parent::__construct($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 modifyClone($modify = '')
+	/** @deprecated  use modify() */
+	public function modifyClone(string $modify = ''): self
 	{
+		trigger_error(__METHOD__ . '() is deprecated, use modify()', E_USER_DEPRECATED);
 		$dolly = clone $this;
 		return $modify ? $dolly->modify($modify) : $dolly;
 	}
 
 
-	public function setTimestamp($timestamp)
+	public function __toString(): string
 	{
-		$zone = $this->getTimezone();
-		$this->__construct('@' . $timestamp);
-		return $this->setTimeZone($zone);
+		return $this->format('Y-m-d H:i:s.u');
 	}
 
 
-	public function getTimestamp()
+	/********************* immutable usage detector ****************d*g**/
+
+
+	public function __destruct()
 	{
-		$ts = $this->format('U');
-		return is_float($tmp = $ts * 1) ? $ts : $tmp;
+		$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
+		if (isset($trace[0]['file'], $trace[1]['function']) && $trace[0]['file'] === __FILE__ && $trace[1]['function'] !== '__construct') {
+			trigger_error(__CLASS__ . ' is immutable now, check how it is used in ' . $trace[1]['file'] . ':' . $trace[1]['line'], E_USER_WARNING);
+		}
 	}
 
 
-	public function __toString()
+	public function add($interval)
 	{
-		return $this->format('Y-m-d H:i:s.u');
+		return parent::add($interval);
 	}
 
 
-	public function __wakeup()
+	public function modify($modify)
 	{
-		if (isset($this->fix, $this->fix[1])) {
-			$this->__construct($this->fix[0], new \DateTimeZone($this->fix[1]));
-			unset($this->fix);
-		} elseif (isset($this->fix)) {
-			$this->__construct($this->fix[0]);
-			unset($this->fix);
-		} else {
-			parent::__wakeup();
-		}
+		return parent::modify($modify);
+	}
+
+
+	public function setDate($year, $month, $day)
+	{
+		return parent::setDate($year, $month, $day);
+	}
+
+
+	public function setISODate($year, $week, $day = 1)
+	{
+		return parent::setISODate($year, $week, $day);
+	}
+
+
+	public function setTime($hour, $minute, $second = 0, $micro = 0)
+	{
+		return parent::setTime($hour, $minute, $second, $micro);
+	}
+
+
+	public function setTimestamp($unixtimestamp)
+	{
+		return parent::setTimestamp($unixtimestamp);
+	}
+
+
+	public function setTimezone($timezone)
+	{
+		return parent::setTimezone($timezone);
+	}
+
+
+	public function sub($interval)
+	{
+		return parent::sub($interval);
 	}
 }

+ 41 - 586
api/vendor/dibi/dibi/src/Dibi/Drivers/FirebirdDriver.php

@@ -1,17 +1,20 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
+use Dibi\Helpers;
 
 
 /**
- * The dibi driver for Firebird/InterBase database.
+ * The driver for Firebird/InterBase database.
  *
  * Driver options:
  *   - database => the path to database file (server:/path/database.fdb)
@@ -20,23 +23,16 @@ use Dibi;
  *   - charset => character encoding to set
  *   - buffers (int) => buffers is the number of database buffers to allocate for the server-side cache. If 0 or omitted, server chooses its own default.
  *   - resource (resource) => existing connection resource
- *   - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
  */
-class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
+class FirebirdDriver implements Dibi\Driver
 {
 	use Dibi\Strict;
 
-	const ERROR_EXCEPTION_THROWN = -836;
+	public const ERROR_EXCEPTION_THROWN = -836;
 
-	/** @var resource|null */
+	/** @var resource */
 	private $connection;
 
-	/** @var resource|null */
-	private $resultSet;
-
-	/** @var bool */
-	private $autoFree = true;
-
 	/** @var resource|null */
 	private $transaction;
 
@@ -47,22 +43,13 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 	/**
 	 * @throws Dibi\NotSupportedException
 	 */
-	public function __construct()
+	public function __construct(array $config)
 	{
 		if (!extension_loaded('interbase')) {
 			throw new Dibi\NotSupportedException("PHP extension 'interbase' is not loaded.");
 		}
-	}
-
 
-	/**
-	 * Connects to a database.
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public function connect(array &$config)
-	{
-		Dibi\Helpers::alias($config, 'database', 'db');
+		Helpers::alias($config, 'database', 'db');
 
 		if (isset($config['resource'])) {
 			$this->connection = $config['resource'];
@@ -92,9 +79,8 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Disconnects from a database.
-	 * @return void
 	 */
-	public function disconnect()
+	public function disconnect(): void
 	{
 		@ibase_close($this->connection); // @ - connection can be already disconnected
 	}
@@ -102,11 +88,9 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return Dibi\ResultDriver|null
 	 * @throws Dibi\DriverException|Dibi\Exception
 	 */
-	public function query($sql)
+	public function query(string $sql): ?Dibi\ResultDriver
 	{
 		$resource = $this->inTransaction ? $this->transaction : $this->connection;
 		$res = ibase_query($resource, $sql);
@@ -129,32 +113,27 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * 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()
+	public function getAffectedRows(): ?int
 	{
-		return ibase_affected_rows($this->connection);
+		return Helpers::false2Null(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)
+	public function getInsertId(?string $sequence): ?int
 	{
-		return ibase_gen_id($sequence, 0, $this->connection);
+		return Helpers::false2Null(ibase_gen_id($sequence, 0, $this->connection));
 	}
 
 
 	/**
 	 * Begins a transaction (if supported).
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function begin($savepoint = null)
+	public function begin(string $savepoint = null): void
 	{
 		if ($savepoint !== null) {
 			throw new Dibi\NotSupportedException('Savepoints are not supported in Firebird/Interbase.');
@@ -166,11 +145,9 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function commit($savepoint = null)
+	public function commit(string $savepoint = null): void
 	{
 		if ($savepoint !== null) {
 			throw new Dibi\NotSupportedException('Savepoints are not supported in Firebird/Interbase.');
@@ -186,11 +163,9 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Rollback changes in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function rollback($savepoint = null)
+	public function rollback(string $savepoint = null): void
 	{
 		if ($savepoint !== null) {
 			throw new Dibi\NotSupportedException('Savepoints are not supported in Firebird/Interbase.');
@@ -206,9 +181,8 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Is in transaction?
-	 * @return bool
 	 */
-	public function inTransaction()
+	public function inTransaction(): bool
 	{
 		return $this->inTransaction;
 	}
@@ -226,24 +200,20 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Returns the connection reflector.
-	 * @return Dibi\Reflector
 	 */
-	public function getReflector()
+	public function getReflector(): Dibi\Reflector
 	{
-		return $this;
+		return new FirebirdReflector($this);
 	}
 
 
 	/**
 	 * Result set driver factory.
-	 * @param  resource
-	 * @return Dibi\ResultDriver
+	 * @param  resource  $resource
 	 */
-	public function createResultDriver($resource)
+	public function createResultDriver($resource): FirebirdResult
 	{
-		$res = clone $this;
-		$res->resultSet = $resource;
-		return $res;
+		return new FirebirdResult($resource);
 	}
 
 
@@ -252,52 +222,37 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Encodes data for use in a SQL statement.
-	 * @param  string
-	 * @return string
 	 */
-	public function escapeText($value)
+	public function escapeText(string $value): string
 	{
 		return "'" . str_replace("'", "''", $value) . "'";
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeBinary($value)
+	public function escapeBinary(string $value): string
 	{
 		return "'" . str_replace("'", "''", $value) . "'";
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeIdentifier($value)
+	public function escapeIdentifier(string $value): string
 	{
 		return '"' . str_replace('"', '""', $value) . '"';
 	}
 
 
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	public function escapeBool($value)
+	public function escapeBool(bool $value): string
 	{
 		return $value ? '1' : '0';
 	}
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDate($value)
+	public function escapeDate($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
 		return $value->format("'Y-m-d'");
@@ -305,535 +260,35 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDateTime($value)
+	public function escapeDateTime($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
-		return $value->format("'Y-m-d H:i:s.u'");
+		return "'" . substr($value->format('Y-m-d H:i:s.u'), 0, -2) . "'";
 	}
 
 
 	/**
 	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
 	 */
-	public function escapeLike($value, $pos)
+	public function escapeLike(string $value, int $pos): string
 	{
-		throw new Dibi\NotImplementedException;
-	}
-
-
-	/**
-	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
-	 */
-	public function unescapeBinary($value)
-	{
-		return $value;
-	}
-
-
-	/** @deprecated */
-	public function escape($value, $type)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		return Dibi\Helpers::escape($this, $value, $type);
+		$value = addcslashes($this->escapeText($value), '%_\\');
+		return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
 	}
 
 
 	/**
 	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
 	 */
-	public function applyLimit(&$sql, $limit, $offset)
+	public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
 	{
 		if ($limit > 0 || $offset > 0) {
 			// http://www.firebirdsql.org/refdocs/langrefupd20-select.html
-			$sql = 'SELECT ' . ($limit > 0 ? 'FIRST ' . Dibi\Helpers::intVal($limit) : '')
-				. ($offset > 0 ? ' SKIP ' . Dibi\Helpers::intVal($offset) : '')
-				. ' * FROM (' . $sql . ')';
-		}
-	}
-
-
-	/********************* result set ********************/
-
-
-	/**
-	 * Automatically frees the resources allocated for this result set.
-	 * @return void
-	 */
-	public function __destruct()
-	{
-		$this->autoFree && $this->getResultResource() && $this->free();
-	}
-
-
-	/**
-	 * Returns the number of rows in a result set.
-	 * @return int
-	 */
-	public function getRowCount()
-	{
-		throw new Dibi\NotSupportedException('Firebird/Interbase do not support returning number of rows in result set.');
-	}
-
-
-	/**
-	 * 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
-	 */
-	public function fetch($assoc)
-	{
-		$result = $assoc ? @ibase_fetch_assoc($this->resultSet, IBASE_TEXT) : @ibase_fetch_row($this->resultSet, IBASE_TEXT); // intentionally @
-
-		if (ibase_errcode()) {
-			if (ibase_errcode() == self::ERROR_EXCEPTION_THROWN) {
-				preg_match('/exception (\d+) (\w+) (.*)/is', ibase_errmsg(), $match);
-				throw new Dibi\ProcedureException($match[3], $match[1], $match[2]);
-
-			} else {
-				throw new Dibi\DriverException(ibase_errmsg(), ibase_errcode());
-			}
-		}
-
-		return $result;
-	}
-
-
-	/**
-	 * Moves cursor position without fetching row.
-	 * @param  int   the 0-based cursor pos to seek to
-	 * @return bool  true on success, false if unable to seek to specified record
-	 * @throws Dibi\Exception
-	 */
-	public function seek($row)
-	{
-		throw new Dibi\NotSupportedException('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 resource|null
-	 */
-	public function getResultResource()
-	{
-		$this->autoFree = false;
-		return is_resource($this->resultSet) ? $this->resultSet : null;
-	}
-
-
-	/**
-	 * Returns metadata for all columns in a result set.
-	 * @return array
-	 */
-	public function getResultColumns()
-	{
-		$count = ibase_num_fields($this->resultSet);
-		$columns = [];
-		for ($i = 0; $i < $count; $i++) {
-			$row = (array) ibase_field_info($this->resultSet, $i);
-			$columns[] = [
-				'name' => $row['name'],
-				'fullname' => $row['name'],
-				'table' => $row['relation'],
-				'nativetype' => $row['type'],
-			];
-		}
-		return $columns;
-	}
-
-
-	/********************* Dibi\Reflector ********************/
-
-
-	/**
-	 * Returns list of tables.
-	 * @return array
-	 */
-	public function getTables()
-	{
-		$res = $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;"
-		);
-		$tables = [];
-		while ($row = $res->fetch(false)) {
-			$tables[] = [
-				'name' => $row[0],
-				'view' => $row[1] === 'TRUE',
-			];
-		}
-		return $tables;
-	}
-
-
-	/**
-	 * Returns metadata for all columns in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getColumns($table)
-	{
-		$table = strtoupper($table);
-		$res = $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;"
-
-		);
-		$columns = [];
-		while ($row = $res->fetch(true)) {
-			$key = $row['FIELD_NAME'];
-			$columns[$key] = [
-				'name' => $key,
-				'table' => $table,
-				'nativetype' => trim($row['FIELD_TYPE']),
-				'size' => $row['FIELD_LENGTH'],
-				'nullable' => $row['NULLABLE'] === 'TRUE',
-				'default' => $row['DEFAULT_VALUE'],
-				'autoincrement' => false,
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns metadata for all indexes in a table (the constraints are included).
-	 * @param  string
-	 * @return array
-	 */
-	public function getIndexes($table)
-	{
-		$table = strtoupper($table);
-		$res = $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"
-		);
-		$indexes = [];
-		while ($row = $res->fetch(true)) {
-			$key = $row['INDEX_NAME'];
-			$indexes[$key]['name'] = $key;
-			$indexes[$key]['unique'] = $row['UNIQUE_FLAG'] === 1;
-			$indexes[$key]['primary'] = $row['CONSTRAINT_TYPE'] === 'PRIMARY KEY';
-			$indexes[$key]['table'] = $table;
-			$indexes[$key]['columns'][$row['FIELD_POSITION']] = $row['FIELD_NAME'];
-		}
-		return $indexes;
-	}
-
-
-	/**
-	 * Returns metadata for all foreign keys in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getForeignKeys($table)
-	{
-		$table = strtoupper($table);
-		$res = $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"
-		);
-		$keys = [];
-		while ($row = $res->fetch(true)) {
-			$key = $row['INDEX_NAME'];
-			$keys[$key] = [
-				'name' => $key,
-				'column' => $row['FIELD_NAME'],
-				'table' => $table,
-			];
-		}
-		return $keys;
-	}
-
-
-	/**
-	 * Returns list of indices in given table (the constraints are not listed).
-	 * @param  string
-	 * @return array
-	 */
-	public function getIndices($table)
-	{
-		$res = $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;"
-		);
-		$indices = [];
-		while ($row = $res->fetch(false)) {
-			$indices[] = $row[0];
-		}
-		return $indices;
-	}
-
-
-	/**
-	 * Returns list of constraints in given table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getConstraints($table)
-	{
-		$res = $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
-			);"
-		);
-		$constraints = [];
-		while ($row = $res->fetch(false)) {
-			$constraints[] = $row[0];
-		}
-		return $constraints;
-	}
-
-
-	/**
-	 * 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)
-	{
-		$res = $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');")
-		);
-		$triggers = [];
-		while ($row = $res->fetch(true)) {
-			$triggers[$row['TRIGGER_NAME']] = [
-				'name' => $row['TRIGGER_NAME'],
-				'table' => $row['TABLE_NAME'],
-				'type' => trim($row['TRIGGER_TYPE']),
-				'event' => trim($row['TRIGGER_EVENT']),
-				'enabled' => trim($row['TRIGGER_ENABLED']) === 'TRUE',
-			];
-		}
-		return $triggers;
-	}
-
-
-	/**
-	 * 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')";
-
-		$res = $this->query($q);
-		$triggers = [];
-		while ($row = $res->fetch(false)) {
-			$triggers[] = $row[0];
-		}
-		return $triggers;
-	}
-
-
-	/**
-	 * Returns metadata from stored procedures and their input and output parameters.
-	 * @param  string
-	 * @return array
-	 */
-	public function getProceduresMeta()
-	{
-		$res = $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;"
-		);
-		$procedures = [];
-		while ($row = $res->fetch(true)) {
-			$key = $row['PROCEDURE_NAME'];
-			$io = trim($row['PARAMETER_TYPE']);
-			$num = $row['PARAMETER_NUMBER'];
-			$procedures[$key]['name'] = $row['PROCEDURE_NAME'];
-			$procedures[$key]['params'][$io][$num]['name'] = $row['PARAMETER_NAME'];
-			$procedures[$key]['params'][$io][$num]['type'] = trim($row['FIELD_TYPE']);
-			$procedures[$key]['params'][$io][$num]['size'] = $row['FIELD_LENGTH'];
-		}
-		return $procedures;
-	}
-
-
-	/**
-	 * Returns list of stored procedures.
-	 * @return array
-	 */
-	public function getProcedures()
-	{
-		$res = $this->query('
-			SELECT TRIM(RDB$PROCEDURE_NAME)
-			FROM RDB$PROCEDURES;'
-		);
-		$procedures = [];
-		while ($row = $res->fetch(false)) {
-			$procedures[] = $row[0];
-		}
-		return $procedures;
-	}
-
-
-	/**
-	 * Returns list of generators.
-	 * @return array
-	 */
-	public function getGenerators()
-	{
-		$res = $this->query('
-			SELECT TRIM(RDB$GENERATOR_NAME)
-			FROM RDB$GENERATORS
-			WHERE RDB$SYSTEM_FLAG = 0;'
-		);
-		$generators = [];
-		while ($row = $res->fetch(false)) {
-			$generators[] = $row[0];
-		}
-		return $generators;
-	}
-
-
-	/**
-	 * Returns list of user defined functions (UDF).
-	 * @return array
-	 */
-	public function getFunctions()
-	{
-		$res = $this->query('
-			SELECT TRIM(RDB$FUNCTION_NAME)
-			FROM RDB$FUNCTIONS
-			WHERE RDB$SYSTEM_FLAG = 0;'
-		);
-		$functions = [];
-		while ($row = $res->fetch(false)) {
-			$functions[] = $row[0];
+			$sql = 'SELECT ' . ($limit > 0 ? 'FIRST ' . $limit : '') . ($offset > 0 ? ' SKIP ' . $offset : '') . ' * FROM (' . $sql . ')';
 		}
-		return $functions;
 	}
 }

+ 377 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/FirebirdReflector.php

@@ -0,0 +1,377 @@
+<?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;
+
+
+/**
+ * The reflector for Firebird/InterBase database.
+ */
+class FirebirdReflector implements Dibi\Reflector
+{
+	use Dibi\Strict;
+
+	/** @var Dibi\Driver */
+	private $driver;
+
+
+	public function __construct(Dibi\Driver $driver)
+	{
+		$this->driver = $driver;
+	}
+
+
+	/**
+	 * Returns list of tables.
+	 */
+	public function getTables(): array
+	{
+		$res = $this->driver->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;"
+		);
+		$tables = [];
+		while ($row = $res->fetch(false)) {
+			$tables[] = [
+				'name' => $row[0],
+				'view' => $row[1] === 'TRUE',
+			];
+		}
+		return $tables;
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a table.
+	 */
+	public function getColumns(string $table): array
+	{
+		$table = strtoupper($table);
+		$res = $this->driver->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;"
+
+		);
+		$columns = [];
+		while ($row = $res->fetch(true)) {
+			$key = $row['FIELD_NAME'];
+			$columns[$key] = [
+				'name' => $key,
+				'table' => $table,
+				'nativetype' => trim($row['FIELD_TYPE']),
+				'size' => $row['FIELD_LENGTH'],
+				'nullable' => $row['NULLABLE'] === 'TRUE',
+				'default' => $row['DEFAULT_VALUE'],
+				'autoincrement' => false,
+			];
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Returns metadata for all indexes in a table (the constraints are included).
+	 */
+	public function getIndexes(string $table): array
+	{
+		$table = strtoupper($table);
+		$res = $this->driver->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"
+		);
+		$indexes = [];
+		while ($row = $res->fetch(true)) {
+			$key = $row['INDEX_NAME'];
+			$indexes[$key]['name'] = $key;
+			$indexes[$key]['unique'] = $row['UNIQUE_FLAG'] === 1;
+			$indexes[$key]['primary'] = $row['CONSTRAINT_TYPE'] === 'PRIMARY KEY';
+			$indexes[$key]['table'] = $table;
+			$indexes[$key]['columns'][$row['FIELD_POSITION']] = $row['FIELD_NAME'];
+		}
+		return $indexes;
+	}
+
+
+	/**
+	 * Returns metadata for all foreign keys in a table.
+	 */
+	public function getForeignKeys(string $table): array
+	{
+		$table = strtoupper($table);
+		$res = $this->driver->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"
+		);
+		$keys = [];
+		while ($row = $res->fetch(true)) {
+			$key = $row['INDEX_NAME'];
+			$keys[$key] = [
+				'name' => $key,
+				'column' => $row['FIELD_NAME'],
+				'table' => $table,
+			];
+		}
+		return $keys;
+	}
+
+
+	/**
+	 * Returns list of indices in given table (the constraints are not listed).
+	 */
+	public function getIndices(string $table): array
+	{
+		$res = $this->driver->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;"
+		);
+		$indices = [];
+		while ($row = $res->fetch(false)) {
+			$indices[] = $row[0];
+		}
+		return $indices;
+	}
+
+
+	/**
+	 * Returns list of constraints in given table.
+	 */
+	public function getConstraints(string $table): array
+	{
+		$res = $this->driver->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
+			);"
+		);
+		$constraints = [];
+		while ($row = $res->fetch(false)) {
+			$constraints[] = $row[0];
+		}
+		return $constraints;
+	}
+
+
+	/**
+	 * Returns metadata for all triggers in a table or database.
+	 * (Only if user has permissions on ALTER TABLE, INSERT/UPDATE/DELETE record in table)
+	 */
+	public function getTriggersMeta(string $table = null): array
+	{
+		$res = $this->driver->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');")
+		);
+		$triggers = [];
+		while ($row = $res->fetch(true)) {
+			$triggers[$row['TRIGGER_NAME']] = [
+				'name' => $row['TRIGGER_NAME'],
+				'table' => $row['TABLE_NAME'],
+				'type' => trim($row['TRIGGER_TYPE']),
+				'event' => trim($row['TRIGGER_EVENT']),
+				'enabled' => trim($row['TRIGGER_ENABLED']) === 'TRUE',
+			];
+		}
+		return $triggers;
+	}
+
+
+	/**
+	 * Returns list of triggers for given table.
+	 * (Only if user has permissions on ALTER TABLE, INSERT/UPDATE/DELETE record in table)
+	 */
+	public function getTriggers(string $table = null): array
+	{
+		$q = 'SELECT TRIM(RDB$TRIGGER_NAME)
+			FROM RDB$TRIGGERS
+			WHERE RDB$SYSTEM_FLAG = 0';
+		$q .= $table === null ? ';' : " AND RDB\$RELATION_NAME = UPPER('$table')";
+
+		$res = $this->driver->query($q);
+		$triggers = [];
+		while ($row = $res->fetch(false)) {
+			$triggers[] = $row[0];
+		}
+		return $triggers;
+	}
+
+
+	/**
+	 * Returns metadata from stored procedures and their input and output parameters.
+	 */
+	public function getProceduresMeta(): array
+	{
+		$res = $this->driver->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;"
+		);
+		$procedures = [];
+		while ($row = $res->fetch(true)) {
+			$key = $row['PROCEDURE_NAME'];
+			$io = trim($row['PARAMETER_TYPE']);
+			$num = $row['PARAMETER_NUMBER'];
+			$procedures[$key]['name'] = $row['PROCEDURE_NAME'];
+			$procedures[$key]['params'][$io][$num]['name'] = $row['PARAMETER_NAME'];
+			$procedures[$key]['params'][$io][$num]['type'] = trim($row['FIELD_TYPE']);
+			$procedures[$key]['params'][$io][$num]['size'] = $row['FIELD_LENGTH'];
+		}
+		return $procedures;
+	}
+
+
+	/**
+	 * Returns list of stored procedures.
+	 */
+	public function getProcedures(): array
+	{
+		$res = $this->driver->query('
+			SELECT TRIM(RDB$PROCEDURE_NAME)
+			FROM RDB$PROCEDURES;'
+		);
+		$procedures = [];
+		while ($row = $res->fetch(false)) {
+			$procedures[] = $row[0];
+		}
+		return $procedures;
+	}
+
+
+	/**
+	 * Returns list of generators.
+	 */
+	public function getGenerators(): array
+	{
+		$res = $this->driver->query('
+			SELECT TRIM(RDB$GENERATOR_NAME)
+			FROM RDB$GENERATORS
+			WHERE RDB$SYSTEM_FLAG = 0;'
+		);
+		$generators = [];
+		while ($row = $res->fetch(false)) {
+			$generators[] = $row[0];
+		}
+		return $generators;
+	}
+
+
+	/**
+	 * Returns list of user defined functions (UDF).
+	 */
+	public function getFunctions(): array
+	{
+		$res = $this->driver->query('
+			SELECT TRIM(RDB$FUNCTION_NAME)
+			FROM RDB$FUNCTIONS
+			WHERE RDB$SYSTEM_FLAG = 0;'
+		);
+		$functions = [];
+		while ($row = $res->fetch(false)) {
+			$functions[] = $row[0];
+		}
+		return $functions;
+	}
+}

+ 138 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/FirebirdResult.php

@@ -0,0 +1,138 @@
+<?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;
+use Dibi\Helpers;
+
+
+/**
+ * The driver for Firebird/InterBase result set.
+ */
+class FirebirdResult implements Dibi\ResultDriver
+{
+	use Dibi\Strict;
+
+	/** @var resource */
+	private $resultSet;
+
+	/** @var bool */
+	private $autoFree = true;
+
+
+	/**
+	 * @param  resource  $resultSet
+	 */
+	public function __construct($resultSet)
+	{
+		$this->resultSet = $resultSet;
+	}
+
+
+	/**
+	 * Automatically frees the resources allocated for this result set.
+	 */
+	public function __destruct()
+	{
+		if ($this->autoFree && $this->getResultResource()) {
+			$this->free();
+		}
+	}
+
+
+	/**
+	 * Returns the number of rows in a result set.
+	 */
+	public function getRowCount(): int
+	{
+		throw new Dibi\NotSupportedException('Firebird/Interbase do not support returning number of rows in result set.');
+	}
+
+
+	/**
+	 * Fetches the row at current position and moves the internal cursor to the next position.
+	 * @param  bool  $assoc   true for associative array, false for numeric
+	 */
+	public function fetch(bool $assoc): ?array
+	{
+		$result = $assoc ? @ibase_fetch_assoc($this->resultSet, IBASE_TEXT) : @ibase_fetch_row($this->resultSet, IBASE_TEXT); // intentionally @
+
+		if (ibase_errcode()) {
+			if (ibase_errcode() == FirebirdDriver::ERROR_EXCEPTION_THROWN) {
+				preg_match('/exception (\d+) (\w+) (.*)/is', ibase_errmsg(), $match);
+				throw new Dibi\ProcedureException($match[3], $match[1], $match[2]);
+
+			} else {
+				throw new Dibi\DriverException(ibase_errmsg(), ibase_errcode());
+			}
+		}
+
+		return Helpers::false2Null($result);
+	}
+
+
+	/**
+	 * Moves cursor position without fetching row.
+	 * @throws Dibi\Exception
+	 */
+	public function seek(int $row): bool
+	{
+		throw new Dibi\NotSupportedException('Firebird/Interbase do not support seek in result set.');
+	}
+
+
+	/**
+	 * Frees the resources allocated for this result set.
+	 */
+	public function free(): void
+	{
+		ibase_free_result($this->resultSet);
+	}
+
+
+	/**
+	 * Returns the result set resource.
+	 * @return resource|null
+	 */
+	public function getResultResource()
+	{
+		$this->autoFree = false;
+		return is_resource($this->resultSet) ? $this->resultSet : null;
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a result set.
+	 */
+	public function getResultColumns(): array
+	{
+		$count = ibase_num_fields($this->resultSet);
+		$columns = [];
+		for ($i = 0; $i < $count; $i++) {
+			$row = (array) ibase_field_info($this->resultSet, $i);
+			$columns[] = [
+				'name' => $row['name'],
+				'fullname' => $row['name'],
+				'table' => $row['relation'],
+				'nativetype' => $row['type'],
+			];
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Decodes data from result set.
+	 */
+	public function unescapeBinary(string $value): string
+	{
+		return $value;
+	}
+}

+ 0 - 409
api/vendor/dibi/dibi/src/Dibi/Drivers/MsSqlDriver.php

@@ -1,409 +0,0 @@
-<?php
-
-/**
- * This file is part of the "dibi" - smart database abstraction layer.
- * Copyright (c) 2005 David Grudl (https://davidgrudl.com)
- */
-
-namespace Dibi\Drivers;
-
-use Dibi;
-
-
-/**
- * The dibi driver for MS SQL database.
- *
- * Driver options:
- *   - host => the MS SQL server host name. It can also include a port number (hostname:port)
- *   - username (or user)
- *   - password (or pass)
- *   - database => the database name to select
- *   - persistent (bool) => try to find a persistent link?
- *   - resource (resource) => existing connection resource
- *   - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
- */
-class MsSqlDriver implements Dibi\Driver, Dibi\ResultDriver
-{
-	use Dibi\Strict;
-
-	/** @var resource|null */
-	private $connection;
-
-	/** @var resource|null */
-	private $resultSet;
-
-	/** @var bool */
-	private $autoFree = true;
-
-
-	/**
-	 * @throws Dibi\NotSupportedException
-	 */
-	public function __construct()
-	{
-		if (!extension_loaded('mssql')) {
-			throw new Dibi\NotSupportedException("PHP extension 'mssql' is not loaded.");
-		}
-	}
-
-
-	/**
-	 * Connects to a database.
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	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 Dibi\DriverException("Can't connect to DB.");
-		}
-
-		if (isset($config['database']) && !@mssql_select_db($this->escapeIdentifier($config['database']), $this->connection)) { // intentionally @
-			throw new Dibi\DriverException("Can't select DB '$config[database]'.");
-		}
-	}
-
-
-	/**
-	 * Disconnects from a database.
-	 * @return void
-	 */
-	public function disconnect()
-	{
-		@mssql_close($this->connection); // @ - connection can be already disconnected
-	}
-
-
-	/**
-	 * Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return Dibi\ResultDriver|null
-	 * @throws Dibi\DriverException
-	 */
-	public function query($sql)
-	{
-		$res = @mssql_query($sql, $this->connection); // intentionally @
-
-		if ($res === false) {
-			throw new Dibi\DriverException(mssql_get_last_message(), 0, $sql);
-
-		} elseif (is_resource($res)) {
-			return $this->createResultDriver($res);
-		}
-		return 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 Dibi\DriverException
-	 */
-	public function begin($savepoint = null)
-	{
-		$this->query('BEGIN TRANSACTION');
-	}
-
-
-	/**
-	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
-	 * @throws Dibi\DriverException
-	 */
-	public function commit($savepoint = null)
-	{
-		$this->query('COMMIT');
-	}
-
-
-	/**
-	 * Rollback changes in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
-	 * @throws Dibi\DriverException
-	 */
-	public function rollback($savepoint = null)
-	{
-		$this->query('ROLLBACK');
-	}
-
-
-	/**
-	 * Returns the connection resource.
-	 * @return resource|null
-	 */
-	public function getResource()
-	{
-		return is_resource($this->connection) ? $this->connection : null;
-	}
-
-
-	/**
-	 * Returns the connection reflector.
-	 * @return Dibi\Reflector
-	 */
-	public function getReflector()
-	{
-		return new MsSqlReflector($this);
-	}
-
-
-	/**
-	 * Result set driver factory.
-	 * @param  resource
-	 * @return Dibi\ResultDriver
-	 */
-	public function createResultDriver($resource)
-	{
-		$res = clone $this;
-		$res->resultSet = $resource;
-		return $res;
-	}
-
-
-	/********************* SQL ****************d*g**/
-
-
-	/**
-	 * Encodes data for use in a SQL statement.
-	 * @param  string    value
-	 * @return string    encoded value
-	 */
-	public function escapeText($value)
-	{
-		return "'" . str_replace("'", "''", $value) . "'";
-	}
-
-
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeBinary($value)
-	{
-		return "'" . str_replace("'", "''", $value) . "'";
-	}
-
-
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeIdentifier($value)
-	{
-		// @see https://msdn.microsoft.com/en-us/library/ms176027.aspx
-		return '[' . str_replace(['[', ']'], ['[[', ']]'], $value) . ']';
-	}
-
-
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	public function escapeBool($value)
-	{
-		return $value ? '1' : '0';
-	}
-
-
-	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
-	 */
-	public function escapeDate($value)
-	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
-			$value = new Dibi\DateTime($value);
-		}
-		return $value->format("'Y-m-d'");
-	}
-
-
-	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
-	 */
-	public function escapeDateTime($value)
-	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
-			$value = new Dibi\DateTime($value);
-		}
-		return $value->format("'Y-m-d H:i:s.u'");
-	}
-
-
-	/**
-	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
-	 */
-	public function escapeLike($value, $pos)
-	{
-		$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
-		return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
-	}
-
-
-	/**
-	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
-	 */
-	public function unescapeBinary($value)
-	{
-		return $value;
-	}
-
-
-	/** @deprecated */
-	public function escape($value, $type)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		return Dibi\Helpers::escape($this, $value, $type);
-	}
-
-
-	/**
-	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
-	 */
-	public function applyLimit(&$sql, $limit, $offset)
-	{
-		if ($offset) {
-			throw new Dibi\NotSupportedException('Offset is not supported by this database.');
-
-		} elseif ($limit < 0) {
-			throw new Dibi\NotSupportedException('Negative offset or limit.');
-
-		} elseif ($limit !== null) {
-			$sql = 'SELECT TOP ' . Dibi\Helpers::intVal($limit) . ' * FROM (' . $sql . ') t';
-		}
-	}
-
-
-	/********************* result set ****************d*g**/
-
-
-	/**
-	 * Automatically frees the resources allocated for this result set.
-	 * @return void
-	 */
-	public function __destruct()
-	{
-		$this->autoFree && $this->getResultResource() && $this->free();
-	}
-
-
-	/**
-	 * 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
-	 */
-	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 bool     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 getResultColumns()
-	{
-		$count = mssql_num_fields($this->resultSet);
-		$columns = [];
-		for ($i = 0; $i < $count; $i++) {
-			$row = (array) mssql_fetch_field($this->resultSet, $i);
-			$columns[] = [
-				'name' => $row['name'],
-				'fullname' => $row['column_source'] ? $row['column_source'] . '.' . $row['name'] : $row['name'],
-				'table' => $row['column_source'],
-				'nativetype' => $row['type'],
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns the result set resource.
-	 * @return resource|null
-	 */
-	public function getResultResource()
-	{
-		$this->autoFree = false;
-		return is_resource($this->resultSet) ? $this->resultSet : null;
-	}
-}

+ 0 - 215
api/vendor/dibi/dibi/src/Dibi/Drivers/MsSqlReflector.php

@@ -1,215 +0,0 @@
-<?php
-
-/**
- * This file is part of the "dibi" - smart database abstraction layer.
- * Copyright (c) 2005 David Grudl (https://davidgrudl.com)
- */
-
-namespace Dibi\Drivers;
-
-use Dibi;
-
-
-/**
- * The dibi reflector for MS SQL databases.
- * @internal
- */
-class MsSqlReflector implements Dibi\Reflector
-{
-	use Dibi\Strict;
-
-	/** @var Dibi\Driver */
-	private $driver;
-
-
-	public function __construct(Dibi\Driver $driver)
-	{
-		$this->driver = $driver;
-	}
-
-
-	/**
-	 * Returns list of tables.
-	 * @return array
-	 */
-	public function getTables()
-	{
-		$res = $this->driver->query('
-			SELECT TABLE_NAME, TABLE_TYPE
-			FROM INFORMATION_SCHEMA.TABLES
-		');
-		$tables = [];
-		while ($row = $res->fetch(false)) {
-			$tables[] = [
-				'name' => $row[0],
-				'view' => isset($row[1]) && $row[1] === 'VIEW',
-			];
-		}
-		return $tables;
-	}
-
-
-	/**
-	 * Returns count of rows in a table
-	 * @param  string
-	 * @return int
-	 */
-	public function getTableCount($table, $fallback = true)
-	{
-		if (empty($table)) {
-			return false;
-		}
-		$result = $this->driver->query("
-			SELECT MAX(rowcnt)
-			FROM sys.sysindexes
-			WHERE id=OBJECT_ID({$this->driver->escapeIdentifier($table)})
-		");
-		$row = $result->fetch(false);
-
-		if (!is_array($row) || count($row) < 1) {
-			if ($fallback) {
-				$row = $this->driver->query("SELECT COUNT(*) FROM {$this->driver->escapeIdentifier($table)}")->fetch(false);
-				$count = Dibi\Helpers::intVal($row[0]);
-			} else {
-				$count = false;
-			}
-		} else {
-			$count = Dibi\Helpers::intVal($row[0]);
-		}
-
-		return $count;
-	}
-
-
-	/**
-	 * Returns metadata for all columns in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getColumns($table)
-	{
-		$res = $this->driver->query("
-			SELECT * FROM
-			INFORMATION_SCHEMA.COLUMNS
-			WHERE TABLE_NAME = {$this->driver->escapeText($table)}
-			ORDER BY TABLE_NAME, ORDINAL_POSITION
-		");
-		$columns = [];
-		while ($row = $res->fetch(true)) {
-			$size = false;
-			$type = strtoupper($row['DATA_TYPE']);
-
-			$size_cols = [
-				'DATETIME' => 'DATETIME_PRECISION',
-				'DECIMAL' => 'NUMERIC_PRECISION',
-				'CHAR' => 'CHARACTER_MAXIMUM_LENGTH',
-				'NCHAR' => 'CHARACTER_OCTET_LENGTH',
-				'NVARCHAR' => 'CHARACTER_OCTET_LENGTH',
-				'VARCHAR' => 'CHARACTER_OCTET_LENGTH',
-			];
-
-			if (isset($size_cols[$type])) {
-				if ($size_cols[$type]) {
-					$size = $row[$size_cols[$type]];
-				}
-			}
-
-			$columns[] = [
-				'name' => $row['COLUMN_NAME'],
-				'table' => $table,
-				'nativetype' => $type,
-				'size' => $size,
-				'unsigned' => null,
-				'nullable' => $row['IS_NULLABLE'] === 'YES',
-				'default' => $row['COLUMN_DEFAULT'],
-				'autoincrement' => false,
-				'vendor' => $row,
-			];
-		}
-
-		return $columns;
-	}
-
-
-	/**
-	 * Returns metadata for all indexes in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getIndexes($table)
-	{
-		$res = $this->driver->query(
-			"SELECT ind.name index_name, ind.index_id, ic.index_column_id,
-					col.name column_name, ind.is_unique, ind.is_primary_key
-			FROM sys.indexes ind
-			INNER JOIN sys.index_columns ic ON
-				(ind.object_id = ic.object_id AND ind.index_id = ic.index_id)
-			INNER JOIN sys.columns col ON
-				(ic.object_id = col.object_id and ic.column_id = col.column_id)
-			INNER JOIN sys.tables t ON
-				(ind.object_id = t.object_id)
-			WHERE t.name = {$this->driver->escapeText($table)}
-				AND t.is_ms_shipped = 0
-			ORDER BY
-				t.name, ind.name, ind.index_id, ic.index_column_id
-		");
-
-		$indexes = [];
-		while ($row = $res->fetch(true)) {
-			$index_name = $row['index_name'];
-
-			if (!isset($indexes[$index_name])) {
-				$indexes[$index_name] = [];
-				$indexes[$index_name]['name'] = $index_name;
-				$indexes[$index_name]['unique'] = (bool) $row['is_unique'];
-				$indexes[$index_name]['primary'] = (bool) $row['is_primary_key'];
-				$indexes[$index_name]['columns'] = [];
-			}
-			$indexes[$index_name]['columns'][] = $row['column_name'];
-		}
-
-		return array_values($indexes);
-	}
-
-
-	/**
-	 * Returns metadata for all foreign keys in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getForeignKeys($table)
-	{
-		$res = $this->driver->query("
-			SELECT f.name AS foreign_key,
-			OBJECT_NAME(f.parent_object_id) AS table_name,
-			COL_NAME(fc.parent_object_id,
-			fc.parent_column_id) AS column_name,
-			OBJECT_NAME (f.referenced_object_id) AS reference_table_name,
-			COL_NAME(fc.referenced_object_id,
-			fc.referenced_column_id) AS reference_column_name,
-			fc.*
-			FROM sys.foreign_keys AS f
-			INNER JOIN sys.foreign_key_columns AS fc
-			ON f.OBJECT_ID = fc.constraint_object_id
-			WHERE OBJECT_NAME(f.parent_object_id) = {$this->driver->escapeText($table)}
-		");
-
-		$keys = [];
-		while ($row = $res->fetch(true)) {
-			$key_name = $row['foreign_key'];
-
-			if (!isset($keys[$key_name])) {
-				$keys[$key_name]['name'] = $row['foreign_key']; // foreign key name
-				$keys[$key_name]['local'] = [$row['column_name']]; // local columns
-				$keys[$key_name]['table'] = $row['reference_table_name']; // referenced table
-				$keys[$key_name]['foreign'] = [$row['reference_column_name']]; // referenced columns
-				$keys[$key_name]['onDelete'] = false;
-				$keys[$key_name]['onUpdate'] = false;
-			} else {
-				$keys[$key_name]['local'][] = $row['column_name']; // local columns
-				$keys[$key_name]['foreign'][] = $row['reference_column_name']; // referenced columns
-			}
-		}
-		return array_values($keys);
-	}
-}

+ 0 - 502
api/vendor/dibi/dibi/src/Dibi/Drivers/MySqlDriver.php

@@ -1,502 +0,0 @@
-<?php
-
-/**
- * This file is part of the "dibi" - smart database abstraction layer.
- * Copyright (c) 2005 David Grudl (https://davidgrudl.com)
- */
-
-namespace Dibi\Drivers;
-
-use Dibi;
-
-
-/**
- * The dibi driver for MySQL database.
- *
- * Driver options:
- *   - host => the MySQL server host name
- *   - port (int) => the port number to attempt to connect to the MySQL server
- *   - socket => the socket or named pipe
- *   - username (or user)
- *   - password (or pass)
- *   - database => the database name to select
- *   - flags (int) => driver specific constants (MYSQL_CLIENT_*)
- *   - charset => character encoding to set (default is utf8)
- *   - persistent (bool) => try to find a persistent link?
- *   - unbuffered (bool) => sends query without fetching and buffering the result rows automatically?
- *   - sqlmode => see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
- *   - resource (resource) => existing connection resource
- *   - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
- */
-class MySqlDriver implements Dibi\Driver, Dibi\ResultDriver
-{
-	use Dibi\Strict;
-
-	const ERROR_ACCESS_DENIED = 1045;
-	const ERROR_DUPLICATE_ENTRY = 1062;
-	const ERROR_DATA_TRUNCATED = 1265;
-
-	/** @var resource|null */
-	private $connection;
-
-	/** @var resource|null */
-	private $resultSet;
-
-	/** @var bool */
-	private $autoFree = true;
-
-	/** @var bool  Is buffered (seekable and countable)? */
-	private $buffered;
-
-
-	/**
-	 * @throws Dibi\NotSupportedException
-	 */
-	public function __construct()
-	{
-		if (!extension_loaded('mysql')) {
-			throw new Dibi\NotSupportedException("PHP extension 'mysql' is not loaded.");
-		}
-	}
-
-
-	/**
-	 * Connects to a database.
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public function connect(array &$config)
-	{
-		if (isset($config['resource'])) {
-			$this->connection = $config['resource'];
-
-		} else {
-			// default values
-			Dibi\Helpers::alias($config, 'flags', 'options');
-			$config += [
-				'charset' => 'utf8',
-				'timezone' => date('P'),
-				'username' => ini_get('mysql.default_user'),
-				'password' => ini_get('mysql.default_password'),
-			];
-			if (!isset($config['host'])) {
-				$host = ini_get('mysql.default_host');
-				if ($host) {
-					$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['flags']); // intentionally @
-			} else {
-				$this->connection = @mysql_pconnect($host, $config['username'], $config['password'], $config['flags']); // intentionally @
-			}
-		}
-
-		if (!is_resource($this->connection)) {
-			throw new Dibi\DriverException(mysql_error(), mysql_errno());
-		}
-
-		if (isset($config['charset'])) {
-			if (!@mysql_set_charset($config['charset'], $this->connection)) { // intentionally @
-				$this->query("SET NAMES '$config[charset]'");
-			}
-		}
-
-		if (isset($config['database'])) {
-			if (!@mysql_select_db($config['database'], $this->connection)) { // intentionally @
-				throw new Dibi\DriverException(mysql_error($this->connection), mysql_errno($this->connection));
-			}
-		}
-
-		if (isset($config['sqlmode'])) {
-			$this->query("SET sql_mode='$config[sqlmode]'");
-		}
-
-		if (isset($config['timezone'])) {
-			$this->query("SET time_zone='$config[timezone]'");
-		}
-
-		$this->buffered = empty($config['unbuffered']);
-	}
-
-
-	/**
-	 * Disconnects from a database.
-	 * @return void
-	 */
-	public function disconnect()
-	{
-		@mysql_close($this->connection); // @ - connection can be already disconnected
-	}
-
-
-	/**
-	 * Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return Dibi\ResultDriver|null
-	 * @throws Dibi\DriverException
-	 */
-	public function query($sql)
-	{
-		if ($this->buffered) {
-			$res = @mysql_query($sql, $this->connection); // intentionally @
-		} else {
-			$res = @mysql_unbuffered_query($sql, $this->connection); // intentionally @
-		}
-
-		if ($code = mysql_errno($this->connection)) {
-			throw MySqliDriver::createException(mysql_error($this->connection), $code, $sql);
-
-		} elseif (is_resource($res)) {
-			return $this->createResultDriver($res);
-		}
-	}
-
-
-	/**
-	 * Retrieves information about the most recently executed query.
-	 * @return array
-	 */
-	public function getInfo()
-	{
-		$res = [];
-		preg_match_all('#(.+?): +(\d+) *#', mysql_info($this->connection), $matches, PREG_SET_ORDER);
-		if (preg_last_error()) {
-			throw new Dibi\PcreException;
-		}
-
-		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 Dibi\DriverException
-	 */
-	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 Dibi\DriverException
-	 */
-	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 Dibi\DriverException
-	 */
-	public function rollback($savepoint = null)
-	{
-		$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
-	}
-
-
-	/**
-	 * Returns the connection resource.
-	 * @return resource|null
-	 */
-	public function getResource()
-	{
-		return is_resource($this->connection) ? $this->connection : null;
-	}
-
-
-	/**
-	 * Returns the connection reflector.
-	 * @return Dibi\Reflector
-	 */
-	public function getReflector()
-	{
-		return new MySqlReflector($this);
-	}
-
-
-	/**
-	 * Result set driver factory.
-	 * @param  resource
-	 * @return Dibi\ResultDriver
-	 */
-	public function createResultDriver($resource)
-	{
-		$res = clone $this;
-		$res->resultSet = $resource;
-		return $res;
-	}
-
-
-	/********************* SQL ****************d*g**/
-
-
-	/**
-	 * Encodes data for use in a SQL statement.
-	 * @param  string    value
-	 * @return string    encoded value
-	 */
-	public function escapeText($value)
-	{
-		if (!is_resource($this->connection)) {
-			throw new Dibi\Exception('Lost connection to server.');
-		}
-		return "'" . mysql_real_escape_string($value, $this->connection) . "'";
-	}
-
-
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeBinary($value)
-	{
-		if (!is_resource($this->connection)) {
-			throw new Dibi\Exception('Lost connection to server.');
-		}
-		return "_binary'" . mysql_real_escape_string($value, $this->connection) . "'";
-	}
-
-
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeIdentifier($value)
-	{
-		// @see http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
-		return '`' . str_replace('`', '``', $value) . '`';
-	}
-
-
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	public function escapeBool($value)
-	{
-		return $value ? 1 : 0;
-	}
-
-
-	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
-	 */
-	public function escapeDate($value)
-	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
-			$value = new Dibi\DateTime($value);
-		}
-		return $value->format("'Y-m-d'");
-	}
-
-
-	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
-	 */
-	public function escapeDateTime($value)
-	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
-			$value = new Dibi\DateTime($value);
-		}
-		return $value->format("'Y-m-d H:i:s.u'");
-	}
-
-
-	/**
-	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
-	 */
-	public function escapeLike($value, $pos)
-	{
-		$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
-		return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
-	}
-
-
-	/**
-	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
-	 */
-	public function unescapeBinary($value)
-	{
-		return $value;
-	}
-
-
-	/** @deprecated */
-	public function escape($value, $type)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		return Dibi\Helpers::escape($this, $value, $type);
-	}
-
-
-	/**
-	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
-	 */
-	public function applyLimit(&$sql, $limit, $offset)
-	{
-		if ($limit < 0 || $offset < 0) {
-			throw new Dibi\NotSupportedException('Negative offset or limit.');
-
-		} elseif ($limit !== null || $offset) {
-			// see http://dev.mysql.com/doc/refman/5.0/en/select.html
-			$sql .= ' LIMIT ' . ($limit === null ? '18446744073709551615' : Dibi\Helpers::intVal($limit))
-				. ($offset ? ' OFFSET ' . Dibi\Helpers::intVal($offset) : '');
-		}
-	}
-
-
-	/********************* result set ****************d*g**/
-
-
-	/**
-	 * Automatically frees the resources allocated for this result set.
-	 * @return void
-	 */
-	public function __destruct()
-	{
-		$this->autoFree && $this->getResultResource() && $this->free();
-	}
-
-
-	/**
-	 * Returns the number of rows in a result set.
-	 * @return int
-	 */
-	public function getRowCount()
-	{
-		if (!$this->buffered) {
-			throw new Dibi\NotSupportedException('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
-	 */
-	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 bool  true on success, false if unable to seek to specified record
-	 * @throws Dibi\Exception
-	 */
-	public function seek($row)
-	{
-		if (!$this->buffered) {
-			throw new Dibi\NotSupportedException('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 getResultColumns()
-	{
-		$count = mysql_num_fields($this->resultSet);
-		$columns = [];
-		for ($i = 0; $i < $count; $i++) {
-			$row = (array) mysql_fetch_field($this->resultSet, $i);
-			$columns[] = [
-				'name' => $row['name'],
-				'table' => $row['table'],
-				'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
-				'nativetype' => strtoupper($row['type']),
-				'type' => $row['type'] === 'time' ? Dibi\Type::TIME_INTERVAL : null,
-				'vendor' => $row,
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns the result set resource.
-	 * @return resource|null
-	 */
-	public function getResultResource()
-	{
-		$this->autoFree = false;
-		return is_resource($this->resultSet) ? $this->resultSet : null;
-	}
-}

+ 8 - 14
api/vendor/dibi/dibi/src/Dibi/Drivers/MySqlReflector.php

@@ -1,17 +1,19 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * The dibi reflector for MySQL databases.
+ * The reflector for MySQL databases.
  * @internal
  */
 class MySqlReflector implements Dibi\Reflector
@@ -30,9 +32,8 @@ class MySqlReflector implements Dibi\Reflector
 
 	/**
 	 * Returns list of tables.
-	 * @return array
 	 */
-	public function getTables()
+	public function getTables(): array
 	{
 		$res = $this->driver->query('SHOW FULL TABLES');
 		$tables = [];
@@ -48,10 +49,8 @@ class MySqlReflector implements Dibi\Reflector
 
 	/**
 	 * Returns metadata for all columns in a table.
-	 * @param  string
-	 * @return array
 	 */
-	public function getColumns($table)
+	public function getColumns(string $table): array
 	{
 		$res = $this->driver->query("SHOW FULL COLUMNS FROM {$this->driver->escapeIdentifier($table)}");
 		$columns = [];
@@ -62,7 +61,6 @@ class MySqlReflector implements Dibi\Reflector
 				'table' => $table,
 				'nativetype' => strtoupper($type[0]),
 				'size' => isset($type[1]) ? (int) $type[1] : null,
-				'unsigned' => (bool) strstr($row['Type'], 'unsigned'),
 				'nullable' => $row['Null'] === 'YES',
 				'default' => $row['Default'],
 				'autoincrement' => $row['Extra'] === 'auto_increment',
@@ -75,10 +73,8 @@ class MySqlReflector implements Dibi\Reflector
 
 	/**
 	 * Returns metadata for all indexes in a table.
-	 * @param  string
-	 * @return array
 	 */
-	public function getIndexes($table)
+	public function getIndexes(string $table): array
 	{
 		$res = $this->driver->query("SHOW INDEX FROM {$this->driver->escapeIdentifier($table)}");
 		$indexes = [];
@@ -94,11 +90,9 @@ class MySqlReflector implements Dibi\Reflector
 
 	/**
 	 * Returns metadata for all foreign keys in a table.
-	 * @param  string
-	 * @return array
 	 * @throws Dibi\NotSupportedException
 	 */
-	public function getForeignKeys($table)
+	public function getForeignKeys(string $table): array
 	{
 		$data = $this->driver->query("SELECT `ENGINE` FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = {$this->driver->escapeText($table)}")->fetch(true);
 		if ($data['ENGINE'] !== 'InnoDB') {

+ 62 - 237
api/vendor/dibi/dibi/src/Dibi/Drivers/MySqliDriver.php

@@ -1,17 +1,19 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * The dibi driver for MySQL database via improved extension.
+ * The driver for MySQL database.
  *
  * Driver options:
  *   - host => the MySQL server host name
@@ -27,24 +29,19 @@ use Dibi;
  *   - unbuffered (bool) => sends query without fetching and buffering the result rows automatically?
  *   - sqlmode => see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
  *   - resource (mysqli) => existing connection resource
- *   - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
  */
-class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
+class MySqliDriver implements Dibi\Driver
 {
 	use Dibi\Strict;
 
-	const ERROR_ACCESS_DENIED = 1045;
-	const ERROR_DUPLICATE_ENTRY = 1062;
-	const ERROR_DATA_TRUNCATED = 1265;
+	public const ERROR_ACCESS_DENIED = 1045;
 
-	/** @var \mysqli|null */
-	private $connection;
+	public const ERROR_DUPLICATE_ENTRY = 1062;
 
-	/** @var \mysqli_result|null */
-	private $resultSet;
+	public const ERROR_DATA_TRUNCATED = 1265;
 
-	/** @var bool */
-	private $autoFree = true;
+	/** @var \mysqli */
+	private $connection;
 
 	/** @var bool  Is buffered (seekable and countable)? */
 	private $buffered;
@@ -53,23 +50,14 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 	/**
 	 * @throws Dibi\NotSupportedException
 	 */
-	public function __construct()
+	public function __construct(array $config)
 	{
 		if (!extension_loaded('mysqli')) {
 			throw new Dibi\NotSupportedException("PHP extension 'mysqli' is not loaded.");
 		}
-	}
-
 
-	/**
-	 * Connects to a database.
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public function connect(array &$config)
-	{
 		mysqli_report(MYSQLI_REPORT_OFF);
-		if (isset($config['resource'])) {
+		if (isset($config['resource']) && $config['resource'] instanceof \mysqli) {
 			$this->connection = $config['resource'];
 
 		} else {
@@ -99,18 +87,26 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 			$this->connection = mysqli_init();
 			if (isset($config['options'])) {
 				foreach ($config['options'] as $key => $value) {
-					mysqli_options($this->connection, $key, $value);
+					$this->connection->options($key, $value);
 				}
 			}
-			@mysqli_real_connect($this->connection, (empty($config['persistent']) ? '' : 'p:') . $config['host'], $config['username'], $config['password'], $config['database'], $config['port'], $config['socket'], $config['flags']); // intentionally @
-
-			if ($errno = mysqli_connect_errno()) {
-				throw new Dibi\DriverException(mysqli_connect_error(), $errno);
+			@$this->connection->real_connect( // intentionally @
+				(empty($config['persistent']) ? '' : 'p:') . $config['host'],
+				$config['username'],
+				$config['password'],
+				$config['database'] ?? '',
+				$config['port'] ?? 0,
+				$config['socket'],
+				$config['flags'] ?? 0
+			);
+
+			if ($this->connection->connect_errno) {
+				throw new Dibi\DriverException($this->connection->connect_error, $this->connection->connect_errno);
 			}
 		}
 
 		if (isset($config['charset'])) {
-			if (!@mysqli_set_charset($this->connection, $config['charset'])) {
+			if (!@$this->connection->set_charset($config['charset'])) {
 				$this->query("SET NAMES '$config[charset]'");
 			}
 		}
@@ -129,38 +125,32 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Disconnects from a database.
-	 * @return void
 	 */
-	public function disconnect()
+	public function disconnect(): void
 	{
-		@mysqli_close($this->connection); // @ - connection can be already disconnected
+		@$this->connection->close(); // @ - connection can be already disconnected
 	}
 
 
 	/**
 	 * Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return Dibi\ResultDriver|null
 	 * @throws Dibi\DriverException
 	 */
-	public function query($sql)
+	public function query(string $sql): ?Dibi\ResultDriver
 	{
-		$res = @mysqli_query($this->connection, $sql, $this->buffered ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT); // intentionally @
+		$res = @$this->connection->query($sql, $this->buffered ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT); // intentionally @
 
 		if ($code = mysqli_errno($this->connection)) {
-			throw self::createException(mysqli_error($this->connection), $code, $sql);
+			throw static::createException(mysqli_error($this->connection), $code, $sql);
 
-		} elseif (is_object($res)) {
+		} elseif ($res instanceof \mysqli_result) {
 			return $this->createResultDriver($res);
 		}
 		return null;
 	}
 
 
-	/**
-	 * @return Dibi\DriverException
-	 */
-	public static function createException($message, $code, $sql)
+	public static function createException(string $message, $code, string $sql): Dibi\DriverException
 	{
 		if (in_array($code, [1216, 1217, 1451, 1452, 1701], true)) {
 			return new Dibi\ForeignKeyConstraintViolationException($message, $code, $sql);
@@ -179,12 +169,11 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Retrieves information about the most recently executed query.
-	 * @return array
 	 */
-	public function getInfo()
+	public function getInfo(): array
 	{
 		$res = [];
-		preg_match_all('#(.+?): +(\d+) *#', mysqli_info($this->connection), $matches, PREG_SET_ORDER);
+		preg_match_all('#(.+?): +(\d+) *#', $this->connection->info, $matches, PREG_SET_ORDER);
 		if (preg_last_error()) {
 			throw new Dibi\PcreException;
 		}
@@ -198,31 +187,27 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * 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()
+	public function getAffectedRows(): ?int
 	{
-		return mysqli_affected_rows($this->connection) === -1 ? false : mysqli_affected_rows($this->connection);
+		return $this->connection->affected_rows === -1 ? null : $this->connection->affected_rows;
 	}
 
 
 	/**
 	 * 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)
+	public function getInsertId(?string $sequence): ?int
 	{
-		return mysqli_insert_id($this->connection);
+		return $this->connection->insert_id;
 	}
 
 
 	/**
 	 * Begins a transaction (if supported).
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function begin($savepoint = null)
+	public function begin(string $savepoint = null): void
 	{
 		$this->query($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
 	}
@@ -230,11 +215,9 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function commit($savepoint = null)
+	public function commit(string $savepoint = null): void
 	{
 		$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
 	}
@@ -242,11 +225,9 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Rollback changes in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function rollback($savepoint = null)
+	public function rollback(string $savepoint = null): void
 	{
 		$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
 	}
@@ -254,9 +235,8 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Returns the connection resource.
-	 * @return \mysqli
 	 */
-	public function getResource()
+	public function getResource(): ?\mysqli
 	{
 		return @$this->connection->thread_id ? $this->connection : null;
 	}
@@ -264,9 +244,8 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Returns the connection reflector.
-	 * @return Dibi\Reflector
 	 */
-	public function getReflector()
+	public function getReflector(): Dibi\Reflector
 	{
 		return new MySqlReflector($this);
 	}
@@ -274,13 +253,10 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Result set driver factory.
-	 * @return Dibi\ResultDriver
 	 */
-	public function createResultDriver(\mysqli_result $resource)
+	public function createResultDriver(\mysqli_result $result): MySqliResult
 	{
-		$res = clone $this;
-		$res->resultSet = $resource;
-		return $res;
+		return new MySqliResult($result, $this->buffered);
 	}
 
 
@@ -289,52 +265,37 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Encodes data for use in a SQL statement.
-	 * @param  string    value
-	 * @return string    encoded value
 	 */
-	public function escapeText($value)
+	public function escapeText(string $value): string
 	{
-		return "'" . mysqli_real_escape_string($this->connection, $value) . "'";
+		return "'" . $this->connection->escape_string($value) . "'";
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeBinary($value)
+	public function escapeBinary(string $value): string
 	{
-		return "_binary'" . mysqli_real_escape_string($this->connection, $value) . "'";
+		return "_binary'" . $this->connection->escape_string($value) . "'";
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeIdentifier($value)
+	public function escapeIdentifier(string $value): string
 	{
 		return '`' . str_replace('`', '``', $value) . '`';
 	}
 
 
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	public function escapeBool($value)
+	public function escapeBool(bool $value): string
 	{
 		return $value ? '1' : '0';
 	}
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDate($value)
+	public function escapeDate($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
 		return $value->format("'Y-m-d'");
@@ -342,12 +303,11 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDateTime($value)
+	public function escapeDateTime($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
 		return $value->format("'Y-m-d H:i:s.u'");
@@ -356,161 +316,26 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
 	 */
-	public function escapeLike($value, $pos)
+	public function escapeLike(string $value, int $pos): string
 	{
 		$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
 		return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
 	}
 
 
-	/**
-	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
-	 */
-	public function unescapeBinary($value)
-	{
-		return $value;
-	}
-
-
-	/** @deprecated */
-	public function escape($value, $type)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		return Dibi\Helpers::escape($this, $value, $type);
-	}
-
-
 	/**
 	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
 	 */
-	public function applyLimit(&$sql, $limit, $offset)
+	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) {
 			// see http://dev.mysql.com/doc/refman/5.0/en/select.html
-			$sql .= ' LIMIT ' . ($limit === null ? '18446744073709551615' : Dibi\Helpers::intVal($limit))
-				. ($offset ? ' OFFSET ' . Dibi\Helpers::intVal($offset) : '');
-		}
-	}
-
-
-	/********************* result set ****************d*g**/
-
-
-	/**
-	 * Automatically frees the resources allocated for this result set.
-	 * @return void
-	 */
-	public function __destruct()
-	{
-		$this->autoFree && $this->getResultResource() && @$this->free();
-	}
-
-
-	/**
-	 * Returns the number of rows in a result set.
-	 * @return int
-	 */
-	public function getRowCount()
-	{
-		if (!$this->buffered) {
-			throw new Dibi\NotSupportedException('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
-	 */
-	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 bool  true on success, false if unable to seek to specified record
-	 * @throws Dibi\Exception
-	 */
-	public function seek($row)
-	{
-		if (!$this->buffered) {
-			throw new Dibi\NotSupportedException('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 getResultColumns()
-	{
-		static $types;
-		if ($types === null) {
-			$consts = get_defined_constants(true);
-			$types = [];
-			foreach (isset($consts['mysqli']) ? $consts['mysqli'] : [] as $key => $value) {
-				if (strncmp($key, 'MYSQLI_TYPE_', 12) === 0) {
-					$types[$value] = substr($key, 12);
-				}
-			}
-			$types[MYSQLI_TYPE_TINY] = $types[MYSQLI_TYPE_SHORT] = $types[MYSQLI_TYPE_LONG] = 'INT';
+			$sql .= ' LIMIT ' . ($limit === null ? '18446744073709551615' : $limit)
+				. ($offset ? ' OFFSET ' . $offset : '');
 		}
-
-		$count = mysqli_num_fields($this->resultSet);
-		$columns = [];
-		for ($i = 0; $i < $count; $i++) {
-			$row = (array) mysqli_fetch_field_direct($this->resultSet, $i);
-			$columns[] = [
-				'name' => $row['name'],
-				'table' => $row['orgtable'],
-				'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
-				'nativetype' => isset($types[$row['type']]) ? $types[$row['type']] : $row['type'],
-				'type' => $row['type'] === MYSQLI_TYPE_TIME ? Dibi\Type::TIME_INTERVAL : null,
-				'vendor' => $row,
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns the result set resource.
-	 * @return \mysqli_result|null
-	 */
-	public function getResultResource()
-	{
-		$this->autoFree = false;
-		return $this->resultSet;
 	}
 }

+ 147 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/MySqliResult.php

@@ -0,0 +1,147 @@
+<?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;
+
+
+/**
+ * The driver for MySQL result set.
+ */
+class MySqliResult implements Dibi\ResultDriver
+{
+	use Dibi\Strict;
+
+	/** @var \mysqli_result */
+	private $resultSet;
+
+	/** @var bool */
+	private $autoFree = true;
+
+	/** @var bool  Is buffered (seekable and countable)? */
+	private $buffered;
+
+
+	public function __construct(\mysqli_result $resultSet, bool $buffered)
+	{
+		$this->resultSet = $resultSet;
+		$this->buffered = $buffered;
+	}
+
+
+	/**
+	 * Automatically frees the resources allocated for this result set.
+	 */
+	public function __destruct()
+	{
+		if ($this->autoFree && $this->getResultResource()) {
+			@$this->free();
+		}
+	}
+
+
+	/**
+	 * Returns the number of rows in a result set.
+	 */
+	public function getRowCount(): int
+	{
+		if (!$this->buffered) {
+			throw new Dibi\NotSupportedException('Row count is not available for unbuffered queries.');
+		}
+		return $this->resultSet->num_rows;
+	}
+
+
+	/**
+	 * Fetches the row at current position and moves the internal cursor to the next position.
+	 * @param  bool  $assoc   true for associative array, false for numeric
+	 */
+	public function fetch(bool $assoc): ?array
+	{
+		return $assoc
+			? $this->resultSet->fetch_assoc()
+			: $this->resultSet->fetch_row();
+	}
+
+
+	/**
+	 * Moves cursor position without fetching row.
+	 * @throws Dibi\Exception
+	 */
+	public function seek(int $row): bool
+	{
+		if (!$this->buffered) {
+			throw new Dibi\NotSupportedException('Cannot seek an unbuffered result set.');
+		}
+		return $this->resultSet->data_seek($row);
+	}
+
+
+	/**
+	 * Frees the resources allocated for this result set.
+	 */
+	public function free(): void
+	{
+		$this->resultSet->free();
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a result set.
+	 */
+	public function getResultColumns(): array
+	{
+		static $types;
+		if ($types === null) {
+			$consts = get_defined_constants(true);
+			$types = [];
+			foreach ($consts['mysqli'] ?? [] as $key => $value) {
+				if (strncmp($key, 'MYSQLI_TYPE_', 12) === 0) {
+					$types[$value] = substr($key, 12);
+				}
+			}
+			$types[MYSQLI_TYPE_TINY] = $types[MYSQLI_TYPE_SHORT] = $types[MYSQLI_TYPE_LONG] = 'INT';
+		}
+
+		$count = $this->resultSet->field_count;
+		$columns = [];
+		for ($i = 0; $i < $count; $i++) {
+			$row = (array) $this->resultSet->fetch_field_direct($i);
+			$columns[] = [
+				'name' => $row['name'],
+				'table' => $row['orgtable'],
+				'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
+				'nativetype' => $types[$row['type']] ?? $row['type'],
+				'type' => $row['type'] === MYSQLI_TYPE_TIME ? Dibi\Type::TIME_INTERVAL : null,
+				'vendor' => $row,
+			];
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Returns the result set resource.
+	 */
+	public function getResultResource(): \mysqli_result
+	{
+		$this->autoFree = false;
+		return $this->resultSet;
+	}
+
+
+	/**
+	 * Decodes data from result set.
+	 */
+	public function unescapeBinary(string $value): string
+	{
+		return $value;
+	}
+}

+ 74 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/NoDataResult.php

@@ -0,0 +1,74 @@
+<?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;
+
+
+/**
+ * The driver for no result set.
+ */
+class NoDataResult implements Dibi\ResultDriver
+{
+	use Dibi\Strict;
+
+	/** @var int */
+	private $rows;
+
+
+	public function __construct(int $rows)
+	{
+		$this->rows = $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()
+	{
+		return null;
+	}
+
+
+	public function unescapeBinary(string $value): string
+	{
+		return $value;
+	}
+}

+ 49 - 290
api/vendor/dibi/dibi/src/Dibi/Drivers/OdbcDriver.php

@@ -1,17 +1,19 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * The dibi driver interacting with databases via ODBC connections.
+ * The driver interacting with databases via ODBC connections.
  *
  * Driver options:
  *   - dsn => driver specific DSN
@@ -19,46 +21,31 @@ use Dibi;
  *   - password (or pass)
  *   - persistent (bool) => try to find a persistent link?
  *   - resource (resource) => existing connection resource
- *   - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
+ *   - microseconds (bool) => use microseconds in datetime format?
  */
-class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
+class OdbcDriver implements Dibi\Driver
 {
 	use Dibi\Strict;
 
-	/** @var resource|null */
+	/** @var resource */
 	private $connection;
 
-	/** @var resource|null */
-	private $resultSet;
+	/** @var int|null  Affected rows */
+	private $affectedRows;
 
 	/** @var bool */
-	private $autoFree = true;
-
-	/** @var int|false  Affected rows */
-	private $affectedRows = false;
-
-	/** @var int  Cursor */
-	private $row = 0;
+	private $microseconds = true;
 
 
 	/**
 	 * @throws Dibi\NotSupportedException
 	 */
-	public function __construct()
+	public function __construct(array $config)
 	{
 		if (!extension_loaded('odbc')) {
 			throw new Dibi\NotSupportedException("PHP extension 'odbc' is not loaded.");
 		}
-	}
 
-
-	/**
-	 * Connects to a database.
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public function connect(array &$config)
-	{
 		if (isset($config['resource'])) {
 			$this->connection = $config['resource'];
 		} else {
@@ -70,23 +57,26 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 			];
 
 			if (empty($config['persistent'])) {
-				$this->connection = @odbc_connect($config['dsn'], $config['username'], $config['password']); // intentionally @
+				$this->connection = @odbc_connect($config['dsn'], $config['username'] ?? '', $config['password'] ?? ''); // intentionally @
 			} else {
-				$this->connection = @odbc_pconnect($config['dsn'], $config['username'], $config['password']); // intentionally @
+				$this->connection = @odbc_pconnect($config['dsn'], $config['username'] ?? '', $config['password'] ?? ''); // intentionally @
 			}
 		}
 
 		if (!is_resource($this->connection)) {
 			throw new Dibi\DriverException(odbc_errormsg() . ' ' . odbc_error());
 		}
+
+		if (isset($config['microseconds'])) {
+			$this->microseconds = (bool) $config['microseconds'];
+		}
 	}
 
 
 	/**
 	 * Disconnects from a database.
-	 * @return void
 	 */
-	public function disconnect()
+	public function disconnect(): void
 	{
 		@odbc_close($this->connection); // @ - connection can be already disconnected
 	}
@@ -94,20 +84,18 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return Dibi\ResultDriver|null
 	 * @throws Dibi\DriverException
 	 */
-	public function query($sql)
+	public function query(string $sql): ?Dibi\ResultDriver
 	{
-		$this->affectedRows = false;
+		$this->affectedRows = null;
 		$res = @odbc_exec($this->connection, $sql); // intentionally @
 
 		if ($res === false) {
 			throw new Dibi\DriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection), 0, $sql);
 
 		} elseif (is_resource($res)) {
-			$this->affectedRows = odbc_num_rows($res);
+			$this->affectedRows = Dibi\Helpers::false2Null(odbc_num_rows($res));
 			return odbc_num_fields($res) ? $this->createResultDriver($res) : null;
 		}
 		return null;
@@ -116,9 +104,8 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * 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()
+	public function getAffectedRows(): ?int
 	{
 		return $this->affectedRows;
 	}
@@ -126,9 +113,8 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * 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)
+	public function getInsertId(?string $sequence): ?int
 	{
 		throw new Dibi\NotSupportedException('ODBC does not support autoincrementing.');
 	}
@@ -136,13 +122,11 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Begins a transaction (if supported).
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function begin($savepoint = null)
+	public function begin(string $savepoint = null): void
 	{
-		if (!odbc_autocommit($this->connection, false)) {
+		if (!odbc_autocommit($this->connection, 0/*false*/)) {
 			throw new Dibi\DriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
 		}
 	}
@@ -150,39 +134,34 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function commit($savepoint = null)
+	public function commit(string $savepoint = null): void
 	{
 		if (!odbc_commit($this->connection)) {
 			throw new Dibi\DriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
 		}
-		odbc_autocommit($this->connection, true);
+		odbc_autocommit($this->connection, 1/*true*/);
 	}
 
 
 	/**
 	 * Rollback changes in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function rollback($savepoint = null)
+	public function rollback(string $savepoint = null): void
 	{
 		if (!odbc_rollback($this->connection)) {
 			throw new Dibi\DriverException(odbc_errormsg($this->connection) . ' ' . odbc_error($this->connection));
 		}
-		odbc_autocommit($this->connection, true);
+		odbc_autocommit($this->connection, 1/*true*/);
 	}
 
 
 	/**
 	 * Is in transaction?
-	 * @return bool
 	 */
-	public function inTransaction()
+	public function inTransaction(): bool
 	{
 		return !odbc_autocommit($this->connection);
 	}
@@ -200,24 +179,20 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Returns the connection reflector.
-	 * @return Dibi\Reflector
 	 */
-	public function getReflector()
+	public function getReflector(): Dibi\Reflector
 	{
-		return $this;
+		return new OdbcReflector($this);
 	}
 
 
 	/**
 	 * Result set driver factory.
-	 * @param  resource
-	 * @return Dibi\ResultDriver
+	 * @param  resource  $resource
 	 */
-	public function createResultDriver($resource)
+	public function createResultDriver($resource): OdbcResult
 	{
-		$res = clone $this;
-		$res->resultSet = $resource;
-		return $res;
+		return new OdbcResult($resource);
 	}
 
 
@@ -226,52 +201,37 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Encodes data for use in a SQL statement.
-	 * @param  string    value
-	 * @return string    encoded value
 	 */
-	public function escapeText($value)
+	public function escapeText(string $value): string
 	{
 		return "'" . str_replace("'", "''", $value) . "'";
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeBinary($value)
+	public function escapeBinary(string $value): string
 	{
 		return "'" . str_replace("'", "''", $value) . "'";
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeIdentifier($value)
+	public function escapeIdentifier(string $value): string
 	{
 		return '[' . str_replace(['[', ']'], ['[[', ']]'], $value) . ']';
 	}
 
 
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	public function escapeBool($value)
+	public function escapeBool(bool $value): string
 	{
 		return $value ? '1' : '0';
 	}
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDate($value)
+	public function escapeDate($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
 		return $value->format('#m/d/Y#');
@@ -279,58 +239,31 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDateTime($value)
+	public function escapeDateTime($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
-		return $value->format('#m/d/Y H:i:s.u#');
+		return $value->format($this->microseconds ? '#m/d/Y H:i:s.u#' : '#m/d/Y H:i:s#');
 	}
 
 
 	/**
 	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
 	 */
-	public function escapeLike($value, $pos)
+	public function escapeLike(string $value, int $pos): string
 	{
 		$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
 		return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
 	}
 
 
-	/**
-	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
-	 */
-	public function unescapeBinary($value)
-	{
-		return $value;
-	}
-
-
-	/** @deprecated */
-	public function escape($value, $type)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		return Dibi\Helpers::escape($this, $value, $type);
-	}
-
-
 	/**
 	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
 	 */
-	public function applyLimit(&$sql, $limit, $offset)
+	public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
 	{
 		if ($offset) {
 			throw new Dibi\NotSupportedException('Offset is not supported by this database.');
@@ -339,181 +272,7 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 			throw new Dibi\NotSupportedException('Negative offset or limit.');
 
 		} elseif ($limit !== null) {
-			$sql = 'SELECT TOP ' . Dibi\Helpers::intVal($limit) . ' * FROM (' . $sql . ') t';
-		}
-	}
-
-
-	/********************* result set ****************d*g**/
-
-
-	/**
-	 * Automatically frees the resources allocated for this result set.
-	 * @return void
-	 */
-	public function __destruct()
-	{
-		$this->autoFree && $this->getResultResource() && $this->free();
-	}
-
-
-	/**
-	 * 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
-	 */
-	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 = [];
-			for ($i = 1; $i <= $count; $i++) {
-				$cols[] = odbc_result($set, $i);
-			}
-			return $cols;
+			$sql = 'SELECT TOP ' . $limit . ' * FROM (' . $sql . ') t';
 		}
 	}
-
-
-	/**
-	 * Moves cursor position without fetching row.
-	 * @param  int   the 0-based cursor pos to seek to
-	 * @return bool  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 getResultColumns()
-	{
-		$count = odbc_num_fields($this->resultSet);
-		$columns = [];
-		for ($i = 1; $i <= $count; $i++) {
-			$columns[] = [
-				'name' => odbc_field_name($this->resultSet, $i),
-				'table' => null,
-				'fullname' => odbc_field_name($this->resultSet, $i),
-				'nativetype' => odbc_field_type($this->resultSet, $i),
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns the result set resource.
-	 * @return resource|null
-	 */
-	public function getResultResource()
-	{
-		$this->autoFree = false;
-		return is_resource($this->resultSet) ? $this->resultSet : null;
-	}
-
-
-	/********************* Dibi\Reflector ****************d*g**/
-
-
-	/**
-	 * Returns list of tables.
-	 * @return array
-	 */
-	public function getTables()
-	{
-		$res = odbc_tables($this->connection);
-		$tables = [];
-		while ($row = odbc_fetch_array($res)) {
-			if ($row['TABLE_TYPE'] === 'TABLE' || $row['TABLE_TYPE'] === 'VIEW') {
-				$tables[] = [
-					'name' => $row['TABLE_NAME'],
-					'view' => $row['TABLE_TYPE'] === 'VIEW',
-				];
-			}
-		}
-		odbc_free_result($res);
-		return $tables;
-	}
-
-
-	/**
-	 * Returns metadata for all columns in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getColumns($table)
-	{
-		$res = odbc_columns($this->connection);
-		$columns = [];
-		while ($row = odbc_fetch_array($res)) {
-			if ($row['TABLE_NAME'] === $table) {
-				$columns[] = [
-					'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($res);
-		return $columns;
-	}
-
-
-	/**
-	 * Returns metadata for all indexes in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getIndexes($table)
-	{
-		throw new Dibi\NotImplementedException;
-	}
-
-
-	/**
-	 * Returns metadata for all foreign keys in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getForeignKeys($table)
-	{
-		throw new Dibi\NotImplementedException;
-	}
 }

+ 92 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/OdbcReflector.php

@@ -0,0 +1,92 @@
+<?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;
+
+
+/**
+ * The reflector for ODBC connections.
+ */
+class OdbcReflector implements Dibi\Reflector
+{
+	use Dibi\Strict;
+
+	/** @var Dibi\Driver */
+	private $driver;
+
+
+	public function __construct(Dibi\Driver $driver)
+	{
+		$this->driver = $driver;
+	}
+
+
+	/**
+	 * Returns list of tables.
+	 */
+	public function getTables(): array
+	{
+		$res = odbc_tables($this->driver->getResource());
+		$tables = [];
+		while ($row = odbc_fetch_array($res)) {
+			if ($row['TABLE_TYPE'] === 'TABLE' || $row['TABLE_TYPE'] === 'VIEW') {
+				$tables[] = [
+					'name' => $row['TABLE_NAME'],
+					'view' => $row['TABLE_TYPE'] === 'VIEW',
+				];
+			}
+		}
+		odbc_free_result($res);
+		return $tables;
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a table.
+	 */
+	public function getColumns(string $table): array
+	{
+		$res = odbc_columns($this->driver->getResource());
+		$columns = [];
+		while ($row = odbc_fetch_array($res)) {
+			if ($row['TABLE_NAME'] === $table) {
+				$columns[] = [
+					'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($res);
+		return $columns;
+	}
+
+
+	/**
+	 * Returns metadata for all indexes in a table.
+	 */
+	public function getIndexes(string $table): array
+	{
+		throw new Dibi\NotImplementedException;
+	}
+
+
+	/**
+	 * Returns metadata for all foreign keys in a table.
+	 */
+	public function getForeignKeys(string $table): array
+	{
+		throw new Dibi\NotImplementedException;
+	}
+}

+ 141 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/OdbcResult.php

@@ -0,0 +1,141 @@
+<?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;
+
+
+/**
+ * The driver interacting with result set via ODBC connections.
+ */
+class OdbcResult implements Dibi\ResultDriver
+{
+	use Dibi\Strict;
+
+	/** @var resource */
+	private $resultSet;
+
+	/** @var bool */
+	private $autoFree = true;
+
+	/** @var int  Cursor */
+	private $row = 0;
+
+
+	/**
+	 * @param  resource  $resultSet
+	 */
+	public function __construct($resultSet)
+	{
+		$this->resultSet = $resultSet;
+	}
+
+
+	/**
+	 * Automatically frees the resources allocated for this result set.
+	 */
+	public function __destruct()
+	{
+		if ($this->autoFree && $this->getResultResource()) {
+			$this->free();
+		}
+	}
+
+
+	/**
+	 * Returns the number of rows in a result set.
+	 */
+	public function getRowCount(): int
+	{
+		// 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  $assoc  true for associative array, false for numeric
+	 */
+	public function fetch(bool $assoc): ?array
+	{
+		if ($assoc) {
+			return Dibi\Helpers::false2Null(odbc_fetch_array($this->resultSet, ++$this->row));
+		} else {
+			$set = $this->resultSet;
+			if (!odbc_fetch_row($set, ++$this->row)) {
+				return null;
+			}
+			$count = odbc_num_fields($set);
+			$cols = [];
+			for ($i = 1; $i <= $count; $i++) {
+				$cols[] = odbc_result($set, $i);
+			}
+			return $cols;
+		}
+	}
+
+
+	/**
+	 * Moves cursor position without fetching row.
+	 */
+	public function seek(int $row): bool
+	{
+		$this->row = $row;
+		return true;
+	}
+
+
+	/**
+	 * Frees the resources allocated for this result set.
+	 */
+	public function free(): void
+	{
+		odbc_free_result($this->resultSet);
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a result set.
+	 */
+	public function getResultColumns(): array
+	{
+		$count = odbc_num_fields($this->resultSet);
+		$columns = [];
+		for ($i = 1; $i <= $count; $i++) {
+			$columns[] = [
+				'name' => odbc_field_name($this->resultSet, $i),
+				'table' => null,
+				'fullname' => odbc_field_name($this->resultSet, $i),
+				'nativetype' => odbc_field_type($this->resultSet, $i),
+			];
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Returns the result set resource.
+	 * @return resource|null
+	 */
+	public function getResultResource()
+	{
+		$this->autoFree = false;
+		return is_resource($this->resultSet) ? $this->resultSet : null;
+	}
+
+
+	/**
+	 * Decodes data from result set.
+	 */
+	public function unescapeBinary(string $value): string
+	{
+		return $value;
+	}
+}

+ 50 - 285
api/vendor/dibi/dibi/src/Dibi/Drivers/OracleDriver.php

@@ -1,17 +1,19 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * The dibi driver for Oracle database.
+ * The driver for Oracle database.
  *
  * Driver options:
  *   - database => the name of the local Oracle instance or the name of the entry in tnsnames.ora
@@ -19,62 +21,42 @@ use Dibi;
  *   - password (or pass)
  *   - charset => character encoding to set
  *   - schema => alters session schema
- *   - nativeDate => use native date format (defaults to false)
+ *   - nativeDate => use native date format (defaults to true)
  *   - resource (resource) => existing connection resource
  *   - persistent => Creates persistent connections with oci_pconnect instead of oci_new_connect
- *   - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
  */
-class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
+class OracleDriver implements Dibi\Driver
 {
 	use Dibi\Strict;
 
-	/** @var resource|null */
+	/** @var resource */
 	private $connection;
 
-	/** @var resource|null */
-	private $resultSet;
-
-	/** @var bool */
-	private $autoFree = true;
-
 	/** @var bool */
 	private $autocommit = true;
 
-	/** @var string  Date and datetime format */
-	private $fmtDate;
-	private $fmtDateTime;
+	/** @var bool  use native datetime format */
+	private $nativeDate;
 
-	/** @var int|false Number of affected rows */
-	private $affectedRows = false;
+	/** @var int|null Number of affected rows */
+	private $affectedRows;
 
 
 	/**
 	 * @throws Dibi\NotSupportedException
 	 */
-	public function __construct()
+	public function __construct(array $config)
 	{
 		if (!extension_loaded('oci8')) {
 			throw new Dibi\NotSupportedException("PHP extension 'oci8' is not loaded.");
 		}
-	}
-
 
-	/**
-	 * Connects to a database.
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public function connect(array &$config)
-	{
 		$foo = &$config['charset'];
 
 		if (isset($config['formatDate']) || isset($config['formatDateTime'])) {
 			trigger_error('OracleDriver: options formatDate and formatDateTime are deprecated.', E_USER_DEPRECATED);
 		}
-		if (empty($config['nativeDate'])) {
-			$this->fmtDate = isset($config['formatDate']) ? $config['formatDate'] : 'U';
-			$this->fmtDateTime = isset($config['formatDateTime']) ? $config['formatDateTime'] : 'U';
-		}
+		$this->nativeDate = $config['nativeDate'] ?? true;
 
 		if (isset($config['resource'])) {
 			$this->connection = $config['resource'];
@@ -97,9 +79,8 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Disconnects from a database.
-	 * @return void
 	 */
-	public function disconnect()
+	public function disconnect(): void
 	{
 		@oci_close($this->connection); // @ - connection can be already disconnected
 	}
@@ -107,22 +88,20 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return Dibi\ResultDriver|null
 	 * @throws Dibi\DriverException
 	 */
-	public function query($sql)
+	public function query(string $sql): ?Dibi\ResultDriver
 	{
-		$this->affectedRows = false;
+		$this->affectedRows = null;
 		$res = oci_parse($this->connection, $sql);
 		if ($res) {
 			@oci_execute($res, $this->autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
 			$err = oci_error($res);
 			if ($err) {
-				throw self::createException($err['message'], $err['code'], $sql);
+				throw static::createException($err['message'], $err['code'], $sql);
 
 			} elseif (is_resource($res)) {
-				$this->affectedRows = oci_num_rows($res);
+				$this->affectedRows = Dibi\Helpers::false2Null(oci_num_rows($res));
 				return oci_num_fields($res) ? $this->createResultDriver($res) : null;
 			}
 		} else {
@@ -133,10 +112,7 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 	}
 
 
-	/**
-	 * @return Dibi\DriverException
-	 */
-	public static function createException($message, $code, $sql)
+	public static function createException(string $message, $code, string $sql): Dibi\DriverException
 	{
 		if (in_array($code, [1, 2299, 38911], true)) {
 			return new Dibi\UniqueConstraintViolationException($message, $code, $sql);
@@ -155,9 +131,8 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * 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()
+	public function getAffectedRows(): ?int
 	{
 		return $this->affectedRows;
 	}
@@ -165,21 +140,18 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * 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)
+	public function getInsertId(?string $sequence): ?int
 	{
 		$row = $this->query("SELECT $sequence.CURRVAL AS ID FROM DUAL")->fetch(true);
-		return isset($row['ID']) ? Dibi\Helpers::intVal($row['ID']) : false;
+		return isset($row['ID']) ? Dibi\Helpers::intVal($row['ID']) : null;
 	}
 
 
 	/**
 	 * Begins a transaction (if supported).
-	 * @param  string  optional savepoint name
-	 * @return void
 	 */
-	public function begin($savepoint = null)
+	public function begin(string $savepoint = null): void
 	{
 		$this->autocommit = false;
 	}
@@ -187,11 +159,9 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function commit($savepoint = null)
+	public function commit(string $savepoint = null): void
 	{
 		if (!oci_commit($this->connection)) {
 			$err = oci_error($this->connection);
@@ -203,11 +173,9 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Rollback changes in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function rollback($savepoint = null)
+	public function rollback(string $savepoint = null): void
 	{
 		if (!oci_rollback($this->connection)) {
 			$err = oci_error($this->connection);
@@ -229,24 +197,20 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Returns the connection reflector.
-	 * @return Dibi\Reflector
 	 */
-	public function getReflector()
+	public function getReflector(): Dibi\Reflector
 	{
-		return $this;
+		return new OracleReflector($this);
 	}
 
 
 	/**
 	 * Result set driver factory.
-	 * @param  resource
-	 * @return Dibi\ResultDriver
+	 * @param  resource  $resource
 	 */
-	public function createResultDriver($resource)
+	public function createResultDriver($resource): OracleResult
 	{
-		$res = clone $this;
-		$res->resultSet = $resource;
-		return $res;
+		return new OracleResult($resource);
 	}
 
 
@@ -255,83 +219,64 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Encodes data for use in a SQL statement.
-	 * @param  string    value
-	 * @return string    encoded value
 	 */
-	public function escapeText($value)
+	public function escapeText(string $value): string
 	{
 		return "'" . str_replace("'", "''", $value) . "'"; // TODO: not tested
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeBinary($value)
+	public function escapeBinary(string $value): string
 	{
 		return "'" . str_replace("'", "''", $value) . "'"; // TODO: not tested
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeIdentifier($value)
+	public function escapeIdentifier(string $value): string
 	{
 		// @see http://download.oracle.com/docs/cd/B10500_01/server.920/a96540/sql_elements9a.htm
 		return '"' . str_replace('"', '""', $value) . '"';
 	}
 
 
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	public function escapeBool($value)
+	public function escapeBool(bool $value): string
 	{
 		return $value ? '1' : '0';
 	}
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDate($value)
+	public function escapeDate($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
-		return $this->fmtDate
-			? $value->format($this->fmtDate)
-			: "to_date('" . $value->format('Y-m-d') . "', 'YYYY-mm-dd')";
+		return $this->nativeDate
+			? "to_date('" . $value->format('Y-m-d') . "', 'YYYY-mm-dd')"
+			: $value->format('U');
 	}
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDateTime($value)
+	public function escapeDateTime($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
-		return $this->fmtDateTime
-			? $value->format($this->fmtDateTime)
-			: "to_date('" . $value->format('Y-m-d G:i:s') . "', 'YYYY-mm-dd hh24:mi:ss')";
+		return $this->nativeDate
+			? "to_date('" . $value->format('Y-m-d G:i:s') . "', 'YYYY-mm-dd hh24:mi:ss')"
+			: $value->format('U');
 	}
 
 
 	/**
 	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
 	 */
-	public function escapeLike($value, $pos)
+	public function escapeLike(string $value, int $pos): string
 	{
 		$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\\%_");
 		$value = str_replace("'", "''", $value);
@@ -339,33 +284,10 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 	}
 
 
-	/**
-	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
-	 */
-	public function unescapeBinary($value)
-	{
-		return $value;
-	}
-
-
-	/** @deprecated */
-	public function escape($value, $type)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		return Dibi\Helpers::escape($this, $value, $type);
-	}
-
-
 	/**
 	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
 	 */
-	public function applyLimit(&$sql, $limit, $offset)
+	public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
 	{
 		if ($limit < 0 || $offset < 0) {
 			throw new Dibi\NotSupportedException('Negative offset or limit.');
@@ -373,168 +295,11 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 		} elseif ($offset) {
 			// see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
 			$sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t '
-				. ($limit !== null ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '')
+				. ($limit !== null ? 'WHERE ROWNUM <= ' . ($offset + $limit) : '')
 				. ') WHERE "__rnum" > ' . $offset;
 
 		} elseif ($limit !== null) {
-			$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . Dibi\Helpers::intVal($limit);
+			$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . $limit;
 		}
 	}
-
-
-	/********************* result set ****************d*g**/
-
-
-	/**
-	 * Automatically frees the resources allocated for this result set.
-	 * @return void
-	 */
-	public function __destruct()
-	{
-		$this->autoFree && $this->getResultResource() && $this->free();
-	}
-
-
-	/**
-	 * Returns the number of rows in a result set.
-	 * @return int
-	 */
-	public function getRowCount()
-	{
-		throw new Dibi\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
-	 */
-	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 bool  true on success, false if unable to seek to specified record
-	 */
-	public function seek($row)
-	{
-		throw new Dibi\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 getResultColumns()
-	{
-		$count = oci_num_fields($this->resultSet);
-		$columns = [];
-		for ($i = 1; $i <= $count; $i++) {
-			$type = oci_field_type($this->resultSet, $i);
-			$columns[] = [
-				'name' => oci_field_name($this->resultSet, $i),
-				'table' => null,
-				'fullname' => oci_field_name($this->resultSet, $i),
-				'nativetype' => $type === 'NUMBER' && oci_field_scale($this->resultSet, $i) === 0 ? 'INTEGER' : $type,
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns the result set resource.
-	 * @return resource|null
-	 */
-	public function getResultResource()
-	{
-		$this->autoFree = false;
-		return is_resource($this->resultSet) ? $this->resultSet : null;
-	}
-
-
-	/********************* Dibi\Reflector ****************d*g**/
-
-
-	/**
-	 * Returns list of tables.
-	 * @return array
-	 */
-	public function getTables()
-	{
-		$res = $this->query('SELECT * FROM cat');
-		$tables = [];
-		while ($row = $res->fetch(false)) {
-			if ($row[1] === 'TABLE' || $row[1] === 'VIEW') {
-				$tables[] = [
-					'name' => $row[0],
-					'view' => $row[1] === 'VIEW',
-				];
-			}
-		}
-		return $tables;
-	}
-
-
-	/**
-	 * Returns metadata for all columns in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getColumns($table)
-	{
-		$res = $this->query('SELECT * FROM "ALL_TAB_COLUMNS" WHERE "TABLE_NAME" = ' . $this->escapeText($table));
-		$columns = [];
-		while ($row = $res->fetch(true)) {
-			$columns[] = [
-				'table' => $row['TABLE_NAME'],
-				'name' => $row['COLUMN_NAME'],
-				'nativetype' => $row['DATA_TYPE'],
-				'size' => isset($row['DATA_LENGTH']) ? $row['DATA_LENGTH'] : null,
-				'nullable' => $row['NULLABLE'] === 'Y',
-				'default' => $row['DATA_DEFAULT'],
-				'vendor' => $row,
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns metadata for all indexes in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getIndexes($table)
-	{
-		throw new Dibi\NotImplementedException;
-	}
-
-
-	/**
-	 * Returns metadata for all foreign keys in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getForeignKeys($table)
-	{
-		throw new Dibi\NotImplementedException;
-	}
 }

+ 89 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/OracleReflector.php

@@ -0,0 +1,89 @@
+<?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;
+
+
+/**
+ * The reflector for Oracle database.
+ */
+class OracleReflector implements Dibi\Reflector
+{
+	use Dibi\Strict;
+
+	/** @var Dibi\Driver */
+	private $driver;
+
+
+	public function __construct(Dibi\Driver $driver)
+	{
+		$this->driver = $driver;
+	}
+
+
+	/**
+	 * Returns list of tables.
+	 */
+	public function getTables(): array
+	{
+		$res = $this->driver->query('SELECT * FROM cat');
+		$tables = [];
+		while ($row = $res->fetch(false)) {
+			if ($row[1] === 'TABLE' || $row[1] === 'VIEW') {
+				$tables[] = [
+					'name' => $row[0],
+					'view' => $row[1] === 'VIEW',
+				];
+			}
+		}
+		return $tables;
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a table.
+	 */
+	public function getColumns(string $table): array
+	{
+		$res = $this->driver->query('SELECT * FROM "ALL_TAB_COLUMNS" WHERE "TABLE_NAME" = ' . $this->driver->escapeText($table));
+		$columns = [];
+		while ($row = $res->fetch(true)) {
+			$columns[] = [
+				'table' => $row['TABLE_NAME'],
+				'name' => $row['COLUMN_NAME'],
+				'nativetype' => $row['DATA_TYPE'],
+				'size' => $row['DATA_LENGTH'] ?? null,
+				'nullable' => $row['NULLABLE'] === 'Y',
+				'default' => $row['DATA_DEFAULT'],
+				'vendor' => $row,
+			];
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Returns metadata for all indexes in a table.
+	 */
+	public function getIndexes(string $table): array
+	{
+		throw new Dibi\NotImplementedException;
+	}
+
+
+	/**
+	 * Returns metadata for all foreign keys in a table.
+	 */
+	public function getForeignKeys(string $table): array
+	{
+		throw new Dibi\NotImplementedException;
+	}
+}

+ 124 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/OracleResult.php

@@ -0,0 +1,124 @@
+<?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;
+
+
+/**
+ * The driver for Oracle result set.
+ */
+class OracleResult implements Dibi\ResultDriver
+{
+	use Dibi\Strict;
+
+	/** @var resource */
+	private $resultSet;
+
+	/** @var bool */
+	private $autoFree = true;
+
+
+	/**
+	 * @param  resource  $resultSet
+	 */
+	public function __construct($resultSet)
+	{
+		$this->resultSet = $resultSet;
+	}
+
+
+	/**
+	 * Automatically frees the resources allocated for this result set.
+	 */
+	public function __destruct()
+	{
+		if ($this->autoFree && $this->getResultResource()) {
+			$this->free();
+		}
+	}
+
+
+	/**
+	 * Returns the number of rows in a result set.
+	 */
+	public function getRowCount(): int
+	{
+		throw new Dibi\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  $assoc  true for associative array, false for numeric
+	 */
+	public function fetch(bool $assoc): ?array
+	{
+		return Dibi\Helpers::false2Null(oci_fetch_array($this->resultSet, ($assoc ? OCI_ASSOC : OCI_NUM) | OCI_RETURN_NULLS));
+	}
+
+
+	/**
+	 * Moves cursor position without fetching row.
+	 */
+	public function seek(int $row): bool
+	{
+		throw new Dibi\NotImplementedException;
+	}
+
+
+	/**
+	 * Frees the resources allocated for this result set.
+	 */
+	public function free(): void
+	{
+		oci_free_statement($this->resultSet);
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a result set.
+	 */
+	public function getResultColumns(): array
+	{
+		$count = oci_num_fields($this->resultSet);
+		$columns = [];
+		for ($i = 1; $i <= $count; $i++) {
+			$type = oci_field_type($this->resultSet, $i);
+			$columns[] = [
+				'name' => oci_field_name($this->resultSet, $i),
+				'table' => null,
+				'fullname' => oci_field_name($this->resultSet, $i),
+				'nativetype' => $type === 'NUMBER' && oci_field_scale($this->resultSet, $i) === 0 ? 'INTEGER' : $type,
+			];
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Returns the result set resource.
+	 * @return resource|null
+	 */
+	public function getResultResource()
+	{
+		$this->autoFree = false;
+		return is_resource($this->resultSet) ? $this->resultSet : null;
+	}
+
+
+	/**
+	 * Decodes data from result set.
+	 */
+	public function unescapeBinary(string $value): string
+	{
+		return $value;
+	}
+}

+ 80 - 221
api/vendor/dibi/dibi/src/Dibi/Drivers/PdoDriver.php

@@ -1,18 +1,21 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
+use Dibi\Helpers;
 use PDO;
 
 
 /**
- * The dibi driver for PDO.
+ * The driver for PDO.
  *
  * Driver options:
  *   - dsn => driver specific DSN
@@ -21,20 +24,16 @@ use PDO;
  *   - options (array) => driver specific options {@see PDO::__construct}
  *   - resource (PDO) => existing connection
  *   - version
- *   - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
  */
-class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
+class PdoDriver implements Dibi\Driver
 {
 	use Dibi\Strict;
 
-	/** @var PDO  Connection resource */
+	/** @var PDO|null  Connection resource */
 	private $connection;
 
-	/** @var \PDOStatement|null  Resultset resource */
-	private $resultSet;
-
-	/** @var int|false  Affected rows */
-	private $affectedRows = false;
+	/** @var int|null  Affected rows */
+	private $affectedRows;
 
 	/** @var string */
 	private $driverName;
@@ -46,24 +45,15 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 	/**
 	 * @throws Dibi\NotSupportedException
 	 */
-	public function __construct()
+	public function __construct(array $config)
 	{
 		if (!extension_loaded('pdo')) {
 			throw new Dibi\NotSupportedException("PHP extension 'pdo' is not loaded.");
 		}
-	}
 
-
-	/**
-	 * Connects to a database.
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public function connect(array &$config)
-	{
 		$foo = &$config['dsn'];
 		$foo = &$config['options'];
-		Dibi\Helpers::alias($config, 'resource', 'pdo');
+		Helpers::alias($config, 'resource', 'pdo');
 
 		if ($config['resource'] instanceof PDO) {
 			$this->connection = $config['resource'];
@@ -79,18 +69,19 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 			}
 		}
 
+		if ($this->connection->getAttribute(PDO::ATTR_ERRMODE) !== PDO::ERRMODE_SILENT) {
+			throw new Dibi\DriverException('PDO connection in exception or warning error mode is not supported.');
+		}
+
 		$this->driverName = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME);
-		$this->serverVersion = isset($config['version'])
-			? $config['version']
-			: @$this->connection->getAttribute(PDO::ATTR_SERVER_VERSION); // @ - may be not supported
+		$this->serverVersion = (string) ($config['version'] ?? @$this->connection->getAttribute(PDO::ATTR_SERVER_VERSION)); // @ - may be not supported
 	}
 
 
 	/**
 	 * Disconnects from a database.
-	 * @return void
 	 */
-	public function disconnect()
+	public function disconnect(): void
 	{
 		$this->connection = null;
 	}
@@ -98,30 +89,19 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return Dibi\ResultDriver|null
 	 * @throws Dibi\DriverException
 	 */
-	public function query($sql)
+	public function query(string $sql): ?Dibi\ResultDriver
 	{
-		// must detect if SQL returns result set or num of affected rows
-		$cmd = strtoupper(substr(ltrim($sql), 0, 6));
-		static $list = ['UPDATE' => 1, 'DELETE' => 1, 'INSERT' => 1, 'REPLAC' => 1];
-		$this->affectedRows = false;
-
-		if (isset($list[$cmd])) {
-			$this->affectedRows = $this->connection->exec($sql);
-			if ($this->affectedRows !== false) {
-				return null;
-			}
-		} else {
-			$res = $this->connection->query($sql);
-			if ($res) {
-				return $this->createResultDriver($res);
-			}
+		$res = $this->connection->query($sql);
+		if ($res) {
+			$this->affectedRows = $res->rowCount();
+			return $res->columnCount() ? $this->createResultDriver($res) : null;
 		}
 
-		list($sqlState, $code, $message) = $this->connection->errorInfo();
+		$this->affectedRows = null;
+
+		[$sqlState, $code, $message] = $this->connection->errorInfo();
 		$message = "SQLSTATE[$sqlState]: $message";
 		switch ($this->driverName) {
 			case 'mysql':
@@ -134,7 +114,7 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 				throw PostgreDriver::createException($message, $sqlState, $sql);
 
 			case 'sqlite':
-				throw Sqlite3Driver::createException($message, $code, $sql);
+				throw SqliteDriver::createException($message, $code, $sql);
 
 			default:
 				throw new Dibi\DriverException($message, $code, $sql);
@@ -144,9 +124,8 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * 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()
+	public function getAffectedRows(): ?int
 	{
 		return $this->affectedRows;
 	}
@@ -154,21 +133,18 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * 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)
+	public function getInsertId(?string $sequence): ?int
 	{
-		return $this->connection->lastInsertId();
+		return Helpers::intVal($this->connection->lastInsertId($sequence));
 	}
 
 
 	/**
 	 * Begins a transaction (if supported).
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function begin($savepoint = null)
+	public function begin(string $savepoint = null): void
 	{
 		if (!$this->connection->beginTransaction()) {
 			$err = $this->connection->errorInfo();
@@ -179,11 +155,9 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function commit($savepoint = null)
+	public function commit(string $savepoint = null): void
 	{
 		if (!$this->connection->commit()) {
 			$err = $this->connection->errorInfo();
@@ -194,11 +168,9 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Rollback changes in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function rollback($savepoint = null)
+	public function rollback(string $savepoint = null): void
 	{
 		if (!$this->connection->rollBack()) {
 			$err = $this->connection->errorInfo();
@@ -209,9 +181,8 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Returns the connection resource.
-	 * @return PDO
 	 */
-	public function getResource()
+	public function getResource(): ?PDO
 	{
 		return $this->connection;
 	}
@@ -219,17 +190,27 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Returns the connection reflector.
-	 * @return Dibi\Reflector
 	 */
-	public function getReflector()
+	public function getReflector(): Dibi\Reflector
 	{
 		switch ($this->driverName) {
 			case 'mysql':
 				return new MySqlReflector($this);
 
+			case 'oci':
+				return new OracleReflector($this);
+
+			case 'pgsql':
+				return new PostgreReflector($this, $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION));
+
 			case 'sqlite':
 				return new SqliteReflector($this);
 
+			case 'mssql':
+			case 'dblib':
+			case 'sqlsrv':
+				return new SqlsrvReflector($this);
+
 			default:
 				throw new Dibi\NotSupportedException;
 		}
@@ -238,14 +219,10 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Result set driver factory.
-	 * @param  \PDOStatement
-	 * @return Dibi\ResultDriver
 	 */
-	public function createResultDriver(\PDOStatement $resource)
+	public function createResultDriver(\PDOStatement $result): PdoResult
 	{
-		$res = clone $this;
-		$res->resultSet = $resource;
-		return $res;
+		return new PdoResult($result, $this->driverName);
 	}
 
 
@@ -254,10 +231,8 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Encodes data for use in a SQL statement.
-	 * @param  string    value
-	 * @return string    encoded value
 	 */
-	public function escapeText($value)
+	public function escapeText(string $value): string
 	{
 		if ($this->driverName === 'odbc') {
 			return "'" . str_replace("'", "''", $value) . "'";
@@ -267,11 +242,7 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeBinary($value)
+	public function escapeBinary(string $value): string
 	{
 		if ($this->driverName === 'odbc') {
 			return "'" . str_replace("'", "''", $value) . "'";
@@ -281,11 +252,7 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeIdentifier($value)
+	public function escapeIdentifier(string $value): string
 	{
 		switch ($this->driverName) {
 			case 'mysql':
@@ -312,11 +279,7 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 	}
 
 
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	public function escapeBool($value)
+	public function escapeBool(bool $value): string
 	{
 		if ($this->driverName === 'pgsql') {
 			return $value ? 'TRUE' : 'FALSE';
@@ -327,12 +290,11 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDate($value)
+	public function escapeDate($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
 		return $value->format($this->driverName === 'odbc' ? '#m/d/Y#' : "'Y-m-d'");
@@ -340,25 +302,30 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDateTime($value)
+	public function escapeDateTime($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
-		return $value->format($this->driverName === 'odbc' ? '#m/d/Y H:i:s.u#' : "'Y-m-d H:i:s.u'");
+		switch ($this->driverName) {
+			case 'odbc':
+				return $value->format('#m/d/Y H:i:s.u#');
+			case 'mssql':
+			case 'dblib':
+			case 'sqlsrv':
+				return 'CONVERT(DATETIME2(7), ' . $value->format("'Y-m-d H:i:s.u'") . ')';
+			default:
+				return $value->format("'Y-m-d H:i:s.u'");
+		}
 	}
 
 
 	/**
 	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
 	 */
-	public function escapeLike($value, $pos)
+	public function escapeLike(string $value, int $pos): string
 	{
 		switch ($this->driverName) {
 			case 'mysql':
@@ -393,33 +360,10 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 	}
 
 
-	/**
-	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
-	 */
-	public function unescapeBinary($value)
-	{
-		return $value;
-	}
-
-
-	/** @deprecated */
-	public function escape($value, $type)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		return Dibi\Helpers::escape($this, $value, $type);
-	}
-
-
 	/**
 	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
 	 */
-	public function applyLimit(&$sql, $limit, $offset)
+	public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
 	{
 		if ($limit < 0 || $offset < 0) {
 			throw new Dibi\NotSupportedException('Negative offset or limit.');
@@ -429,24 +373,24 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 			case 'mysql':
 				if ($limit !== null || $offset) {
 					// see http://dev.mysql.com/doc/refman/5.0/en/select.html
-					$sql .= ' LIMIT ' . ($limit === null ? '18446744073709551615' : Dibi\Helpers::intVal($limit))
-						. ($offset ? ' OFFSET ' . Dibi\Helpers::intVal($offset) : '');
+					$sql .= ' LIMIT ' . ($limit === null ? '18446744073709551615' : $limit)
+						. ($offset ? ' OFFSET ' . $offset : '');
 				}
 				break;
 
 			case 'pgsql':
 				if ($limit !== null) {
-					$sql .= ' LIMIT ' . Dibi\Helpers::intVal($limit);
+					$sql .= ' LIMIT ' . $limit;
 				}
 				if ($offset) {
-					$sql .= ' OFFSET ' . Dibi\Helpers::intVal($offset);
+					$sql .= ' OFFSET ' . $offset;
 				}
 				break;
 
 			case 'sqlite':
 				if ($limit !== null || $offset) {
-					$sql .= ' LIMIT ' . ($limit === null ? '-1' : Dibi\Helpers::intVal($limit))
-						. ($offset ? ' OFFSET ' . Dibi\Helpers::intVal($offset) : '');
+					$sql .= ' LIMIT ' . ($limit === null ? '-1' : $limit)
+						. ($offset ? ' OFFSET ' . $offset : '');
 				}
 				break;
 
@@ -454,11 +398,11 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 				if ($offset) {
 					// see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
 					$sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t '
-						. ($limit !== null ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '')
+						. ($limit !== null ? 'WHERE ROWNUM <= ' . ($offset + $limit) : '')
 						. ') WHERE "__rnum" > ' . $offset;
 
 				} elseif ($limit !== null) {
-					$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . Dibi\Helpers::intVal($limit);
+					$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . $limit;
 				}
 				break;
 
@@ -475,104 +419,19 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
 					break;
 				}
 				// break omitted
+
 			case 'odbc':
 				if ($offset) {
 					throw new Dibi\NotSupportedException('Offset is not supported by this database.');
 
 				} elseif ($limit !== null) {
-					$sql = 'SELECT TOP ' . Dibi\Helpers::intVal($limit) . ' * FROM (' . $sql . ') t';
+					$sql = 'SELECT TOP ' . $limit . ' * FROM (' . $sql . ') t';
 					break;
 				}
 				// break omitted
+
 			default:
 				throw new Dibi\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()
-	{
-		return $this->resultSet->rowCount();
-	}
-
-
-	/**
-	 * 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
-	 */
-	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 bool  true on success, false if unable to seek to specified record
-	 */
-	public function seek($row)
-	{
-		throw new Dibi\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 Dibi\Exception
-	 */
-	public function getResultColumns()
-	{
-		$count = $this->resultSet->columnCount();
-		$columns = [];
-		for ($i = 0; $i < $count; $i++) {
-			$row = @$this->resultSet->getColumnMeta($i); // intentionally @
-			if ($row === false) {
-				throw new Dibi\NotSupportedException('Driver does not support meta data.');
-			}
-			$row = $row + [
-				'table' => null,
-				'native_type' => 'VAR_STRING',
-			];
-
-			$columns[] = [
-				'name' => $row['name'],
-				'table' => $row['table'],
-				'nativetype' => $row['native_type'],
-				'type' => $row['native_type'] === 'TIME' && $this->driverName === 'mysql' ? Dibi\Type::TIME_INTERVAL : null,
-				'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
-				'vendor' => $row,
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns the result set resource.
-	 * @return \PDOStatement|null
-	 */
-	public function getResultResource()
-	{
-		return $this->resultSet;
-	}
 }

+ 122 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/PdoResult.php

@@ -0,0 +1,122 @@
+<?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;
+use Dibi\Helpers;
+use PDO;
+
+
+/**
+ * The driver for PDO result set.
+ */
+class PdoResult implements Dibi\ResultDriver
+{
+	use Dibi\Strict;
+
+	/** @var \PDOStatement|null */
+	private $resultSet;
+
+	/** @var string */
+	private $driverName;
+
+
+	public function __construct(\PDOStatement $resultSet, string $driverName)
+	{
+		$this->resultSet = $resultSet;
+		$this->driverName = $driverName;
+	}
+
+
+	/**
+	 * Returns the number of rows in a result set.
+	 */
+	public function getRowCount(): int
+	{
+		return $this->resultSet->rowCount();
+	}
+
+
+	/**
+	 * Fetches the row at current position and moves the internal cursor to the next position.
+	 * @param  bool  $assoc  true for associative array, false for numeric
+	 */
+	public function fetch(bool $assoc): ?array
+	{
+		return Helpers::false2Null($this->resultSet->fetch($assoc ? PDO::FETCH_ASSOC : PDO::FETCH_NUM));
+	}
+
+
+	/**
+	 * Moves cursor position without fetching row.
+	 */
+	public function seek(int $row): bool
+	{
+		throw new Dibi\NotSupportedException('Cannot seek an unbuffered result set.');
+	}
+
+
+	/**
+	 * Frees the resources allocated for this result set.
+	 */
+	public function free(): void
+	{
+		$this->resultSet = null;
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a result set.
+	 * @throws Dibi\Exception
+	 */
+	public function getResultColumns(): array
+	{
+		$count = $this->resultSet->columnCount();
+		$columns = [];
+		for ($i = 0; $i < $count; $i++) {
+			$row = @$this->resultSet->getColumnMeta($i); // intentionally @
+			if ($row === false) {
+				throw new Dibi\NotSupportedException('Driver does not support meta data.');
+			}
+			$row = $row + [
+				'table' => null,
+				'native_type' => 'VAR_STRING',
+			];
+
+			$columns[] = [
+				'name' => $row['name'],
+				'table' => $row['table'],
+				'nativetype' => $row['native_type'],
+				'type' => $row['native_type'] === 'TIME' && $this->driverName === 'mysql' ? Dibi\Type::TIME_INTERVAL : null,
+				'fullname' => $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'],
+				'vendor' => $row,
+			];
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Returns the result set resource.
+	 */
+	public function getResultResource(): ?\PDOStatement
+	{
+		return $this->resultSet;
+	}
+
+
+	/**
+	 * Decodes data from result set.
+	 */
+	public function unescapeBinary(string $value): string
+	{
+		return $value;
+	}
+}

+ 48 - 445
api/vendor/dibi/dibi/src/Dibi/Drivers/PostgreDriver.php

@@ -1,17 +1,20 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
+use Dibi\Helpers;
 
 
 /**
- * The dibi driver for PostgreSQL database.
+ * The driver for PostgreSQL database.
  *
  * Driver options:
  *   - host, hostaddr, port, dbname, user, password, connect_timeout, options, sslmode, service => see PostgreSQL API
@@ -20,43 +23,27 @@ use Dibi;
  *   - charset => character encoding to set (default is utf8)
  *   - persistent (bool) => try to find a persistent link?
  *   - resource (resource) => existing connection resource
- *   - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
  */
-class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
+class PostgreDriver implements Dibi\Driver
 {
 	use Dibi\Strict;
 
-	/** @var resource|null */
+	/** @var resource */
 	private $connection;
 
-	/** @var resource|null */
-	private $resultSet;
-
-	/** @var bool */
-	private $autoFree = true;
-
-	/** @var int|false  Affected rows */
-	private $affectedRows = false;
+	/** @var int|null  Affected rows */
+	private $affectedRows;
 
 
 	/**
 	 * @throws Dibi\NotSupportedException
 	 */
-	public function __construct()
+	public function __construct(array $config)
 	{
 		if (!extension_loaded('pgsql')) {
 			throw new Dibi\NotSupportedException("PHP extension 'pgsql' is not loaded.");
 		}
-	}
 
-
-	/**
-	 * Connects to a database.
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public function connect(array &$config)
-	{
 		$error = null;
 		if (isset($config['resource'])) {
 			$this->connection = $config['resource'];
@@ -69,8 +56,8 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 				$string = $config['string'];
 			} else {
 				$string = '';
-				Dibi\Helpers::alias($config, 'user', 'username');
-				Dibi\Helpers::alias($config, 'dbname', 'database');
+				Helpers::alias($config, 'user', 'username');
+				Helpers::alias($config, 'dbname', 'database');
 				foreach (['host', 'hostaddr', 'port', 'dbname', 'user', 'password', 'connect_timeout', 'options', 'sslmode', 'service'] as $key) {
 					if (isset($config[$key])) {
 						$string .= $key . '=' . $config[$key] . ' ';
@@ -78,7 +65,7 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 				}
 			}
 
-			set_error_handler(function ($severity, $message) use (&$error) {
+			set_error_handler(function (int $severity, string $message) use (&$error) {
 				$error = $message;
 			});
 			if (empty($config['persistent'])) {
@@ -96,7 +83,7 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 		pg_set_error_verbosity($this->connection, PGSQL_ERRORS_VERBOSE);
 
 		if (isset($config['charset']) && pg_set_client_encoding($this->connection, $config['charset'])) {
-			throw self::createException(pg_last_error($this->connection));
+			throw static::createException(pg_last_error($this->connection));
 		}
 
 		if (isset($config['schema'])) {
@@ -107,9 +94,8 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Disconnects from a database.
-	 * @return void
 	 */
-	public function disconnect()
+	public function disconnect(): void
 	{
 		@pg_close($this->connection); // @ - connection can be already disconnected
 	}
@@ -117,9 +103,8 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Pings database.
-	 * @return bool
 	 */
-	public function ping()
+	public function ping(): bool
 	{
 		return pg_ping($this->connection);
 	}
@@ -127,20 +112,18 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return Dibi\ResultDriver|null
 	 * @throws Dibi\DriverException
 	 */
-	public function query($sql)
+	public function query(string $sql): ?Dibi\ResultDriver
 	{
-		$this->affectedRows = false;
+		$this->affectedRows = null;
 		$res = @pg_query($this->connection, $sql); // intentionally @
 
 		if ($res === false) {
-			throw self::createException(pg_last_error($this->connection), null, $sql);
+			throw static::createException(pg_last_error($this->connection), null, $sql);
 
 		} elseif (is_resource($res)) {
-			$this->affectedRows = pg_affected_rows($res);
+			$this->affectedRows = Helpers::false2Null(pg_affected_rows($res));
 			if (pg_num_fields($res)) {
 				return $this->createResultDriver($res);
 			}
@@ -149,10 +132,7 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 	}
 
 
-	/**
-	 * @return Dibi\DriverException
-	 */
-	public static function createException($message, $code = null, $sql = null)
+	public static function createException(string $message, $code = null, string $sql = null): Dibi\DriverException
 	{
 		if ($code === null && preg_match('#^ERROR:\s+(\S+):\s*#', $message, $m)) {
 			$code = $m[1];
@@ -179,9 +159,8 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * 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()
+	public function getAffectedRows(): ?int
 	{
 		return $this->affectedRows;
 	}
@@ -189,9 +168,8 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * 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)
+	public function getInsertId(?string $sequence): ?int
 	{
 		if ($sequence === null) {
 			// PostgreSQL 8.1 is needed
@@ -201,21 +179,19 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 		}
 
 		if (!$res) {
-			return false;
+			return null;
 		}
 
 		$row = $res->fetch(false);
-		return is_array($row) ? $row[0] : false;
+		return is_array($row) ? (int) $row[0] : null;
 	}
 
 
 	/**
 	 * Begins a transaction (if supported).
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function begin($savepoint = null)
+	public function begin(string $savepoint = null): void
 	{
 		$this->query($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
 	}
@@ -223,11 +199,9 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function commit($savepoint = null)
+	public function commit(string $savepoint = null): void
 	{
 		$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
 	}
@@ -235,11 +209,9 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Rollback changes in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function rollback($savepoint = null)
+	public function rollback(string $savepoint = null): void
 	{
 		$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
 	}
@@ -247,9 +219,8 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Is in transaction?
-	 * @return bool
 	 */
-	public function inTransaction()
+	public function inTransaction(): bool
 	{
 		return !in_array(pg_transaction_status($this->connection), [PGSQL_TRANSACTION_UNKNOWN, PGSQL_TRANSACTION_IDLE], true);
 	}
@@ -267,24 +238,20 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Returns the connection reflector.
-	 * @return Dibi\Reflector
 	 */
-	public function getReflector()
+	public function getReflector(): Dibi\Reflector
 	{
-		return $this;
+		return new PostgreReflector($this, pg_parameter_status($this->connection, 'server_version'));
 	}
 
 
 	/**
 	 * Result set driver factory.
-	 * @param  resource
-	 * @return Dibi\ResultDriver
+	 * @param  resource  $resource
 	 */
-	public function createResultDriver($resource)
+	public function createResultDriver($resource): PostgreResult
 	{
-		$res = clone $this;
-		$res->resultSet = $resource;
-		return $res;
+		return new PostgreResult($resource);
 	}
 
 
@@ -293,10 +260,8 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Encodes data for use in a SQL statement.
-	 * @param  string    value
-	 * @return string    encoded value
 	 */
-	public function escapeText($value)
+	public function escapeText(string $value): string
 	{
 		if (!is_resource($this->connection)) {
 			throw new Dibi\Exception('Lost connection to server.');
@@ -305,11 +270,7 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeBinary($value)
+	public function escapeBinary(string $value): string
 	{
 		if (!is_resource($this->connection)) {
 			throw new Dibi\Exception('Lost connection to server.');
@@ -318,34 +279,25 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeIdentifier($value)
+	public function escapeIdentifier(string $value): string
 	{
 		// @see http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
 		return '"' . str_replace('"', '""', $value) . '"';
 	}
 
 
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	public function escapeBool($value)
+	public function escapeBool(bool $value): string
 	{
 		return $value ? 'TRUE' : 'FALSE';
 	}
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDate($value)
+	public function escapeDate($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
 		return $value->format("'Y-m-d'");
@@ -353,12 +305,11 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDateTime($value)
+	public function escapeDateTime($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
 		return $value->format("'Y-m-d H:i:s.u'");
@@ -367,11 +318,8 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 
 	/**
 	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
 	 */
-	public function escapeLike($value, $pos)
+	public function escapeLike(string $value, int $pos): string
 	{
 		$bs = pg_escape_string($this->connection, '\\'); // standard_conforming_strings = on/off
 		$value = pg_escape_string($this->connection, $value);
@@ -380,364 +328,19 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
 	}
 
 
-	/**
-	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
-	 */
-	public function unescapeBinary($value)
-	{
-		return pg_unescape_bytea($value);
-	}
-
-
-	/** @deprecated */
-	public function escape($value, $type)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		return Dibi\Helpers::escape($this, $value, $type);
-	}
-
-
 	/**
 	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
 	 */
-	public function applyLimit(&$sql, $limit, $offset)
+	public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
 	{
 		if ($limit < 0 || $offset < 0) {
 			throw new Dibi\NotSupportedException('Negative offset or limit.');
 		}
 		if ($limit !== null) {
-			$sql .= ' LIMIT ' . Dibi\Helpers::intVal($limit);
+			$sql .= ' LIMIT ' . $limit;
 		}
 		if ($offset) {
-			$sql .= ' OFFSET ' . Dibi\Helpers::intVal($offset);
-		}
-	}
-
-
-	/********************* result set ****************d*g**/
-
-
-	/**
-	 * Automatically frees the resources allocated for this result set.
-	 * @return void
-	 */
-	public function __destruct()
-	{
-		$this->autoFree && $this->getResultResource() && $this->free();
-	}
-
-
-	/**
-	 * 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
-	 */
-	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 bool  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 getResultColumns()
-	{
-		$count = pg_num_fields($this->resultSet);
-		$columns = [];
-		for ($i = 0; $i < $count; $i++) {
-			$row = [
-				'name' => pg_field_name($this->resultSet, $i),
-				'table' => pg_field_table($this->resultSet, $i),
-				'nativetype' => pg_field_type($this->resultSet, $i),
-			];
-			$row['fullname'] = $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'];
-			$columns[] = $row;
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns the result set resource.
-	 * @return resource|null
-	 */
-	public function getResultResource()
-	{
-		$this->autoFree = false;
-		return is_resource($this->resultSet) ? $this->resultSet : null;
-	}
-
-
-	/********************* Dibi\Reflector ****************d*g**/
-
-
-	/**
-	 * Returns list of tables.
-	 * @return array
-	 */
-	public function getTables()
-	{
-		$version = pg_parameter_status($this->getResource(), 'server_version');
-		if ($version < 7.4) {
-			throw new Dibi\DriverException('Reflection requires PostgreSQL 7.4 and newer.');
-		}
-
-		$query = "
-			SELECT
-				table_name AS name,
-				CASE table_type
-					WHEN 'VIEW' THEN 1
-					ELSE 0
-				END AS view
-			FROM
-				information_schema.tables
-			WHERE
-				table_schema = ANY (current_schemas(false))";
-
-		if ($version >= 9.3) {
-			$query .= '
-				UNION ALL
-				SELECT
-					matviewname, 1
-				FROM
-					pg_matviews
-				WHERE
-					schemaname = ANY (current_schemas(false))';
-		}
-
-		$res = $this->query($query);
-		$tables = pg_fetch_all($res->resultSet);
-		return $tables ? $tables : [];
-	}
-
-
-	/**
-	 * Returns metadata for all columns in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getColumns($table)
-	{
-		$_table = $this->escapeText($this->escapeIdentifier($table));
-		$res = $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.oid = $_table::regclass
-		");
-		$primary = (int) pg_fetch_object($res->resultSet)->indkey;
-
-		$res = $this->query("
-			SELECT *
-			FROM information_schema.columns c
-			JOIN pg_class ON pg_class.relname = c.table_name
-			JOIN pg_namespace nsp ON nsp.oid = pg_class.relnamespace AND nsp.nspname = c.table_schema
-			WHERE pg_class.oid = $_table::regclass
-			ORDER BY c.ordinal_position
-		");
-
-		if (!$res->getRowCount()) {
-			$res = $this->query("
-				SELECT
-					a.attname AS column_name,
-					pg_type.typname AS udt_name,
-					a.attlen AS numeric_precision,
-					a.atttypmod-4 AS character_maximum_length,
-					NOT a.attnotnull AS is_nullable,
-					a.attnum AS ordinal_position,
-					adef.adsrc AS column_default
-				FROM
-					pg_attribute a
-					JOIN pg_type ON a.atttypid = pg_type.oid
-					JOIN pg_class cls ON a.attrelid = cls.oid
-					LEFT JOIN pg_attrdef adef ON adef.adnum = a.attnum AND adef.adrelid = a.attrelid
-				WHERE
-					cls.relkind IN ('r', 'v', 'mv')
-					AND a.attrelid = $_table::regclass
-					AND a.attnum > 0
-					AND NOT a.attisdropped
-				ORDER BY ordinal_position
-			");
-		}
-
-		$columns = [];
-		while ($row = $res->fetch(true)) {
-			$size = (int) max($row['character_maximum_length'], $row['numeric_precision']);
-			$columns[] = [
-				'name' => $row['column_name'],
-				'table' => $table,
-				'nativetype' => strtoupper($row['udt_name']),
-				'size' => $size > 0 ? $size : null,
-				'nullable' => $row['is_nullable'] === 'YES' || $row['is_nullable'] === 't',
-				'default' => $row['column_default'],
-				'autoincrement' => (int) $row['ordinal_position'] === $primary && substr($row['column_default'], 0, 7) === 'nextval',
-				'vendor' => $row,
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns metadata for all indexes in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getIndexes($table)
-	{
-		$_table = $this->escapeText($this->escapeIdentifier($table));
-		$res = $this->query("
-			SELECT
-				a.attnum AS ordinal_position,
-				a.attname AS column_name
-			FROM
-				pg_attribute a
-				JOIN pg_class cls ON a.attrelid = cls.oid
-			WHERE
-				a.attrelid = $_table::regclass
-				AND a.attnum > 0
-				AND NOT a.attisdropped
-			ORDER BY ordinal_position
-		");
-
-		$columns = [];
-		while ($row = $res->fetch(true)) {
-			$columns[$row['ordinal_position']] = $row['column_name'];
+			$sql .= ' OFFSET ' . $offset;
 		}
-
-		$res = $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.oid = $_table::regclass
-		");
-
-		$indexes = [];
-		while ($row = $res->fetch(true)) {
-			$indexes[$row['relname']]['name'] = $row['relname'];
-			$indexes[$row['relname']]['unique'] = $row['indisunique'] === 't';
-			$indexes[$row['relname']]['primary'] = $row['indisprimary'] === 't';
-			foreach (explode(' ', $row['indkey']) as $index) {
-				$indexes[$row['relname']]['columns'][] = $columns[$index];
-			}
-		}
-		return array_values($indexes);
-	}
-
-
-	/**
-	 * Returns metadata for all foreign keys in a table.
-	 * @param  string
-	 * @return array
-	 */
-	public function getForeignKeys($table)
-	{
-		$_table = $this->escapeText($this->escapeIdentifier($table));
-
-		$res = $this->query("
-			SELECT
-				c.conname AS name,
-				lt.attname AS local,
-				c.confrelid::regclass AS table,
-				ft.attname AS foreign,
-
-				CASE c.confupdtype
-					WHEN 'a' THEN 'NO ACTION'
-					WHEN 'r' THEN 'RESTRICT'
-					WHEN 'c' THEN 'CASCADE'
-					WHEN 'n' THEN 'SET NULL'
-					WHEN 'd' THEN 'SET DEFAULT'
-					ELSE 'UNKNOWN'
-				END AS \"onUpdate\",
-
-				CASE c.confdeltype
-					WHEN 'a' THEN 'NO ACTION'
-					WHEN 'r' THEN 'RESTRICT'
-					WHEN 'c' THEN 'CASCADE'
-					WHEN 'n' THEN 'SET NULL'
-					WHEN 'd' THEN 'SET DEFAULT'
-					ELSE 'UNKNOWN'
-				END AS \"onDelete\",
-
-				c.conkey,
-				lt.attnum AS lnum,
-				c.confkey,
-				ft.attnum AS fnum
-			FROM
-				pg_constraint c
-				JOIN pg_attribute lt ON c.conrelid = lt.attrelid AND lt.attnum = ANY (c.conkey)
-				JOIN pg_attribute ft ON c.confrelid = ft.attrelid AND ft.attnum = ANY (c.confkey)
-			WHERE
-				c.contype = 'f'
-				AND
-				c.conrelid = $_table::regclass
-		");
-
-		$fKeys = $references = [];
-		while ($row = $res->fetch(true)) {
-			if (!isset($fKeys[$row['name']])) {
-				$fKeys[$row['name']] = [
-					'name' => $row['name'],
-					'table' => $row['table'],
-					'local' => [],
-					'foreign' => [],
-					'onUpdate' => $row['onUpdate'],
-					'onDelete' => $row['onDelete'],
-				];
-
-				$l = explode(',', trim($row['conkey'], '{}'));
-				$f = explode(',', trim($row['confkey'], '{}'));
-
-				$references[$row['name']] = array_combine($l, $f);
-			}
-
-			if (isset($references[$row['name']][$row['lnum']]) && $references[$row['name']][$row['lnum']] === $row['fnum']) {
-				$fKeys[$row['name']]['local'][] = $row['local'];
-				$fKeys[$row['name']]['foreign'][] = $row['foreign'];
-			}
-		}
-
-		return $fKeys;
 	}
 }

+ 259 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/PostgreReflector.php

@@ -0,0 +1,259 @@
+<?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;
+
+
+/**
+ * The reflector for PostgreSQL database.
+ */
+class PostgreReflector implements Dibi\Reflector
+{
+	use Dibi\Strict;
+
+	/** @var Dibi\Driver */
+	private $driver;
+
+	/** @var string */
+	private $version;
+
+
+	public function __construct(Dibi\Driver $driver, string $version)
+	{
+		if ($version < 7.4) {
+			throw new Dibi\DriverException('Reflection requires PostgreSQL 7.4 and newer.');
+		}
+		$this->driver = $driver;
+		$this->version = $version;
+	}
+
+
+	/**
+	 * Returns list of tables.
+	 */
+	public function getTables(): array
+	{
+		$query = "
+			SELECT
+				table_name AS name,
+				CASE table_type
+					WHEN 'VIEW' THEN 1
+					ELSE 0
+				END AS view
+			FROM
+				information_schema.tables
+			WHERE
+				table_schema = ANY (current_schemas(false))";
+
+		if ($this->version >= 9.3) {
+			$query .= '
+				UNION ALL
+				SELECT
+					matviewname, 1
+				FROM
+					pg_matviews
+				WHERE
+					schemaname = ANY (current_schemas(false))';
+		}
+
+		$res = $this->driver->query($query);
+		$tables = [];
+		while ($row = $res->fetch(true)) {
+			$tables[] = $row;
+		}
+		return $tables;
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a table.
+	 */
+	public function getColumns(string $table): array
+	{
+		$_table = $this->driver->escapeText($this->driver->escapeIdentifier($table));
+		$res = $this->driver->query("
+			SELECT indkey
+			FROM pg_class
+			LEFT JOIN pg_index on pg_class.oid = pg_index.indrelid AND pg_index.indisprimary
+			WHERE pg_class.oid = $_table::regclass
+		");
+		$primary = (int) $res->fetch(true)['indkey'];
+
+		$res = $this->driver->query("
+			SELECT *
+			FROM information_schema.columns c
+			JOIN pg_class ON pg_class.relname = c.table_name
+			JOIN pg_namespace nsp ON nsp.oid = pg_class.relnamespace AND nsp.nspname = c.table_schema
+			WHERE pg_class.oid = $_table::regclass
+			ORDER BY c.ordinal_position
+		");
+
+		if (!$res->getRowCount()) {
+			$res = $this->driver->query("
+				SELECT
+					a.attname AS column_name,
+					pg_type.typname AS udt_name,
+					a.attlen AS numeric_precision,
+					a.atttypmod-4 AS character_maximum_length,
+					NOT a.attnotnull AS is_nullable,
+					a.attnum AS ordinal_position,
+					adef.adsrc AS column_default
+				FROM
+					pg_attribute a
+					JOIN pg_type ON a.atttypid = pg_type.oid
+					JOIN pg_class cls ON a.attrelid = cls.oid
+					LEFT JOIN pg_attrdef adef ON adef.adnum = a.attnum AND adef.adrelid = a.attrelid
+				WHERE
+					cls.relkind IN ('r', 'v', 'mv')
+					AND a.attrelid = $_table::regclass
+					AND a.attnum > 0
+					AND NOT a.attisdropped
+				ORDER BY ordinal_position
+			");
+		}
+
+		$columns = [];
+		while ($row = $res->fetch(true)) {
+			$size = (int) max($row['character_maximum_length'], $row['numeric_precision']);
+			$columns[] = [
+				'name' => $row['column_name'],
+				'table' => $table,
+				'nativetype' => strtoupper($row['udt_name']),
+				'size' => $size > 0 ? $size : null,
+				'nullable' => $row['is_nullable'] === 'YES' || $row['is_nullable'] === 't' || $row['is_nullable'] === true,
+				'default' => $row['column_default'],
+				'autoincrement' => (int) $row['ordinal_position'] === $primary && substr($row['column_default'] ?? '', 0, 7) === 'nextval',
+				'vendor' => $row,
+			];
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Returns metadata for all indexes in a table.
+	 */
+	public function getIndexes(string $table): array
+	{
+		$_table = $this->driver->escapeText($this->driver->escapeIdentifier($table));
+		$res = $this->driver->query("
+			SELECT
+				a.attnum AS ordinal_position,
+				a.attname AS column_name
+			FROM
+				pg_attribute a
+				JOIN pg_class cls ON a.attrelid = cls.oid
+			WHERE
+				a.attrelid = $_table::regclass
+				AND a.attnum > 0
+				AND NOT a.attisdropped
+			ORDER BY ordinal_position
+		");
+
+		$columns = [];
+		while ($row = $res->fetch(true)) {
+			$columns[$row['ordinal_position']] = $row['column_name'];
+		}
+
+		$res = $this->driver->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.oid = $_table::regclass
+		");
+
+		$indexes = [];
+		while ($row = $res->fetch(true)) {
+			$indexes[$row['relname']]['name'] = $row['relname'];
+			$indexes[$row['relname']]['unique'] = $row['indisunique'] === 't' || $row['indisunique'] === true;
+			$indexes[$row['relname']]['primary'] = $row['indisprimary'] === 't' || $row['indisprimary'] === true;
+			foreach (explode(' ', $row['indkey']) as $index) {
+				$indexes[$row['relname']]['columns'][] = $columns[$index];
+			}
+		}
+		return array_values($indexes);
+	}
+
+
+	/**
+	 * Returns metadata for all foreign keys in a table.
+	 */
+	public function getForeignKeys(string $table): array
+	{
+		$_table = $this->driver->escapeText($this->driver->escapeIdentifier($table));
+
+		$res = $this->driver->query("
+			SELECT
+				c.conname AS name,
+				lt.attname AS local,
+				c.confrelid::regclass AS table,
+				ft.attname AS foreign,
+
+				CASE c.confupdtype
+					WHEN 'a' THEN 'NO ACTION'
+					WHEN 'r' THEN 'RESTRICT'
+					WHEN 'c' THEN 'CASCADE'
+					WHEN 'n' THEN 'SET NULL'
+					WHEN 'd' THEN 'SET DEFAULT'
+					ELSE 'UNKNOWN'
+				END AS \"onUpdate\",
+
+				CASE c.confdeltype
+					WHEN 'a' THEN 'NO ACTION'
+					WHEN 'r' THEN 'RESTRICT'
+					WHEN 'c' THEN 'CASCADE'
+					WHEN 'n' THEN 'SET NULL'
+					WHEN 'd' THEN 'SET DEFAULT'
+					ELSE 'UNKNOWN'
+				END AS \"onDelete\",
+
+				c.conkey,
+				lt.attnum AS lnum,
+				c.confkey,
+				ft.attnum AS fnum
+			FROM
+				pg_constraint c
+				JOIN pg_attribute lt ON c.conrelid = lt.attrelid AND lt.attnum = ANY (c.conkey)
+				JOIN pg_attribute ft ON c.confrelid = ft.attrelid AND ft.attnum = ANY (c.confkey)
+			WHERE
+				c.contype = 'f'
+				AND
+				c.conrelid = $_table::regclass
+		");
+
+		$fKeys = $references = [];
+		while ($row = $res->fetch(true)) {
+			if (!isset($fKeys[$row['name']])) {
+				$fKeys[$row['name']] = [
+					'name' => $row['name'],
+					'table' => $row['table'],
+					'local' => [],
+					'foreign' => [],
+					'onUpdate' => $row['onUpdate'],
+					'onDelete' => $row['onDelete'],
+				];
+
+				$l = explode(',', trim($row['conkey'], '{}'));
+				$f = explode(',', trim($row['confkey'], '{}'));
+
+				$references[$row['name']] = array_combine($l, $f);
+			}
+
+			if (isset($references[$row['name']][$row['lnum']]) && $references[$row['name']][$row['lnum']] === $row['fnum']) {
+				$fKeys[$row['name']]['local'][] = $row['local'];
+				$fKeys[$row['name']]['foreign'][] = $row['foreign'];
+			}
+		}
+
+		return $fKeys;
+	}
+}

+ 125 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/PostgreResult.php

@@ -0,0 +1,125 @@
+<?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;
+use Dibi\Helpers;
+
+
+/**
+ * The driver for PostgreSQL result set.
+ */
+class PostgreResult implements Dibi\ResultDriver
+{
+	use Dibi\Strict;
+
+	/** @var resource */
+	private $resultSet;
+
+	/** @var bool */
+	private $autoFree = true;
+
+
+	/**
+	 * @param  resource  $resultSet
+	 */
+	public function __construct($resultSet)
+	{
+		$this->resultSet = $resultSet;
+	}
+
+
+	/**
+	 * Automatically frees the resources allocated for this result set.
+	 */
+	public function __destruct()
+	{
+		if ($this->autoFree && $this->getResultResource()) {
+			$this->free();
+		}
+	}
+
+
+	/**
+	 * Returns the number of rows in a result set.
+	 */
+	public function getRowCount(): int
+	{
+		return pg_num_rows($this->resultSet);
+	}
+
+
+	/**
+	 * Fetches the row at current position and moves the internal cursor to the next position.
+	 * @param  bool  $assoc  true for associative array, false for numeric
+	 */
+	public function fetch(bool $assoc): ?array
+	{
+		return Helpers::false2Null(pg_fetch_array($this->resultSet, null, $assoc ? PGSQL_ASSOC : PGSQL_NUM));
+	}
+
+
+	/**
+	 * Moves cursor position without fetching row.
+	 */
+	public function seek(int $row): bool
+	{
+		return pg_result_seek($this->resultSet, $row);
+	}
+
+
+	/**
+	 * Frees the resources allocated for this result set.
+	 */
+	public function free(): void
+	{
+		pg_free_result($this->resultSet);
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a result set.
+	 */
+	public function getResultColumns(): array
+	{
+		$count = pg_num_fields($this->resultSet);
+		$columns = [];
+		for ($i = 0; $i < $count; $i++) {
+			$row = [
+				'name' => pg_field_name($this->resultSet, $i),
+				'table' => pg_field_table($this->resultSet, $i),
+				'nativetype' => pg_field_type($this->resultSet, $i),
+			];
+			$row['fullname'] = $row['table'] ? $row['table'] . '.' . $row['name'] : $row['name'];
+			$columns[] = $row;
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Returns the result set resource.
+	 * @return resource|null
+	 */
+	public function getResultResource()
+	{
+		$this->autoFree = false;
+		return is_resource($this->resultSet) ? $this->resultSet : null;
+	}
+
+
+	/**
+	 * Decodes data from result set.
+	 */
+	public function unescapeBinary(string $value): string
+	{
+		return pg_unescape_bytea($value);
+	}
+}

+ 5 - 484
api/vendor/dibi/dibi/src/Dibi/Drivers/Sqlite3Driver.php

@@ -1,497 +1,18 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
  * Copyright (c) 2005 David Grudl (https://davidgrudl.com)
  */
 
-namespace Dibi\Drivers;
+declare(strict_types=1);
 
-use Dibi;
-use SQLite3;
+namespace Dibi\Drivers;
 
 
 /**
- * The dibi driver for SQLite3 database.
- *
- * Driver options:
- *   - database (or file) => the filename of the SQLite3 database
- *   - 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 (SQLite3) => existing connection resource
- *   - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
+ * Alias for SqliteDriver driver.
  */
-class Sqlite3Driver implements Dibi\Driver, Dibi\ResultDriver
+class Sqlite3Driver extends SqliteDriver
 {
-	use Dibi\Strict;
-
-	/** @var SQLite3|null */
-	private $connection;
-
-	/** @var \SQLite3Result|null */
-	private $resultSet;
-
-	/** @var bool */
-	private $autoFree = true;
-
-	/** @var string  Date and datetime format */
-	private $fmtDate;
-	private $fmtDateTime;
-
-	/** @var string  character encoding */
-	private $dbcharset;
-	private $charset;
-
-
-	/**
-	 * @throws Dibi\NotSupportedException
-	 */
-	public function __construct()
-	{
-		if (!extension_loaded('sqlite3')) {
-			throw new Dibi\NotSupportedException("PHP extension 'sqlite3' is not loaded.");
-		}
-	}
-
-
-	/**
-	 * Connects to a database.
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public function connect(array &$config)
-	{
-		Dibi\Helpers::alias($config, 'database', 'file');
-		$this->fmtDate = isset($config['formatDate']) ? $config['formatDate'] : 'U';
-		$this->fmtDateTime = isset($config['formatDateTime']) ? $config['formatDateTime'] : 'U';
-
-		if (isset($config['resource']) && $config['resource'] instanceof SQLite3) {
-			$this->connection = $config['resource'];
-		} else {
-			try {
-				$this->connection = new SQLite3($config['database']);
-			} catch (\Exception $e) {
-				throw new Dibi\DriverException($e->getMessage(), $e->getCode());
-			}
-		}
-
-		$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;
-		}
-
-		// enable foreign keys support (defaultly disabled; if disabled then foreign key constraints are not enforced)
-		$version = SQLite3::version();
-		if ($version['versionNumber'] >= '3006019') {
-			$this->query('PRAGMA foreign_keys = ON');
-		}
-	}
-
-
-	/**
-	 * Disconnects from a database.
-	 * @return void
-	 */
-	public function disconnect()
-	{
-		$this->connection->close();
-	}
-
-
-	/**
-	 * Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return Dibi\ResultDriver|null
-	 * @throws Dibi\DriverException
-	 */
-	public function query($sql)
-	{
-		if ($this->dbcharset !== null) {
-			$sql = iconv($this->charset, $this->dbcharset . '//IGNORE', $sql);
-		}
-
-		$res = @$this->connection->query($sql); // intentionally @
-		if ($code = $this->connection->lastErrorCode()) {
-			throw self::createException($this->connection->lastErrorMsg(), $code, $sql);
-
-		} elseif ($res instanceof \SQLite3Result && $res->numColumns()) {
-			return $this->createResultDriver($res);
-		}
-		return null;
-	}
-
-
-	/**
-	 * @return Dibi\DriverException
-	 */
-	public static function createException($message, $code, $sql)
-	{
-		if ($code !== 19) {
-			return new Dibi\DriverException($message, $code, $sql);
-
-		} elseif (strpos($message, 'must be unique') !== false
-			|| strpos($message, 'is not unique') !== false
-			|| strpos($message, 'UNIQUE constraint failed') !== false
-		) {
-			return new Dibi\UniqueConstraintViolationException($message, $code, $sql);
-
-		} elseif (strpos($message, 'may not be NULL') !== false
-			|| strpos($message, 'NOT NULL constraint failed') !== false
-		) {
-			return new Dibi\NotNullConstraintViolationException($message, $code, $sql);
-
-		} elseif (strpos($message, 'foreign key constraint failed') !== false
-			|| strpos($message, 'FOREIGN KEY constraint failed') !== false
-		) {
-			return new Dibi\ForeignKeyConstraintViolationException($message, $code, $sql);
-
-		} else {
-			return new Dibi\ConstraintViolationException($message, $code, $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
-	 */
-	public function getAffectedRows()
-	{
-		return $this->connection->changes();
-	}
-
-
-	/**
-	 * 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->lastInsertRowID();
-	}
-
-
-	/**
-	 * Begins a transaction (if supported).
-	 * @param  string  optional savepoint name
-	 * @return void
-	 * @throws Dibi\DriverException
-	 */
-	public function begin($savepoint = null)
-	{
-		$this->query($savepoint ? "SAVEPOINT $savepoint" : 'BEGIN');
-	}
-
-
-	/**
-	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
-	 * @throws Dibi\DriverException
-	 */
-	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 Dibi\DriverException
-	 */
-	public function rollback($savepoint = null)
-	{
-		$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
-	}
-
-
-	/**
-	 * Returns the connection resource.
-	 * @return SQLite3
-	 */
-	public function getResource()
-	{
-		return $this->connection;
-	}
-
-
-	/**
-	 * Returns the connection reflector.
-	 * @return Dibi\Reflector
-	 */
-	public function getReflector()
-	{
-		return new SqliteReflector($this);
-	}
-
-
-	/**
-	 * Result set driver factory.
-	 * @param  \SQLite3Result
-	 * @return Dibi\ResultDriver
-	 */
-	public function createResultDriver(\SQLite3Result $resource)
-	{
-		$res = clone $this;
-		$res->resultSet = $resource;
-		return $res;
-	}
-
-
-	/********************* SQL ****************d*g**/
-
-
-	/**
-	 * Encodes data for use in a SQL statement.
-	 * @param  string    value
-	 * @return string    encoded value
-	 */
-	public function escapeText($value)
-	{
-		return "'" . $this->connection->escapeString($value) . "'";
-	}
-
-
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeBinary($value)
-	{
-		return "X'" . bin2hex((string) $value) . "'";
-	}
-
-
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeIdentifier($value)
-	{
-		return '[' . strtr($value, '[]', '  ') . ']';
-	}
-
-
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	public function escapeBool($value)
-	{
-		return $value ? '1' : '0';
-	}
-
-
-	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
-	 */
-	public function escapeDate($value)
-	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
-			$value = new Dibi\DateTime($value);
-		}
-		return $value->format($this->fmtDate);
-	}
-
-
-	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
-	 */
-	public function escapeDateTime($value)
-	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
-			$value = new Dibi\DateTime($value);
-		}
-		return $value->format($this->fmtDateTime);
-	}
-
-
-	/**
-	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
-	 */
-	public function escapeLike($value, $pos)
-	{
-		$value = addcslashes($this->connection->escapeString($value), '%_\\');
-		return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
-	}
-
-
-	/**
-	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
-	 */
-	public function unescapeBinary($value)
-	{
-		return $value;
-	}
-
-
-	/** @deprecated */
-	public function escape($value, $type)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		return Dibi\Helpers::escape($this, $value, $type);
-	}
-
-
-	/**
-	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
-	 */
-	public function applyLimit(&$sql, $limit, $offset)
-	{
-		if ($limit < 0 || $offset < 0) {
-			throw new Dibi\NotSupportedException('Negative offset or limit.');
-
-		} elseif ($limit !== null || $offset) {
-			$sql .= ' LIMIT ' . ($limit === null ? '-1' : Dibi\Helpers::intVal($limit))
-				. ($offset ? ' OFFSET ' . Dibi\Helpers::intVal($offset) : '');
-		}
-	}
-
-
-	/********************* result set ****************d*g**/
-
-
-	/**
-	 * Automatically frees the resources allocated for this result set.
-	 * @return void
-	 */
-	public function __destruct()
-	{
-		$this->autoFree && $this->resultSet && @$this->free();
-	}
-
-
-	/**
-	 * Returns the number of rows in a result set.
-	 * @return int
-	 * @throws Dibi\NotSupportedException
-	 */
-	public function getRowCount()
-	{
-		throw new Dibi\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
-	 */
-	public function fetch($assoc)
-	{
-		$row = $this->resultSet->fetchArray($assoc ? SQLITE3_ASSOC : SQLITE3_NUM);
-		$charset = $this->charset === null ? null : $this->charset . '//TRANSLIT';
-		if ($row && ($assoc || $charset)) {
-			$tmp = [];
-			foreach ($row as $k => $v) {
-				if ($charset !== null && is_string($v)) {
-					$v = iconv($this->dbcharset, $charset, $v);
-				}
-				$tmp[str_replace(['[', ']'], '', $k)] = $v;
-			}
-			return $tmp;
-		}
-		return $row;
-	}
-
-
-	/**
-	 * Moves cursor position without fetching row.
-	 * @param  int   the 0-based cursor pos to seek to
-	 * @return bool  true on success, false if unable to seek to specified record
-	 * @throws Dibi\NotSupportedException
-	 */
-	public function seek($row)
-	{
-		throw new Dibi\NotSupportedException('Cannot seek an unbuffered result set.');
-	}
-
-
-	/**
-	 * Frees the resources allocated for this result set.
-	 * @return void
-	 */
-	public function free()
-	{
-		$this->resultSet->finalize();
-		$this->resultSet = null;
-	}
-
-
-	/**
-	 * Returns metadata for all columns in a result set.
-	 * @return array
-	 */
-	public function getResultColumns()
-	{
-		$count = $this->resultSet->numColumns();
-		$columns = [];
-		static $types = [SQLITE3_INTEGER => 'int', SQLITE3_FLOAT => 'float', SQLITE3_TEXT => 'text', SQLITE3_BLOB => 'blob', SQLITE3_NULL => 'null'];
-		for ($i = 0; $i < $count; $i++) {
-			$columns[] = [
-				'name' => $this->resultSet->columnName($i),
-				'table' => null,
-				'fullname' => $this->resultSet->columnName($i),
-				'nativetype' => $types[$this->resultSet->columnType($i)],
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns the result set resource.
-	 * @return \SQLite3Result|null
-	 */
-	public function getResultResource()
-	{
-		$this->autoFree = false;
-		return $this->resultSet;
-	}
-
-
-	/********************* 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, callable $callback, $numArgs = -1)
-	{
-		$this->connection->createFunction($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, callable $rowCallback, callable $agrCallback, $numArgs = -1)
-	{
-		$this->connection->createAggregate($name, $rowCallback, $agrCallback, $numArgs);
-	}
 }

+ 18 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/Sqlite3Result.php

@@ -0,0 +1,18 @@
+<?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;
+
+
+/**
+ * Alias for SqliteResult driver.
+ */
+class Sqlite3Result extends SqliteResult
+{
+}

+ 301 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/SqliteDriver.php

@@ -0,0 +1,301 @@
+<?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;
+use Dibi\Helpers;
+use SQLite3;
+
+
+/**
+ * The driver for SQLite v3 database.
+ *
+ * Driver options:
+ *   - database (or file) => the filename of the SQLite3 database
+ *   - formatDate => how to format date in SQL (@see date)
+ *   - formatDateTime => how to format datetime in SQL (@see date)
+ *   - resource (SQLite3) => existing connection resource
+ */
+class SqliteDriver implements Dibi\Driver
+{
+	use Dibi\Strict;
+
+	/** @var SQLite3 */
+	private $connection;
+
+	/** @var string  Date format */
+	private $fmtDate;
+
+	/** @var string  Datetime format */
+	private $fmtDateTime;
+
+
+	/**
+	 * @throws Dibi\NotSupportedException
+	 */
+	public function __construct(array $config)
+	{
+		if (!extension_loaded('sqlite3')) {
+			throw new Dibi\NotSupportedException("PHP extension 'sqlite3' is not loaded.");
+		}
+
+		if (isset($config['dbcharset']) || isset($config['charset'])) {
+			throw new Dibi\NotSupportedException('Options dbcharset and charset are not longer supported.');
+		}
+
+		Helpers::alias($config, 'database', 'file');
+		$this->fmtDate = $config['formatDate'] ?? 'U';
+		$this->fmtDateTime = $config['formatDateTime'] ?? 'U';
+
+		if (isset($config['resource']) && $config['resource'] instanceof SQLite3) {
+			$this->connection = $config['resource'];
+		} else {
+			try {
+				$this->connection = new SQLite3($config['database']);
+			} catch (\Exception $e) {
+				throw new Dibi\DriverException($e->getMessage(), $e->getCode());
+			}
+		}
+
+		// enable foreign keys support (defaultly disabled; if disabled then foreign key constraints are not enforced)
+		$version = SQLite3::version();
+		if ($version['versionNumber'] >= '3006019') {
+			$this->query('PRAGMA foreign_keys = ON');
+		}
+	}
+
+
+	/**
+	 * Disconnects from a database.
+	 */
+	public function disconnect(): void
+	{
+		$this->connection->close();
+	}
+
+
+	/**
+	 * Executes the SQL query.
+	 * @throws Dibi\DriverException
+	 */
+	public function query(string $sql): ?Dibi\ResultDriver
+	{
+		$res = @$this->connection->query($sql); // intentionally @
+		if ($code = $this->connection->lastErrorCode()) {
+			throw static::createException($this->connection->lastErrorMsg(), $code, $sql);
+
+		} elseif ($res instanceof \SQLite3Result && $res->numColumns()) {
+			return $this->createResultDriver($res);
+		}
+		return null;
+	}
+
+
+	public static function createException(string $message, $code, string $sql): Dibi\DriverException
+	{
+		if ($code !== 19) {
+			return new Dibi\DriverException($message, $code, $sql);
+
+		} elseif (strpos($message, 'must be unique') !== false
+			|| strpos($message, 'is not unique') !== false
+			|| strpos($message, 'UNIQUE constraint failed') !== false
+		) {
+			return new Dibi\UniqueConstraintViolationException($message, $code, $sql);
+
+		} elseif (strpos($message, 'may not be null') !== false
+			|| strpos($message, 'NOT NULL constraint failed') !== false
+		) {
+			return new Dibi\NotNullConstraintViolationException($message, $code, $sql);
+
+		} elseif (strpos($message, 'foreign key constraint failed') !== false
+			|| strpos($message, 'FOREIGN KEY constraint failed') !== false
+		) {
+			return new Dibi\ForeignKeyConstraintViolationException($message, $code, $sql);
+
+		} else {
+			return new Dibi\ConstraintViolationException($message, $code, $sql);
+		}
+	}
+
+
+	/**
+	 * Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
+	 */
+	public function getAffectedRows(): ?int
+	{
+		return $this->connection->changes();
+	}
+
+
+	/**
+	 * Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
+	 */
+	public function getInsertId(?string $sequence): ?int
+	{
+		return $this->connection->lastInsertRowID();
+	}
+
+
+	/**
+	 * Begins a transaction (if supported).
+	 * @throws Dibi\DriverException
+	 */
+	public function begin(string $savepoint = null): void
+	{
+		$this->query($savepoint ? "SAVEPOINT $savepoint" : 'BEGIN');
+	}
+
+
+	/**
+	 * Commits statements in a transaction.
+	 * @throws Dibi\DriverException
+	 */
+	public function commit(string $savepoint = null): void
+	{
+		$this->query($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
+	}
+
+
+	/**
+	 * Rollback changes in a transaction.
+	 * @throws Dibi\DriverException
+	 */
+	public function rollback(string $savepoint = null): void
+	{
+		$this->query($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
+	}
+
+
+	/**
+	 * Returns the connection resource.
+	 */
+	public function getResource(): ?SQLite3
+	{
+		return $this->connection;
+	}
+
+
+	/**
+	 * Returns the connection reflector.
+	 */
+	public function getReflector(): Dibi\Reflector
+	{
+		return new SqliteReflector($this);
+	}
+
+
+	/**
+	 * Result set driver factory.
+	 */
+	public function createResultDriver(\SQLite3Result $result): SqliteResult
+	{
+		return new SqliteResult($result);
+	}
+
+
+	/********************* SQL ****************d*g**/
+
+
+	/**
+	 * Encodes data for use in a SQL statement.
+	 */
+	public function escapeText(string $value): string
+	{
+		return "'" . $this->connection->escapeString($value) . "'";
+	}
+
+
+	public function escapeBinary(string $value): string
+	{
+		return "X'" . bin2hex($value) . "'";
+	}
+
+
+	public function escapeIdentifier(string $value): string
+	{
+		return '[' . strtr($value, '[]', '  ') . ']';
+	}
+
+
+	public function escapeBool(bool $value): string
+	{
+		return $value ? '1' : '0';
+	}
+
+
+	/**
+	 * @param  \DateTimeInterface|string|int  $value
+	 */
+	public function escapeDate($value): string
+	{
+		if (!$value instanceof \DateTimeInterface) {
+			$value = new Dibi\DateTime($value);
+		}
+		return $value->format($this->fmtDate);
+	}
+
+
+	/**
+	 * @param  \DateTimeInterface|string|int  $value
+	 */
+	public function escapeDateTime($value): string
+	{
+		if (!$value instanceof \DateTimeInterface) {
+			$value = new Dibi\DateTime($value);
+		}
+		return $value->format($this->fmtDateTime);
+	}
+
+
+	/**
+	 * Encodes string for use in a LIKE statement.
+	 */
+	public function escapeLike(string $value, int $pos): string
+	{
+		$value = addcslashes($this->connection->escapeString($value), '%_\\');
+		return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
+	}
+
+
+	/**
+	 * 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 === null ? '-1' : $limit)
+				. ($offset ? ' OFFSET ' . $offset : '');
+		}
+	}
+
+
+	/********************* user defined functions ****************d*g**/
+
+
+	/**
+	 * Registers an user defined function for use in SQL statements.
+	 */
+	public function registerFunction(string $name, callable $callback, int $numArgs = -1): void
+	{
+		$this->connection->createFunction($name, $callback, $numArgs);
+	}
+
+
+	/**
+	 * Registers an aggregating user defined function for use in SQL statements.
+	 */
+	public function registerAggregateFunction(string $name, callable $rowCallback, callable $agrCallback, int $numArgs = -1): void
+	{
+		$this->connection->createAggregate($name, $rowCallback, $agrCallback, $numArgs);
+	}
+}

+ 8 - 14
api/vendor/dibi/dibi/src/Dibi/Drivers/SqliteReflector.php

@@ -1,18 +1,19 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * The dibi reflector for SQLite database.
- * @internal
+ * The reflector for SQLite database.
  */
 class SqliteReflector implements Dibi\Reflector
 {
@@ -30,9 +31,8 @@ class SqliteReflector implements Dibi\Reflector
 
 	/**
 	 * Returns list of tables.
-	 * @return array
 	 */
-	public function getTables()
+	public function getTables(): array
 	{
 		$res = $this->driver->query("
 			SELECT name, type = 'view' as view FROM sqlite_master WHERE type IN ('table', 'view')
@@ -50,10 +50,8 @@ class SqliteReflector implements Dibi\Reflector
 
 	/**
 	 * Returns metadata for all columns in a table.
-	 * @param  string
-	 * @return array
 	 */
-	public function getColumns($table)
+	public function getColumns(string $table): array
 	{
 		$res = $this->driver->query("PRAGMA table_info({$this->driver->escapeIdentifier($table)})");
 		$columns = [];
@@ -78,10 +76,8 @@ class SqliteReflector implements Dibi\Reflector
 
 	/**
 	 * Returns metadata for all indexes in a table.
-	 * @param  string
-	 * @return array
 	 */
-	public function getIndexes($table)
+	public function getIndexes(string $table): array
 	{
 		$res = $this->driver->query("PRAGMA index_list({$this->driver->escapeIdentifier($table)})");
 		$indexes = [];
@@ -129,10 +125,8 @@ class SqliteReflector implements Dibi\Reflector
 
 	/**
 	 * Returns metadata for all foreign keys in a table.
-	 * @param  string
-	 * @return array
 	 */
-	public function getForeignKeys($table)
+	public function getForeignKeys(string $table): array
 	{
 		$res = $this->driver->query("PRAGMA foreign_key_list({$this->driver->escapeIdentifier($table)})");
 		$keys = [];

+ 123 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/SqliteResult.php

@@ -0,0 +1,123 @@
+<?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;
+use Dibi\Helpers;
+
+
+/**
+ * The driver for SQLite result set.
+ */
+class SqliteResult implements Dibi\ResultDriver
+{
+	use Dibi\Strict;
+
+	/** @var \SQLite3Result */
+	private $resultSet;
+
+	/** @var bool */
+	private $autoFree = true;
+
+
+	public function __construct(\SQLite3Result $resultSet)
+	{
+		$this->resultSet = $resultSet;
+	}
+
+
+	/**
+	 * Automatically frees the resources allocated for this result set.
+	 */
+	public function __destruct()
+	{
+		if ($this->autoFree && $this->getResultResource()) {
+			@$this->free();
+		}
+	}
+
+
+	/**
+	 * Returns the number of rows in a result set.
+	 * @throws Dibi\NotSupportedException
+	 */
+	public function getRowCount(): int
+	{
+		throw new Dibi\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  $assoc  true for associative array, false for numeric
+	 */
+	public function fetch(bool $assoc): ?array
+	{
+		return Helpers::false2Null($this->resultSet->fetchArray($assoc ? SQLITE3_ASSOC : SQLITE3_NUM));
+	}
+
+
+	/**
+	 * Moves cursor position without fetching row.
+	 * @throws Dibi\NotSupportedException
+	 */
+	public function seek(int $row): bool
+	{
+		throw new Dibi\NotSupportedException('Cannot seek an unbuffered result set.');
+	}
+
+
+	/**
+	 * Frees the resources allocated for this result set.
+	 */
+	public function free(): void
+	{
+		$this->resultSet->finalize();
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a result set.
+	 */
+	public function getResultColumns(): array
+	{
+		$count = $this->resultSet->numColumns();
+		$columns = [];
+		static $types = [SQLITE3_INTEGER => 'int', SQLITE3_FLOAT => 'float', SQLITE3_TEXT => 'text', SQLITE3_BLOB => 'blob', SQLITE3_NULL => 'null'];
+		for ($i = 0; $i < $count; $i++) {
+			$columns[] = [
+				'name' => $this->resultSet->columnName($i),
+				'table' => null,
+				'fullname' => $this->resultSet->columnName($i),
+				'nativetype' => $types[$this->resultSet->columnType($i)],
+			];
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Returns the result set resource.
+	 */
+	public function getResultResource(): \SQLite3Result
+	{
+		$this->autoFree = false;
+		return $this->resultSet;
+	}
+
+
+	/**
+	 * Decodes data from result set.
+	 */
+	public function unescapeBinary(string $value): string
+	{
+		return $value;
+	}
+}

+ 38 - 197
api/vendor/dibi/dibi/src/Dibi/Drivers/SqlsrvDriver.php

@@ -1,19 +1,20 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
-use Dibi\Connection;
 use Dibi\Helpers;
 
 
 /**
- * The dibi driver for Microsoft SQL Server and SQL Azure databases.
+ * The driver for Microsoft SQL Server and SQL Azure databases.
  *
  * Driver options:
  *   - host => the MS SQL server host name. It can also include a port number (hostname:port)
@@ -23,23 +24,16 @@ use Dibi\Helpers;
  *   - options (array) => connection options {@link https://msdn.microsoft.com/en-us/library/cc296161(SQL.90).aspx}
  *   - charset => character encoding to set (default is UTF-8)
  *   - resource (resource) => existing connection resource
- *   - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
  */
-class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
+class SqlsrvDriver implements Dibi\Driver
 {
 	use Dibi\Strict;
 
-	/** @var resource|null */
+	/** @var resource */
 	private $connection;
 
-	/** @var resource|null */
-	private $resultSet;
-
-	/** @var bool */
-	private $autoFree = true;
-
-	/** @var int|false  Affected rows */
-	private $affectedRows = false;
+	/** @var int|null  Affected rows */
+	private $affectedRows;
 
 	/** @var string */
 	private $version = '';
@@ -48,21 +42,12 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 	/**
 	 * @throws Dibi\NotSupportedException
 	 */
-	public function __construct()
+	public function __construct(array $config)
 	{
 		if (!extension_loaded('sqlsrv')) {
 			throw new Dibi\NotSupportedException("PHP extension 'sqlsrv' is not loaded.");
 		}
-	}
-
 
-	/**
-	 * Connects to a database.
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public function connect(array &$config)
-	{
 		Helpers::alias($config, 'options|UID', 'username');
 		Helpers::alias($config, 'options|PWD', 'password');
 		Helpers::alias($config, 'options|Database', 'database');
@@ -75,9 +60,7 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 			$options = $config['options'];
 
 			// Default values
-			if (!isset($options['CharacterSet'])) {
-				$options['CharacterSet'] = 'UTF-8';
-			}
+			$options['CharacterSet'] = $options['CharacterSet'] ?? 'UTF-8';
 			$options['PWD'] = (string) $options['PWD'];
 			$options['UID'] = (string) $options['UID'];
 			$options['Database'] = (string) $options['Database'];
@@ -95,9 +78,8 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Disconnects from a database.
-	 * @return void
 	 */
-	public function disconnect()
+	public function disconnect(): void
 	{
 		@sqlsrv_close($this->connection); // @ - connection can be already disconnected
 	}
@@ -105,13 +87,11 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return Dibi\ResultDriver|null
 	 * @throws Dibi\DriverException
 	 */
-	public function query($sql)
+	public function query(string $sql): ?Dibi\ResultDriver
 	{
-		$this->affectedRows = false;
+		$this->affectedRows = null;
 		$res = sqlsrv_query($this->connection, $sql);
 
 		if ($res === false) {
@@ -119,7 +99,7 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 			throw new Dibi\DriverException($info[0]['message'], $info[0]['code'], $sql);
 
 		} elseif (is_resource($res)) {
-			$this->affectedRows = sqlsrv_rows_affected($res);
+			$this->affectedRows = Helpers::false2Null(sqlsrv_rows_affected($res));
 			return sqlsrv_num_fields($res) ? $this->createResultDriver($res) : null;
 		}
 		return null;
@@ -128,9 +108,8 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * 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()
+	public function getAffectedRows(): ?int
 	{
 		return $this->affectedRows;
 	}
@@ -138,26 +117,23 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * 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)
+	public function getInsertId(?string $sequence): ?int
 	{
 		$res = sqlsrv_query($this->connection, 'SELECT SCOPE_IDENTITY()');
 		if (is_resource($res)) {
 			$row = sqlsrv_fetch_array($res, SQLSRV_FETCH_NUMERIC);
-			return $row[0];
+			return Dibi\Helpers::intVal($row[0]);
 		}
-		return false;
+		return null;
 	}
 
 
 	/**
 	 * Begins a transaction (if supported).
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function begin($savepoint = null)
+	public function begin(string $savepoint = null): void
 	{
 		sqlsrv_begin_transaction($this->connection);
 	}
@@ -165,11 +141,9 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function commit($savepoint = null)
+	public function commit(string $savepoint = null): void
 	{
 		sqlsrv_commit($this->connection);
 	}
@@ -177,11 +151,9 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Rollback changes in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws Dibi\DriverException
 	 */
-	public function rollback($savepoint = null)
+	public function rollback(string $savepoint = null): void
 	{
 		sqlsrv_rollback($this->connection);
 	}
@@ -199,9 +171,8 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Returns the connection reflector.
-	 * @return Dibi\Reflector
 	 */
-	public function getReflector()
+	public function getReflector(): Dibi\Reflector
 	{
 		return new SqlsrvReflector($this);
 	}
@@ -209,14 +180,11 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Result set driver factory.
-	 * @param  resource
-	 * @return Dibi\ResultDriver
+	 * @param  resource  $resource
 	 */
-	public function createResultDriver($resource)
+	public function createResultDriver($resource): SqlsrvResult
 	{
-		$res = clone $this;
-		$res->resultSet = $resource;
-		return $res;
+		return new SqlsrvResult($resource);
 	}
 
 
@@ -225,53 +193,38 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 
 	/**
 	 * Encodes data for use in a SQL statement.
-	 * @param  string    value
-	 * @return string    encoded value
 	 */
-	public function escapeText($value)
+	public function escapeText(string $value): string
 	{
 		return "'" . str_replace("'", "''", $value) . "'";
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeBinary($value)
+	public function escapeBinary(string $value): string
 	{
 		return "'" . str_replace("'", "''", $value) . "'";
 	}
 
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	public function escapeIdentifier($value)
+	public function escapeIdentifier(string $value): string
 	{
 		// @see https://msdn.microsoft.com/en-us/library/ms176027.aspx
 		return '[' . str_replace(']', ']]', $value) . ']';
 	}
 
 
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	public function escapeBool($value)
+	public function escapeBool(bool $value): string
 	{
 		return $value ? '1' : '0';
 	}
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDate($value)
+	public function escapeDate($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
 		return $value->format("'Y-m-d'");
@@ -279,58 +232,31 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	public function escapeDateTime($value)
+	public function escapeDateTime($value): string
 	{
-		if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
+		if (!$value instanceof \DateTimeInterface) {
 			$value = new Dibi\DateTime($value);
 		}
-		return $value->format("'Y-m-d H:i:s.u'");
+		return 'CONVERT(DATETIME2(7), ' . $value->format("'Y-m-d H:i:s.u'") . ')';
 	}
 
 
 	/**
 	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
 	 */
-	public function escapeLike($value, $pos)
+	public function escapeLike(string $value, int $pos): string
 	{
 		$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
 		return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
 	}
 
 
-	/**
-	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
-	 */
-	public function unescapeBinary($value)
-	{
-		return $value;
-	}
-
-
-	/** @deprecated */
-	public function escape($value, $type)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		return Helpers::escape($this, $value, $type);
-	}
-
-
 	/**
 	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
 	 */
-	public function applyLimit(&$sql, $limit, $offset)
+	public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
 	{
 		if ($limit < 0 || $offset < 0) {
 			throw new Dibi\NotSupportedException('Negative offset or limit.');
@@ -351,89 +277,4 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
 			$sql = sprintf('%s OFFSET %d ROWS', rtrim($sql), $offset);
 		}
 	}
-
-
-	/********************* result set ****************d*g**/
-
-
-	/**
-	 * Automatically frees the resources allocated for this result set.
-	 * @return void
-	 */
-	public function __destruct()
-	{
-		$this->autoFree && $this->getResultResource() && $this->free();
-	}
-
-
-	/**
-	 * Returns the number of rows in a result set.
-	 * @return int
-	 */
-	public function getRowCount()
-	{
-		throw new Dibi\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
-	 */
-	public function fetch($assoc)
-	{
-		return sqlsrv_fetch_array($this->resultSet, $assoc ? SQLSRV_FETCH_ASSOC : SQLSRV_FETCH_NUMERIC);
-	}
-
-
-	/**
-	 * Moves cursor position without fetching row.
-	 * @param  int   the 0-based cursor pos to seek to
-	 * @return bool  true on success, false if unable to seek to specified record
-	 */
-	public function seek($row)
-	{
-		throw new Dibi\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 getResultColumns()
-	{
-		$columns = [];
-		foreach ((array) sqlsrv_field_metadata($this->resultSet) as $fieldMetadata) {
-			$columns[] = [
-				'name' => $fieldMetadata['Name'],
-				'fullname' => $fieldMetadata['Name'],
-				'nativetype' => $fieldMetadata['Type'],
-			];
-		}
-		return $columns;
-	}
-
-
-	/**
-	 * Returns the result set resource.
-	 * @return resource|null
-	 */
-	public function getResultResource()
-	{
-		$this->autoFree = false;
-		return is_resource($this->resultSet) ? $this->resultSet : null;
-	}
 }

+ 9 - 16
api/vendor/dibi/dibi/src/Dibi/Drivers/SqlsrvReflector.php

@@ -1,18 +1,19 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * The dibi reflector for Microsoft SQL Server and SQL Azure databases.
- * @internal
+ * The reflector for Microsoft SQL Server and SQL Azure databases.
  */
 class SqlsrvReflector implements Dibi\Reflector
 {
@@ -30,9 +31,8 @@ class SqlsrvReflector implements Dibi\Reflector
 
 	/**
 	 * Returns list of tables.
-	 * @return array
 	 */
-	public function getTables()
+	public function getTables(): array
 	{
 		$res = $this->driver->query("SELECT TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES WHERE [TABLE_SCHEMA] = 'dbo'");
 		$tables = [];
@@ -48,10 +48,8 @@ class SqlsrvReflector implements Dibi\Reflector
 
 	/**
 	 * Returns metadata for all columns in a table.
-	 * @param  string
-	 * @return array
 	 */
-	public function getColumns($table)
+	public function getColumns(string $table): array
 	{
 		$res = $this->driver->query("
 			SELECT c.name as COLUMN_NAME, c.is_identity AS AUTO_INCREMENT
@@ -87,7 +85,6 @@ class SqlsrvReflector implements Dibi\Reflector
 				'table' => $table,
 				'nativetype' => strtoupper($row['DATA_TYPE']),
 				'size' => $row['CHARACTER_MAXIMUM_LENGTH'],
-				'unsigned' => true,
 				'nullable' => $row['IS_NULLABLE'] === 'YES',
 				'default' => $row['COLUMN_DEFAULT'],
 				'autoincrement' => $autoIncrements[$row['COLUMN_NAME']],
@@ -100,10 +97,8 @@ class SqlsrvReflector implements Dibi\Reflector
 
 	/**
 	 * Returns metadata for all indexes in a table.
-	 * @param  string
-	 * @return array
 	 */
-	public function getIndexes($table)
+	public function getIndexes(string $table): array
 	{
 		$keyUsagesRes = $this->driver->query(sprintf('EXEC [sys].[sp_helpindex] @objname = N%s', $this->driver->escapeText($table)));
 		$keyUsages = [];
@@ -117,7 +112,7 @@ class SqlsrvReflector implements Dibi\Reflector
 			$indexes[$row['name']]['name'] = $row['name'];
 			$indexes[$row['name']]['unique'] = $row['is_unique'] === 1;
 			$indexes[$row['name']]['primary'] = $row['is_primary_key'] === 1;
-			$indexes[$row['name']]['columns'] = isset($keyUsages[$row['name']]) ? $keyUsages[$row['name']] : [];
+			$indexes[$row['name']]['columns'] = $keyUsages[$row['name']] ?? [];
 		}
 		return array_values($indexes);
 	}
@@ -125,10 +120,8 @@ class SqlsrvReflector implements Dibi\Reflector
 
 	/**
 	 * Returns metadata for all foreign keys in a table.
-	 * @param  string
-	 * @return array
 	 */
-	public function getForeignKeys($table)
+	public function getForeignKeys(string $table): array
 	{
 		throw new Dibi\NotImplementedException;
 	}

+ 121 - 0
api/vendor/dibi/dibi/src/Dibi/Drivers/SqlsrvResult.php

@@ -0,0 +1,121 @@
+<?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;
+
+
+/**
+ * The driver for Microsoft SQL Server and SQL Azure result set.
+ */
+class SqlsrvResult implements Dibi\ResultDriver
+{
+	use Dibi\Strict;
+
+	/** @var resource */
+	private $resultSet;
+
+	/** @var bool */
+	private $autoFree = true;
+
+
+	/**
+	 * @param  resource  $resultSet
+	 */
+	public function __construct($resultSet)
+	{
+		$this->resultSet = $resultSet;
+	}
+
+
+	/**
+	 * Automatically frees the resources allocated for this result set.
+	 */
+	public function __destruct()
+	{
+		if ($this->autoFree && $this->getResultResource()) {
+			$this->free();
+		}
+	}
+
+
+	/**
+	 * Returns the number of rows in a result set.
+	 */
+	public function getRowCount(): int
+	{
+		throw new Dibi\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  $assoc  true for associative array, false for numeric
+	 */
+	public function fetch(bool $assoc): ?array
+	{
+		return sqlsrv_fetch_array($this->resultSet, $assoc ? SQLSRV_FETCH_ASSOC : SQLSRV_FETCH_NUMERIC);
+	}
+
+
+	/**
+	 * Moves cursor position without fetching row.
+	 */
+	public function seek(int $row): bool
+	{
+		throw new Dibi\NotSupportedException('Cannot seek an unbuffered result set.');
+	}
+
+
+	/**
+	 * Frees the resources allocated for this result set.
+	 */
+	public function free(): void
+	{
+		sqlsrv_free_stmt($this->resultSet);
+	}
+
+
+	/**
+	 * Returns metadata for all columns in a result set.
+	 */
+	public function getResultColumns(): array
+	{
+		$columns = [];
+		foreach ((array) sqlsrv_field_metadata($this->resultSet) as $fieldMetadata) {
+			$columns[] = [
+				'name' => $fieldMetadata['Name'],
+				'fullname' => $fieldMetadata['Name'],
+				'nativetype' => $fieldMetadata['Type'],
+			];
+		}
+		return $columns;
+	}
+
+
+	/**
+	 * Returns the result set resource.
+	 * @return resource|null
+	 */
+	public function getResultResource()
+	{
+		$this->autoFree = false;
+		return is_resource($this->resultSet) ? $this->resultSet : null;
+	}
+
+
+	/**
+	 * Decodes data from result set.
+	 */
+	public function unescapeBinary(string $value): string
+	{
+		return $value;
+	}
+}

+ 16 - 11
api/vendor/dibi/dibi/src/Dibi/Event.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
@@ -16,7 +18,8 @@ class Event
 	use Strict;
 
 	/** event type */
-	const CONNECT = 1,
+	public const
+		CONNECT = 1,
 		SELECT = 4,
 		INSERT = 8,
 		DELETE = 16,
@@ -43,18 +46,18 @@ class Event
 	/** @var float */
 	public $time;
 
-	/** @var int */
+	/** @var int|null */
 	public $count;
 
-	/** @var array */
+	/** @var array|null */
 	public $source;
 
 
-	public function __construct(Connection $connection, $type, $sql = null)
+	public function __construct(Connection $connection, int $type, string $sql = null)
 	{
 		$this->connection = $connection;
 		$this->type = $type;
-		$this->sql = trim($sql);
+		$this->sql = trim((string) $sql);
 		$this->time = -microtime(true);
 
 		if ($type === self::QUERY && preg_match('#\(?\s*(SELECT|UPDATE|INSERT|DELETE)#iA', $this->sql, $matches)) {
@@ -65,22 +68,24 @@ class Event
 			$this->type = $types[strtoupper($matches[1])];
 		}
 
-		$rc = new \ReflectionClass('dibi');
-		$dibiDir = dirname($rc->getFileName()) . DIRECTORY_SEPARATOR;
-		foreach (debug_backtrace(false) as $row) {
+		$dibiDir = dirname((new \ReflectionClass('dibi'))->getFileName()) . DIRECTORY_SEPARATOR;
+		foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) as $row) {
 			if (isset($row['file']) && is_file($row['file']) && strpos($row['file'], $dibiDir) !== 0) {
 				$this->source = [$row['file'], (int) $row['line']];
 				break;
 			}
 		}
 
-		\dibi::$elapsedTime = false;
+		\dibi::$elapsedTime = null;
 		\dibi::$numOfQueries++;
 		\dibi::$sql = $sql;
 	}
 
 
-	public function done($result = null)
+	/**
+	 * @param  Result|DriverException|null  $result
+	 */
+	public function done($result = null): self
 	{
 		$this->result = $result;
 		try {

+ 6 - 4
api/vendor/dibi/dibi/src/Dibi/Expression.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
@@ -19,13 +21,13 @@ class Expression
 	private $values;
 
 
-	public function __construct()
+	public function __construct(...$values)
 	{
-		$this->values = func_get_args();
+		$this->values = $values;
 	}
 
 
-	public function getValues()
+	public function getValues(): array
 	{
 		return $this->values;
 	}

+ 38 - 82
api/vendor/dibi/dibi/src/Dibi/Fluent.php

@@ -1,19 +1,21 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * dibi SQL builder via fluent interfaces. EXPERIMENTAL!
+ * SQL builder via fluent interfaces.
  *
  * @method Fluent select(...$field)
  * @method Fluent distinct()
- * @method Fluent from($table)
+ * @method Fluent from($table, ...$args = null)
  * @method Fluent where(...$cond)
  * @method Fluent groupBy(...$field)
  * @method Fluent having(...$cond)
@@ -27,13 +29,16 @@ namespace Dibi;
  * @method Fluent outerJoin(...$table)
  * @method Fluent as(...$field)
  * @method Fluent on(...$cond)
+ * @method Fluent and(...$cond)
  * @method Fluent using(...$cond)
+ * @method Fluent asc()
+ * @method Fluent desc()
  */
 class Fluent implements IDataSource
 {
 	use Strict;
 
-	const REMOVE = false;
+	public const REMOVE = false;
 
 	/** @var array */
 	public static $masks = [
@@ -86,7 +91,7 @@ class Fluent implements IDataSource
 	/** @var array */
 	private $setups = [];
 
-	/** @var string */
+	/** @var string|null */
 	private $command;
 
 	/** @var array */
@@ -95,16 +100,13 @@ class Fluent implements IDataSource
 	/** @var array */
 	private $flags = [];
 
-	/** @var array */
+	/** @var array|null */
 	private $cursor;
 
 	/** @var HashMap  normalized clauses */
 	private static $normalizer;
 
 
-	/**
-	 * @param  Connection
-	 */
 	public function __construct(Connection $connection)
 	{
 		$this->connection = $connection;
@@ -117,11 +119,8 @@ class Fluent implements IDataSource
 
 	/**
 	 * Appends new argument to the clause.
-	 * @param  string clause name
-	 * @param  array  arguments
-	 * @return self
 	 */
-	public function __call($clause, $args)
+	public function __call(string $clause, array $args): self
 	{
 		$clause = self::$normalizer->$clause;
 
@@ -206,10 +205,8 @@ class Fluent implements IDataSource
 
 	/**
 	 * Switch to a clause.
-	 * @param  string clause name
-	 * @return self
 	 */
-	public function clause($clause)
+	public function clause(string $clause): self
 	{
 		$this->cursor = &$this->clauses[self::$normalizer->$clause];
 		if ($this->cursor === null) {
@@ -222,10 +219,8 @@ class Fluent implements IDataSource
 
 	/**
 	 * Removes a clause.
-	 * @param  string clause name
-	 * @return self
 	 */
-	public function removeClause($clause)
+	public function removeClause(string $clause): self
 	{
 		$this->clauses[self::$normalizer->$clause] = null;
 		return $this;
@@ -234,11 +229,8 @@ class Fluent implements IDataSource
 
 	/**
 	 * Change a SQL flag.
-	 * @param  string  flag name
-	 * @param  bool  value
-	 * @return self
 	 */
-	public function setFlag($flag, $value = true)
+	public function setFlag(string $flag, bool $value = true): self
 	{
 		$flag = strtoupper($flag);
 		if ($value) {
@@ -252,10 +244,8 @@ class Fluent implements IDataSource
 
 	/**
 	 * Is a flag set?
-	 * @param  string  flag name
-	 * @return bool
 	 */
-	final public function getFlag($flag)
+	final public function getFlag(string $flag): bool
 	{
 		return isset($this->flags[strtoupper($flag)]);
 	}
@@ -263,19 +253,14 @@ class Fluent implements IDataSource
 
 	/**
 	 * Returns SQL command.
-	 * @return string
 	 */
-	final public function getCommand()
+	final public function getCommand(): ?string
 	{
 		return $this->command;
 	}
 
 
-	/**
-	 * Returns the dibi connection.
-	 * @return Connection
-	 */
-	final public function getConnection()
+	final public function getConnection(): Connection
 	{
 		return $this->connection;
 	}
@@ -283,11 +268,8 @@ class Fluent implements IDataSource
 
 	/**
 	 * Adds Result setup.
-	 * @param  string  method
-	 * @param  mixed   args
-	 * @return self
 	 */
-	public function setupResult($method)
+	public function setupResult(string $method): self
 	{
 		$this->setups[] = func_get_args();
 		return $this;
@@ -299,11 +281,10 @@ class Fluent implements IDataSource
 
 	/**
 	 * Generates and executes SQL query.
-	 * @param  mixed what to return?
-	 * @return Result|int  result set or number of affected rows
+	 * @return Result|int|null  result set or number of affected rows
 	 * @throws Exception
 	 */
-	public function execute($return = null)
+	public function execute(string $return = null)
 	{
 		$res = $this->query($this->_export());
 		switch ($return) {
@@ -319,7 +300,7 @@ class Fluent implements IDataSource
 
 	/**
 	 * Generates, executes SQL query and fetches the single row.
-	 * @return Row|false
+	 * @return Row|array|null
 	 */
 	public function fetch()
 	{
@@ -333,7 +314,7 @@ class Fluent implements IDataSource
 
 	/**
 	 * Like fetch(), but returns only first field.
-	 * @return mixed  value on success, false if no next record
+	 * @return mixed  value on success, null if no next record
 	 */
 	public function fetchSingle()
 	{
@@ -347,11 +328,8 @@ class Fluent implements IDataSource
 
 	/**
 	 * Fetches all records from table.
-	 * @param  int  offset
-	 * @param  int  limit
-	 * @return array
 	 */
-	public function fetchAll($offset = null, $limit = null)
+	public function fetchAll(int $offset = null, int $limit = null): array
 	{
 		return $this->query($this->_export(null, ['%ofs %lmt', $offset, $limit]))->fetchAll();
 	}
@@ -359,10 +337,9 @@ class Fluent implements IDataSource
 
 	/**
 	 * Fetches all records from table and returns associative tree.
-	 * @param  string  associative descriptor
-	 * @return array
+	 * @param  string  $assoc  associative descriptor
 	 */
-	public function fetchAssoc($assoc)
+	public function fetchAssoc(string $assoc): array
 	{
 		return $this->query($this->_export())->fetchAssoc($assoc);
 	}
@@ -370,11 +347,8 @@ class Fluent implements IDataSource
 
 	/**
 	 * 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)
+	public function fetchPairs(string $key = null, string $value = null): array
 	{
 		return $this->query($this->_export())->fetchPairs($key, $value);
 	}
@@ -382,11 +356,8 @@ class Fluent implements IDataSource
 
 	/**
 	 * Required by the IteratorAggregate interface.
-	 * @param  int  offset
-	 * @param  int  limit
-	 * @return ResultIterator
 	 */
-	public function getIterator($offset = null, $limit = null)
+	public function getIterator(int $offset = null, int $limit = null): ResultIterator
 	{
 		return $this->query($this->_export(null, ['%ofs %lmt', $offset, $limit]))->getIterator();
 	}
@@ -394,19 +365,14 @@ class Fluent implements IDataSource
 
 	/**
 	 * Generates and prints SQL query or it's part.
-	 * @param  string clause name
-	 * @return bool
 	 */
-	public function test($clause = null)
+	public function test(string $clause = null): bool
 	{
 		return $this->connection->test($this->_export($clause));
 	}
 
 
-	/**
-	 * @return int
-	 */
-	public function count()
+	public function count(): int
 	{
 		return Helpers::intVal($this->query([
 			'SELECT COUNT(*) FROM (%ex', $this->_export(), ') [data]',
@@ -414,14 +380,12 @@ class Fluent implements IDataSource
 	}
 
 
-	/**
-	 * @return Result|int
-	 */
-	private function query($args)
+	private function query($args): Result
 	{
 		$res = $this->connection->query($args);
 		foreach ($this->setups as $setup) {
-			call_user_func_array([$res, array_shift($setup)], $setup);
+			$method = array_shift($setup);
+			$res->$method(...$setup);
 		}
 		return $res;
 	}
@@ -430,10 +394,7 @@ class Fluent implements IDataSource
 	/********************* exporting ****************d*g**/
 
 
-	/**
-	 * @return DataSource
-	 */
-	public function toDataSource()
+	public function toDataSource(): DataSource
 	{
 		return new DataSource($this->connection->translate($this->_export()), $this->connection);
 	}
@@ -441,13 +402,12 @@ class Fluent implements IDataSource
 
 	/**
 	 * Returns SQL query.
-	 * @return string
 	 */
-	final public function __toString()
+	final public function __toString(): string
 	{
 		try {
 			return $this->connection->translate($this->_export());
-		} catch (\Exception $e) {
+		} catch (\Throwable $e) {
 			trigger_error($e->getMessage(), E_USER_ERROR);
 			return '';
 		}
@@ -456,10 +416,8 @@ class Fluent implements IDataSource
 
 	/**
 	 * Generates parameters for Translator.
-	 * @param  string clause name
-	 * @return array
 	 */
-	protected function _export($clause = null, $args = [])
+	protected function _export(string $clause = null, array $args = []): array
 	{
 		if ($clause === null) {
 			$data = $this->clauses;
@@ -495,11 +453,9 @@ class Fluent implements IDataSource
 
 	/**
 	 * Format camelCase clause name to UPPER CASE.
-	 * @param  string
-	 * @return string
 	 * @internal
 	 */
-	public static function _formatClause($s)
+	public static function _formatClause(string $s): string
 	{
 		if ($s === 'order' || $s === 'group') {
 			$s .= 'By';

+ 12 - 10
api/vendor/dibi/dibi/src/Dibi/HashMap.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
@@ -14,6 +16,7 @@ namespace Dibi;
  */
 abstract class HashMapBase
 {
+	/** @var callable */
 	private $callback;
 
 
@@ -23,13 +26,13 @@ abstract class HashMapBase
 	}
 
 
-	public function setCallback(callable $callback)
+	public function setCallback(callable $callback): void
 	{
 		$this->callback = $callback;
 	}
 
 
-	public function getCallback()
+	public function getCallback(): callable
 	{
 		return $this->callback;
 	}
@@ -38,27 +41,26 @@ abstract class HashMapBase
 
 /**
  * Lazy cached storage.
- *
  * @internal
  */
 final class HashMap extends HashMapBase
 {
-	public function __set($nm, $val)
+	public function __set(string $nm, $val)
 	{
-		if ($nm == '') {
+		if ($nm === '') {
 			$nm = "\xFF";
 		}
 		$this->$nm = $val;
 	}
 
 
-	public function __get($nm)
+	public function __get(string $nm)
 	{
-		if ($nm == '') {
+		if ($nm === '') {
 			$nm = "\xFF";
-			return isset($this->$nm) ? $this->$nm : $this->$nm = call_user_func($this->getCallback(), '');
+			return isset($this->$nm) ? $this->$nm : $this->$nm = $this->getCallback()('');
 		} else {
-			return $this->$nm = call_user_func($this->getCallback(), $nm);
+			return $this->$nm = $this->getCallback()($nm);
 		}
 	}
 }

+ 34 - 29
api/vendor/dibi/dibi/src/Dibi/Helpers.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
@@ -12,21 +14,19 @@ class Helpers
 {
 	use Strict;
 
-	/** @var array */
+	/** @var HashMap */
 	private static $types;
 
 
 	/**
 	 * Prints out a syntax highlighted version of the SQL command or Result.
-	 * @param  string|Result
-	 * @param  bool  return output instead of printing it?
-	 * @return string
+	 * @param  string|Result  $sql
 	 */
-	public static function dump($sql = null, $return = false)
+	public static function dump($sql = null, bool $return = false): ?string
 	{
 		ob_start();
 		if ($sql instanceof Result && PHP_SAPI === 'cli') {
-			$hasColors = (substr(getenv('TERM'), 0, 5) === 'xterm');
+			$hasColors = (substr((string) getenv('TERM'), 0, 5) === 'xterm');
 			$maxLen = 0;
 			foreach ($sql as $i => $row) {
 				if ($i === 0) {
@@ -88,8 +88,8 @@ class Helpers
 			// syntax highlight
 			$highlighter = "#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is";
 			if (PHP_SAPI === 'cli') {
-				if (substr(getenv('TERM'), 0, 5) === 'xterm') {
-					$sql = preg_replace_callback($highlighter, function ($m) {
+				if (substr((string) getenv('TERM'), 0, 5) === 'xterm') {
+					$sql = preg_replace_callback($highlighter, function (array $m) {
 						if (!empty($m[1])) { // comment
 							return "\033[1;30m" . $m[1] . "\033[0m";
 
@@ -108,7 +108,7 @@ class Helpers
 
 			} else {
 				$sql = htmlspecialchars($sql);
-				$sql = preg_replace_callback($highlighter, function ($m) {
+				$sql = preg_replace_callback($highlighter, function (array $m) {
 					if (!empty($m[1])) { // comment
 						return '<em style="color:gray">' . $m[1] . '</em>';
 
@@ -130,16 +130,16 @@ class Helpers
 			return ob_get_clean();
 		} else {
 			ob_end_flush();
+			return null;
 		}
 	}
 
 
 	/**
 	 * Finds the best suggestion.
-	 * @return string|null
 	 * @internal
 	 */
-	public static function getSuggestion(array $items, $value)
+	public static function getSuggestion(array $items, string $value): ?string
 	{
 		$best = null;
 		$min = (strlen($value) / 4 + 1) * 10 + .1;
@@ -155,7 +155,7 @@ class Helpers
 
 
 	/** @internal */
-	public static function escape(Driver $driver, $value, $type)
+	public static function escape(Driver $driver, $value, string $type): string
 	{
 		static $types = [
 			Type::TEXT => 'text',
@@ -175,11 +175,9 @@ class Helpers
 
 	/**
 	 * Heuristic type detection.
-	 * @param  string
-	 * @return string|null
 	 * @internal
 	 */
-	public static function detectType($type)
+	public static function detectType(string $type): ?string
 	{
 		static $patterns = [
 			'^_' => Type::TEXT, // PostgreSQL arrays
@@ -191,6 +189,7 @@ class Helpers
 			'TIME' => Type::DATETIME, // DATETIME, TIMESTAMP
 			'DATE' => Type::DATE,
 			'BOOL' => Type::BOOL,
+			'JSON' => Type::JSON,
 		];
 
 		foreach ($patterns as $s => $val) {
@@ -205,7 +204,7 @@ class Helpers
 	/**
 	 * @internal
 	 */
-	public static function getTypeCache()
+	public static function getTypeCache(): HashMap
 	{
 		if (self::$types === null) {
 			self::$types = new HashMap([__CLASS__, 'detectType']);
@@ -216,12 +215,8 @@ class Helpers
 
 	/**
 	 * 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)
+	public static function alias(array &$config, string $key, string $alias): void
 	{
 		$foo = &$config;
 		foreach (explode('|', $key) as $key) {
@@ -239,7 +234,7 @@ class Helpers
 	 * Import SQL dump from file.
 	 * @return int  count of sql commands
 	 */
-	public static function loadFromFile(Connection $connection, $file, callable $onProgress = null)
+	public static function loadFromFile(Connection $connection, string $file, callable $onProgress = null): int
 	{
 		@set_time_limit(0); // intentionally @
 
@@ -264,7 +259,7 @@ class Helpers
 				$sql = '';
 				$count++;
 				if ($onProgress) {
-					call_user_func($onProgress, $count, isset($stat['size']) ? $size * 100 / $stat['size'] : null);
+					$onProgress($count, isset($stat['size']) ? $size * 100 / $stat['size'] : null);
 				}
 
 			} else {
@@ -276,7 +271,7 @@ class Helpers
 			$driver->query($sql);
 			$count++;
 			if ($onProgress) {
-				call_user_func($onProgress, $count, isset($stat['size']) ? 100 : null);
+				$onProgress($count, isset($stat['size']) ? 100 : null);
 			}
 		}
 		fclose($handle);
@@ -286,15 +281,25 @@ class Helpers
 
 	/**
 	 * @internal
-	 * @return string|int
 	 */
-	public static function intVal($value)
+	public static function false2Null($val)
+	{
+		return $val === false ? null : $val;
+	}
+
+
+	/**
+	 * @internal
+	 */
+	public static function intVal($value): int
 	{
 		if (is_int($value)) {
 			return $value;
 		} elseif (is_string($value) && preg_match('#-?\d++\z#A', $value)) {
-			// support for long numbers - keep them unchanged
-			return is_float($number = $value * 1) ? $value : $number;
+			if (is_float($value * 1)) {
+				throw new Exception("Number $value is greater than integer.");
+			}
+			return (int) $value;
 		} else {
 			throw new Exception("Expected number, '$value' given.");
 		}

+ 4 - 5
api/vendor/dibi/dibi/src/Dibi/Literal.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
@@ -25,10 +27,7 @@ class Literal
 	}
 
 
-	/**
-	 * @return string
-	 */
-	public function __toString()
+	public function __toString(): string
 	{
 		return $this->value;
 	}

+ 7 - 6
api/vendor/dibi/dibi/src/Dibi/Loggers/FileLogger.php

@@ -1,17 +1,19 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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\Loggers;
 
 use Dibi;
 
 
 /**
- * dibi file logger.
+ * Dibi file logger.
  */
 class FileLogger
 {
@@ -24,18 +26,17 @@ class FileLogger
 	public $filter;
 
 
-	public function __construct($file, $filter = null)
+	public function __construct(string $file, int $filter = null)
 	{
 		$this->file = $file;
-		$this->filter = $filter ? (int) $filter : Dibi\Event::QUERY;
+		$this->filter = $filter ?: Dibi\Event::QUERY;
 	}
 
 
 	/**
 	 * After event notification.
-	 * @return void
 	 */
-	public function logEvent(Dibi\Event $event)
+	public function logEvent(Dibi\Event $event): void
 	{
 		if (($event->type & $this->filter) === 0) {
 			return;

+ 0 - 94
api/vendor/dibi/dibi/src/Dibi/Loggers/FirePhpLogger.php

@@ -1,94 +0,0 @@
-<?php
-
-/**
- * This file is part of the "dibi" - smart database abstraction layer.
- * Copyright (c) 2005 David Grudl (https://davidgrudl.com)
- */
-
-namespace Dibi\Loggers;
-
-use Dibi;
-
-
-/**
- * dibi FirePHP logger.
- */
-class FirePhpLogger
-{
-	use Dibi\Strict;
-
-	/** maximum number of rows */
-	public static $maxQueries = 30;
-
-	/** maximum SQL length */
-	public static $maxLength = 1000;
-
-	/** size of json stream chunk */
-	public static $streamChunkSize = 4990;
-
-	/** @var int */
-	public $filter;
-
-	/** @var int  Elapsed time for all queries */
-	public $totalTime = 0;
-
-	/** @var int  Number of all queries */
-	public $numOfQueries = 0;
-
-	/** @var array */
-	private static $fireTable = [['Time', 'SQL Statement', 'Rows', 'Connection']];
-
-
-	/**
-	 * @return bool
-	 */
-	public static function isAvailable()
-	{
-		return isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'FirePHP/');
-	}
-
-
-	public function __construct($filter = null)
-	{
-		$this->filter = $filter ? (int) $filter : Dibi\Event::QUERY;
-	}
-
-
-	/**
-	 * After event notification.
-	 * @return void
-	 */
-	public function logEvent(Dibi\Event $event)
-	{
-		if (headers_sent() || ($event->type & $this->filter) === 0 || count(self::$fireTable) > self::$maxQueries) {
-			return;
-		}
-
-		if (!$this->numOfQueries) {
-			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');
-		}
-		$this->totalTime += $event->time;
-		$this->numOfQueries++;
-		self::$fireTable[] = [
-			sprintf('%0.3f', $event->time * 1000),
-			strlen($event->sql) > self::$maxLength ? substr($event->sql, 0, self::$maxLength) . '...' : $event->sql,
-			$event->result instanceof \Exception ? 'ERROR' : (string) $event->count,
-			$event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name'),
-		];
-
-		$payload = json_encode([
-			[
-				'Type' => 'TABLE',
-				'Label' => 'dibi profiler (' . $this->numOfQueries . ' SQL queries took ' . sprintf('%0.3f', $this->totalTime * 1000) . ' ms)',
-			],
-			self::$fireTable,
-		]);
-		foreach (str_split($payload, self::$streamChunkSize) 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|");
-	}
-}

+ 21 - 61
api/vendor/dibi/dibi/src/Dibi/Reflection/Column.php

@@ -1,14 +1,15 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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\Reflection;
 
 use Dibi;
-use Dibi\Type;
 
 
 /**
@@ -20,9 +21,8 @@ use Dibi\Type;
  * @property-read string $type
  * @property-read mixed $nativeType
  * @property-read int|null $size
- * @property-read bool|null $unsigned
- * @property-read bool|null $nullable
- * @property-read bool|null $autoIncrement
+ * @property-read bool $nullable
+ * @property-read bool $autoIncrement
  * @property-read mixed $default
  */
 class Column
@@ -43,37 +43,25 @@ class Column
 	}
 
 
-	/**
-	 * @return string
-	 */
-	public function getName()
+	public function getName(): string
 	{
 		return $this->info['name'];
 	}
 
 
-	/**
-	 * @return string
-	 */
-	public function getFullName()
+	public function getFullName(): string
 	{
-		return isset($this->info['fullname']) ? $this->info['fullname'] : null;
+		return $this->info['fullname'] ?? null;
 	}
 
 
-	/**
-	 * @return bool
-	 */
-	public function hasTable()
+	public function hasTable(): bool
 	{
 		return !empty($this->info['table']);
 	}
 
 
-	/**
-	 * @return Table
-	 */
-	public function getTable()
+	public function getTable(): Table
 	{
 		if (empty($this->info['table']) || !$this->reflector) {
 			throw new Dibi\Exception('Table is unknown or not available.');
@@ -82,66 +70,39 @@ class Column
 	}
 
 
-	/**
-	 * @return string|null
-	 */
-	public function getTableName()
+	public function getTableName(): ?string
 	{
 		return isset($this->info['table']) && $this->info['table'] != null ? $this->info['table'] : null; // intentionally ==
 	}
 
 
-	/**
-	 * @return string
-	 */
-	public function getType()
+	public function getType(): ?string
 	{
 		return Dibi\Helpers::getTypeCache()->{$this->info['nativetype']};
 	}
 
 
-	/**
-	 * @return string
-	 */
-	public function getNativeType()
+	public function getNativeType(): string
 	{
 		return $this->info['nativetype'];
 	}
 
 
-	/**
-	 * @return int|null
-	 */
-	public function getSize()
+	public function getSize(): ?int
 	{
 		return isset($this->info['size']) ? (int) $this->info['size'] : null;
 	}
 
 
-	/**
-	 * @return bool|null
-	 */
-	public function isUnsigned()
+	public function isNullable(): bool
 	{
-		return isset($this->info['unsigned']) ? (bool) $this->info['unsigned'] : null;
+		return !empty($this->info['nullable']);
 	}
 
 
-	/**
-	 * @return bool|null
-	 */
-	public function isNullable()
-	{
-		return isset($this->info['nullable']) ? (bool) $this->info['nullable'] : null;
-	}
-
-
-	/**
-	 * @return bool|null
-	 */
-	public function isAutoIncrement()
+	public function isAutoIncrement(): bool
 	{
-		return isset($this->info['autoincrement']) ? (bool) $this->info['autoincrement'] : null;
+		return !empty($this->info['autoincrement']);
 	}
 
 
@@ -150,16 +111,15 @@ class Column
 	 */
 	public function getDefault()
 	{
-		return isset($this->info['default']) ? $this->info['default'] : null;
+		return $this->info['default'] ?? null;
 	}
 
 
 	/**
-	 * @param  string
 	 * @return mixed
 	 */
-	public function getVendorInfo($key)
+	public function getVendorInfo(string $key)
 	{
-		return isset($this->info['vendor'][$key]) ? $this->info['vendor'][$key] : null;
+		return $this->info['vendor'][$key] ?? null;
 	}
 }

+ 12 - 24
api/vendor/dibi/dibi/src/Dibi/Reflection/Database.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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\Reflection;
 
 use Dibi;
@@ -24,24 +26,21 @@ class Database
 	/** @var Dibi\Reflector */
 	private $reflector;
 
-	/** @var string */
+	/** @var string|null */
 	private $name;
 
-	/** @var array */
+	/** @var Table[]|null */
 	private $tables;
 
 
-	public function __construct(Dibi\Reflector $reflector, $name)
+	public function __construct(Dibi\Reflector $reflector, string $name = null)
 	{
 		$this->reflector = $reflector;
 		$this->name = $name;
 	}
 
 
-	/**
-	 * @return string
-	 */
-	public function getName()
+	public function getName(): ?string
 	{
 		return $this->name;
 	}
@@ -50,7 +49,7 @@ class Database
 	/**
 	 * @return Table[]
 	 */
-	public function getTables()
+	public function getTables(): array
 	{
 		$this->init();
 		return array_values($this->tables);
@@ -60,7 +59,7 @@ class Database
 	/**
 	 * @return string[]
 	 */
-	public function getTableNames()
+	public function getTableNames(): array
 	{
 		$this->init();
 		$res = [];
@@ -71,11 +70,7 @@ class Database
 	}
 
 
-	/**
-	 * @param  string
-	 * @return Table
-	 */
-	public function getTable($name)
+	public function getTable(string $name): Table
 	{
 		$this->init();
 		$l = strtolower($name);
@@ -88,21 +83,14 @@ class Database
 	}
 
 
-	/**
-	 * @param  string
-	 * @return bool
-	 */
-	public function hasTable($name)
+	public function hasTable(string $name): bool
 	{
 		$this->init();
 		return isset($this->tables[strtolower($name)]);
 	}
 
 
-	/**
-	 * @return void
-	 */
-	protected function init()
+	protected function init(): void
 	{
 		if ($this->tables === null) {
 			$this->tables = [];

+ 6 - 10
api/vendor/dibi/dibi/src/Dibi/Reflection/ForeignKey.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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\Reflection;
 
 use Dibi;
@@ -27,26 +29,20 @@ class ForeignKey
 	private $references;
 
 
-	public function __construct($name, array $references)
+	public function __construct(string $name, array $references)
 	{
 		$this->name = $name;
 		$this->references = $references;
 	}
 
 
-	/**
-	 * @return string
-	 */
-	public function getName()
+	public function getName(): string
 	{
 		return $this->name;
 	}
 
 
-	/**
-	 * @return array
-	 */
-	public function getReferences()
+	public function getReferences(): array
 	{
 		return $this->references;
 	}

+ 7 - 17
api/vendor/dibi/dibi/src/Dibi/Reflection/Index.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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\Reflection;
 
 use Dibi;
@@ -32,37 +34,25 @@ class Index
 	}
 
 
-	/**
-	 * @return string
-	 */
-	public function getName()
+	public function getName(): string
 	{
 		return $this->info['name'];
 	}
 
 
-	/**
-	 * @return array
-	 */
-	public function getColumns()
+	public function getColumns(): array
 	{
 		return $this->info['columns'];
 	}
 
 
-	/**
-	 * @return bool
-	 */
-	public function isUnique()
+	public function isUnique(): bool
 	{
 		return !empty($this->info['unique']);
 	}
 
 
-	/**
-	 * @return bool
-	 */
-	public function isPrimary()
+	public function isPrimary(): bool
 	{
 		return !empty($this->info['primary']);
 	}

+ 10 - 20
api/vendor/dibi/dibi/src/Dibi/Reflection/Result.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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\Reflection;
 
 use Dibi;
@@ -23,10 +25,10 @@ class Result
 	/** @var Dibi\ResultDriver */
 	private $driver;
 
-	/** @var array */
+	/** @var Column[]|null */
 	private $columns;
 
-	/** @var array */
+	/** @var string[]|null */
 	private $names;
 
 
@@ -39,7 +41,7 @@ class Result
 	/**
 	 * @return Column[]
 	 */
-	public function getColumns()
+	public function getColumns(): array
 	{
 		$this->initColumns();
 		return array_values($this->columns);
@@ -47,10 +49,9 @@ class Result
 
 
 	/**
-	 * @param  bool
 	 * @return string[]
 	 */
-	public function getColumnNames($fullNames = false)
+	public function getColumnNames(bool $fullNames = false): array
 	{
 		$this->initColumns();
 		$res = [];
@@ -61,11 +62,7 @@ class Result
 	}
 
 
-	/**
-	 * @param  string
-	 * @return Column
-	 */
-	public function getColumn($name)
+	public function getColumn(string $name): Column
 	{
 		$this->initColumns();
 		$l = strtolower($name);
@@ -78,21 +75,14 @@ class Result
 	}
 
 
-	/**
-	 * @param  string
-	 * @return bool
-	 */
-	public function hasColumn($name)
+	public function hasColumn(string $name): bool
 	{
 		$this->initColumns();
 		return isset($this->names[strtolower($name)]);
 	}
 
 
-	/**
-	 * @return void
-	 */
-	protected function initColumns()
+	protected function initColumns(): void
 	{
 		if ($this->columns === null) {
 			$this->columns = [];

+ 19 - 43
api/vendor/dibi/dibi/src/Dibi/Reflection/Table.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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\Reflection;
 
 use Dibi;
@@ -34,16 +36,16 @@ class Table
 	/** @var bool */
 	private $view;
 
-	/** @var array */
+	/** @var Column[]|null */
 	private $columns;
 
-	/** @var array */
+	/** @var ForeignKey[]|null */
 	private $foreignKeys;
 
-	/** @var array */
+	/** @var Index[]|null */
 	private $indexes;
 
-	/** @var Index */
+	/** @var Index|null */
 	private $primaryKey;
 
 
@@ -55,19 +57,13 @@ class Table
 	}
 
 
-	/**
-	 * @return string
-	 */
-	public function getName()
+	public function getName(): string
 	{
 		return $this->name;
 	}
 
 
-	/**
-	 * @return bool
-	 */
-	public function isView()
+	public function isView(): bool
 	{
 		return $this->view;
 	}
@@ -76,7 +72,7 @@ class Table
 	/**
 	 * @return Column[]
 	 */
-	public function getColumns()
+	public function getColumns(): array
 	{
 		$this->initColumns();
 		return array_values($this->columns);
@@ -86,7 +82,7 @@ class Table
 	/**
 	 * @return string[]
 	 */
-	public function getColumnNames()
+	public function getColumnNames(): array
 	{
 		$this->initColumns();
 		$res = [];
@@ -97,11 +93,7 @@ class Table
 	}
 
 
-	/**
-	 * @param  string
-	 * @return Column
-	 */
-	public function getColumn($name)
+	public function getColumn(string $name): Column
 	{
 		$this->initColumns();
 		$l = strtolower($name);
@@ -114,11 +106,7 @@ class Table
 	}
 
 
-	/**
-	 * @param  string
-	 * @return bool
-	 */
-	public function hasColumn($name)
+	public function hasColumn(string $name): bool
 	{
 		$this->initColumns();
 		return isset($this->columns[strtolower($name)]);
@@ -128,7 +116,7 @@ class Table
 	/**
 	 * @return ForeignKey[]
 	 */
-	public function getForeignKeys()
+	public function getForeignKeys(): array
 	{
 		$this->initForeignKeys();
 		return $this->foreignKeys;
@@ -138,27 +126,21 @@ class Table
 	/**
 	 * @return Index[]
 	 */
-	public function getIndexes()
+	public function getIndexes(): array
 	{
 		$this->initIndexes();
 		return $this->indexes;
 	}
 
 
-	/**
-	 * @return Index
-	 */
-	public function getPrimaryKey()
+	public function getPrimaryKey(): Index
 	{
 		$this->initIndexes();
 		return $this->primaryKey;
 	}
 
 
-	/**
-	 * @return void
-	 */
-	protected function initColumns()
+	protected function initColumns(): void
 	{
 		if ($this->columns === null) {
 			$this->columns = [];
@@ -169,10 +151,7 @@ class Table
 	}
 
 
-	/**
-	 * @return void
-	 */
-	protected function initIndexes()
+	protected function initIndexes(): void
 	{
 		if ($this->indexes === null) {
 			$this->initColumns();
@@ -190,10 +169,7 @@ class Table
 	}
 
 
-	/**
-	 * @return void
-	 */
-	protected function initForeignKeys()
+	protected function initForeignKeys(): void
 	{
 		throw new Dibi\NotImplementedException;
 	}

+ 62 - 106
api/vendor/dibi/dibi/src/Dibi/Result.php

@@ -1,28 +1,17 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * 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('col1');
- * $assoc = $result->fetchAssoc('col1[]col2->col3');
- *
- * unset($result);
- * </code>
+ * Query result.
  *
  * @property-read int $rowCount
  */
@@ -30,53 +19,39 @@ class Result implements IDataSource
 {
 	use Strict;
 
-	/** @var array  ResultDriver */
+	/** @var ResultDriver */
 	private $driver;
 
 	/** @var array  Translate table */
 	private $types = [];
 
-	/** @var Reflection\Result */
+	/** @var Reflection\Result|null */
 	private $meta;
 
 	/** @var bool  Already fetched? Used for allowance for first seek(0) */
 	private $fetched = false;
 
-	/** @var string  returned object class */
-	private $rowClass = 'Dibi\Row';
+	/** @var string|null  returned object class */
+	private $rowClass = Row::class;
 
-	/** @var callable  returned object factory*/
+	/** @var callable|null  returned object factory */
 	private $rowFactory;
 
 	/** @var array  format */
 	private $formats = [];
 
 
-	/**
-	 * @param  ResultDriver
-	 */
-	public function __construct($driver)
+	public function __construct(ResultDriver $driver)
 	{
 		$this->driver = $driver;
 		$this->detectTypes();
 	}
 
 
-	/**
-	 * @deprecated
-	 */
-	final public function getResource()
-	{
-		trigger_error(__METHOD__ . '() is deprecated, use getResultDriver()->getResultResource().', E_USER_DEPRECATED);
-		return $this->getResultDriver()->getResultResource();
-	}
-
-
 	/**
 	 * Frees the resources allocated for this result set.
-	 * @return void
 	 */
-	final public function free()
+	final public function free(): void
 	{
 		if ($this->driver !== null) {
 			$this->driver->free();
@@ -87,10 +62,9 @@ class Result implements IDataSource
 
 	/**
 	 * Safe access to property $driver.
-	 * @return ResultDriver
 	 * @throws \RuntimeException
 	 */
-	final public function getResultDriver()
+	final public function getResultDriver(): ResultDriver
 	{
 		if ($this->driver === null) {
 			throw new \RuntimeException('Result-set was released from memory.');
@@ -105,23 +79,18 @@ class Result implements IDataSource
 
 	/**
 	 * Moves cursor position without fetching row.
-	 * @param  int      the 0-based cursor pos to seek to
-	 * @return bool     true on success, false if unable to seek to specified record
 	 * @throws Exception
 	 */
-	final public function seek($row)
+	final public function seek(int $row): bool
 	{
-		return ($row != 0 || $this->fetched) // intentionally ==
-			? (bool) $this->getResultDriver()->seek($row)
-			: true;
+		return ($row !== 0 || $this->fetched) ? $this->getResultDriver()->seek($row) : true;
 	}
 
 
 	/**
 	 * Required by the Countable interface.
-	 * @return int
 	 */
-	final public function count()
+	final public function count(): int
 	{
 		return $this->getResultDriver()->getRowCount();
 	}
@@ -129,9 +98,8 @@ class Result implements IDataSource
 
 	/**
 	 * Returns the number of rows in a result set.
-	 * @return int
 	 */
-	final public function getRowCount()
+	final public function getRowCount(): int
 	{
 		return $this->getResultDriver()->getRowCount();
 	}
@@ -139,23 +107,29 @@ class Result implements IDataSource
 
 	/**
 	 * Required by the IteratorAggregate interface.
-	 * @return ResultIterator
 	 */
-	final public function getIterator()
+	final public function getIterator(): ResultIterator
 	{
 		return new ResultIterator($this);
 	}
 
 
+	/**
+	 * Returns the number of columns in a result set.
+	 */
+	final public function getColumnCount(): int
+	{
+		return count($this->types);
+	}
+
+
 	/********************* fetching rows ****************d*g**/
 
 
 	/**
 	 * Set fetched object class. This class should extend the Row class.
-	 * @param  string
-	 * @return self
 	 */
-	public function setRowClass($class)
+	public function setRowClass(?string $class): self
 	{
 		$this->rowClass = $class;
 		return $this;
@@ -164,9 +138,8 @@ class Result implements IDataSource
 
 	/**
 	 * Returns fetched object class name.
-	 * @return string
 	 */
-	public function getRowClass()
+	public function getRowClass(): ?string
 	{
 		return $this->rowClass;
 	}
@@ -174,9 +147,8 @@ class Result implements IDataSource
 
 	/**
 	 * Set a factory to create fetched object instances. These should extend the Row class.
-	 * @return self
 	 */
-	public function setRowFactory(callable $callback)
+	public function setRowFactory(callable $callback): self
 	{
 		$this->rowFactory = $callback;
 		return $this;
@@ -186,20 +158,20 @@ class Result implements IDataSource
 	/**
 	 * Fetches the row at current position, process optional type conversion.
 	 * and moves the internal cursor to the next position
-	 * @return Row|false
+	 * @return Row|array|null
 	 */
 	final public function fetch()
 	{
 		$row = $this->getResultDriver()->fetch(true);
-		if (!is_array($row)) {
-			return false;
+		if ($row === null) {
+			return null;
 		}
 		$this->fetched = true;
 		$this->normalize($row);
 		if ($this->rowFactory) {
-			return call_user_func($this->rowFactory, $row);
+			return ($this->rowFactory)($row);
 		} elseif ($this->rowClass) {
-			$row = new $this->rowClass($row);
+			return new $this->rowClass($row);
 		}
 		return $row;
 	}
@@ -207,13 +179,13 @@ class Result implements IDataSource
 
 	/**
 	 * Like fetch(), but returns only first field.
-	 * @return mixed value on success, false if no next record
+	 * @return mixed value on success, null if no next record
 	 */
 	final public function fetchSingle()
 	{
 		$row = $this->getResultDriver()->fetch(true);
-		if (!is_array($row)) {
-			return false;
+		if ($row === null) {
+			return null;
 		}
 		$this->fetched = true;
 		$this->normalize($row);
@@ -223,14 +195,12 @@ class Result implements IDataSource
 
 	/**
 	 * Fetches all records from table.
-	 * @param  int  offset
-	 * @param  int  limit
-	 * @return Row[]
+	 * @return Row[]|array[]
 	 */
-	final public function fetchAll($offset = null, $limit = null)
+	final public function fetchAll(int $offset = null, int $limit = null): array
 	{
-		$limit = $limit === null ? -1 : Helpers::intVal($limit);
-		$this->seek($offset);
+		$limit = $limit === null ? -1 : $limit;
+		$this->seek($offset ?: 0);
 		$row = $this->fetch();
 		if (!$row) {
 			return [];  // empty result set
@@ -256,11 +226,9 @@ class Result implements IDataSource
 	 *   builds a tree:          $tree[$val1][$index][$val2]->col3[$val3] = {record}
 	 * - associative descriptor: col1|col2->col3=col4
 	 *   builds a tree:          $tree[$val1][$val2]->col3[$val3] = val4
-	 * @param  string  associative descriptor
-	 * @return array
 	 * @throws \InvalidArgumentException
 	 */
-	final public function fetchAssoc($assoc)
+	final public function fetchAssoc(string $assoc): array
 	{
 		if (strpos($assoc, ',') !== false) {
 			return $this->oldFetchAssoc($assoc);
@@ -331,7 +299,7 @@ class Result implements IDataSource
 	/**
 	 * @deprecated
 	 */
-	private function oldFetchAssoc($assoc)
+	private function oldFetchAssoc(string $assoc)
 	{
 		$this->seek(0);
 		$row = $this->fetch();
@@ -402,12 +370,9 @@ class Result implements IDataSource
 
 	/**
 	 * 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)
+	final public function fetchPairs(string $key = null, string $value = null): array
 	{
 		$this->seek(0);
 		$row = $this->fetch();
@@ -464,14 +429,13 @@ class Result implements IDataSource
 
 	/**
 	 * Autodetect column types.
-	 * @return void
 	 */
-	private function detectTypes()
+	private function detectTypes(): void
 	{
 		$cache = Helpers::getTypeCache();
 		try {
 			foreach ($this->getResultDriver()->getResultColumns() as $col) {
-				$this->types[$col['name']] = isset($col['type']) ? $col['type'] : $cache->{$col['nativetype']};
+				$this->types[$col['name']] = $col['type'] ?? $cache->{$col['nativetype']};
 			}
 		} catch (NotSupportedException $e) {
 		}
@@ -480,10 +444,8 @@ class Result implements IDataSource
 
 	/**
 	 * Converts values to specified type and format.
-	 * @param  array
-	 * @return void
 	 */
-	private function normalize(array &$row)
+	private function normalize(array &$row): void
 	{
 		foreach ($this->types as $key => $type) {
 			if (!isset($row[$key])) { // null
@@ -528,7 +490,10 @@ class Result implements IDataSource
 				$row[$key]->invert = (int) (bool) $m[1];
 
 			} elseif ($type === Type::BINARY) {
-				$row[$key] = $this->getResultDriver()->unescapeBinary($value);
+				$row[$key] = is_string($value) ? $this->getResultDriver()->unescapeBinary($value) : $value;
+
+			} elseif ($type === Type::JSON) {
+				$row[$key] = json_decode($value, true);
 			}
 		}
 	}
@@ -536,34 +501,28 @@ class Result implements IDataSource
 
 	/**
 	 * Define column type.
-	 * @param  string  column
-	 * @param  string  type (use constant Type::*)
-	 * @return self
+	 * @param  string|null  $type  use constant Type::*
 	 */
-	final public function setType($col, $type)
+	final public function setType(string $column, ?string $type): self
 	{
-		$this->types[$col] = $type;
+		$this->types[$column] = $type;
 		return $this;
 	}
 
 
 	/**
 	 * Returns column type.
-	 * @return string
 	 */
-	final public function getType($col)
+	final public function getType(string $column): ?string
 	{
-		return isset($this->types[$col]) ? $this->types[$col] : null;
+		return $this->types[$column] ?? null;
 	}
 
 
 	/**
 	 * Sets date format.
-	 * @param  string
-	 * @param  string|null  format
-	 * @return self
 	 */
-	final public function setFormat($type, $format)
+	final public function setFormat(string $type, ?string $format): self
 	{
 		$this->formats[$type] = $format;
 		return $this;
@@ -572,11 +531,10 @@ class Result implements IDataSource
 
 	/**
 	 * Returns data format.
-	 * @return string|null
 	 */
-	final public function getFormat($type)
+	final public function getFormat(string $type): ?string
 	{
-		return isset($this->formats[$type]) ? $this->formats[$type] : null;
+		return $this->formats[$type] ?? null;
 	}
 
 
@@ -585,9 +543,8 @@ class Result implements IDataSource
 
 	/**
 	 * Returns a meta information about the current result set.
-	 * @return Reflection\Result
 	 */
-	public function getInfo()
+	public function getInfo(): Reflection\Result
 	{
 		if ($this->meta === null) {
 			$this->meta = new Reflection\Result($this->getResultDriver());
@@ -599,7 +556,7 @@ class Result implements IDataSource
 	/**
 	 * @return Reflection\Column[]
 	 */
-	final public function getColumns()
+	final public function getColumns(): array
 	{
 		return $this->getInfo()->getColumns();
 	}
@@ -610,9 +567,8 @@ class Result implements IDataSource
 
 	/**
 	 * Displays complete result set as HTML or text table for debug purposes.
-	 * @return void
 	 */
-	final public function dump()
+	final public function dump(): void
 	{
 		echo Helpers::dump($this);
 	}

+ 8 - 22
api/vendor/dibi/dibi/src/Dibi/ResultIterator.php

@@ -1,24 +1,17 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
  * External result set iterator.
- *
- * This can be returned by Result::getIterator() method or using foreach
- * <code>
- * $result = dibi::query('SELECT * FROM table');
- * foreach ($result as $row) {
- *    print_r($row);
- * }
- * unset($result);
- * </code>
  */
 class ResultIterator implements \Iterator, \Countable
 {
@@ -31,12 +24,9 @@ class ResultIterator implements \Iterator, \Countable
 	private $row;
 
 	/** @var int */
-	private $pointer;
+	private $pointer = 0;
 
 
-	/**
-	 * @param  Result
-	 */
 	public function __construct(Result $result)
 	{
 		$this->result = $result;
@@ -45,9 +35,8 @@ class ResultIterator implements \Iterator, \Countable
 
 	/**
 	 * Rewinds the iterator to the first element.
-	 * @return void
 	 */
-	public function rewind()
+	public function rewind(): void
 	{
 		$this->pointer = 0;
 		$this->result->seek(0);
@@ -77,9 +66,8 @@ class ResultIterator implements \Iterator, \Countable
 
 	/**
 	 * Moves forward to next element.
-	 * @return void
 	 */
-	public function next()
+	public function next(): void
 	{
 		$this->row = $this->result->fetch();
 		$this->pointer++;
@@ -88,9 +76,8 @@ class ResultIterator implements \Iterator, \Countable
 
 	/**
 	 * Checks if there is a current element after calls to rewind() or next().
-	 * @return bool
 	 */
-	public function valid()
+	public function valid(): bool
 	{
 		return !empty($this->row);
 	}
@@ -98,9 +85,8 @@ class ResultIterator implements \Iterator, \Countable
 
 	/**
 	 * Required by the Countable interface.
-	 * @return int
 	 */
-	public function count()
+	public function count(): int
 	{
 		return $this->result->getRowCount();
 	}

+ 8 - 8
api/vendor/dibi/dibi/src/Dibi/Row.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
@@ -13,7 +15,7 @@ namespace Dibi;
  */
 class Row implements \ArrayAccess, \IteratorAggregate, \Countable
 {
-	public function __construct($arr)
+	public function __construct(array $arr)
 	{
 		foreach ($arr as $k => $v) {
 			$this->$k = $v;
@@ -21,7 +23,7 @@ class Row implements \ArrayAccess, \IteratorAggregate, \Countable
 	}
 
 
-	public function toArray()
+	public function toArray(): array
 	{
 		return (array) $this;
 	}
@@ -29,11 +31,9 @@ class Row implements \ArrayAccess, \IteratorAggregate, \Countable
 
 	/**
 	 * Converts value to DateTime object.
-	 * @param  string key
-	 * @param  string format
-	 * @return \DateTime
+	 * @return DateTime|string|null
 	 */
-	public function asDateTime($key, $format = null)
+	public function asDateTime(string $key, string $format = null)
 	{
 		$time = $this[$key];
 		if (!$time instanceof DateTime) {
@@ -46,7 +46,7 @@ class Row implements \ArrayAccess, \IteratorAggregate, \Countable
 	}
 
 
-	public function __get($key)
+	public function __get(string $key)
 	{
 		$hint = Helpers::getSuggestion(array_keys((array) $this), $key);
 		trigger_error("Attempt to read missing column '$key'" . ($hint ? ", did you mean '$hint'?" : '.'), E_USER_NOTICE);

+ 17 - 28
api/vendor/dibi/dibi/src/Dibi/Strict.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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 ReflectionClass;
@@ -25,11 +27,13 @@ trait Strict
 	 * Call to undefined method.
 	 * @throws \LogicException
 	 */
-	public function __call($name, $args)
+	public function __call(string $name, array $args)
 	{
-		if ($cb = self::extensionMethod(get_class($this) . '::' . $name)) { // back compatiblity
+		$class = get_class($this);
+		if ($cb = self::extensionMethod($class . '::' . $name)) { // back compatiblity
+			trigger_error("Extension methods such as $class::$name() are deprecated", E_USER_DEPRECATED);
 			array_unshift($args, $this);
-			return call_user_func_array($cb, $args);
+			return $cb(...$args);
 		}
 		$class = method_exists($this, $name) ? 'parent' : get_class($this);
 		$items = (new ReflectionClass($this))->getMethods(ReflectionMethod::IS_PUBLIC);
@@ -42,7 +46,7 @@ trait Strict
 	 * Call to undefined static method.
 	 * @throws \LogicException
 	 */
-	public static function __callStatic($name, $args)
+	public static function __callStatic(string $name, array $args)
 	{
 		$rc = new ReflectionClass(get_called_class());
 		$items = array_intersect($rc->getMethods(ReflectionMethod::IS_PUBLIC), $rc->getMethods(ReflectionMethod::IS_STATIC));
@@ -55,7 +59,7 @@ trait Strict
 	 * Access to undeclared property.
 	 * @throws \LogicException
 	 */
-	public function &__get($name)
+	public function &__get(string $name)
 	{
 		if ((method_exists($this, $m = 'get' . $name) || method_exists($this, $m = 'is' . $name))
 			&& (new ReflectionMethod($this, $m))->isPublic()
@@ -74,7 +78,7 @@ trait Strict
 	 * Access to undeclared property.
 	 * @throws \LogicException
 	 */
-	public function __set($name, $value)
+	public function __set(string $name, $value)
 	{
 		$rc = new ReflectionClass($this);
 		$items = array_diff($rc->getProperties(ReflectionProperty::IS_PUBLIC), $rc->getProperties(ReflectionProperty::IS_STATIC));
@@ -83,10 +87,7 @@ trait Strict
 	}
 
 
-	/**
-	 * @return bool
-	 */
-	public function __isset($name)
+	public function __isset(string $name): bool
 	{
 		return false;
 	}
@@ -96,7 +97,7 @@ trait Strict
 	 * Access to undeclared property.
 	 * @throws \LogicException
 	 */
-	public function __unset($name)
+	public function __unset(string $name)
 	{
 		$class = get_class($this);
 		throw new \LogicException("Attempt to unset undeclared property $class::$$name.");
@@ -104,31 +105,18 @@ trait Strict
 
 
 	/**
-	 * @param  string  method name
-	 * @param  callable
 	 * @return mixed
+	 * @deprecated
 	 */
-	public static function extensionMethod($name, $callback = null)
+	public static function extensionMethod(string $name, callable $callback = null)
 	{
 		if (strpos($name, '::') === false) {
 			$class = get_called_class();
 		} else {
-			list($class, $name) = explode('::', $name);
+			[$class, $name] = explode('::', $name);
 			$class = (new ReflectionClass($class))->getName();
 		}
 
-		if (self::$extMethods === null) { // for backwards compatibility
-			$list = get_defined_functions();
-			foreach ($list['user'] as $fce) {
-				$pair = explode('_prototype_', $fce);
-				if (count($pair) === 2) {
-					trigger_error("Extension method defined as $fce() is deprecated, use $class::extensionMethod('$name', ...).", E_USER_DEPRECATED);
-					self::$extMethods[$pair[1]][(new ReflectionClass($pair[0]))->getName()] = $fce;
-					self::$extMethods[$pair[1]][''] = null;
-				}
-			}
-		}
-
 		$list = &self::$extMethods[strtolower($name)];
 		if ($callback === null) { // getter
 			$cache = &$list[''][$class];
@@ -144,6 +132,7 @@ trait Strict
 			return $cache = false;
 
 		} else { // setter
+			trigger_error("Extension methods such as $class::$name() are deprecated", E_USER_DEPRECATED);
 			$list[$class] = $callback;
 			$list[''] = null;
 		}

+ 34 - 38
api/vendor/dibi/dibi/src/Dibi/Translator.php

@@ -1,15 +1,17 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * dibi SQL translator.
+ * SQL translator.
  */
 final class Translator
 {
@@ -39,10 +41,10 @@ final class Translator
 	/** @var int */
 	private $ifLevelStart = 0;
 
-	/** @var int */
+	/** @var int|null */
 	private $limit;
 
-	/** @var int */
+	/** @var int|null */
 	private $offset;
 
 	/** @var HashMap */
@@ -59,17 +61,16 @@ final class Translator
 
 	/**
 	 * Generates SQL. Can be called only once.
-	 * @param  array
-	 * @return string
 	 * @throws Exception
 	 */
-	public function translate(array $args)
+	public function translate(array $args): string
 	{
 		$args = array_values($args);
 		while (count($args) === 1 && is_array($args[0])) { // implicit array expansion
 			$args = array_values($args[0]);
 		}
 		$this->args = $args;
+		$this->errors = [];
 
 		$commandIns = null;
 		$lastArr = null;
@@ -142,7 +143,7 @@ final class Translator
 			}
 
 			// default processing
-			$sql[] = $this->formatValue($arg, false);
+			$sql[] = $this->formatValue($arg, null);
 		} // while
 
 
@@ -167,11 +168,9 @@ final class Translator
 
 	/**
 	 * Apply modifier to single value.
-	 * @param  mixed
-	 * @param  string
-	 * @return string
+	 * @param  mixed  $value
 	 */
-	public function formatValue($value, $modifier)
+	public function formatValue($value, ?string $modifier): string
 	{
 		if ($this->comment) {
 			return '...';
@@ -196,7 +195,7 @@ final class Translator
 							$pair = explode('%', $k, 2); // split into identifier & modifier
 							$k = $this->identifiers->{$pair[0]} . ' ';
 							if (!isset($pair[1])) {
-								$v = $this->formatValue($v, false);
+								$v = $this->formatValue($v, null);
 								$vx[] = $k . ($v === 'NULL' ? 'IS ' : '= ') . $v;
 
 							} elseif ($pair[1] === 'ex') {
@@ -238,7 +237,7 @@ final class Translator
 					foreach ($value as $k => $v) {
 						$pair = explode('%', $k, 2); // split into identifier & modifier
 						$vx[] = $this->identifiers->{$pair[0]} . '='
-							. $this->formatValue($v, isset($pair[1]) ? $pair[1] : (is_array($v) ? 'ex' : false));
+							. $this->formatValue($v, $pair[1] ?? (is_array($v) ? 'ex!' : null));
 					}
 					return implode(', ', $vx);
 
@@ -247,7 +246,7 @@ final class Translator
 				case 'l': // (val, val, ...)
 					foreach ($value as $k => $v) {
 						$pair = explode('%', (string) $k, 2); // split into identifier & modifier
-						$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : (is_array($v) ? 'ex' : false));
+						$vx[] = $this->formatValue($v, $pair[1] ?? (is_array($v) ? 'ex!' : null));
 					}
 					return '(' . (($vx || $modifier === 'l') ? implode(', ', $vx) : 'NULL') . ')';
 
@@ -256,7 +255,7 @@ final class Translator
 					foreach ($value as $k => $v) {
 						$pair = explode('%', $k, 2); // split into identifier & modifier
 						$kx[] = $this->identifiers->{$pair[0]};
-						$vx[] = $this->formatValue($v, isset($pair[1]) ? $pair[1] : (is_array($v) ? 'ex' : false));
+						$vx[] = $this->formatValue($v, $pair[1] ?? (is_array($v) ? 'ex!' : null));
 					}
 					return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
 
@@ -277,7 +276,7 @@ final class Translator
 						$pair = explode('%', $k, 2); // split into identifier & modifier
 						$kx[] = $this->identifiers->{$pair[0]};
 						foreach ($v as $k2 => $v2) {
-							$vx[$k2][] = $this->formatValue($v2, isset($pair[1]) ? $pair[1] : (is_array($v2) ? 'ex' : false));
+							$vx[$k2][] = $this->formatValue($v2, $pair[1] ?? (is_array($v2) ? 'ex!' : null));
 						}
 					}
 					foreach ($vx as $k => $v) {
@@ -298,9 +297,12 @@ final class Translator
 					}
 					return implode(', ', $vx);
 
+				case 'ex!':
+					trigger_error('Use Dibi\Expression instead of array: ' . implode(', ', array_filter($value, 'is_scalar')), E_USER_WARNING);
+					// break omitted
 				case 'ex':
 				case 'sql':
-					return call_user_func_array([$this->connection, 'translate'], $value);
+					return $this->connection->translate(...$value);
 
 				default:  // value, value, value - all with the same modifier
 					foreach ($value as $v) {
@@ -315,8 +317,12 @@ final class Translator
 		if ($modifier) {
 			if ($value !== null && !is_scalar($value)) {  // array is already processed
 				if ($value instanceof Literal && ($modifier === 'sql' || $modifier === 'SQL')) {
-					$modifier = 'SQL';
-				} elseif (($value instanceof \DateTime || $value instanceof \DateTimeInterface) && ($modifier === 'd' || $modifier === 't' || $modifier === 'dt')) {
+					return (string) $value;
+
+				} elseif ($value instanceof Expression && $modifier === 'ex') {
+					return $this->connection->translate(...$value->getValues());
+
+				} elseif ($value instanceof \DateTimeInterface && ($modifier === 'd' || $modifier === 't' || $modifier === 'dt')) {
 					// continue
 				} else {
 					$type = is_object($value) ? get_class($value) : gettype($value);
@@ -332,15 +338,12 @@ final class Translator
 					return $value === null ? 'NULL' : $this->driver->escapeBinary($value);
 
 				case 'b':  // boolean
-					return $value === null ? 'NULL' : $this->driver->escapeBool($value);
+					return $value === null ? 'NULL' : $this->driver->escapeBool((bool) $value);
 
 				case 'sN': // string or null
 				case 'sn':
 					return $value == '' ? 'NULL' : $this->driver->escapeText((string) $value); // notice two equal signs
 
-				case 'in': // deprecated
-					trigger_error('Modifier %in is deprecated, use %iN.', E_USER_DEPRECATED);
-					// break omitted
 				case 'iN': // signed int or null
 					if ($value == '') {
 						$value = null;
@@ -353,9 +356,6 @@ final class Translator
 					} elseif (is_string($value)) {
 						if (preg_match('#[+-]?\d++(?:e\d+)?\z#A', $value)) {
 							return $value; // support for long numbers - keep them unchanged
-						} elseif (substr($value, 1, 1) === 'x' && is_numeric($value)) {
-							trigger_error('Support for hex strings has been deprecated.', E_USER_DEPRECATED);
-							return (string) hexdec($value);
 						} else {
 							throw new Exception("Expected number, '$value' given.");
 						}
@@ -452,14 +452,14 @@ final class Translator
 		} elseif ($value === null) {
 			return 'NULL';
 
-		} elseif ($value instanceof \DateTime || $value instanceof \DateTimeInterface) {
+		} elseif ($value instanceof \DateTimeInterface) {
 			return $this->driver->escapeDateTime($value);
 
 		} elseif ($value instanceof Literal) {
 			return (string) $value;
 
 		} elseif ($value instanceof Expression) {
-			return call_user_func_array([$this->connection, 'translate'], $value->getValues());
+			return $this->connection->translate(...$value->getValues());
 
 		} else {
 			$type = is_object($value) ? get_class($value) : gettype($value);
@@ -470,10 +470,8 @@ final class Translator
 
 	/**
 	 * PREG callback from translate() or formatValue().
-	 * @param  array
-	 * @return string
 	 */
-	private function cb($matches)
+	private function cb(array $matches): string
 	{
 		//    [1] => `ident`
 		//    [2] => [ident]
@@ -496,7 +494,7 @@ final class Translator
 			}
 
 			$cursor++;
-			return $this->formatValue($this->args[$cursor - 1], false);
+			return $this->formatValue($this->args[$cursor - 1], null);
 		}
 
 		if (!empty($matches[10])) { // modifier
@@ -592,7 +590,7 @@ final class Translator
 		if ($matches[8]) { // SQL identifier substitution
 			$m = substr($matches[8], 0, -1);
 			$m = $this->connection->getSubstitutes()->$m;
-			return $matches[9] == '' ? $this->formatValue($m, false) : $m . $matches[9]; // value or identifier
+			return $matches[9] == '' ? $this->formatValue($m, null) : $m . $matches[9]; // value or identifier
 		}
 
 		throw new \Exception('this should be never executed');
@@ -600,12 +598,10 @@ final class Translator
 
 
 	/**
-	 * Apply substitutions to indentifier and delimites it.
-	 * @param  string indentifier
-	 * @return string
+	 * Apply substitutions to identifier and delimites it.
 	 * @internal
 	 */
-	public function delimite($value)
+	public function delimite(string $value): string
 	{
 		$value = $this->connection->substitute($value);
 		$parts = explode('.', $value);

+ 5 - 2
api/vendor/dibi/dibi/src/Dibi/Type.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
@@ -13,9 +15,10 @@ namespace Dibi;
  */
 class Type
 {
-	const
+	public const
 		TEXT = 's', // as 'string'
 		BINARY = 'bin',
+		JSON = 'json',
 		BOOL = 'b',
 		INTEGER = 'i',
 		FLOAT = 'f',

+ 54 - 314
api/vendor/dibi/dibi/src/Dibi/dibi.php

@@ -1,70 +1,69 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
  * Copyright (c) 2005 David Grudl (https://davidgrudl.com)
  */
 
-use Dibi\Type;
+declare(strict_types=1);
 
 
 /**
- * This class is static container class for creating DB objects and
- * store connections info.
+ * Static container class for Dibi connections.
+ *
+ * @method void disconnect()
+ * @method Dibi\Result query(...$args)
+ * @method Dibi\Result nativeQuery(...$args)
+ * @method bool test(...$args)
+ * @method Dibi\DataSource dataSource(...$args)
+ * @method Dibi\Row|null fetch(...$args)
+ * @method array fetchAll(...$args)
+ * @method mixed fetchSingle(...$args)
+ * @method array fetchPairs(...$args)
+ * @method int getAffectedRows()
+ * @method int getInsertId(string $sequence = null)
+ * @method void begin(string $savepoint = null)
+ * @method void commit(string $savepoint = null)
+ * @method void rollback(string $savepoint = null)
+ * @method Dibi\Reflection\Database getDatabaseInfo()
+ * @method Dibi\Fluent command()
+ * @method Dibi\Fluent select(...$args)
+ * @method Dibi\Fluent update(string|string[] $table, array $args)
+ * @method Dibi\Fluent insert(string $table, array $args)
+ * @method Dibi\Fluent delete(string $table)
+ * @method Dibi\HashMap getSubstitutes()
+ * @method int loadFile(string $file)
  */
 class dibi
 {
 	use Dibi\Strict;
 
-	const
+	public const
 		AFFECTED_ROWS = 'a',
 		IDENTIFIER = 'n';
 
 	/** version */
-	const
-		VERSION = '3.1.0',
-		REVISION = 'released on 2017-09-25';
+	public const
+		VERSION = '4.0.1';
 
 	/** sorting order */
-	const
+	public const
 		ASC = 'ASC',
 		DESC = 'DESC';
 
-	/** @deprecated */
-	const
-		TEXT = Type::TEXT,
-		BINARY = Type::BINARY,
-		BOOL = Type::BOOL,
-		INTEGER = Type::INTEGER,
-		FLOAT = Type::FLOAT,
-		DATE = Type::DATE,
-		DATETIME = Type::DATETIME,
-		TIME = Type::TIME,
-		FIELD_TEXT = Type::TEXT,
-		FIELD_BINARY = Type::BINARY,
-		FIELD_BOOL = Type::BOOL,
-		FIELD_INTEGER = Type::INTEGER,
-		FIELD_FLOAT = Type::FLOAT,
-		FIELD_DATE = Type::DATE,
-		FIELD_DATETIME = Type::DATETIME,
-		FIELD_TIME = Type::TIME;
-
-	/** @var string  Last SQL command @see dibi::query() */
+	/** @var string|null  Last SQL command @see dibi::query() */
 	public static $sql;
 
-	/** @var int  Elapsed time for last query */
+	/** @var float|null  Elapsed time for last query */
 	public static $elapsedTime;
 
-	/** @var int  Elapsed time for all queries */
+	/** @var float  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 = 'mysqli';
-
-	/** @var Dibi\Connection[]  Connection registry storage for DibiConnection objects */
+	/** @var Dibi\Connection[]  Connection registry storage for Dibi\Connection objects */
 	private static $registry = [];
 
 	/** @var Dibi\Connection  Current connection */
@@ -85,32 +84,19 @@ class dibi
 
 	/**
 	 * Creates a new Connection object and connects it to specified database.
-	 * @param  mixed   connection parameters
-	 * @param  string  connection name
-	 * @return Dibi\Connection
+	 * @param  array   $config  connection parameters
 	 * @throws Dibi\Exception
 	 */
-	public static function connect($config = [], $name = '0')
+	public static function connect($config = [], string $name = '0'): Dibi\Connection
 	{
 		return self::$connection = self::$registry[$name] = new Dibi\Connection($config, $name);
 	}
 
 
-	/**
-	 * Disconnects from database (doesn't destroy Connection object).
-	 * @return void
-	 */
-	public static function disconnect()
-	{
-		self::getConnection()->disconnect();
-	}
-
-
 	/**
 	 * Returns true when connection was established.
-	 * @return bool
 	 */
-	public static function isConnected()
+	public static function isConnected(): bool
 	{
 		return (self::$connection !== null) && self::$connection->isConnected();
 	}
@@ -118,11 +104,9 @@ class dibi
 
 	/**
 	 * Retrieve active connection.
-	 * @param  string   connection registy name
-	 * @return Dibi\Connection
 	 * @throws Dibi\Exception
 	 */
-	public static function getConnection($name = null)
+	public static function getConnection(string $name = null): Dibi\Connection
 	{
 		if ($name === null) {
 			if (self::$connection === null) {
@@ -142,309 +126,65 @@ class dibi
 
 	/**
 	 * Sets connection.
-	 * @param  Dibi\Connection
-	 * @return Dibi\Connection
 	 */
-	public static function setConnection(Dibi\Connection $connection)
+	public static function setConnection(Dibi\Connection $connection): Dibi\Connection
 	{
 		return self::$connection = $connection;
 	}
 
 
-	/**
-	 * @deprecated
-	 */
-	public static function activate($name)
-	{
-		trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
-		self::$connection = self::getConnection($name);
-	}
-
-
 	/********************* monostate for active connection ****************d*g**/
 
 
 	/**
-	 * Generates and executes SQL query - Monostate for Dibi\Connection::query().
-	 * @param  array|mixed      one or more arguments
-	 * @return Dibi\Result|int   result set or number of affected rows
-	 * @throws Dibi\Exception
-	 */
-	public static function query($args)
-	{
-		$args = func_get_args();
-		return self::getConnection()->query($args);
-	}
-
-
-	/**
-	 * Executes the SQL query - Monostate for Dibi\Connection::nativeQuery().
-	 * @param  string           SQL statement.
-	 * @return Dibi\Result|int   result set or number of affected rows
-	 */
-	public static function nativeQuery($sql)
-	{
-		return self::getConnection()->nativeQuery($sql);
-	}
-
-
-	/**
-	 * Generates and prints SQL query - Monostate for Dibi\Connection::test().
-	 * @param  array|mixed  one or more arguments
-	 * @return bool
+	 * Monostate for Dibi\Connection.
 	 */
-	public static function test($args)
+	public static function __callStatic(string $name, array $args)
 	{
-		$args = func_get_args();
-		return self::getConnection()->test($args);
-	}
-
-
-	/**
-	 * Generates and returns SQL query as DataSource - Monostate for Dibi\Connection::test().
-	 * @param  array|mixed      one or more arguments
-	 * @return Dibi\DataSource
-	 */
-	public static function dataSource($args)
-	{
-		$args = func_get_args();
-		return self::getConnection()->dataSource($args);
-	}
-
-
-	/**
-	 * Executes SQL query and fetch result - Monostate for Dibi\Connection::query() & fetch().
-	 * @param  array|mixed    one or more arguments
-	 * @return Dibi\Row
-	 * @throws Dibi\Exception
-	 */
-	public static function fetch($args)
-	{
-		$args = func_get_args();
-		return self::getConnection()->query($args)->fetch();
-	}
-
-
-	/**
-	 * Executes SQL query and fetch results - Monostate for Dibi\Connection::query() & fetchAll().
-	 * @param  array|mixed    one or more arguments
-	 * @return Dibi\Row[]
-	 * @throws Dibi\Exception
-	 */
-	public static function fetchAll($args)
-	{
-		$args = func_get_args();
-		return self::getConnection()->query($args)->fetchAll();
-	}
-
-
-	/**
-	 * Executes SQL query and fetch first column - Monostate for Dibi\Connection::query() & fetchSingle().
-	 * @param  array|mixed    one or more arguments
-	 * @return mixed
-	 * @throws Dibi\Exception
-	 */
-	public static function fetchSingle($args)
-	{
-		$args = func_get_args();
-		return self::getConnection()->query($args)->fetchSingle();
-	}
-
-
-	/**
-	 * Executes SQL query and fetch pairs - Monostate for Dibi\Connection::query() & fetchPairs().
-	 * @param  array|mixed    one or more arguments
-	 * @return array
-	 * @throws Dibi\Exception
-	 */
-	public static function fetchPairs($args)
-	{
-		$args = func_get_args();
-		return self::getConnection()->query($args)->fetchPairs();
-	}
-
-
-	/**
-	 * Gets the number of affected rows.
-	 * Monostate for Dibi\Connection::getAffectedRows()
-	 * @return int  number of rows
-	 * @throws Dibi\Exception
-	 */
-	public static function getAffectedRows()
-	{
-		return self::getConnection()->getAffectedRows();
+		return self::getConnection()->$name(...$args);
 	}
 
 
 	/**
 	 * @deprecated
 	 */
-	public static function affectedRows()
+	public static function affectedRows(): int
 	{
 		trigger_error(__METHOD__ . '() is deprecated, use getAffectedRows()', E_USER_DEPRECATED);
 		return self::getConnection()->getAffectedRows();
 	}
 
 
-	/**
-	 * Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
-	 * Monostate for Dibi\Connection::getInsertId()
-	 * @param  string     optional sequence name
-	 * @return int
-	 * @throws Dibi\Exception
-	 */
-	public static function getInsertId($sequence = null)
-	{
-		return self::getConnection()->getInsertId($sequence);
-	}
-
-
 	/**
 	 * @deprecated
 	 */
-	public static function insertId($sequence = null)
+	public static function insertId(string $sequence = null): int
 	{
 		trigger_error(__METHOD__ . '() is deprecated, use getInsertId()', E_USER_DEPRECATED);
 		return self::getConnection()->getInsertId($sequence);
 	}
 
 
-	/**
-	 * Begins a transaction - Monostate for Dibi\Connection::begin().
-	 * @param  string  optional savepoint name
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public static function begin($savepoint = null)
-	{
-		self::getConnection()->begin($savepoint);
-	}
-
-
-	/**
-	 * Commits statements in a transaction - Monostate for Dibi\Connection::commit($savepoint = null).
-	 * @param  string  optional savepoint name
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public static function commit($savepoint = null)
-	{
-		self::getConnection()->commit($savepoint);
-	}
-
-
-	/**
-	 * Rollback changes in a transaction - Monostate for Dibi\Connection::rollback().
-	 * @param  string  optional savepoint name
-	 * @return void
-	 * @throws Dibi\Exception
-	 */
-	public static function rollback($savepoint = null)
-	{
-		self::getConnection()->rollback($savepoint);
-	}
-
-
-	/**
-	 * Gets a information about the current database - Monostate for Dibi\Connection::getDatabaseInfo().
-	 * @return Dibi\Reflection\Database
-	 */
-	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 Dibi\Helpers::loadFromFile(self::getConnection(), $file);
-	}
-
-
-	/********************* fluent SQL builders ****************d*g**/
-
-
-	/**
-	 * @return Dibi\Fluent
-	 */
-	public static function command()
-	{
-		return self::getConnection()->command();
-	}
-
-
-	/**
-	 * @param  mixed    column name
-	 * @return Dibi\Fluent
-	 */
-	public static function select($args)
-	{
-		$args = func_get_args();
-		return call_user_func_array([self::getConnection(), 'select'], $args);
-	}
-
-
-	/**
-	 * @param  string   table
-	 * @param  array
-	 * @return Dibi\Fluent
-	 */
-	public static function update($table, $args)
-	{
-		return self::getConnection()->update($table, $args);
-	}
-
-
-	/**
-	 * @param  string   table
-	 * @param  array
-	 * @return Dibi\Fluent
-	 */
-	public static function insert($table, $args)
-	{
-		return self::getConnection()->insert($table, $args);
-	}
-
-
-	/**
-	 * @param  string   table
-	 * @return Dibi\Fluent
-	 */
-	public static function delete($table)
-	{
-		return self::getConnection()->delete($table);
-	}
-
-
-	/********************* substitutions ****************d*g**/
+	/********************* misc tools ****************d*g**/
 
 
 	/**
-	 * Returns substitution hashmap - Monostate for Dibi\Connection::getSubstitutes().
-	 * @return Dibi\HashMap
+	 * Prints out a syntax highlighted version of the SQL command or Result.
+	 * @param  string|Dibi\Result  $sql
+	 * @param  bool  $return  return output instead of printing it?
 	 */
-	public static function getSubstitutes()
+	public static function dump($sql = null, bool $return = false): ?string
 	{
-		return self::getConnection()->getSubstitutes();
+		return Dibi\Helpers::dump($sql, $return);
 	}
 
 
-	/********************* misc tools ****************d*g**/
-
-
 	/**
-	 * Prints out a syntax highlighted version of the SQL command or Result.
-	 * @param  string|Result
-	 * @param  bool  return output instead of printing it?
-	 * @return string
+	 * Strips microseconds part.
 	 */
-	public static function dump($sql = null, $return = false)
+	public static function stripMicroseconds(\DateTimeInterface $dt): \DateTimeInterface
 	{
-		return Dibi\Helpers::dump($sql, $return);
+		$class = get_class($dt);
+		return new $class($dt->format('Y-m-d H:i:s'), $dt->getTimezone());
 	}
 }

+ 15 - 26
api/vendor/dibi/dibi/src/Dibi/exceptions.php

@@ -1,15 +1,17 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
 /**
- * dibi common exception.
+ * Dibi common exception.
  */
 class Exception extends \Exception
 {
@@ -18,32 +20,23 @@ class Exception extends \Exception
 
 
 	/**
-	 * Construct a dibi exception.
-	 * @param  string  Message describing the exception
-	 * @param  mixed
-	 * @param  string  SQL command
+	 * @param  int|string  $code
 	 */
-	public function __construct($message = '', $code = 0, $sql = null)
+	public function __construct(string $message = '', $code = 0, string $sql = null, \Throwable $previous = null)
 	{
-		parent::__construct($message);
+		parent::__construct($message, 0, $previous);
 		$this->code = $code;
 		$this->sql = $sql;
 	}
 
 
-	/**
-	 * @return string  The SQL passed to the constructor
-	 */
-	final public function getSql()
+	final public function getSql(): ?string
 	{
 		return $this->sql;
 	}
 
 
-	/**
-	 * @return string  string represenation of exception with SQL command
-	 */
-	public function __toString()
+	public function __toString(): string
 	{
 		return parent::__toString() . ($this->sql ? "\nSQL: " . $this->sql : '');
 	}
@@ -63,7 +56,7 @@ class DriverException extends Exception
  */
 class PcreException extends Exception
 {
-	public function __construct($message = '%msg.')
+	public function __construct(string $message = '%msg.')
 	{
 		static $messages = [
 			PREG_INTERNAL_ERROR => 'Internal error',
@@ -73,7 +66,7 @@ class PcreException extends Exception
 			5 => 'Offset didn\'t correspond to the begin of a valid UTF-8 code point', // PREG_BAD_UTF8_OFFSET_ERROR
 		];
 		$code = preg_last_error();
-		parent::__construct(str_replace('%msg', isset($messages[$code]) ? $messages[$code] : 'Unknown error', $message), $code);
+		parent::__construct(str_replace('%msg', $messages[$code] ?? 'Unknown error', $message), $code);
 	}
 }
 
@@ -99,24 +92,20 @@ class ProcedureException extends Exception
 
 	/**
 	 * 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)
+	public function __construct(string $message = '', int $code = 0, string $severity = '', string $sql = null)
 	{
-		parent::__construct($message, (int) $code, $sql);
+		parent::__construct($message, $code, $sql);
 		$this->severity = $severity;
 	}
 
 
 	/**
 	 * Gets the exception severity.
-	 * @return string
 	 */
-	public function getSeverity()
+	public function getSeverity(): string
 	{
-		$this->severity;
+		return $this->severity;
 	}
 }
 

+ 96 - 91
api/vendor/dibi/dibi/src/Dibi/interfaces.php

@@ -1,10 +1,12 @@
 <?php
 
 /**
- * This file is part of the "dibi" - smart database abstraction layer.
+ * 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;
 
 
@@ -19,69 +21,49 @@ interface IDataSource extends \Countable, \IteratorAggregate
 
 
 /**
- * dibi driver interface.
+ * Driver interface.
  */
 interface Driver
 {
-
-	/**
-	 * Connects to a database.
-	 * @param  array
-	 * @return void
-	 * @throws Exception
-	 */
-	function connect(array &$config);
-
 	/**
 	 * Disconnects from a database.
-	 * @return void
 	 * @throws Exception
 	 */
-	function disconnect();
+	function disconnect(): void;
 
 	/**
 	 * Internal: Executes the SQL query.
-	 * @param  string      SQL statement.
-	 * @return ResultDriver|null
 	 * @throws DriverException
 	 */
-	function query($sql);
+	function query(string $sql): ?ResultDriver;
 
 	/**
 	 * 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();
+	function getAffectedRows(): ?int;
 
 	/**
 	 * 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);
+	function getInsertId(?string $sequence): ?int;
 
 	/**
 	 * Begins a transaction (if supported).
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws DriverException
 	 */
-	function begin($savepoint = null);
+	function begin(string $savepoint = null): void;
 
 	/**
 	 * Commits statements in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws DriverException
 	 */
-	function commit($savepoint = null);
+	function commit(string $savepoint = null): void;
 
 	/**
 	 * Rollback changes in a transaction.
-	 * @param  string  optional savepoint name
-	 * @return void
 	 * @throws DriverException
 	 */
-	function rollback($savepoint = null);
+	function rollback(string $savepoint = null): void;
 
 	/**
 	 * Returns the connection resource.
@@ -91,106 +73,76 @@ interface Driver
 
 	/**
 	 * Returns the connection reflector.
-	 * @return Reflector
 	 */
-	function getReflector();
+	function getReflector(): Reflector;
 
 	/**
 	 * Encodes data for use in a SQL statement.
-	 * @param  string    value
-	 * @return string    encoded value
 	 */
-	function escapeText($value);
+	function escapeText(string $value): string;
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	function escapeBinary($value);
+	function escapeBinary(string $value): string;
 
-	/**
-	 * @param  string
-	 * @return string
-	 */
-	function escapeIdentifier($value);
+	function escapeIdentifier(string $value): string;
 
-	/**
-	 * @param  bool
-	 * @return string
-	 */
-	function escapeBool($value);
+	function escapeBool(bool $value): string;
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	function escapeDate($value);
+	function escapeDate($value): string;
 
 	/**
-	 * @param  \DateTime|\DateTimeInterface|string|int
-	 * @return string
+	 * @param  \DateTimeInterface|string|int  $value
 	 */
-	function escapeDateTime($value);
+	function escapeDateTime($value): string;
 
 	/**
 	 * Encodes string for use in a LIKE statement.
-	 * @param  string
-	 * @param  int
-	 * @return string
 	 */
-	function escapeLike($value, $pos);
+	function escapeLike(string $value, int $pos): string;
 
 	/**
 	 * Injects LIMIT/OFFSET to the SQL query.
-	 * @param  string
-	 * @param  int|null
-	 * @param  int|null
-	 * @return void
 	 */
-	function applyLimit(&$sql, $limit, $offset);
+	function applyLimit(string &$sql, ?int $limit, ?int $offset): void;
 }
 
 
 /**
- * dibi result set driver interface.
+ * Result set driver interface.
  */
 interface ResultDriver
 {
-
 	/**
 	 * Returns the number of rows in a result set.
-	 * @return int
 	 */
-	function getRowCount();
+	function getRowCount(): int;
 
 	/**
 	 * Moves cursor position without fetching row.
-	 * @param  int      the 0-based cursor pos to seek to
-	 * @return bool     true on success, false if unable to seek to specified record
+	 * @return bool  true on success, false if unable to seek to specified record
 	 * @throws Exception
 	 */
-	function seek($row);
+	function seek(int $row): bool;
 
 	/**
 	 * 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
+	 * @param  bool  $type  true for associative array, false for numeric
 	 * @internal
 	 */
-	function fetch($type);
+	function fetch(bool $type): ?array;
 
 	/**
 	 * Frees the resources allocated for this result set.
-	 * @param  resource  result set resource
-	 * @return void
 	 */
-	function free();
+	function free(): void;
 
 	/**
 	 * Returns metadata for all columns in a result set.
 	 * @return array of {name, nativetype [, table, fullname, (int) size, (bool) nullable, (mixed) default, (bool) autoincrement, (array) vendor ]}
 	 */
-	function getResultColumns();
+	function getResultColumns(): array;
 
 	/**
 	 * Returns the result set resource.
@@ -200,43 +152,96 @@ interface ResultDriver
 
 	/**
 	 * Decodes data from result set.
-	 * @param  string
-	 * @return string
 	 */
-	function unescapeBinary($value);
+	function unescapeBinary(string $value): string;
 }
 
 
 /**
- * dibi driver reflection.
+ * Reflection driver.
  */
 interface Reflector
 {
-
 	/**
 	 * Returns list of tables.
 	 * @return array of {name [, (bool) view ]}
 	 */
-	function getTables();
+	function getTables(): array;
 
 	/**
 	 * Returns metadata for all columns in a table.
-	 * @param  string
 	 * @return array of {name, nativetype [, table, fullname, (int) size, (bool) nullable, (mixed) default, (bool) autoincrement, (array) vendor ]}
 	 */
-	function getColumns($table);
+	function getColumns(string $table): array;
 
 	/**
 	 * Returns metadata for all indexes in a table.
-	 * @param  string
 	 * @return array of {name, (array of names) columns [, (bool) unique, (bool) primary ]}
 	 */
-	function getIndexes($table);
+	function getIndexes(string $table): array;
 
 	/**
 	 * Returns metadata for all foreign keys in a table.
-	 * @param  string
-	 * @return array
 	 */
-	function getForeignKeys($table);
+	function getForeignKeys(string $table): array;
+}
+
+
+/**
+ * Dibi connection.
+ */
+interface IConnection
+{
+	/**
+	 * Connects to a database.
+	 */
+	function connect(): void;
+
+	/**
+	 * Disconnects from a database.
+	 */
+	function disconnect(): void;
+
+	/**
+	 * Returns true when connection was established.
+	 */
+	function isConnected(): bool;
+
+	/**
+	 * Returns the driver and connects to a database in lazy mode.
+	 */
+	function getDriver(): Driver;
+
+	/**
+	 * Generates (translates) and executes SQL query.
+	 * @throws Exception
+	 */
+	function query(...$args): Result;
+
+	/**
+	 * Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
+	 * @throws Exception
+	 */
+	function getAffectedRows(): int;
+
+	/**
+	 * Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
+	 * @throws Exception
+	 */
+	function getInsertId(string $sequence = null): int;
+
+	/**
+	 * Begins a transaction (if supported).
+	 */
+	function begin(string $savepoint = null): void;
+
+	/**
+	 * Commits statements in a transaction.
+	 */
+	function commit(string $savepoint = null): void;
+
+	/**
+	 * Rollback changes in a transaction.
+	 */
+	function rollback(string $savepoint = null): void;
 }

+ 0 - 140
api/vendor/dibi/dibi/src/loader.php

@@ -1,140 +0,0 @@
-<?php
-
-/**
- * This file is part of the "dibi" - smart database abstraction layer.
- * Copyright (c) 2005 David Grudl (https://davidgrudl.com)
- */
-
-
-if (PHP_VERSION_ID < 50404) {
-	throw new Exception('Dibi requires PHP 5.4.4 or newer.');
-}
-
-
-spl_autoload_register(function ($class) {
-	static $map = [
-		'dibi' => 'dibi.php',
-		'Dibi\Bridges\Nette\DibiExtension22' => 'Bridges/Nette/DibiExtension22.php',
-		'Dibi\Bridges\Tracy\Panel' => 'Bridges/Tracy/Panel.php',
-		'Dibi\Connection' => 'Connection.php',
-		'Dibi\DataSource' => 'DataSource.php',
-		'Dibi\DateTime' => 'DateTime.php',
-		'Dibi\Driver' => 'interfaces.php',
-		'Dibi\DriverException' => 'exceptions.php',
-		'Dibi\Drivers\FirebirdDriver' => 'Drivers/FirebirdDriver.php',
-		'Dibi\Drivers\SqlsrvDriver' => 'Drivers/SqlsrvDriver.php',
-		'Dibi\Drivers\SqlsrvReflector' => 'Drivers/SqlsrvReflector.php',
-		'Dibi\Drivers\MsSqlDriver' => 'Drivers/MsSqlDriver.php',
-		'Dibi\Drivers\MsSqlReflector' => 'Drivers/MsSqlReflector.php',
-		'Dibi\Drivers\MySqlDriver' => 'Drivers/MySqlDriver.php',
-		'Dibi\Drivers\MySqliDriver' => 'Drivers/MySqliDriver.php',
-		'Dibi\Drivers\MySqlReflector' => 'Drivers/MySqlReflector.php',
-		'Dibi\Drivers\OdbcDriver' => 'Drivers/OdbcDriver.php',
-		'Dibi\Drivers\OracleDriver' => 'Drivers/OracleDriver.php',
-		'Dibi\Drivers\PdoDriver' => 'Drivers/PdoDriver.php',
-		'Dibi\Drivers\PostgreDriver' => 'Drivers/PostgreDriver.php',
-		'Dibi\Drivers\Sqlite3Driver' => 'Drivers/Sqlite3Driver.php',
-		'Dibi\Drivers\SqliteReflector' => 'Drivers/SqliteReflector.php',
-		'Dibi\Event' => 'Event.php',
-		'Dibi\Exception' => 'exceptions.php',
-		'Dibi\Fluent' => 'Fluent.php',
-		'Dibi\HashMap' => 'HashMap.php',
-		'Dibi\HashMapBase' => 'HashMap.php',
-		'Dibi\Helpers' => 'Helpers.php',
-		'Dibi\IDataSource' => 'interfaces.php',
-		'Dibi\Literal' => 'Literal.php',
-		'Dibi\Loggers\FileLogger' => 'Loggers/FileLogger.php',
-		'Dibi\Loggers\FirePhpLogger' => 'Loggers/FirePhpLogger.php',
-		'Dibi\NotImplementedException' => 'exceptions.php',
-		'Dibi\NotSupportedException' => 'exceptions.php',
-		'Dibi\PcreException' => 'exceptions.php',
-		'Dibi\ProcedureException' => 'exceptions.php',
-		'Dibi\Reflection\Column' => 'Reflection/Column.php',
-		'Dibi\Reflection\Database' => 'Reflection/Database.php',
-		'Dibi\Reflection\ForeignKey' => 'Reflection/ForeignKey.php',
-		'Dibi\Reflection\Index' => 'Reflection/Index.php',
-		'Dibi\Reflection\Result' => 'Reflection/Result.php',
-		'Dibi\Reflection\Table' => 'Reflection/Table.php',
-		'Dibi\Reflector' => 'interfaces.php',
-		'Dibi\Result' => 'Result.php',
-		'Dibi\ResultDriver' => 'interfaces.php',
-		'Dibi\ResultIterator' => 'ResultIterator.php',
-		'Dibi\Row' => 'Row.php',
-		'Dibi\Strict' => 'Strict.php',
-		'Dibi\Translator' => 'Translator.php',
-		'Dibi\Type' => 'Type.php',
-	], $old2new = [
-		'Dibi' => 'dibi.php',
-		'DibiColumnInfo' => 'Dibi\Reflection\Column',
-		'DibiConnection' => 'Dibi\Connection',
-		'DibiDatabaseInfo' => 'Dibi\Reflection\Database',
-		'DibiDataSource' => 'Dibi\DataSource',
-		'DibiDateTime' => 'Dibi\DateTime',
-		'DibiDriverException' => 'Dibi\DriverException',
-		'DibiEvent' => 'Dibi\Event',
-		'DibiException' => 'Dibi\Exception',
-		'DibiFileLogger' => 'Dibi\Loggers\FileLogger',
-		'DibiFirebirdDriver' => 'Dibi\Drivers\FirebirdDriver',
-		'DibiFirePhpLogger' => 'Dibi\Loggers\FirePhpLogger',
-		'DibiFluent' => 'Dibi\Fluent',
-		'DibiForeignKeyInfo' => 'Dibi\Reflection\ForeignKey',
-		'DibiHashMap' => 'Dibi\HashMap',
-		'DibiHashMapBase' => 'Dibi\HashMapBase',
-		'DibiIndexInfo' => 'Dibi\Reflection\Index',
-		'DibiLiteral' => 'Dibi\Literal',
-		'DibiMsSql2005Driver' => 'Dibi\Drivers\SqlsrvDriver',
-		'DibiMsSql2005Reflector' => 'Dibi\Drivers\SqlsrvReflector',
-		'DibiMsSqlDriver' => 'Dibi\Drivers\MsSqlDriver',
-		'DibiMsSqlReflector' => 'Dibi\Drivers\MsSqlReflector',
-		'DibiMySqlDriver' => 'Dibi\Drivers\MySqlDriver',
-		'DibiMySqliDriver' => 'Dibi\Drivers\MySqliDriver',
-		'DibiMySqlReflector' => 'Dibi\Drivers\MySqlReflector',
-		'DibiNotImplementedException' => 'Dibi\NotImplementedException',
-		'DibiNotSupportedException' => 'Dibi\NotSupportedException',
-		'DibiOdbcDriver' => 'Dibi\Drivers\OdbcDriver',
-		'DibiOracleDriver' => 'Dibi\Drivers\OracleDriver',
-		'DibiPcreException' => 'Dibi\PcreException',
-		'DibiPdoDriver' => 'Dibi\Drivers\PdoDriver',
-		'DibiPostgreDriver' => 'Dibi\Drivers\PostgreDriver',
-		'DibiProcedureException' => 'Dibi\ProcedureException',
-		'DibiResult' => 'Dibi\Result',
-		'DibiResultInfo' => 'Dibi\Reflection\Result',
-		'DibiResultIterator' => 'Dibi\ResultIterator',
-		'DibiRow' => 'Dibi\Row',
-		'DibiSqlite3Driver' => 'Dibi\Drivers\Sqlite3Driver',
-		'DibiSqliteReflector' => 'Dibi\Drivers\SqliteReflector',
-		'DibiTableInfo' => 'Dibi\Reflection\Table',
-		'DibiTranslator' => 'Dibi\Translator',
-		'IDataSource' => 'Dibi\IDataSource',
-		'IDibiDriver' => 'Dibi\Driver',
-		'IDibiReflector' => 'Dibi\Reflector',
-		'IDibiResultDriver' => 'Dibi\ResultDriver',
-		'Dibi\Drivers\MsSql2005Driver' => 'Dibi\Drivers\SqlsrvDriver',
-		'Dibi\Drivers\MsSql2005Reflector' => 'Dibi\Drivers\SqlsrvReflector',
-	];
-	if (isset($map[$class])) {
-		require __DIR__ . '/Dibi/' . $map[$class];
-	} elseif (isset($old2new[$class])) {
-		class_alias($old2new[$class], $class);
-	}
-});
-
-
-// preload for compatiblity
-array_map('class_exists', [
-	'DibiConnection',
-	'DibiDateTime',
-	'DibiDriverException',
-	'DibiEvent',
-	'DibiException',
-	'DibiFluent',
-	'DibiLiteral',
-	'DibiNotImplementedException',
-	'DibiNotSupportedException',
-	'DibiPcreException',
-	'DibiProcedureException',
-	'DibiResult',
-	'DibiRow',
-	'IDataSource',
-	'IDibiDriver',
-]);