├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build.php ├── composer.json ├── composer.lock ├── demo ├── setup-how-to-integrate.php ├── usage-native-pdo.php ├── usage-query-builder.php └── usage-short-cut-methods.php ├── init.php ├── phpunit.xml ├── src ├── Builder.php ├── Builder │ ├── Delete.php │ ├── Ignore.php │ ├── Insert.php │ ├── Replace.php │ ├── Select.php │ └── Update.php ├── Configuration.php ├── Helpers.php ├── Library.php ├── Native.php ├── Report.php ├── Report │ └── Database │ │ └── Structure.php └── Server.php └── tests ├── LibraryTest.php └── bootstrap.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | composer 4 | demo/index.php 5 | clover.xml 6 | vendor -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | sudo: false 3 | 4 | matrix: 5 | fast_finish: true 6 | include: 7 | - php: 5.5 8 | - php: 5.6 9 | - php: 7.0 10 | - php: 7.1 11 | - php: 7.2 12 | - php: 8.0 13 | - php: 8.1 14 | - php: 8.2 15 | 16 | before_script: 17 | - composer self-update 18 | - composer install --prefer-source --no-progress --no-interaction 19 | 20 | script: 21 | - vendor/bin/phpunit 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Kodols 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MySQL Library for PHP 2 | 3 | [![Build Status](https://travis-ci.org/kodols/php-mysql-library.svg?branch=master)](https://travis-ci.org/kodols/php-mysql-library) 4 | [![Latest Stable Version](https://poser.pugx.org/kodols/PHP-MySQL-Library/v/stable.svg)](https://packagist.org/packages/kodols/php-mysql-library) 5 | [![Total Downloads](https://poser.pugx.org/kodols/PHP-MySQL-Library/downloads.svg)](packagist.org/packages/kodols/php-mysql-library) 6 | [![License](https://poser.pugx.org/kodols/PHP-MySQL-Library/license.svg)](packagist.org/packages/kodols/php-mysql-library) 7 | 8 | This library will give you access to everything you need from MySQL in PHP. 9 | 10 | See our [Object Reference](https://github.com/kodols/PHP-MySQL-Library/wiki) to learn what is possible, or view our [demo folder](https://github.com/kodols/PHP-MySQL-Library/tree/master/demo) for examples. 11 | 12 | ## About 13 | 14 | The library is a hybrid between PHP's PDO and generic query building. 15 | 16 | Started as a helper class for in-house projects and grown into a usefull tool for Kodols Ltd. A decision was made to make this library public give others the chance to use a well oriented library for database management. 17 | 18 | Library will keep getting support and upgrades as this has been become the goto library for Kodols Ltd. to use for our projects. 19 | 20 | This library supports access to the native PDO methods, few helper methods to simplify commonly used methods and a query builder to really give you access to build cool statements. 21 | 22 | ### Prerequisites 23 | 24 | This library will work on PHP 5.4 or later 25 | 26 | ### Installing 27 | 28 | You can clone this git repository into your project 29 | 30 | ``` 31 | git clone git://github.com/kodols/PHP-MySQL-Library.git 32 | ``` 33 | 34 | or you can use composer 35 | 36 | ``` 37 | composer require kodols/php-mysql-library 38 | ``` 39 | 40 | ## Deployment 41 | 42 | The integration process is very simple, you call the main library class, add a configuration and you are all set. 43 | However we would recommend spend some time to really prepare the environment so you get the best out of this library. 44 | The library is based in `src/` with its namespace `\Kodols\MySQL`. In our examples we will use a demo variable $KML (Kodols MySQL Library), but of course you can use any variable you like. 45 | 46 | ``` 47 | $KML = new \Kodols\MySQL\Library; 48 | ``` 49 | 50 | Once you have successfuly create the object you need to add MySQL connection details to it. The library supports multiple configurations attached and multiple connections established in the same request. 51 | 52 | ``` 53 | $config = $KML->newConfiguration(); 54 | $config->setHostname('my.host.com'); 55 | $config->setUsername('web'); 56 | $config->setPassword('42412'); 57 | $config->setDatabase('project'); 58 | ``` 59 | The `$config` variable is `\Kodols\MySQL\Configuration` object, see Wiki for in depth details. 60 | 61 | Once configuration is created you can attach it to the main library via `$KML->attachConfiguration($config);` and start using the library. However if your environment has multiple database endpoints, or maybe you have production, development and local environment, then you can setup it as follows: 62 | ``` 63 | $config = $KML->newConfiguration(); 64 | $config->setHostname('my.host.com'); 65 | ... 66 | $KML->attachConfiguration($config, 'live'); 67 | ``` 68 | So when you call the server variable you can choose with of the server endpoints you want to use. 69 | 70 | ## Contributors 71 | 72 | We welcome a good idea, bug fixes, suggestions and requests. 73 | This list will be updated every time a new contribution has been made. 74 | 75 | * **Edgars Kohs** - *author* - [Kodols Ltd.](http://www.kodols.com) 76 | 77 | ## License 78 | 79 | This project is licensed under the MIT License - see the [https://github.com/kodols/php-mysql-library/blob/master/LICENSE](LICENSE) file for details 80 | -------------------------------------------------------------------------------- /build.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | =5.3.3" 96 | }, 97 | "require-dev": { 98 | "phpunit/phpunit": "~4.0" 99 | }, 100 | "suggest": { 101 | "dflydev/markdown": "~1.0", 102 | "erusev/parsedown": "~1.0" 103 | }, 104 | "type": "library", 105 | "extra": { 106 | "branch-alias": { 107 | "dev-master": "2.0.x-dev" 108 | } 109 | }, 110 | "autoload": { 111 | "psr-0": { 112 | "phpDocumentor": [ 113 | "src/" 114 | ] 115 | } 116 | }, 117 | "notification-url": "https://packagist.org/downloads/", 118 | "license": [ 119 | "MIT" 120 | ], 121 | "authors": [ 122 | { 123 | "name": "Mike van Riel", 124 | "email": "mike.vanriel@naenius.com" 125 | } 126 | ], 127 | "support": { 128 | "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", 129 | "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/2.x" 130 | }, 131 | "time": "2016-01-25T08:17:30+00:00" 132 | }, 133 | { 134 | "name": "phpspec/prophecy", 135 | "version": "v1.5.0", 136 | "source": { 137 | "type": "git", 138 | "url": "https://github.com/phpspec/prophecy.git", 139 | "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7" 140 | }, 141 | "dist": { 142 | "type": "zip", 143 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7", 144 | "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7", 145 | "shasum": "" 146 | }, 147 | "require": { 148 | "doctrine/instantiator": "^1.0.2", 149 | "phpdocumentor/reflection-docblock": "~2.0", 150 | "sebastian/comparator": "~1.1" 151 | }, 152 | "require-dev": { 153 | "phpspec/phpspec": "~2.0" 154 | }, 155 | "type": "library", 156 | "extra": { 157 | "branch-alias": { 158 | "dev-master": "1.4.x-dev" 159 | } 160 | }, 161 | "autoload": { 162 | "psr-0": { 163 | "Prophecy\\": "src/" 164 | } 165 | }, 166 | "notification-url": "https://packagist.org/downloads/", 167 | "license": [ 168 | "MIT" 169 | ], 170 | "authors": [ 171 | { 172 | "name": "Konstantin Kudryashov", 173 | "email": "ever.zet@gmail.com", 174 | "homepage": "http://everzet.com" 175 | }, 176 | { 177 | "name": "Marcello Duarte", 178 | "email": "marcello.duarte@gmail.com" 179 | } 180 | ], 181 | "description": "Highly opinionated mocking framework for PHP 5.3+", 182 | "homepage": "https://github.com/phpspec/prophecy", 183 | "keywords": [ 184 | "Double", 185 | "Dummy", 186 | "fake", 187 | "mock", 188 | "spy", 189 | "stub" 190 | ], 191 | "support": { 192 | "issues": "https://github.com/phpspec/prophecy/issues", 193 | "source": "https://github.com/phpspec/prophecy/tree/master" 194 | }, 195 | "time": "2015-08-13T10:07:40+00:00" 196 | }, 197 | { 198 | "name": "phpunit/php-code-coverage", 199 | "version": "2.2.4", 200 | "source": { 201 | "type": "git", 202 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 203 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" 204 | }, 205 | "dist": { 206 | "type": "zip", 207 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", 208 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", 209 | "shasum": "" 210 | }, 211 | "require": { 212 | "php": ">=5.3.3", 213 | "phpunit/php-file-iterator": "~1.3", 214 | "phpunit/php-text-template": "~1.2", 215 | "phpunit/php-token-stream": "~1.3", 216 | "sebastian/environment": "^1.3.2", 217 | "sebastian/version": "~1.0" 218 | }, 219 | "require-dev": { 220 | "ext-xdebug": ">=2.1.4", 221 | "phpunit/phpunit": "~4" 222 | }, 223 | "suggest": { 224 | "ext-dom": "*", 225 | "ext-xdebug": ">=2.2.1", 226 | "ext-xmlwriter": "*" 227 | }, 228 | "type": "library", 229 | "extra": { 230 | "branch-alias": { 231 | "dev-master": "2.2.x-dev" 232 | } 233 | }, 234 | "autoload": { 235 | "classmap": [ 236 | "src/" 237 | ] 238 | }, 239 | "notification-url": "https://packagist.org/downloads/", 240 | "license": [ 241 | "BSD-3-Clause" 242 | ], 243 | "authors": [ 244 | { 245 | "name": "Sebastian Bergmann", 246 | "email": "sb@sebastian-bergmann.de", 247 | "role": "lead" 248 | } 249 | ], 250 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 251 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 252 | "keywords": [ 253 | "coverage", 254 | "testing", 255 | "xunit" 256 | ], 257 | "support": { 258 | "irc": "irc://irc.freenode.net/phpunit", 259 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", 260 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/2.2" 261 | }, 262 | "time": "2015-10-06T15:47:00+00:00" 263 | }, 264 | { 265 | "name": "phpunit/php-file-iterator", 266 | "version": "1.4.5", 267 | "source": { 268 | "type": "git", 269 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 270 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" 271 | }, 272 | "dist": { 273 | "type": "zip", 274 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", 275 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", 276 | "shasum": "" 277 | }, 278 | "require": { 279 | "php": ">=5.3.3" 280 | }, 281 | "type": "library", 282 | "extra": { 283 | "branch-alias": { 284 | "dev-master": "1.4.x-dev" 285 | } 286 | }, 287 | "autoload": { 288 | "classmap": [ 289 | "src/" 290 | ] 291 | }, 292 | "notification-url": "https://packagist.org/downloads/", 293 | "license": [ 294 | "BSD-3-Clause" 295 | ], 296 | "authors": [ 297 | { 298 | "name": "Sebastian Bergmann", 299 | "email": "sb@sebastian-bergmann.de", 300 | "role": "lead" 301 | } 302 | ], 303 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 304 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 305 | "keywords": [ 306 | "filesystem", 307 | "iterator" 308 | ], 309 | "support": { 310 | "irc": "irc://irc.freenode.net/phpunit", 311 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", 312 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5" 313 | }, 314 | "time": "2017-11-27T13:52:08+00:00" 315 | }, 316 | { 317 | "name": "phpunit/php-text-template", 318 | "version": "1.2.1", 319 | "source": { 320 | "type": "git", 321 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 322 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 323 | }, 324 | "dist": { 325 | "type": "zip", 326 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 327 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 328 | "shasum": "" 329 | }, 330 | "require": { 331 | "php": ">=5.3.3" 332 | }, 333 | "type": "library", 334 | "autoload": { 335 | "classmap": [ 336 | "src/" 337 | ] 338 | }, 339 | "notification-url": "https://packagist.org/downloads/", 340 | "license": [ 341 | "BSD-3-Clause" 342 | ], 343 | "authors": [ 344 | { 345 | "name": "Sebastian Bergmann", 346 | "email": "sebastian@phpunit.de", 347 | "role": "lead" 348 | } 349 | ], 350 | "description": "Simple template engine.", 351 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 352 | "keywords": [ 353 | "template" 354 | ], 355 | "support": { 356 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues", 357 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" 358 | }, 359 | "time": "2015-06-21T13:50:34+00:00" 360 | }, 361 | { 362 | "name": "phpunit/php-timer", 363 | "version": "1.0.8", 364 | "source": { 365 | "type": "git", 366 | "url": "https://github.com/sebastianbergmann/php-timer.git", 367 | "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" 368 | }, 369 | "dist": { 370 | "type": "zip", 371 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", 372 | "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", 373 | "shasum": "" 374 | }, 375 | "require": { 376 | "php": ">=5.3.3" 377 | }, 378 | "require-dev": { 379 | "phpunit/phpunit": "~4|~5" 380 | }, 381 | "type": "library", 382 | "autoload": { 383 | "classmap": [ 384 | "src/" 385 | ] 386 | }, 387 | "notification-url": "https://packagist.org/downloads/", 388 | "license": [ 389 | "BSD-3-Clause" 390 | ], 391 | "authors": [ 392 | { 393 | "name": "Sebastian Bergmann", 394 | "email": "sb@sebastian-bergmann.de", 395 | "role": "lead" 396 | } 397 | ], 398 | "description": "Utility class for timing", 399 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 400 | "keywords": [ 401 | "timer" 402 | ], 403 | "support": { 404 | "irc": "irc://irc.freenode.net/phpunit", 405 | "issues": "https://github.com/sebastianbergmann/php-timer/issues", 406 | "source": "https://github.com/sebastianbergmann/php-timer/tree/master" 407 | }, 408 | "time": "2016-05-12T18:03:57+00:00" 409 | }, 410 | { 411 | "name": "phpunit/php-token-stream", 412 | "version": "1.4.12", 413 | "source": { 414 | "type": "git", 415 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 416 | "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" 417 | }, 418 | "dist": { 419 | "type": "zip", 420 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", 421 | "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", 422 | "shasum": "" 423 | }, 424 | "require": { 425 | "ext-tokenizer": "*", 426 | "php": ">=5.3.3" 427 | }, 428 | "require-dev": { 429 | "phpunit/phpunit": "~4.2" 430 | }, 431 | "type": "library", 432 | "extra": { 433 | "branch-alias": { 434 | "dev-master": "1.4-dev" 435 | } 436 | }, 437 | "autoload": { 438 | "classmap": [ 439 | "src/" 440 | ] 441 | }, 442 | "notification-url": "https://packagist.org/downloads/", 443 | "license": [ 444 | "BSD-3-Clause" 445 | ], 446 | "authors": [ 447 | { 448 | "name": "Sebastian Bergmann", 449 | "email": "sebastian@phpunit.de" 450 | } 451 | ], 452 | "description": "Wrapper around PHP's tokenizer extension.", 453 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 454 | "keywords": [ 455 | "tokenizer" 456 | ], 457 | "support": { 458 | "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", 459 | "source": "https://github.com/sebastianbergmann/php-token-stream/tree/1.4" 460 | }, 461 | "abandoned": true, 462 | "time": "2017-12-04T08:55:13+00:00" 463 | }, 464 | { 465 | "name": "phpunit/phpunit", 466 | "version": "4.8.36", 467 | "source": { 468 | "type": "git", 469 | "url": "https://github.com/sebastianbergmann/phpunit.git", 470 | "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" 471 | }, 472 | "dist": { 473 | "type": "zip", 474 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", 475 | "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", 476 | "shasum": "" 477 | }, 478 | "require": { 479 | "ext-dom": "*", 480 | "ext-json": "*", 481 | "ext-pcre": "*", 482 | "ext-reflection": "*", 483 | "ext-spl": "*", 484 | "php": ">=5.3.3", 485 | "phpspec/prophecy": "^1.3.1", 486 | "phpunit/php-code-coverage": "~2.1", 487 | "phpunit/php-file-iterator": "~1.4", 488 | "phpunit/php-text-template": "~1.2", 489 | "phpunit/php-timer": "^1.0.6", 490 | "phpunit/phpunit-mock-objects": "~2.3", 491 | "sebastian/comparator": "~1.2.2", 492 | "sebastian/diff": "~1.2", 493 | "sebastian/environment": "~1.3", 494 | "sebastian/exporter": "~1.2", 495 | "sebastian/global-state": "~1.0", 496 | "sebastian/version": "~1.0", 497 | "symfony/yaml": "~2.1|~3.0" 498 | }, 499 | "suggest": { 500 | "phpunit/php-invoker": "~1.1" 501 | }, 502 | "bin": [ 503 | "phpunit" 504 | ], 505 | "type": "library", 506 | "extra": { 507 | "branch-alias": { 508 | "dev-master": "4.8.x-dev" 509 | } 510 | }, 511 | "autoload": { 512 | "classmap": [ 513 | "src/" 514 | ] 515 | }, 516 | "notification-url": "https://packagist.org/downloads/", 517 | "license": [ 518 | "BSD-3-Clause" 519 | ], 520 | "authors": [ 521 | { 522 | "name": "Sebastian Bergmann", 523 | "email": "sebastian@phpunit.de", 524 | "role": "lead" 525 | } 526 | ], 527 | "description": "The PHP Unit Testing framework.", 528 | "homepage": "https://phpunit.de/", 529 | "keywords": [ 530 | "phpunit", 531 | "testing", 532 | "xunit" 533 | ], 534 | "support": { 535 | "issues": "https://github.com/sebastianbergmann/phpunit/issues", 536 | "source": "https://github.com/sebastianbergmann/phpunit/tree/4.8.36" 537 | }, 538 | "time": "2017-06-21T08:07:12+00:00" 539 | }, 540 | { 541 | "name": "phpunit/phpunit-mock-objects", 542 | "version": "2.3.8", 543 | "source": { 544 | "type": "git", 545 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 546 | "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" 547 | }, 548 | "dist": { 549 | "type": "zip", 550 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", 551 | "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", 552 | "shasum": "" 553 | }, 554 | "require": { 555 | "doctrine/instantiator": "^1.0.2", 556 | "php": ">=5.3.3", 557 | "phpunit/php-text-template": "~1.2", 558 | "sebastian/exporter": "~1.2" 559 | }, 560 | "require-dev": { 561 | "phpunit/phpunit": "~4.4" 562 | }, 563 | "suggest": { 564 | "ext-soap": "*" 565 | }, 566 | "type": "library", 567 | "extra": { 568 | "branch-alias": { 569 | "dev-master": "2.3.x-dev" 570 | } 571 | }, 572 | "autoload": { 573 | "classmap": [ 574 | "src/" 575 | ] 576 | }, 577 | "notification-url": "https://packagist.org/downloads/", 578 | "license": [ 579 | "BSD-3-Clause" 580 | ], 581 | "authors": [ 582 | { 583 | "name": "Sebastian Bergmann", 584 | "email": "sb@sebastian-bergmann.de", 585 | "role": "lead" 586 | } 587 | ], 588 | "description": "Mock Object library for PHPUnit", 589 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 590 | "keywords": [ 591 | "mock", 592 | "xunit" 593 | ], 594 | "support": { 595 | "irc": "irc://irc.freenode.net/phpunit", 596 | "issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues", 597 | "source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/2.3" 598 | }, 599 | "abandoned": true, 600 | "time": "2015-10-02T06:51:40+00:00" 601 | }, 602 | { 603 | "name": "sebastian/comparator", 604 | "version": "1.2.4", 605 | "source": { 606 | "type": "git", 607 | "url": "https://github.com/sebastianbergmann/comparator.git", 608 | "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" 609 | }, 610 | "dist": { 611 | "type": "zip", 612 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", 613 | "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", 614 | "shasum": "" 615 | }, 616 | "require": { 617 | "php": ">=5.3.3", 618 | "sebastian/diff": "~1.2", 619 | "sebastian/exporter": "~1.2 || ~2.0" 620 | }, 621 | "require-dev": { 622 | "phpunit/phpunit": "~4.4" 623 | }, 624 | "type": "library", 625 | "extra": { 626 | "branch-alias": { 627 | "dev-master": "1.2.x-dev" 628 | } 629 | }, 630 | "autoload": { 631 | "classmap": [ 632 | "src/" 633 | ] 634 | }, 635 | "notification-url": "https://packagist.org/downloads/", 636 | "license": [ 637 | "BSD-3-Clause" 638 | ], 639 | "authors": [ 640 | { 641 | "name": "Jeff Welch", 642 | "email": "whatthejeff@gmail.com" 643 | }, 644 | { 645 | "name": "Volker Dusch", 646 | "email": "github@wallbash.com" 647 | }, 648 | { 649 | "name": "Bernhard Schussek", 650 | "email": "bschussek@2bepublished.at" 651 | }, 652 | { 653 | "name": "Sebastian Bergmann", 654 | "email": "sebastian@phpunit.de" 655 | } 656 | ], 657 | "description": "Provides the functionality to compare PHP values for equality", 658 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 659 | "keywords": [ 660 | "comparator", 661 | "compare", 662 | "equality" 663 | ], 664 | "support": { 665 | "issues": "https://github.com/sebastianbergmann/comparator/issues", 666 | "source": "https://github.com/sebastianbergmann/comparator/tree/1.2" 667 | }, 668 | "time": "2017-01-29T09:50:25+00:00" 669 | }, 670 | { 671 | "name": "sebastian/diff", 672 | "version": "1.4.1", 673 | "source": { 674 | "type": "git", 675 | "url": "https://github.com/sebastianbergmann/diff.git", 676 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" 677 | }, 678 | "dist": { 679 | "type": "zip", 680 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", 681 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", 682 | "shasum": "" 683 | }, 684 | "require": { 685 | "php": ">=5.3.3" 686 | }, 687 | "require-dev": { 688 | "phpunit/phpunit": "~4.8" 689 | }, 690 | "type": "library", 691 | "extra": { 692 | "branch-alias": { 693 | "dev-master": "1.4-dev" 694 | } 695 | }, 696 | "autoload": { 697 | "classmap": [ 698 | "src/" 699 | ] 700 | }, 701 | "notification-url": "https://packagist.org/downloads/", 702 | "license": [ 703 | "BSD-3-Clause" 704 | ], 705 | "authors": [ 706 | { 707 | "name": "Kore Nordmann", 708 | "email": "mail@kore-nordmann.de" 709 | }, 710 | { 711 | "name": "Sebastian Bergmann", 712 | "email": "sebastian@phpunit.de" 713 | } 714 | ], 715 | "description": "Diff implementation", 716 | "homepage": "https://github.com/sebastianbergmann/diff", 717 | "keywords": [ 718 | "diff" 719 | ], 720 | "support": { 721 | "issues": "https://github.com/sebastianbergmann/diff/issues", 722 | "source": "https://github.com/sebastianbergmann/diff/tree/master" 723 | }, 724 | "time": "2015-12-08T07:14:41+00:00" 725 | }, 726 | { 727 | "name": "sebastian/environment", 728 | "version": "1.3.7", 729 | "source": { 730 | "type": "git", 731 | "url": "https://github.com/sebastianbergmann/environment.git", 732 | "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716" 733 | }, 734 | "dist": { 735 | "type": "zip", 736 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716", 737 | "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716", 738 | "shasum": "" 739 | }, 740 | "require": { 741 | "php": ">=5.3.3" 742 | }, 743 | "require-dev": { 744 | "phpunit/phpunit": "~4.4" 745 | }, 746 | "type": "library", 747 | "extra": { 748 | "branch-alias": { 749 | "dev-master": "1.3.x-dev" 750 | } 751 | }, 752 | "autoload": { 753 | "classmap": [ 754 | "src/" 755 | ] 756 | }, 757 | "notification-url": "https://packagist.org/downloads/", 758 | "license": [ 759 | "BSD-3-Clause" 760 | ], 761 | "authors": [ 762 | { 763 | "name": "Sebastian Bergmann", 764 | "email": "sebastian@phpunit.de" 765 | } 766 | ], 767 | "description": "Provides functionality to handle HHVM/PHP environments", 768 | "homepage": "http://www.github.com/sebastianbergmann/environment", 769 | "keywords": [ 770 | "Xdebug", 771 | "environment", 772 | "hhvm" 773 | ], 774 | "support": { 775 | "issues": "https://github.com/sebastianbergmann/environment/issues", 776 | "source": "https://github.com/sebastianbergmann/environment/tree/1.3.7" 777 | }, 778 | "time": "2016-05-17T03:18:57+00:00" 779 | }, 780 | { 781 | "name": "sebastian/exporter", 782 | "version": "1.2.2", 783 | "source": { 784 | "type": "git", 785 | "url": "https://github.com/sebastianbergmann/exporter.git", 786 | "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" 787 | }, 788 | "dist": { 789 | "type": "zip", 790 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", 791 | "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", 792 | "shasum": "" 793 | }, 794 | "require": { 795 | "php": ">=5.3.3", 796 | "sebastian/recursion-context": "~1.0" 797 | }, 798 | "require-dev": { 799 | "ext-mbstring": "*", 800 | "phpunit/phpunit": "~4.4" 801 | }, 802 | "type": "library", 803 | "extra": { 804 | "branch-alias": { 805 | "dev-master": "1.3.x-dev" 806 | } 807 | }, 808 | "autoload": { 809 | "classmap": [ 810 | "src/" 811 | ] 812 | }, 813 | "notification-url": "https://packagist.org/downloads/", 814 | "license": [ 815 | "BSD-3-Clause" 816 | ], 817 | "authors": [ 818 | { 819 | "name": "Jeff Welch", 820 | "email": "whatthejeff@gmail.com" 821 | }, 822 | { 823 | "name": "Volker Dusch", 824 | "email": "github@wallbash.com" 825 | }, 826 | { 827 | "name": "Bernhard Schussek", 828 | "email": "bschussek@2bepublished.at" 829 | }, 830 | { 831 | "name": "Sebastian Bergmann", 832 | "email": "sebastian@phpunit.de" 833 | }, 834 | { 835 | "name": "Adam Harvey", 836 | "email": "aharvey@php.net" 837 | } 838 | ], 839 | "description": "Provides the functionality to export PHP variables for visualization", 840 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 841 | "keywords": [ 842 | "export", 843 | "exporter" 844 | ], 845 | "support": { 846 | "issues": "https://github.com/sebastianbergmann/exporter/issues", 847 | "source": "https://github.com/sebastianbergmann/exporter/tree/master" 848 | }, 849 | "time": "2016-06-17T09:04:28+00:00" 850 | }, 851 | { 852 | "name": "sebastian/global-state", 853 | "version": "1.1.1", 854 | "source": { 855 | "type": "git", 856 | "url": "https://github.com/sebastianbergmann/global-state.git", 857 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" 858 | }, 859 | "dist": { 860 | "type": "zip", 861 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", 862 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", 863 | "shasum": "" 864 | }, 865 | "require": { 866 | "php": ">=5.3.3" 867 | }, 868 | "require-dev": { 869 | "phpunit/phpunit": "~4.2" 870 | }, 871 | "suggest": { 872 | "ext-uopz": "*" 873 | }, 874 | "type": "library", 875 | "extra": { 876 | "branch-alias": { 877 | "dev-master": "1.0-dev" 878 | } 879 | }, 880 | "autoload": { 881 | "classmap": [ 882 | "src/" 883 | ] 884 | }, 885 | "notification-url": "https://packagist.org/downloads/", 886 | "license": [ 887 | "BSD-3-Clause" 888 | ], 889 | "authors": [ 890 | { 891 | "name": "Sebastian Bergmann", 892 | "email": "sebastian@phpunit.de" 893 | } 894 | ], 895 | "description": "Snapshotting of global state", 896 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 897 | "keywords": [ 898 | "global state" 899 | ], 900 | "support": { 901 | "issues": "https://github.com/sebastianbergmann/global-state/issues", 902 | "source": "https://github.com/sebastianbergmann/global-state/tree/1.1.1" 903 | }, 904 | "time": "2015-10-12T03:26:01+00:00" 905 | }, 906 | { 907 | "name": "sebastian/recursion-context", 908 | "version": "1.0.5", 909 | "source": { 910 | "type": "git", 911 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 912 | "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" 913 | }, 914 | "dist": { 915 | "type": "zip", 916 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", 917 | "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", 918 | "shasum": "" 919 | }, 920 | "require": { 921 | "php": ">=5.3.3" 922 | }, 923 | "require-dev": { 924 | "phpunit/phpunit": "~4.4" 925 | }, 926 | "type": "library", 927 | "extra": { 928 | "branch-alias": { 929 | "dev-master": "1.0.x-dev" 930 | } 931 | }, 932 | "autoload": { 933 | "classmap": [ 934 | "src/" 935 | ] 936 | }, 937 | "notification-url": "https://packagist.org/downloads/", 938 | "license": [ 939 | "BSD-3-Clause" 940 | ], 941 | "authors": [ 942 | { 943 | "name": "Jeff Welch", 944 | "email": "whatthejeff@gmail.com" 945 | }, 946 | { 947 | "name": "Sebastian Bergmann", 948 | "email": "sebastian@phpunit.de" 949 | }, 950 | { 951 | "name": "Adam Harvey", 952 | "email": "aharvey@php.net" 953 | } 954 | ], 955 | "description": "Provides functionality to recursively process PHP variables", 956 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 957 | "support": { 958 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues", 959 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/master" 960 | }, 961 | "time": "2016-10-03T07:41:43+00:00" 962 | }, 963 | { 964 | "name": "sebastian/version", 965 | "version": "1.0.6", 966 | "source": { 967 | "type": "git", 968 | "url": "https://github.com/sebastianbergmann/version.git", 969 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" 970 | }, 971 | "dist": { 972 | "type": "zip", 973 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", 974 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", 975 | "shasum": "" 976 | }, 977 | "type": "library", 978 | "autoload": { 979 | "classmap": [ 980 | "src/" 981 | ] 982 | }, 983 | "notification-url": "https://packagist.org/downloads/", 984 | "license": [ 985 | "BSD-3-Clause" 986 | ], 987 | "authors": [ 988 | { 989 | "name": "Sebastian Bergmann", 990 | "email": "sebastian@phpunit.de", 991 | "role": "lead" 992 | } 993 | ], 994 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 995 | "homepage": "https://github.com/sebastianbergmann/version", 996 | "support": { 997 | "issues": "https://github.com/sebastianbergmann/version/issues", 998 | "source": "https://github.com/sebastianbergmann/version/tree/1.0.6" 999 | }, 1000 | "time": "2015-06-21T13:59:46+00:00" 1001 | }, 1002 | { 1003 | "name": "symfony/polyfill-ctype", 1004 | "version": "v1.27.0", 1005 | "source": { 1006 | "type": "git", 1007 | "url": "https://github.com/symfony/polyfill-ctype.git", 1008 | "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" 1009 | }, 1010 | "dist": { 1011 | "type": "zip", 1012 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", 1013 | "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", 1014 | "shasum": "" 1015 | }, 1016 | "require": { 1017 | "php": ">=7.1" 1018 | }, 1019 | "provide": { 1020 | "ext-ctype": "*" 1021 | }, 1022 | "suggest": { 1023 | "ext-ctype": "For best performance" 1024 | }, 1025 | "type": "library", 1026 | "extra": { 1027 | "branch-alias": { 1028 | "dev-main": "1.27-dev" 1029 | }, 1030 | "thanks": { 1031 | "name": "symfony/polyfill", 1032 | "url": "https://github.com/symfony/polyfill" 1033 | } 1034 | }, 1035 | "autoload": { 1036 | "files": [ 1037 | "bootstrap.php" 1038 | ], 1039 | "psr-4": { 1040 | "Symfony\\Polyfill\\Ctype\\": "" 1041 | } 1042 | }, 1043 | "notification-url": "https://packagist.org/downloads/", 1044 | "license": [ 1045 | "MIT" 1046 | ], 1047 | "authors": [ 1048 | { 1049 | "name": "Gert de Pagter", 1050 | "email": "BackEndTea@gmail.com" 1051 | }, 1052 | { 1053 | "name": "Symfony Community", 1054 | "homepage": "https://symfony.com/contributors" 1055 | } 1056 | ], 1057 | "description": "Symfony polyfill for ctype functions", 1058 | "homepage": "https://symfony.com", 1059 | "keywords": [ 1060 | "compatibility", 1061 | "ctype", 1062 | "polyfill", 1063 | "portable" 1064 | ], 1065 | "support": { 1066 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" 1067 | }, 1068 | "funding": [ 1069 | { 1070 | "url": "https://symfony.com/sponsor", 1071 | "type": "custom" 1072 | }, 1073 | { 1074 | "url": "https://github.com/fabpot", 1075 | "type": "github" 1076 | }, 1077 | { 1078 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1079 | "type": "tidelift" 1080 | } 1081 | ], 1082 | "time": "2022-11-03T14:55:06+00:00" 1083 | }, 1084 | { 1085 | "name": "symfony/yaml", 1086 | "version": "v3.4.47", 1087 | "source": { 1088 | "type": "git", 1089 | "url": "https://github.com/symfony/yaml.git", 1090 | "reference": "88289caa3c166321883f67fe5130188ebbb47094" 1091 | }, 1092 | "dist": { 1093 | "type": "zip", 1094 | "url": "https://api.github.com/repos/symfony/yaml/zipball/88289caa3c166321883f67fe5130188ebbb47094", 1095 | "reference": "88289caa3c166321883f67fe5130188ebbb47094", 1096 | "shasum": "" 1097 | }, 1098 | "require": { 1099 | "php": "^5.5.9|>=7.0.8", 1100 | "symfony/polyfill-ctype": "~1.8" 1101 | }, 1102 | "conflict": { 1103 | "symfony/console": "<3.4" 1104 | }, 1105 | "require-dev": { 1106 | "symfony/console": "~3.4|~4.0" 1107 | }, 1108 | "suggest": { 1109 | "symfony/console": "For validating YAML files using the lint command" 1110 | }, 1111 | "type": "library", 1112 | "autoload": { 1113 | "psr-4": { 1114 | "Symfony\\Component\\Yaml\\": "" 1115 | }, 1116 | "exclude-from-classmap": [ 1117 | "/Tests/" 1118 | ] 1119 | }, 1120 | "notification-url": "https://packagist.org/downloads/", 1121 | "license": [ 1122 | "MIT" 1123 | ], 1124 | "authors": [ 1125 | { 1126 | "name": "Fabien Potencier", 1127 | "email": "fabien@symfony.com" 1128 | }, 1129 | { 1130 | "name": "Symfony Community", 1131 | "homepage": "https://symfony.com/contributors" 1132 | } 1133 | ], 1134 | "description": "Symfony Yaml Component", 1135 | "homepage": "https://symfony.com", 1136 | "support": { 1137 | "source": "https://github.com/symfony/yaml/tree/v3.4.47" 1138 | }, 1139 | "funding": [ 1140 | { 1141 | "url": "https://symfony.com/sponsor", 1142 | "type": "custom" 1143 | }, 1144 | { 1145 | "url": "https://github.com/fabpot", 1146 | "type": "github" 1147 | }, 1148 | { 1149 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1150 | "type": "tidelift" 1151 | } 1152 | ], 1153 | "time": "2020-10-24T10:57:07+00:00" 1154 | } 1155 | ], 1156 | "aliases": [], 1157 | "minimum-stability": "stable", 1158 | "stability-flags": [], 1159 | "prefer-stable": false, 1160 | "prefer-lowest": false, 1161 | "platform": { 1162 | "php": "^5.4.0|~7.0|~8.0" 1163 | }, 1164 | "platform-dev": [], 1165 | "plugin-api-version": "2.3.0" 1166 | } 1167 | -------------------------------------------------------------------------------- /demo/setup-how-to-integrate.php: -------------------------------------------------------------------------------- 1 | newConfiguration(); 29 | $config->setPassword('secret'); 30 | $config->setDatabase('project'); 31 | 32 | /* 33 | * Step 3: 34 | * Attach the configuration to the library via 35 | * attachConfiguration method 36 | * 37 | * argument 0: configuration object 38 | * argument 1: configuration identifier - default value "default" 39 | */ 40 | $KML->attachConfiguration($config, 'demo'); 41 | 42 | /* 43 | * Optional Step 4: 44 | * If your project has multiple database endpoints you may 45 | * add more than one configuration to the library. 46 | * If your configuration is similar to previously fiven one 47 | * you may just edit the one created before as that would not 48 | * affect already attached configurations. Alternatively, create 49 | * a new configuration object via newConfiguration() method 50 | */ 51 | $config->setDatabase('projet_live'); 52 | $KML->attachConfiguration($config, 'live'); 53 | 54 | /* 55 | * Step 5: 56 | * You are all setup, start using the library 57 | */ 58 | 59 | // to access the "demo" database: 60 | $demo = $KML->connect('demo'); 61 | // to access the "live" database: 62 | $live = $KML->connect('live'); 63 | // to access the "default" database: 64 | $default = $KML->connect(); 65 | -------------------------------------------------------------------------------- /demo/usage-native-pdo.php: -------------------------------------------------------------------------------- 1 | newConfiguration(); 12 | $config->setDatabase('project'); 13 | 14 | $KML->attachConfiguration($config); 15 | 16 | /* 17 | * Get the server object 18 | */ 19 | $db = $KML->connect(); 20 | 21 | /* 22 | * Start using generic PDO functions as per PHP documentation. 23 | */ 24 | 25 | // http://php.net/manual/en/pdo.prepare.php 26 | $res = $db->prepare('SELECT * FROM users WHERE email LIKE ?'); 27 | $res->execute([ 28 | '%ed%' 29 | ]); 30 | 31 | var_dump([ 32 | 'count' => $res->rowCount(), 33 | 'one_row' => $res->fetch(), 34 | 'all_rows' => $res->fetchAll() 35 | ]); 36 | 37 | // http://php.net/manual/en/pdo.query.php 38 | $res = $db->query('SELECT * FROM users'); 39 | 40 | var_dump([ 41 | 'count' => $res->rowCount(), 42 | 'one_row' => $res->fetch(), 43 | 'all_rows' => $res->fetchAll() 44 | ]); 45 | 46 | // etc.., full method view is available at http://php.net/manual/en/class.pdo.php -------------------------------------------------------------------------------- /demo/usage-query-builder.php: -------------------------------------------------------------------------------- 1 | newConfiguration(); 12 | $config->setDatabase('project'); 13 | 14 | $KML->attachConfiguration($config); 15 | 16 | /* 17 | * Get the server object 18 | */ 19 | $db = $KML->connect(); 20 | 21 | // SELECT 22 | // * 23 | // FROM 24 | // users 25 | $db->build('select') 26 | ->from('users') 27 | ->execute(); 28 | 29 | // SELECT 30 | // username 31 | // FROM 32 | // users 33 | $db->build('select') 34 | ->column('username') 35 | ->from('users') 36 | ->execute(); 37 | 38 | // SELECT 39 | // a.username 40 | // FROM 41 | // users a 42 | // RIGHT JOIN projects b 43 | // ON b.user = a.id 44 | $db->build('select') 45 | ->column('a.username') 46 | ->from('users', 'a') 47 | ->join('projects', 'b', 'right') 48 | ->on('b.user', '=', 'a.id') 49 | ->execute(); 50 | 51 | // SELECT 52 | // a.username, 53 | // ( 54 | // SELECT 55 | // count(0) 56 | // FROM 57 | // projects b 58 | // WHERE 59 | // b.id = a.id 60 | // ) 61 | // FROM 62 | // users a 63 | $db->build('select') 64 | ->column('a.username') 65 | ->subquery( 66 | $db->build('select') 67 | ->raw_column('count(0)') 68 | ->from('projects', 'b') 69 | ->raw_where('b.id', '=', 'a.id') 70 | ) 71 | ->from('users', 'a') 72 | ->execute(); 73 | 74 | // SELECT 75 | // * 76 | // FROM 77 | // business 78 | // WHERE 79 | // related IN("4","3","1") 80 | $db->build('select') 81 | ->from('business') 82 | ->where_in_values('related', [4, 3, 1]) 83 | ->execute(); 84 | 85 | // SELECT 86 | // a.name 87 | // FROM 88 | // users a 89 | // WHERE 90 | // a.id IN( 91 | // SELECT 92 | // b.user 93 | // FROM 94 | // projects b 95 | // WHERE 96 | // b.validated = "yes" 97 | // ) 98 | $db->build('select') 99 | ->column('a.name') 100 | ->from('users', 'a') 101 | ->where_in_subquery( 102 | 'a.id', 103 | $db->build('select') 104 | ->column('b.user') 105 | ->from('projects', 'b') 106 | ->where('b.validated', '=', 'yes') 107 | ) 108 | ->execute(); 109 | 110 | // SELECT 111 | // id 112 | // FROM 113 | // users 114 | // WHERE 115 | // ( 116 | // created BETWEEN "1485229920" AND "1485249932" 117 | // OR validated = "yes" 118 | // ) AND ( 119 | // activated = "yes" 120 | // OR ( 121 | // validated = "yes" AND 122 | // single = "no" 123 | // ) 124 | // ) 125 | $db->build('select') 126 | ->column('id') 127 | ->from('users') 128 | ->open() 129 | ->where('created', 'between', '1485229920', 'and', '1485249932') 130 | ->or_where('validated', '=', 'yes') 131 | ->close() 132 | ->open() 133 | ->where('activated', '=', 'yes') 134 | ->or_open() 135 | ->where('validated', '=', 'yes') 136 | ->where('single', '=', 'no') 137 | ->close() 138 | ->close() 139 | ->execute(); 140 | 141 | // UPDATE 142 | // users 143 | // SET 144 | // username = "ed", 145 | // update_count = update_count + 1 146 | // WHERE 147 | // id = 1234 148 | $db->build('update') 149 | ->table('users') 150 | ->set('username', '=', 'ed') 151 | ->set('update_count', '=', 'update_count + 1', true) 152 | ->where('id', '=', '1234') 153 | ->execute(); 154 | 155 | // UPDATE 156 | // original a 157 | // INNER JOIN updated b 158 | // ON a.URL = b.URL 159 | // SET a.funded = b.funded, 160 | // a.days = b.days 161 | $db->builder('update') 162 | ->table('original', 'a') 163 | ->join('updated', 'b', 'innser') 164 | ->on('a.URL', '=', 'b.URL') 165 | ->set('a.funded', '=', 'b.funded', true) 166 | ->set('a.days', '=', 'b.days', true) 167 | ->execute(); 168 | 169 | // DELETE posts 170 | // FROM posts 171 | // INNER JOIN projects ON projects.project_id = posts.project_id 172 | // WHERE projects.client_id = "312" 173 | $db->builder('delete') 174 | ->column('posts') 175 | ->from('posts') 176 | ->join('projects') 177 | ->on('projects.project_id', '=', 'posts.project_id') 178 | ->where('projects.client_id', '=', "312") 179 | ->execute(); 180 | 181 | // INSERT INTO 182 | // table 183 | // (username, password) 184 | // VALUES("ed","w3lcome") 185 | $insert_id = $db->builder('insert') 186 | ->into('table') 187 | ->set('username', 'ed') 188 | ->set('password', 'w3lcome') 189 | ->execute(); 190 | 191 | // INSERT IGNORE INTO 192 | // table 193 | // (username, password) 194 | // VALUES("ed","w3lcome") 195 | $insert_id = $db->builder('ignore') 196 | ->into('table') 197 | ->set('username', 'ed') 198 | ->set('password', 'w3lcome') 199 | ->execute(); 200 | 201 | // REPLACE INTO 202 | // table 203 | // VALUES("ed","w3lcome") 204 | $insert_id = $db->builder('replace') 205 | ->into('table') 206 | ->value('ed') 207 | ->value('w3lcome') 208 | ->execute(); 209 | -------------------------------------------------------------------------------- /demo/usage-short-cut-methods.php: -------------------------------------------------------------------------------- 1 | newConfiguration(); 12 | $config->setDatabase('project'); 13 | 14 | $KML->attachConfiguration($config); 15 | 16 | /* 17 | * Get the server object 18 | */ 19 | $db = $KML->connect(); 20 | 21 | /* 22 | * INSERT INTO users (username, password) VALUES("ed","w3lcome") 23 | */ 24 | $insert_id = $db->insert('users', [ 25 | 'username' => 'ed', 26 | 'password' => 'w3lcome' 27 | ]); 28 | 29 | /* 30 | * INSERT IGNORE INTO users (username, password) VALUES("ed","w3lcome") 31 | */ 32 | $insert_id = $db->ignore('users', [ 33 | 'username' => 'ed', 34 | 'password' => 'w3lcome' 35 | ]); 36 | 37 | /* 38 | * REPLACE INTO users (username, password) VALUES("ed","w3lcome") 39 | */ 40 | $insert_id = $db->replace('users', [ 41 | 'username' => 'ed', 42 | 'password' => 'w3lcome' 43 | ]); 44 | 45 | /* 46 | * DELETE FROM users WHERE username = "ed" AND password = "w3lcome" 47 | */ 48 | $db->delete('users', [ 49 | 'username' => 'ed', 50 | 'password' => 'w3lcome' 51 | ]); 52 | 53 | /* 54 | * UPDATE users SET username = "edward" WHERE username = "ed" AND password = "w3lcome" 55 | */ 56 | $db->update('users', [ 57 | 'username' => 'edward' 58 | ], [ 59 | 'username' => 'ed', 60 | 'password' => 'w3lcome' 61 | ]); 62 | -------------------------------------------------------------------------------- /init.php: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | tests 16 | 17 | 18 | 19 | 20 | src 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Builder.php: -------------------------------------------------------------------------------- 1 | execute(); 32 | 33 | return call_user_func_array([$resource, 'fetch'], $options); 34 | } 35 | 36 | // http://php.net/manual/en/pdostatement.fetchall.php 37 | public function fetchAll($fetch_style = null, $fetch_argument = null, $ctor_args = null) 38 | { 39 | $options = []; 40 | 41 | if ($fetch_style !== null) { 42 | $options[] = $fetch_style; 43 | } 44 | 45 | if ($fetch_argument !== null) { 46 | $options[] = $fetch_argument; 47 | } 48 | 49 | if ($ctor_args !== null) { 50 | $options[] = $ctor_args; 51 | } 52 | 53 | $resource = $this->execute(); 54 | 55 | return call_user_func_array([$resource, 'fetchAll'], $options); 56 | } 57 | 58 | public function execute($keepParameters = false) 59 | { 60 | if (!$this->compiled) { 61 | $this->compile(); 62 | } 63 | 64 | if ($this->server->isLogEnabled()) { 65 | $this->server->logQuery($this->buildFormat, $this->debug()); 66 | } 67 | 68 | $native = $this->server->getNativePdo(); 69 | 70 | $resource = $native->prepare($this->compiled_query); 71 | $resource->execute($this->compiled_params); 72 | 73 | $this->compiled = false; 74 | $this->compiled_query = ''; 75 | 76 | if (!$keepParameters) { 77 | $this->compiled_params = []; 78 | } 79 | 80 | return $resource; 81 | } 82 | 83 | public function debug($return_pdo = false) 84 | { 85 | if (!$this->compiled) { 86 | $this->compile(); 87 | } 88 | 89 | $query = $this->compiled_query; 90 | 91 | foreach ($this->compiled_params as $param_key => $param_value) { 92 | if (!is_numeric($param_key)) { 93 | $query = str_replace($param_key, '"' . $param_value . '"', $query); 94 | } 95 | } 96 | 97 | if ($return_pdo) { 98 | return [ 99 | 'query' => $this->compiled_query, 100 | 'parameters' => $this->compiled_params 101 | ]; 102 | } 103 | 104 | return $query; 105 | } 106 | 107 | protected function clean($variable) 108 | { 109 | $variable = str_replace(['`', ' ', "\n", "\r", "\t"], '', $variable); 110 | 111 | if (strpos($variable, '.') !== false) { 112 | return '`' . str_replace('.', '`.`', $variable) . '`'; 113 | } 114 | 115 | return '`' . $variable . '`'; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/Builder/Delete.php: -------------------------------------------------------------------------------- 1 | compileIndexActive = hash('crc32', self::$compileIndex); 28 | $this->server = $server; 29 | } 30 | 31 | public function reset() 32 | { 33 | return new self($this->server); 34 | } 35 | 36 | protected function compile() 37 | { 38 | $this->compiled_query = ''; 39 | $this->compiled_query .= 'DELETE'; 40 | 41 | $raw_column = 0; 42 | $column = 0; 43 | $holder = []; 44 | 45 | foreach ($this->column_indexes as $index) { 46 | list($column_name, $column_alias) = $this->{$index}[$$index++]; 47 | 48 | if ($index == 'column') { 49 | $column_name = $this->clean($column_name); 50 | } 51 | 52 | if ($column_alias !== null) { 53 | $column_alias = $this->clean($column_alias); 54 | $holder[] = $column_name . ' AS ' . $column_alias; 55 | } else { 56 | $holder[] = $column_name; 57 | } 58 | } 59 | 60 | if (count($holder)) { 61 | $this->compiled_query .= ' ' . implode(', ', $holder); 62 | } 63 | 64 | $this->compiled_query .= ' FROM'; 65 | 66 | $holder = []; 67 | foreach ($this->from as $data) { 68 | $data[0] = $this->clean($data[0]); 69 | 70 | if ($data[1] !== null) { 71 | $data[1] = $this->clean($data[1]); 72 | $holder[] = $data[0] . ' AS ' . $data[1] . ''; 73 | } else { 74 | $holder[] = $data[0]; 75 | } 76 | } 77 | 78 | $this->compiled_query .= ' ' . implode(', ', $holder); 79 | 80 | foreach ($this->joins as $joinIndex => $joinData) { 81 | list($table, $alias, $format) = $joinData; 82 | 83 | $format = strtoupper($format); 84 | $table = $this->clean($table); 85 | 86 | if ($alias !== null) { 87 | $alias = $this->clean($alias); 88 | $this->compiled_query .= ' ' . $format . ($format ? ' ' : '') . 'JOIN ' . $table . ' AS ' . $alias; 89 | } else { 90 | $this->compiled_query .= ' ' . $format . ($format ? ' ' : '') . 'JOIN ' . $table; 91 | } 92 | 93 | if (isset($this->on[$joinIndex])) { 94 | $holder = ''; 95 | foreach ($this->on[$joinIndex] as $on) { 96 | list($field1, $operator, $field2, $statement) = $on; 97 | $holder .= ($holder ? ' ' . $statement : 'ON'); 98 | 99 | $field1 = $this->clean($field1); 100 | $field2 = $this->clean($field2); 101 | 102 | $holder .= ' ' . $field1 . ' ' . $operator . ' ' . $field2; 103 | } 104 | 105 | $this->compiled_query .= ' ' . $holder; 106 | } 107 | } 108 | 109 | $raw_where = 0; 110 | $where = 0; 111 | $where_in_values = 0; 112 | $where_in_subquery = 0; 113 | 114 | $holder = ''; 115 | $was_change = true; 116 | 117 | foreach ($this->where_indexes as $windex) { 118 | if ($windex == 'and_open' || $windex == 'or_open') { 119 | $holder .= ($holder ? ($windex == 'and_open' ? ' AND ' : ' OR ') : '') . '('; 120 | $was_change = true; 121 | continue; 122 | } elseif ($windex == 'close') { 123 | $holder .= ')'; 124 | continue; 125 | } elseif ($windex == 'where') { 126 | list($field, $operator, $value, $format, $values2, $splitter) = $this->{$windex}[$$windex++]; 127 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 128 | $was_change = false; 129 | 130 | $field = $this->clean($field); 131 | $key = ':c' . $this->compileIndexActive . 'v' . hash('crc32', count($this->compiled_params)); 132 | $this->compiled_params[$key] = $value; 133 | $holder .= $field . ' ' . $operator . ' ' . $key; 134 | 135 | if ($format !== null) { 136 | $holder .= ' ' . $format; 137 | } 138 | 139 | if ($values2 !== null) { 140 | $key = ':c' . $this->compileIndexActive . 'v' . hash('crc32', count($this->compiled_params)); 141 | $this->compiled_params[$key] = $values2; 142 | $holder .= ' ' . $key; 143 | } 144 | } elseif ($windex == 'raw_where') { 145 | list($field, $operator, $value, $format, $values2, $splitter) = $this->{$windex}[$$windex++]; 146 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 147 | $was_change = false; 148 | 149 | $field = $this->clean($field); 150 | $holder .= $field . ' ' . $operator . ' ' . $value; 151 | 152 | if ($format !== null) { 153 | $holder .= ' ' . $format; 154 | } 155 | 156 | if ($values2 !== null) { 157 | $holder .= ' ' . $values2; 158 | } 159 | } elseif ($windex == 'where_in_values') { 160 | list($field, $values, $splitter, $prefix) = $this->{$windex}[$$windex++]; 161 | $field = $this->clean($field); 162 | 163 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 164 | $was_change = false; 165 | 166 | $holder .= $field . ($prefix ? ' ' . $prefix : '') . ' IN('; 167 | 168 | $i = 0; 169 | foreach ($values as $index => $value) { 170 | if ($i++) { 171 | $holder .= ', '; 172 | } 173 | $key = ':c' . $this->compileIndexActive . 'v' . hash('crc32', count($this->compiled_params)); 174 | $this->compiled_params[$key] = $value; 175 | $holder .= $key; 176 | } 177 | $holder .= ')'; 178 | } elseif ($windex == 'where_in_subquery') { 179 | list($field, $value, $splitter, $prefix) = $this->{$windex}[$$windex++]; 180 | $field = $this->clean($field); 181 | 182 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 183 | $was_change = false; 184 | 185 | $holder .= $field . ($prefix ? ' ' . $prefix : '') . ' IN(' . $value . ')'; 186 | } 187 | } 188 | 189 | if ($holder) { 190 | $this->compiled_query .= ' WHERE ' . $holder; 191 | } 192 | 193 | $this->compiled = true; 194 | } 195 | 196 | private $raw_column = []; 197 | 198 | public function raw_column($name, $alias = null) 199 | { 200 | $this->compiled = false; 201 | $this->raw_column[] = [$name, $alias]; 202 | $this->column_indexes[] = 'raw_column'; 203 | return $this; 204 | } 205 | 206 | private $column = []; 207 | 208 | public function column($name, $alias = null) 209 | { 210 | $this->compiled = false; 211 | $this->column[] = [$name, $alias]; 212 | $this->column_indexes[] = 'column'; 213 | return $this; 214 | } 215 | 216 | public function subquery($query, $alias = null) 217 | { 218 | $this->compiled = false; 219 | if (!is_string($query)) { 220 | if ($query instanceof Select) { 221 | $query = $query->debug(true); 222 | $this->compiled_params = array_merge($this->compiled_params, $query['parameters']); 223 | $query = $query['query']; 224 | } else { 225 | throw new Exception('WHERE IN SUBQUERY requires either a raw sql query string or a SELECT builder that has not been executed.'); 226 | } 227 | } 228 | 229 | $this->raw_column[] = ['(' . $query . ')', $alias]; 230 | $this->column_indexes[] = 'raw_column'; 231 | 232 | return $this; 233 | } 234 | 235 | 236 | private $from = []; 237 | 238 | public function from($name, $alias = null) 239 | { 240 | $this->compiled = false; 241 | $this->from[] = [$name, $alias]; 242 | return $this; 243 | } 244 | 245 | private $joins = []; 246 | 247 | public function join($table, $alias = null, $format = 'LEFT') 248 | { 249 | $this->compiled = false; 250 | if (!$format) { 251 | $format = ''; 252 | } 253 | 254 | $this->joins[] = [$table, $alias, $format]; 255 | 256 | return $this; 257 | } 258 | 259 | private $on = []; 260 | 261 | public function on($field1, $operator, $field2, $format = 'AND') 262 | { 263 | $this->compiled = false; 264 | if (!count($this->joins)) { 265 | throw new Exception('Cannot call query builders ON if there was no join initiated.'); 266 | } 267 | 268 | $joinIndex = count($this->joins) - 1; 269 | 270 | if (!isset($this->on[$joinIndex])) { 271 | $this->on[$joinIndex] = []; 272 | } 273 | 274 | $this->on[$joinIndex][] = [$field1, $operator, $field2, strtoupper($format)]; 275 | 276 | return $this; 277 | } 278 | 279 | private $where = []; 280 | 281 | public function where($field, $operator, $value, $format = null, $values2 = null, $splitter = 'AND') 282 | { 283 | $this->compiled = false; 284 | $this->where_indexes[] = 'where'; 285 | $this->where[] = [$field, $operator, $value, $format, $values2, $splitter]; 286 | return $this; 287 | } 288 | 289 | public function or_where($field, $operator, $value, $format = null, $values2 = null) 290 | { 291 | return $this->where($field, $operator, $value, $format, $values2, 'OR'); 292 | } 293 | 294 | public function and_where($field, $operator, $value, $format = null, $values2 = null) 295 | { 296 | return $this->where($field, $operator, $value, $format, $values2, 'AND'); 297 | } 298 | 299 | private $raw_where = []; 300 | 301 | public function raw_where($field, $operator, $value, $format = null, $values2 = null, $splitter = 'AND') 302 | { 303 | $this->compiled = false; 304 | $this->where_indexes[] = 'raw_where'; 305 | $this->raw_where[] = [$field, $operator, $value, $format, $values2, $splitter]; 306 | return $this; 307 | } 308 | 309 | public function raw_or_where($field, $operator, $value, $format = null, $values2 = null) 310 | { 311 | return $this->raw_where($field, $operator, $value, $format, $values2, 'OR'); 312 | } 313 | 314 | public function raw_and_where($field, $operator, $value, $format = null, $values2 = null) 315 | { 316 | return $this->raw_where($field, $operator, $value, $format, $values2, 'AND'); 317 | } 318 | 319 | public function open() 320 | { 321 | $this->compiled = false; 322 | $this->where_indexes[] = 'and_open'; 323 | return $this; 324 | } 325 | 326 | public function or_open() 327 | { 328 | $this->compiled = false; 329 | $this->where_indexes[] = 'or_open'; 330 | return $this; 331 | } 332 | 333 | public function close() 334 | { 335 | $this->compiled = false; 336 | $this->where_indexes[] = 'close'; 337 | return $this; 338 | } 339 | 340 | private $where_in_values = []; 341 | 342 | public function where_in_values($field, array $values, $splitter = 'AND', $prefix = '') 343 | { 344 | $this->compiled = false; 345 | 346 | if (!count($values)) { 347 | throw new Exception('The WHERE_IN_VALUES requires $values array to have values.'); 348 | } 349 | 350 | $this->where_indexes[] = 'where_in_values'; 351 | $this->where_in_values[] = [$field, $values, $splitter, $prefix]; 352 | return $this; 353 | } 354 | 355 | public function or_where_in_values($field, array $values) 356 | { 357 | return $this->where_in_values($field, $values, 'OR'); 358 | } 359 | 360 | public function and_where_in_values($field, array $values) 361 | { 362 | return $this->where_in_values($field, $values, 'AND'); 363 | } 364 | 365 | public function where_not_in_values($field, array $values, $splitter = 'AND') 366 | { 367 | return $this->where_in_values($field, $values, $splitter, 'NOT'); 368 | } 369 | 370 | public function and_where_not_in_values($field, array $values) 371 | { 372 | return $this->where_in_values($field, $values, 'AND', 'NOT'); 373 | } 374 | 375 | public function or_where_not_in_values($field, array $values) 376 | { 377 | return $this->where_in_values($field, $values, 'OR', 'NOT'); 378 | } 379 | 380 | private $where_in_subquery = []; 381 | 382 | public function where_in_subquery($field, $value, $splitter = 'AND', $prefix = '') 383 | { 384 | $this->compiled = false; 385 | 386 | if (!is_string($value)) { 387 | if ($value instanceof Select) { 388 | $value = $value->debug(true); 389 | $this->compiled_params = array_merge($this->compiled_params, $value['parameters']); 390 | $value = $value['query']; 391 | } else { 392 | throw new Exception('WHERE IN SUBQUERY requires either a raw sql query string or a SELECT builder that has not been executed.'); 393 | } 394 | } 395 | 396 | $this->where_indexes[] = 'where_in_subquery'; 397 | $this->where_in_subquery[] = [$field, $value, $splitter, $prefix]; 398 | return $this; 399 | } 400 | 401 | public function and_where_in_subquery($field, $value) 402 | { 403 | return $this->where_in_subquery($field, $value); 404 | } 405 | 406 | public function or_where_in_subquery($field, $value) 407 | { 408 | return $this->where_in_subquery($field, $value, 'OR'); 409 | } 410 | 411 | public function where_not_in_subquery($field, $value) 412 | { 413 | return $this->where_in_subquery($field, $value, 'AND', 'NOT'); 414 | } 415 | 416 | public function and_where_not_in_subquery($field, $value) 417 | { 418 | return $this->where_in_subquery($field, $value, 'AND', 'NOT'); 419 | } 420 | 421 | public function or_where_not_in_subquery($field, $value) 422 | { 423 | return $this->where_in_subquery($field, $value, 'OR', 'NOT'); 424 | } 425 | 426 | } 427 | -------------------------------------------------------------------------------- /src/Builder/Ignore.php: -------------------------------------------------------------------------------- 1 | options['on_duplicate_key_update'] = !empty($options['on_duplicate_key_update']); 24 | $this->server = $server; 25 | } 26 | 27 | public function into($name) 28 | { 29 | return $this->table($name); 30 | } 31 | 32 | public function table($name) 33 | { 34 | $this->compiled = false; 35 | $this->table = $name; 36 | return $this; 37 | } 38 | 39 | public function set($column, $value) 40 | { 41 | $this->compiled = false; 42 | $this->values[$column] = $value; 43 | return $this; 44 | } 45 | 46 | public function value($value) 47 | { 48 | $this->compiled = false; 49 | $this->values[] = $value; 50 | return $this; 51 | } 52 | 53 | protected function compile() 54 | { 55 | $this->compiled_query = $this->method . ' '; 56 | $this->compiled_params = []; 57 | 58 | $this->compiled_query .= $this->clean($this->table); 59 | 60 | $useColumnKeys = true; 61 | $columnKeys = ''; 62 | $queryValues = ''; 63 | $updates = []; 64 | 65 | foreach ($this->values as $key => $value) { 66 | $value_key = ':v' . count($this->compiled_params); 67 | 68 | if ($useColumnKeys) { 69 | if (is_numeric($key)) { 70 | $useColumnKeys = false; 71 | } else { 72 | $columnKeys .= ($columnKeys ? ',' : '') . $this->clean($key); 73 | 74 | if (!empty($this->options['on_duplicate_key_update'])) { 75 | $updates[] = $this->clean($key).'='.$value_key; 76 | } 77 | } 78 | } 79 | 80 | $queryValues .= ($queryValues ? ',' : '') . $value_key; 81 | $this->compiled_params[$value_key] = $value; 82 | } 83 | 84 | if ($useColumnKeys) { 85 | $this->compiled_query .= ' (' . $columnKeys . ')'; 86 | } 87 | 88 | $this->compiled_query .= ' VALUES(' . $queryValues . ')'; 89 | 90 | if($useColumnKeys && !empty($this->options['on_duplicate_key_update']) && count($updates)){ 91 | $this->compiled_query .= ' ON DUPLICATE KEY UPDATE '.implode(', ', $updates); 92 | } 93 | 94 | $this->compiled = true; 95 | } 96 | 97 | public function execute($keepParameters = false) 98 | { 99 | parent::execute($keepParameters); 100 | return $this->server->lastInsertId(); 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /src/Builder/Replace.php: -------------------------------------------------------------------------------- 1 | compileIndexActive = hash('crc32', self::$compileIndex); 27 | $this->server = $server; 28 | } 29 | 30 | public function reset() 31 | { 32 | return new self($this->server); 33 | } 34 | 35 | protected function compile() 36 | { 37 | $this->compiled_query = 'SELECT'; 38 | 39 | if ($this->distinct) { 40 | if (!count($this->column_indexes)) { 41 | throw new Exception('Cannot use DISTINCT if no columns are selected'); 42 | } 43 | $this->compiled_query .= ' DISTINCT'; 44 | } 45 | 46 | $raw_column = 0; 47 | $column = 0; 48 | $subquery = 0; 49 | $holder = []; 50 | 51 | if (!count($this->column_indexes)) { 52 | $this->compiled_query .= ' * '; 53 | } else { 54 | foreach ($this->column_indexes as $index) { 55 | list($column_name, $column_alias) = $this->{$index}[$$index++]; 56 | 57 | if ($index == 'column') { 58 | $column_name = $this->clean($column_name); 59 | } 60 | 61 | if ($column_alias !== null) { 62 | $column_alias = $this->clean($column_alias); 63 | $holder[] = $column_name . ' AS ' . $column_alias; 64 | } else { 65 | $holder[] = $column_name; 66 | } 67 | } 68 | 69 | if (count($holder)) { 70 | $this->compiled_query .= ' ' . implode(', ', $holder); 71 | } 72 | } 73 | 74 | $this->compiled_query .= ' FROM'; 75 | 76 | $holder = []; 77 | foreach ($this->from as $data) { 78 | $data[0] = $this->clean($data[0]); 79 | 80 | if ($data[1] !== null) { 81 | $data[1] = $this->clean($data[1]); 82 | $holder[] = $data[0] . ' AS ' . $data[1] . ''; 83 | } else { 84 | $holder[] = $data[0]; 85 | } 86 | } 87 | 88 | $this->compiled_query .= ' ' . implode(', ', $holder); 89 | 90 | foreach ($this->joins as $joinIndex => $joinData) { 91 | list($table, $alias, $format) = $joinData; 92 | 93 | $format = strtoupper($format); 94 | $table = $this->clean($table); 95 | 96 | if ($alias !== null) { 97 | $alias = $this->clean($alias); 98 | $this->compiled_query .= ' ' . $format . ($format ? ' ' : '') . 'JOIN ' . $table . ' AS ' . $alias; 99 | } else { 100 | $this->compiled_query .= ' ' . $format . ($format ? ' ' : '') . 'JOIN ' . $table; 101 | } 102 | 103 | if (isset($this->on[$joinIndex])) { 104 | $holder = ''; 105 | foreach ($this->on[$joinIndex] as $on) { 106 | list($field1, $operator, $field2, $statement, $applyAsString) = $on; 107 | $holder .= ($holder ? ' ' . $statement : 'ON'); 108 | 109 | $field1 = $this->clean($field1); 110 | $field2 = $applyAsString === false ? $this->clean($field2) : $field2; 111 | 112 | $holder .= ' ' . $field1 . ' ' . $operator . ' ' . $field2; 113 | } 114 | 115 | $this->compiled_query .= ' ' . $holder; 116 | } 117 | } 118 | 119 | $raw_where = 0; 120 | $where = 0; 121 | $where_in_values = 0; 122 | $where_in_subquery = 0; 123 | 124 | $holder = ''; 125 | $was_change = true; 126 | 127 | foreach ($this->where_indexes as $windex) { 128 | if ($windex == 'and_open' || $windex == 'or_open') { 129 | $holder .= ($holder ? ($windex == 'and_open' ? ' AND ' : ' OR ') : '') . '('; 130 | $was_change = true; 131 | continue; 132 | } elseif ($windex == 'close') { 133 | $holder .= ')'; 134 | continue; 135 | } elseif ($windex == 'where') { 136 | list($field, $operator, $value, $format, $values2, $splitter) = $this->{$windex}[$$windex++]; 137 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 138 | $was_change = false; 139 | 140 | $field = $this->clean($field); 141 | $key = ':c' . $this->compileIndexActive . 'v' . hash('crc32', count($this->compiled_params)); 142 | $this->compiled_params[$key] = $value; 143 | $holder .= $field . ' ' . $operator . ' ' . $key; 144 | 145 | if ($format !== null) { 146 | $holder .= ' ' . $format; 147 | } 148 | 149 | if ($values2 !== null) { 150 | $key = ':c' . $this->compileIndexActive . 'v' . hash('crc32', count($this->compiled_params)); 151 | $this->compiled_params[$key] = $values2; 152 | $holder .= ' ' . $key; 153 | } 154 | } elseif ($windex == 'raw_where') { 155 | list($field, $operator, $value, $format, $values2, $splitter) = $this->{$windex}[$$windex++]; 156 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 157 | $was_change = false; 158 | 159 | $field = $this->clean($field); 160 | $holder .= $field . ' ' . $operator . ' ' . $value; 161 | 162 | if ($format !== null) { 163 | $holder .= ' ' . $format; 164 | } 165 | 166 | if ($values2 !== null) { 167 | $holder .= ' ' . $values2; 168 | } 169 | } elseif ($windex == 'where_in_values') { 170 | list($field, $values, $splitter, $prefix) = $this->{$windex}[$$windex++]; 171 | $field = $this->clean($field); 172 | 173 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 174 | $was_change = false; 175 | 176 | $holder .= $field . ($prefix ? ' ' . $prefix : '') . ' IN('; 177 | 178 | $i = 0; 179 | foreach ($values as $index => $value) { 180 | if ($i++) { 181 | $holder .= ', '; 182 | } 183 | $key = ':c' . $this->compileIndexActive . 'v' . hash('crc32', count($this->compiled_params)); 184 | $this->compiled_params[$key] = $value; 185 | $holder .= $key; 186 | } 187 | $holder .= ')'; 188 | } elseif ($windex == 'where_in_subquery') { 189 | list($field, $value, $splitter, $prefix) = $this->{$windex}[$$windex++]; 190 | $field = $this->clean($field); 191 | 192 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 193 | $was_change = false; 194 | 195 | $holder .= $field . ($prefix ? ' ' . $prefix : '') . ' IN(' . $value . ')'; 196 | } 197 | } 198 | 199 | if ($holder) { 200 | $this->compiled_query .= ' WHERE ' . $holder; 201 | } 202 | 203 | if (count($this->group_by) || count($this->raw_group_by)) { 204 | $this->compiled_query .= ' GROUP BY'; 205 | $holder = ''; 206 | foreach ($this->group_by as $column) { 207 | $column = $this->clean($column); 208 | $holder .= ($holder ? ', ' : '') . $column; 209 | } 210 | foreach ($this->raw_group_by as $column) { 211 | $holder .= ($holder ? ', ' : '') . $column; 212 | } 213 | $this->compiled_query .= ' ' . $holder; 214 | } 215 | 216 | if (count($this->order_by)) { 217 | $this->compiled_query .= ' ORDER BY'; 218 | $holder = ''; 219 | foreach ($this->order_by as $column) { 220 | list($name, $direction) = $column; 221 | 222 | $name = $this->clean($name); 223 | $holder .= ($holder ? ', ' : '') . $name . ' ' . strtoupper($direction); 224 | } 225 | $this->compiled_query .= ' ' . $holder; 226 | } 227 | 228 | if ($this->offset !== null && $this->limit !== null) { 229 | $this->compiled_query .= ' LIMIT ' . strval($this->offset) . ',' . strval($this->limit); 230 | } elseif ($this->offset !== null) { 231 | $this->compiled_query .= ' OFFSET ' . strval($this->offset); 232 | } elseif ($this->limit !== null) { 233 | $this->compiled_query .= ' LIMIT ' . strval($this->limit); 234 | } 235 | 236 | $this->compiled = true; 237 | } 238 | 239 | private $distinct = false; 240 | 241 | public function distinct() 242 | { 243 | $this->compiled = false; 244 | $this->distinct = true; 245 | return $this; 246 | } 247 | 248 | private $raw_column = []; 249 | 250 | public function raw_column($name, $alias = null) 251 | { 252 | $this->compiled = false; 253 | $this->raw_column[] = [$name, $alias]; 254 | $this->column_indexes[] = 'raw_column'; 255 | return $this; 256 | } 257 | 258 | private $column = []; 259 | 260 | public function column($name, $alias = null) 261 | { 262 | $this->compiled = false; 263 | $this->column[] = [$name, $alias]; 264 | $this->column_indexes[] = 'column'; 265 | return $this; 266 | } 267 | 268 | public function reset_column() 269 | { 270 | $this->compiled = false; 271 | $this->raw_column = []; 272 | $this->column = []; 273 | $this->column_indexes = []; 274 | return $this; 275 | } 276 | 277 | public function subquery($query, $alias = null) 278 | { 279 | $this->compiled = false; 280 | if (!is_string($query)) { 281 | if ($query instanceof Select) { 282 | $query = $query->debug(true); 283 | $this->compiled_params = array_merge($this->compiled_params, $query['parameters']); 284 | $query = $query['query']; 285 | } else { 286 | throw new Exception('WHERE IN SUBQUERY requires either a raw sql query string or a SELECT builder that has not been executed.'); 287 | } 288 | } 289 | 290 | $this->raw_column[] = ['(' . $query . ')', $alias]; 291 | $this->column_indexes[] = 'raw_column'; 292 | 293 | return $this; 294 | } 295 | 296 | 297 | private $from = []; 298 | 299 | public function from($name, $alias = null) 300 | { 301 | $this->compiled = false; 302 | $this->from[] = [$name, $alias]; 303 | return $this; 304 | } 305 | 306 | private $joins = []; 307 | 308 | public function join($table, $alias = null, $format = 'LEFT') 309 | { 310 | $this->compiled = false; 311 | if (!$format) { 312 | $format = ''; 313 | } 314 | 315 | $this->joins[] = [$table, $alias, $format]; 316 | 317 | return $this; 318 | } 319 | 320 | private $on = []; 321 | 322 | public function on($field1, $operator, $field2, $format = 'AND', $applyAsString = false) 323 | { 324 | $this->compiled = false; 325 | if (!count($this->joins)) { 326 | throw new Exception('Cannot call query builders ON if there was no join initiated.'); 327 | } 328 | 329 | $joinIndex = count($this->joins) - 1; 330 | 331 | if (!isset($this->on[$joinIndex])) { 332 | $this->on[$joinIndex] = []; 333 | } 334 | 335 | $this->on[$joinIndex][] = [$field1, $operator, $field2, strtoupper($format), boolval($applyAsString)]; 336 | 337 | return $this; 338 | } 339 | 340 | private $where = []; 341 | 342 | public function where($field, $operator, $value, $format = null, $values2 = null, $splitter = 'AND') 343 | { 344 | $this->compiled = false; 345 | $this->where_indexes[] = 'where'; 346 | $this->where[] = [$field, $operator, $value, $format, $values2, $splitter]; 347 | return $this; 348 | } 349 | 350 | public function or_where($field, $operator, $value, $format = null, $values2 = null) 351 | { 352 | return $this->where($field, $operator, $value, $format, $values2, 'OR'); 353 | } 354 | 355 | public function and_where($field, $operator, $value, $format = null, $values2 = null) 356 | { 357 | return $this->where($field, $operator, $value, $format, $values2, 'AND'); 358 | } 359 | 360 | private $raw_where = []; 361 | 362 | public function raw_where($field, $operator, $value, $format = null, $values2 = null, $splitter = 'AND') 363 | { 364 | $this->compiled = false; 365 | $this->where_indexes[] = 'raw_where'; 366 | $this->raw_where[] = [$field, $operator, $value, $format, $values2, $splitter]; 367 | return $this; 368 | } 369 | 370 | public function raw_or_where($field, $operator, $value, $format = null, $values2 = null) 371 | { 372 | return $this->raw_where($field, $operator, $value, $format, $values2, 'OR'); 373 | } 374 | 375 | public function raw_and_where($field, $operator, $value, $format = null, $values2 = null) 376 | { 377 | return $this->raw_where($field, $operator, $value, $format, $values2, 'AND'); 378 | } 379 | 380 | public function open() 381 | { 382 | $this->compiled = false; 383 | $this->where_indexes[] = 'and_open'; 384 | return $this; 385 | } 386 | 387 | public function or_open() 388 | { 389 | $this->compiled = false; 390 | $this->where_indexes[] = 'or_open'; 391 | return $this; 392 | } 393 | 394 | public function close() 395 | { 396 | $this->compiled = false; 397 | $this->where_indexes[] = 'close'; 398 | return $this; 399 | } 400 | 401 | private $where_in_values = []; 402 | 403 | public function where_in_values($field, array $values, $splitter = 'AND', $prefix = '') 404 | { 405 | $this->compiled = false; 406 | if (!count($values)) { 407 | throw new Exception('The WHERE_IN_VALUES requires $values array to have values.'); 408 | } 409 | 410 | $this->where_indexes[] = 'where_in_values'; 411 | $this->where_in_values[] = [$field, $values, $splitter, $prefix]; 412 | return $this; 413 | } 414 | 415 | public function or_where_in_values($field, array $values) 416 | { 417 | return $this->where_in_values($field, $values, 'OR'); 418 | } 419 | 420 | public function and_where_in_values($field, array $values) 421 | { 422 | return $this->where_in_values($field, $values, 'AND'); 423 | } 424 | 425 | public function where_not_in_values($field, array $values, $splitter = 'AND') 426 | { 427 | return $this->where_in_values($field, $values, $splitter, 'NOT'); 428 | } 429 | 430 | public function and_where_not_in_values($field, array $values) 431 | { 432 | return $this->where_in_values($field, $values, 'AND', 'NOT'); 433 | } 434 | 435 | public function or_where_not_in_values($field, array $values) 436 | { 437 | return $this->where_in_values($field, $values, 'OR', 'NOT'); 438 | } 439 | 440 | private $where_in_subquery = []; 441 | 442 | public function where_in_subquery($field, $value, $splitter = 'AND', $prefix = '') 443 | { 444 | $this->compiled = false; 445 | if (!is_string($value)) { 446 | if ($value instanceof Select) { 447 | $value = $value->debug(true); 448 | $this->compiled_params = array_merge($this->compiled_params, $value['parameters']); 449 | $value = $value['query']; 450 | } else { 451 | throw new Exception('WHERE IN SUBQUERY requires either a raw sql query string or a SELECT builder that has not been executed.'); 452 | } 453 | } 454 | 455 | $this->where_indexes[] = 'where_in_subquery'; 456 | $this->where_in_subquery[] = [$field, $value, $splitter, $prefix]; 457 | return $this; 458 | } 459 | 460 | public function and_where_in_subquery($field, $value) 461 | { 462 | return $this->where_in_subquery($field, $value); 463 | } 464 | 465 | public function or_where_in_subquery($field, $value) 466 | { 467 | return $this->where_in_subquery($field, $value, 'OR'); 468 | } 469 | 470 | public function where_not_in_subquery($field, $value, $splitter = 'AND') 471 | { 472 | return $this->where_in_subquery($field, $value, $splitter, 'NOT'); 473 | } 474 | 475 | public function and_where_not_in_subquery($field, $value) 476 | { 477 | return $this->where_in_subquery($field, $value, 'AND', 'NOT'); 478 | } 479 | 480 | public function or_where_not_in_subquery($field, $value) 481 | { 482 | return $this->where_in_subquery($field, $value, 'OR', 'NOT'); 483 | } 484 | 485 | private $group_by = []; 486 | 487 | public function group_by($column) 488 | { 489 | $this->compiled = false; 490 | $this->group_by[] = $column; 491 | return $this; 492 | } 493 | 494 | private $raw_group_by = []; 495 | 496 | public function raw_group_by($column) 497 | { 498 | $this->compiled = false; 499 | $this->raw_group_by[] = $column; 500 | return $this; 501 | } 502 | 503 | private $order_by = []; 504 | 505 | public function order_by($column, $direction) 506 | { 507 | $this->compiled = false; 508 | $direction = strtolower($direction); 509 | 510 | if (!in_array($direction, ['asc', 'desc'])) { 511 | throw new Exception('ORDER BY ' . $column . ' - the given direction "' . $direction . '" is not valid, provide ASC or DESC'); 512 | } 513 | 514 | $this->order_by[] = [$column, $direction]; 515 | return $this; 516 | } 517 | 518 | private $offset = null; 519 | 520 | public function offset($offset) 521 | { 522 | $this->compiled = false; 523 | if (!is_numeric($offset)) { 524 | throw new Exception('Offset must be an integer.'); 525 | } 526 | $this->offset = $offset; 527 | return $this; 528 | } 529 | 530 | private $limit = null; 531 | 532 | public function limit($limit) 533 | { 534 | $this->compiled = false; 535 | if (!is_numeric($limit)) { 536 | throw new Exception('Offset must be an integer.'); 537 | } 538 | $this->limit = $limit; 539 | return $this; 540 | } 541 | 542 | } 543 | -------------------------------------------------------------------------------- /src/Builder/Update.php: -------------------------------------------------------------------------------- 1 | compileIndexActive = hash('crc32', self::$compileIndex); 26 | $this->server = $server; 27 | } 28 | 29 | public function reset() 30 | { 31 | return new self($this->server); 32 | } 33 | 34 | protected function compile() 35 | { 36 | $this->compiled_query .= 'UPDATE'; 37 | 38 | $holder = []; 39 | foreach ($this->table as $data) { 40 | $data[0] = $this->clean($data[0]); 41 | 42 | if ($data[1] !== null) { 43 | $data[1] = $this->clean($data[1]); 44 | $holder[] = $data[0] . ' AS ' . $data[1] . ''; 45 | } else { 46 | $holder[] = $data[0]; 47 | } 48 | } 49 | 50 | $this->compiled_query .= ' ' . implode(', ', $holder); 51 | 52 | foreach ($this->joins as $joinIndex => $joinData) { 53 | list($table, $alias, $format) = $joinData; 54 | 55 | $format = strtoupper($format); 56 | $table = $this->clean($table); 57 | 58 | if ($alias !== null) { 59 | $alias = $this->clean($alias); 60 | $this->compiled_query .= ' ' . $format . ($format ? ' ' : '') . 'JOIN ' . $table . ' AS ' . $alias; 61 | } else { 62 | $this->compiled_query .= ' ' . $format . ($format ? ' ' : '') . 'JOIN ' . $table; 63 | } 64 | 65 | if (isset($this->on[$joinIndex])) { 66 | $holder = ''; 67 | foreach ($this->on[$joinIndex] as $on) { 68 | list($field1, $operator, $field2, $statement) = $on; 69 | $holder .= ($holder ? ' ' . $statement : 'ON'); 70 | 71 | $field1 = $this->clean($field1); 72 | $field2 = $this->clean($field2); 73 | 74 | $holder .= ' ' . $field1 . ' ' . $operator . ' ' . $field2; 75 | } 76 | 77 | $this->compiled_query .= ' ' . $holder; 78 | } 79 | } 80 | 81 | $holder = []; 82 | 83 | foreach ($this->set as $set) { 84 | list($column, $operator, $value, $rawValue) = $set; 85 | 86 | if ($rawValue) { 87 | $key = $value; 88 | } else { 89 | $key = ':c' . $this->compileIndexActive . 'v' . hash('crc32', count($this->compiled_params)); 90 | $this->compiled_params[$key] = $value; 91 | } 92 | 93 | $column = $this->clean($column); 94 | $holder[] = $column . ' ' . $operator . ' ' . $key; 95 | } 96 | 97 | if (!count($holder)) { 98 | throw new Exception('UPDATE build failed, no SET parameters given'); 99 | } 100 | 101 | $this->compiled_query .= ' SET ' . implode(', ', $holder); 102 | 103 | $raw_where = 0; 104 | $where = 0; 105 | $where_in_values = 0; 106 | $where_in_subquery = 0; 107 | 108 | $holder = ''; 109 | $was_change = true; 110 | 111 | foreach ($this->where_indexes as $windex) { 112 | if ($windex == 'and_open' || $windex == 'or_open') { 113 | $holder .= ($holder ? ($windex == 'and_open' ? ' AND ' : ' OR ') : '') . '('; 114 | $was_change = true; 115 | continue; 116 | } elseif ($windex == 'close') { 117 | $holder .= ')'; 118 | continue; 119 | } elseif ($windex == 'where') { 120 | list($field, $operator, $value, $format, $values2, $splitter) = $this->{$windex}[$$windex++]; 121 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 122 | $was_change = false; 123 | 124 | $field = $this->clean($field); 125 | $key = ':c' . $this->compileIndexActive . 'v' . hash('crc32', count($this->compiled_params)); 126 | $this->compiled_params[$key] = $value; 127 | $holder .= $field . ' ' . $operator . ' ' . $key; 128 | 129 | if ($format !== null) { 130 | $holder .= ' ' . $format; 131 | } 132 | 133 | if ($values2 !== null) { 134 | $key = ':c' . $this->compileIndexActive . 'v' . hash('crc32', count($this->compiled_params)); 135 | $this->compiled_params[$key] = $values2; 136 | $holder .= ' ' . $key; 137 | } 138 | } elseif ($windex == 'raw_where') { 139 | list($field, $operator, $value, $format, $values2, $splitter) = $this->{$windex}[$$windex++]; 140 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 141 | $was_change = false; 142 | 143 | $field = $this->clean($field); 144 | $holder .= $field . ' ' . $operator . ' ' . $value; 145 | 146 | if ($format !== null) { 147 | $holder .= ' ' . $format; 148 | } 149 | 150 | if ($values2 !== null) { 151 | $holder .= ' ' . $values2; 152 | } 153 | } elseif ($windex == 'where_in_values') { 154 | list($field, $values, $splitter, $prefix) = $this->{$windex}[$$windex++]; 155 | $field = $this->clean($field); 156 | 157 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 158 | $was_change = false; 159 | 160 | $holder .= $field . ($prefix ? ' ' . $prefix : '') . ' IN('; 161 | 162 | $i = 0; 163 | foreach ($values as $index => $value) { 164 | if ($i++) { 165 | $holder .= ', '; 166 | } 167 | $key = ':c' . $this->compileIndexActive . 'v' . hash('crc32', count($this->compiled_params)); 168 | $this->compiled_params[$key] = $value; 169 | $holder .= $key; 170 | } 171 | $holder .= ')'; 172 | } elseif ($windex == 'where_in_subquery') { 173 | list($field, $value, $splitter, $prefix) = $this->{$windex}[$$windex++]; 174 | $field = $this->clean($field); 175 | 176 | $holder .= ($was_change ? '' : ' ' . $splitter . ' '); 177 | $was_change = false; 178 | 179 | $holder .= $field . ($prefix ? ' ' . $prefix : '') . ' IN(' . $value . ')'; 180 | } 181 | } 182 | 183 | if ($holder) { 184 | $this->compiled_query .= ' WHERE ' . $holder; 185 | } 186 | 187 | $this->compiled = true; 188 | } 189 | 190 | private $table = []; 191 | 192 | public function table($name, $alias = null) 193 | { 194 | $this->compiled = false; 195 | $this->table[] = [$name, $alias]; 196 | return $this; 197 | } 198 | 199 | private $joins = []; 200 | 201 | public function join($table, $alias = null, $format = 'LEFT') 202 | { 203 | $this->compiled = false; 204 | if (!$format) { 205 | $format = ''; 206 | } 207 | 208 | $this->joins[] = [$table, $alias, $format]; 209 | 210 | return $this; 211 | } 212 | 213 | private $on = []; 214 | 215 | public function on($field1, $operator, $field2, $format = 'AND') 216 | { 217 | $this->compiled = false; 218 | if (!count($this->joins)) { 219 | throw new Exception('Cannot call query builders ON if there was no join initiated.'); 220 | } 221 | 222 | $joinIndex = count($this->joins) - 1; 223 | 224 | if (!isset($this->on[$joinIndex])) { 225 | $this->on[$joinIndex] = []; 226 | } 227 | 228 | $this->on[$joinIndex][] = [$field1, $operator, $field2, strtoupper($format)]; 229 | 230 | return $this; 231 | } 232 | 233 | private $where = []; 234 | 235 | public function where($field, $operator, $value, $format = null, $values2 = null, $splitter = 'AND') 236 | { 237 | $this->compiled = false; 238 | $this->where_indexes[] = 'where'; 239 | $this->where[] = [$field, $operator, $value, $format, $values2, $splitter]; 240 | return $this; 241 | } 242 | 243 | public function or_where($field, $operator, $value, $format = null, $values2 = null) 244 | { 245 | return $this->where($field, $operator, $value, $format, $values2, 'OR'); 246 | } 247 | 248 | public function and_where($field, $operator, $value, $format = null, $values2 = null) 249 | { 250 | return $this->where($field, $operator, $value, $format, $values2, 'AND'); 251 | } 252 | 253 | private $raw_where = []; 254 | 255 | public function raw_where($field, $operator, $value, $format = null, $values2 = null, $splitter = 'AND') 256 | { 257 | $this->compiled = false; 258 | $this->where_indexes[] = 'raw_where'; 259 | $this->raw_where[] = [$field, $operator, $value, $format, $values2, $splitter]; 260 | return $this; 261 | } 262 | 263 | public function raw_or_where($field, $operator, $value, $format = null, $values2 = null) 264 | { 265 | return $this->raw_where($field, $operator, $value, $format, $values2, 'OR'); 266 | } 267 | 268 | public function raw_and_where($field, $operator, $value, $format = null, $values2 = null) 269 | { 270 | return $this->raw_where($field, $operator, $value, $format, $values2, 'AND'); 271 | } 272 | 273 | public function open() 274 | { 275 | $this->where_indexes[] = 'and_open'; 276 | return $this; 277 | } 278 | 279 | public function or_open() 280 | { 281 | $this->where_indexes[] = 'or_open'; 282 | return $this; 283 | } 284 | 285 | public function close() 286 | { 287 | $this->where_indexes[] = 'close'; 288 | return $this; 289 | } 290 | 291 | private $where_in_values = []; 292 | 293 | public function where_in_values($field, array $values, $splitter = 'AND', $prefix = '') 294 | { 295 | $this->compiled = false; 296 | if (!count($values)) { 297 | throw new Exception('The WHERE_IN_VALUES requires $values array to have values.'); 298 | } 299 | 300 | $this->where_indexes[] = 'where_in_values'; 301 | $this->where_in_values[] = [$field, $values, $splitter, $prefix]; 302 | return $this; 303 | } 304 | 305 | public function or_where_in_values($field, array $values) 306 | { 307 | return $this->where_in_values($field, $values, 'OR'); 308 | } 309 | 310 | public function and_where_in_values($field, array $values) 311 | { 312 | return $this->where_in_values($field, $values, 'AND'); 313 | } 314 | 315 | public function where_not_in_values($field, array $values, $splitter = 'AND') 316 | { 317 | return $this->where_in_values($field, $values, $splitter, 'NOT'); 318 | } 319 | 320 | public function and_where_not_in_values($field, array $values) 321 | { 322 | return $this->where_in_values($field, $values, 'AND', 'NOT'); 323 | } 324 | 325 | public function or_where_not_in_values($field, array $values) 326 | { 327 | return $this->where_in_values($field, $values, 'OR', 'NOT'); 328 | } 329 | 330 | private $where_in_subquery = []; 331 | 332 | public function where_in_subquery($field, $value, $splitter = 'AND', $prefix = '') 333 | { 334 | $this->compiled = false; 335 | if (!is_string($value)) { 336 | if ($value instanceof Select) { 337 | $value = $value->debug(true); 338 | $this->compiled_params = array_merge($this->compiled_params, $value['parameters']); 339 | $value = $value['query']; 340 | } else { 341 | throw new Exception('WHERE IN SUBQUERY requires either a raw sql query string or a SELECT builder that has not been executed.'); 342 | } 343 | } 344 | 345 | $this->where_indexes[] = 'where_in_subquery'; 346 | $this->where_in_subquery[] = [$field, $value, $splitter, $prefix]; 347 | return $this; 348 | } 349 | 350 | public function and_where_in_subquery($field, $value) 351 | { 352 | return $this->where_in_subquery($field, $value); 353 | } 354 | 355 | public function or_where_in_subquery($field, $value) 356 | { 357 | return $this->where_in_subquery($field, $value, 'OR'); 358 | } 359 | 360 | public function where_not_in_subquery($field, $value) 361 | { 362 | return $this->where_in_subquery($field, $value, 'AND', 'NOT'); 363 | } 364 | 365 | public function and_where_not_in_subquery($field, $value) 366 | { 367 | return $this->where_in_subquery($field, $value, 'AND', 'NOT'); 368 | } 369 | 370 | public function or_where_not_in_subquery($field, $value) 371 | { 372 | return $this->where_in_subquery($field, $value, 'OR', 'NOT'); 373 | } 374 | 375 | private $set = []; 376 | 377 | public function set($column, $operator, $value, $rawValue = false) 378 | { 379 | $this->compiled = false; 380 | $this->set[] = [$column, $operator, $value, $rawValue]; 381 | return $this; 382 | } 383 | 384 | } 385 | -------------------------------------------------------------------------------- /src/Configuration.php: -------------------------------------------------------------------------------- 1 | $prop; 37 | } 38 | 39 | if (substr($method, 0, 3) == 'set') { 40 | $prop = strtolower(substr($method, 3)); 41 | if (!property_exists($this, $prop)) { 42 | throw new Exception('Trying to set an unknown configuration variable: ' . $prop); 43 | } 44 | if (!isset($arguments[0])) { 45 | throw new Exception('Trying to set configuration variable ' . $prop . ' without providing its value.'); 46 | } 47 | $this->$prop = $arguments[0]; 48 | return $this; 49 | } 50 | 51 | throw new Exception('Trying to call an unknown configuration method: ' . $method); 52 | } 53 | 54 | public function attach() 55 | { 56 | $class = new self(get_object_vars($this)); 57 | return $class; 58 | } 59 | 60 | public function __construct($properties = []) 61 | { 62 | if (!count($properties)) { 63 | return; 64 | } 65 | 66 | foreach ($properties as $property => $value) { 67 | $this->$property = $value; 68 | } 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /src/Helpers.php: -------------------------------------------------------------------------------- 1 | !empty($options['on_duplicate_key_update']), 12 | ]; 13 | 14 | $builder = $this->build($type, $options)->into($table); 15 | 16 | foreach ($values as $key => $value) { 17 | if (is_numeric($key)) { 18 | $builder->value($value); 19 | } else { 20 | $builder->set($key, $value); 21 | } 22 | } 23 | 24 | return $builder->execute(); 25 | } 26 | 27 | public function insert($table, array $values = [], array $options = []) 28 | { 29 | return $this->__call_insert($table, $values, 'insert', $options); 30 | } 31 | 32 | public function ignore($table, array $values = []) 33 | { 34 | return $this->__call_insert($table, $values, 'ignore'); 35 | } 36 | 37 | public function replace($table, array $values = []) 38 | { 39 | return $this->__call_insert($table, $values, 'replace'); 40 | } 41 | 42 | public function delete($table, array $values = []) 43 | { 44 | $builder = $this->build('delete')->from($table); 45 | 46 | foreach ($values as $key => $value) { 47 | $builder->where($key, '=', $value); 48 | } 49 | 50 | $builder->execute(); 51 | } 52 | 53 | public function update($table, array $set = [], array $where = []) 54 | { 55 | $builder = $this->build('update')->table($table); 56 | 57 | foreach ($set as $key => $value) { 58 | $builder->set($key, '=', $value); 59 | } 60 | 61 | foreach ($where as $key => $value) { 62 | $builder->where($key, '=', $value); 63 | } 64 | 65 | $builder->execute(); 66 | } 67 | 68 | public function replaceMany($table, array $input, $get_query = false, $database = null){ 69 | return $this->insertMany($table, $input, $get_query, $database, 'replace'); 70 | } 71 | 72 | public function ignoreMany($table, array $input, $get_query = false, $database = null){ 73 | return $this->insertMany($table, $input, $get_query, $database, 'insert ignore'); 74 | } 75 | 76 | public function insertMany($table, array $input, $get_query = false, $database = null, $method = 'insert') 77 | { 78 | if (empty($input)) { 79 | return false; 80 | } 81 | 82 | $table = str_replace('.', '`.`', $table); 83 | 84 | $keys = []; 85 | $values = []; 86 | $data = []; 87 | $rows = count($input); 88 | $columns = count(reset($input)); 89 | 90 | $query = $method . ' INTO ' . ($database !== null ? '`' . $database . '`.' : '') . '`' . $table . '` ('; 91 | 92 | foreach (reset($input) as $key => $value) { 93 | $keys[] = '`' . $key . '`'; 94 | } 95 | 96 | $query .= implode(',', $keys) . ') VALUES'; 97 | 98 | foreach ($input as $index => $row) 99 | { 100 | foreach ($row as $key => $value) 101 | { 102 | $keyName = ':v' . $index . $key; 103 | $values[] = $keyName; 104 | $data[$keyName] = $value; 105 | } 106 | 107 | if ($index != 0) { 108 | $query .= ','; 109 | } 110 | 111 | $query .= ' (' . implode(',', $values) . ')'; 112 | 113 | $values = []; 114 | } 115 | 116 | if ($get_query) { 117 | foreach ($data as $key => $value) { 118 | $query = str_replace($key, "'".str_replace("'","\\\'", $value), $query); 119 | } 120 | return $query; 121 | } 122 | 123 | $db = $this->prepare($query); 124 | $db->execute($data); 125 | } 126 | } -------------------------------------------------------------------------------- /src/Library.php: -------------------------------------------------------------------------------- 1 | attach(); 30 | 31 | return $this; 32 | } 33 | 34 | private static $connections = []; 35 | 36 | public function hasAttached($id) 37 | { 38 | return !empty(self::$configurationDetails[$id]); 39 | } 40 | 41 | public function connect($connection_id = 'default') 42 | { 43 | if (!isset(self::$connections[$connection_id])) { 44 | if (!isset(self::$configurationDetails[$connection_id])) { 45 | throw new Exception('Provided database connection id "' . $connection_id . '" has not been attached'); 46 | } 47 | self::$connections[$connection_id] = new Server(self::$configurationDetails[$connection_id]); 48 | } 49 | 50 | return self::$connections[$connection_id]; 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /src/Native.php: -------------------------------------------------------------------------------- 1 | isLogEnabled()) { 17 | $this->logQuery('native-pdo[beginTransaction]', ''); 18 | } 19 | return $this->createPDO()->beginTransaction(); 20 | } 21 | 22 | // http://php.net/manual/en/pdo.commit.php 23 | public function commit() 24 | { 25 | if ($this->isLogEnabled()) { 26 | $this->logQuery('native-pdo[commit]', ''); 27 | } 28 | return $this->createPDO()->commit(); 29 | } 30 | 31 | // http://php.net/manual/en/pdo.errorcode.php 32 | public function errorCode() 33 | { 34 | if ($this->isLogEnabled()) { 35 | $this->logQuery('native-pdo[errorCode]', ''); 36 | } 37 | return $this->createPDO()->errorCode(); 38 | } 39 | 40 | // http://php.net/manual/en/pdo.errorinfo.php 41 | public function errorInfo() 42 | { 43 | if ($this->isLogEnabled()) { 44 | $this->logQuery('native-pdo[errorInfo]', ''); 45 | } 46 | return $this->createPDO()->errorInfo(); 47 | } 48 | 49 | // http://php.net/manual/en/pdo.exec.php 50 | public function exec($statement) 51 | { 52 | if ($this->isLogEnabled()) { 53 | $this->logQuery('native-pdo[errorInfo]', $statement); 54 | } 55 | return $this->createPDO()->exec($statement); 56 | } 57 | 58 | // http://php.net/manual/en/pdo.getattribute.php 59 | public function getAttribute($attribute) 60 | { 61 | if ($this->isLogEnabled()) { 62 | $this->logQuery('native-pdo[getAttribute]', $name); 63 | } 64 | return $this->createPDO()->getAttribute($name); 65 | } 66 | 67 | // http://php.net/manual/en/pdo.getavailabledrivers.php 68 | public function getAvailableDrivers() 69 | { 70 | if ($this->isLogEnabled()) { 71 | $this->logQuery('native-pdo[getAvailableDrivers]', ''); 72 | } 73 | return $this->createPOD()->getAvailableDrivers(); 74 | } 75 | 76 | // http://php.net/manual/en/pdo.intransaction.php 77 | public function inTransaction() 78 | { 79 | if ($this->isLogEnabled()) { 80 | $this->logQuery('native-pdo[inTransaction]', ''); 81 | } 82 | return $this->createPDO()->inTransaction(); 83 | } 84 | 85 | // http://php.net/manual/en/pdo.lastinsertid.php 86 | public function lastInsertId($name = null) 87 | { 88 | if ($this->isLogEnabled()) { 89 | $this->logQuery('native-pdo[lastInsertId]', $name); 90 | } 91 | return $this->createPDO()->lastInsertId($name); 92 | } 93 | 94 | // http://php.net/manual/en/pdo.prepare.php 95 | public function prepare($statement, $driver_options = []) 96 | { 97 | if ($this->isLogEnabled()) { 98 | $this->logQuery('native-pdo[prepare]', [$statement, $driver_options]); 99 | } 100 | return $this->createPDO()->prepare($statement, $driver_options); 101 | } 102 | 103 | // http://php.net/manual/en/pdo.query.php 104 | public function query($statement, $mode = null, $info1 = null, $info2 = null) 105 | { 106 | $pdo = $this->createPDO(); 107 | $options = [$statement]; 108 | 109 | if ($mode !== null) { 110 | $options[] = $mode; 111 | } 112 | 113 | if ($info1 !== null) { 114 | $options[] = $info1; 115 | } 116 | 117 | if ($info2 !== null) { 118 | $options[] = $info2; 119 | } 120 | 121 | $this->logQuery('native-pdo[query]', $options); 122 | 123 | return call_user_func_array([$pdo, 'query'], $options); 124 | } 125 | 126 | // http://php.net/manual/en/pdo.quote.php 127 | public function quote($string, $parameter_type = null) 128 | { 129 | $pdo = $this->createPDO(); 130 | $options = [$string]; 131 | 132 | if ($parameter_type !== null) { 133 | $options[] = $parameter_type; 134 | } 135 | 136 | $this->logQuery('native-pdo[quote]', $options); 137 | 138 | return call_user_func_array([$pdo, 'quote'], $options); 139 | } 140 | 141 | // http://php.net/manual/en/pdo.rollback.php 142 | public function rollBack() 143 | { 144 | $this->logQuery('native-pdo[rollBack]', ''); 145 | return $this->createPDO()->rollBack(); 146 | } 147 | 148 | // http://php.net/manual/en/pdo.setattribute.php 149 | public function setAttribute($attribute, $value) 150 | { 151 | $this->logQuery('native-pdo[setAttribute]', [$attribute, $value]); 152 | return $this->createPDO()->setAttribute($attribute, $value); 153 | } 154 | 155 | } -------------------------------------------------------------------------------- /src/Report.php: -------------------------------------------------------------------------------- 1 | attach($this); 14 | return $report->result(); 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /src/Report/Database/Structure.php: -------------------------------------------------------------------------------- 1 | server = $server; 16 | $this->configuration = $server->getConfiguration(); 17 | return $this; 18 | } 19 | 20 | private $result = null; 21 | 22 | public function result($fresh = false) 23 | { 24 | if ($this->result !== null) { 25 | if (!$fresh) { 26 | return $this->result; 27 | } 28 | } 29 | 30 | $info = []; 31 | $info['size'] = [ 32 | 'bytes' => 0, 33 | 'mb' => 0 34 | ]; 35 | $info['rows'] = 0; 36 | $info['name'] = $this->configuration->getDatabase(); 37 | 38 | $tables = []; 39 | 40 | foreach ($this->server->build('select') 41 | ->column('ist.DATA_LENGTH') 42 | ->column('ist.INDEX_LENGTH') 43 | ->column('ist.TABLE_ROWS') 44 | ->column('ist.TABLE_NAME') 45 | ->column('ist.CREATE_TIME') 46 | ->from('information_schema.TABLES', 'ist') 47 | ->where('TABLE_SCHEMA', '=', $this->configuration->getDatabase()) 48 | ->execute() 49 | ->fetchAll() as $ist) { 50 | $table = []; 51 | $table['size'] = []; 52 | $table['size']['bytes'] = $ist->DATA_LENGTH + $ist->INDEX_LENGTH; 53 | $table['size']['mb'] = @round(($table['size']['bytes'] / 1024 / 1024), 2); 54 | $table['rows'] = $ist->TABLE_ROWS; 55 | $table['name'] = $ist->TABLE_NAME; 56 | $table['created'] = strtotime($ist->CREATE_TIME); 57 | 58 | $info['size']['bytes'] += $table['size']['bytes']; 59 | $info['rows'] += $table['rows']; 60 | 61 | $tables[] = $table; 62 | } 63 | 64 | $info['size']['mb'] = @round(($info['size']['bytes'] / 1024 / 1024), 2); 65 | 66 | $this->result = [ 67 | 'database' => $info, 68 | 'tables' => $tables 69 | ]; 70 | 71 | return $this->result; 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /src/Server.php: -------------------------------------------------------------------------------- 1 | state = self::DISCONNECTED; 37 | $this->configuration = $configuration; 38 | } 39 | 40 | public function getConfiguration() 41 | { 42 | return $this->configuration; 43 | } 44 | 45 | protected function createPDO() 46 | { 47 | // do not connect if already connected 48 | if ($this->state == self::CONNECTED) { 49 | // do not connect if the grace timeout not reached 50 | if ((time() - $this->pdo_connection_time) <= $this->configuration->getTimeout()) { 51 | return $this->pdo; 52 | } 53 | 54 | // require a fresh connection 55 | $this->pdo = null; 56 | $this->state = self::DISCONNECTED; 57 | } 58 | 59 | $dsn = 'mysql:host=' . $this->configuration->getHostname() . ';'; 60 | $dsn .= 'port=' . $this->configuration->getPort() . ';'; 61 | $dsn .= 'dbname=' . $this->configuration->getDatabase(); 62 | 63 | $options = []; 64 | $options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION; 65 | $options[PDO::ATTR_DEFAULT_FETCH_MODE] = PDO::FETCH_OBJ; 66 | $options[PDO::ATTR_PERSISTENT] = $this->configuration->getPersistent() ? true : false; 67 | 68 | $command = ''; 69 | if ($encoding = $this->configuration->getEncoding()) { 70 | $command .= 'SET NAMES \'' . $encoding . '\''; 71 | } 72 | 73 | if (!empty($command)) { 74 | $options[PDO::MYSQL_ATTR_INIT_COMMAND] = $command; 75 | } 76 | 77 | $this->pdo = new PDO($dsn, $this->configuration->getUsername(), $this->configuration->getPassword(), $options); 78 | $this->pdo_connection_time = time(); 79 | $this->state = self::CONNECTED; 80 | return $this->pdo; 81 | } 82 | 83 | public function getNativePdo() 84 | { 85 | return $this->createPDO(); 86 | } 87 | 88 | public function build($format, array $options = []) 89 | { 90 | if ($format == 'insert') { 91 | return new Insert($this, $options); 92 | } elseif ($format == 'replace') { 93 | return new Replace($this); 94 | } elseif ($format == 'ignore') { 95 | return new Ignore($this); 96 | } elseif ($format == 'select') { 97 | return new Select($this); 98 | } elseif ($format == 'delete') { 99 | return new Delete($this); 100 | } elseif ($format == 'update') { 101 | return new Update($this); 102 | } else { 103 | throw new Exception('Requested build format "' . $format . '" does not exist."'); 104 | } 105 | } 106 | 107 | public function isLogEnabled() 108 | { 109 | return (bool)$this->configuration->getLog(); 110 | } 111 | 112 | public function logQuery($format, $query) 113 | { 114 | $backtrace = debug_backtrace(); 115 | array_shift($backtrace); // remove builder call 116 | 117 | self::$queryLog[] = [ 118 | 'format' => $format, 119 | 'query' => $query, 120 | 'caller' => [ 121 | 'filename' => $backtrace[0]['file'], 122 | 'line_number' => $backtrace[0]['line'] 123 | ] 124 | ]; 125 | } 126 | 127 | public function getQueryLog() 128 | { 129 | return self::$queryLog; 130 | } 131 | 132 | } -------------------------------------------------------------------------------- /tests/LibraryTest.php: -------------------------------------------------------------------------------- 1 | KML instanceof \Kodols\MySQL\Library) { 15 | $this->KML = new \Kodols\MySQL\Library; 16 | } 17 | } 18 | 19 | private function installBasicConfig($id) 20 | { 21 | $this->generateLibrary(); 22 | $this->KML->attachConfiguration($this->KML->newConfiguration(), $id); 23 | } 24 | 25 | public function testConfigurationObject() 26 | { 27 | $this->generateLibrary(); 28 | 29 | $config = $this->KML->newConfiguration(); 30 | 31 | $this->assertInstanceOf(\Kodols\MySQL\Configuration::class, $config); 32 | 33 | $config->setDatabase('unittest'); 34 | $this->assertEquals('unittest', $config->getDatabase()); 35 | 36 | $this->assertInstanceOf(\Kodols\MySQL\Library::class, $this->KML->attachConfiguration($config, 'testConfigurationObject')); 37 | } 38 | 39 | public function testAbilityToExecuteNativeMethodsFromMainObject() 40 | { 41 | $this->installBasicConfig('testAbilityToExecuteNativeMethodsFromMainObject'); 42 | $server = $this->KML->connect('testAbilityToExecuteNativeMethodsFromMainObject'); 43 | 44 | $this->assertTrue(method_exists($server, 'beginTransaction')); 45 | $this->assertTrue(method_exists($server, 'commit')); 46 | $this->assertTrue(method_exists($server, 'errorCode')); 47 | $this->assertTrue(method_exists($server, 'errorInfo')); 48 | $this->assertTrue(method_exists($server, 'exec')); 49 | $this->assertTrue(method_exists($server, 'getAttribute')); 50 | $this->assertTrue(method_exists($server, 'getAvailableDrivers')); 51 | $this->assertTrue(method_exists($server, 'inTransaction')); 52 | $this->assertTrue(method_exists($server, 'lastInsertId')); 53 | $this->assertTrue(method_exists($server, 'prepare')); 54 | $this->assertTrue(method_exists($server, 'query')); 55 | $this->assertTrue(method_exists($server, 'quote')); 56 | $this->assertTrue(method_exists($server, 'rollBack')); 57 | $this->assertTrue(method_exists($server, 'setAttribute')); 58 | } 59 | 60 | public function testAbilityToExecuteHelperMethodsFromMainObject() 61 | { 62 | $this->installBasicConfig('testAbilityToExecuteHelperMethodsFromMainObject'); 63 | $server = $this->KML->connect('testAbilityToExecuteHelperMethodsFromMainObject'); 64 | 65 | $this->assertTrue(method_exists($server, 'insert')); 66 | $this->assertTrue(method_exists($server, 'ignore')); 67 | $this->assertTrue(method_exists($server, 'replace')); 68 | $this->assertTrue(method_exists($server, 'update')); 69 | $this->assertTrue(method_exists($server, 'delete')); 70 | } 71 | 72 | public function testBuilderInitialisation() 73 | { 74 | $this->installBasicConfig('testBuilderInitialisation'); 75 | $server = $this->KML->connect('testBuilderInitialisation'); 76 | 77 | $this->assertInstanceOf(\Kodols\MySQL\Builder\Delete::class, $server->build('delete')); 78 | $this->assertInstanceOf(\Kodols\MySQL\Builder\Update::class, $server->build('update')); 79 | $this->assertInstanceOf(\Kodols\MySQL\Builder\Select::class, $server->build('select')); 80 | $this->assertInstanceOf(\Kodols\MySQL\Builder\Insert::class, $server->build('insert')); 81 | $this->assertInstanceOf(\Kodols\MySQL\Builder\Ignore::class, $server->build('ignore')); 82 | $this->assertInstanceOf(\Kodols\MySQL\Builder\Replace::class, $server->build('replace')); 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 |