├── .env.example ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── config └── definitions.php ├── database.sql ├── public ├── .htaccess └── index.php └── src └── App ├── Controllers ├── ProductIndex.php └── Products.php ├── Database.php ├── Middleware ├── AddJsonResponseHeader.php └── GetProduct.php └── Repositories └── ProductRepository.php /.env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= 2 | DB_NAME= 3 | DB_USER= 4 | DB_PASS= 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | /vendor/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Dave Hollingworth 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 | # Slim PHP REST API 2 | 3 | Source code to accompany this video: https://youtu.be/PHZtujcTRPk 4 | 5 | [![REST API with PHP and MySQL | Full Slim PHP Micro Framework Tutorial](https://img.youtube.com/vi/PHZtujcTRPk/0.jpg)](https://youtu.be/PHZtujcTRPk) 6 | 7 | ## Topics covered in the video 8 | * Slim basics 9 | * Code organisation in Slim 10 | * Using third-party packages in Slim 11 | * Dependency Injection 12 | * Middleware 13 | * Slim controllers 14 | * Slim configuration 15 | 16 | Complete API course, including authentication: https://davehollingworth.net/phpapisy 17 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "slim/slim": "^4.12", 4 | "slim/psr7": "^1.6", 5 | "php-di/php-di": "^7.0", 6 | "vlucas/valitron": "^1.4", 7 | "vlucas/phpdotenv": "^5.6" 8 | }, 9 | "autoload": { 10 | "psr-4": { 11 | "": "src/" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "2d52e8bea1cb98dae5da88638978c8b9", 8 | "packages": [ 9 | { 10 | "name": "fig/http-message-util", 11 | "version": "1.1.5", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/php-fig/http-message-util.git", 15 | "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", 20 | "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": "^5.3 || ^7.0 || ^8.0" 25 | }, 26 | "suggest": { 27 | "psr/http-message": "The package containing the PSR-7 interfaces" 28 | }, 29 | "type": "library", 30 | "extra": { 31 | "branch-alias": { 32 | "dev-master": "1.1.x-dev" 33 | } 34 | }, 35 | "autoload": { 36 | "psr-4": { 37 | "Fig\\Http\\Message\\": "src/" 38 | } 39 | }, 40 | "notification-url": "https://packagist.org/downloads/", 41 | "license": [ 42 | "MIT" 43 | ], 44 | "authors": [ 45 | { 46 | "name": "PHP-FIG", 47 | "homepage": "https://www.php-fig.org/" 48 | } 49 | ], 50 | "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", 51 | "keywords": [ 52 | "http", 53 | "http-message", 54 | "psr", 55 | "psr-7", 56 | "request", 57 | "response" 58 | ], 59 | "support": { 60 | "issues": "https://github.com/php-fig/http-message-util/issues", 61 | "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" 62 | }, 63 | "time": "2020-11-24T22:02:12+00:00" 64 | }, 65 | { 66 | "name": "graham-campbell/result-type", 67 | "version": "v1.1.2", 68 | "source": { 69 | "type": "git", 70 | "url": "https://github.com/GrahamCampbell/Result-Type.git", 71 | "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862" 72 | }, 73 | "dist": { 74 | "type": "zip", 75 | "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/fbd48bce38f73f8a4ec8583362e732e4095e5862", 76 | "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862", 77 | "shasum": "" 78 | }, 79 | "require": { 80 | "php": "^7.2.5 || ^8.0", 81 | "phpoption/phpoption": "^1.9.2" 82 | }, 83 | "require-dev": { 84 | "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" 85 | }, 86 | "type": "library", 87 | "autoload": { 88 | "psr-4": { 89 | "GrahamCampbell\\ResultType\\": "src/" 90 | } 91 | }, 92 | "notification-url": "https://packagist.org/downloads/", 93 | "license": [ 94 | "MIT" 95 | ], 96 | "authors": [ 97 | { 98 | "name": "Graham Campbell", 99 | "email": "hello@gjcampbell.co.uk", 100 | "homepage": "https://github.com/GrahamCampbell" 101 | } 102 | ], 103 | "description": "An Implementation Of The Result Type", 104 | "keywords": [ 105 | "Graham Campbell", 106 | "GrahamCampbell", 107 | "Result Type", 108 | "Result-Type", 109 | "result" 110 | ], 111 | "support": { 112 | "issues": "https://github.com/GrahamCampbell/Result-Type/issues", 113 | "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.2" 114 | }, 115 | "funding": [ 116 | { 117 | "url": "https://github.com/GrahamCampbell", 118 | "type": "github" 119 | }, 120 | { 121 | "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", 122 | "type": "tidelift" 123 | } 124 | ], 125 | "time": "2023-11-12T22:16:48+00:00" 126 | }, 127 | { 128 | "name": "laravel/serializable-closure", 129 | "version": "v1.3.3", 130 | "source": { 131 | "type": "git", 132 | "url": "https://github.com/laravel/serializable-closure.git", 133 | "reference": "3dbf8a8e914634c48d389c1234552666b3d43754" 134 | }, 135 | "dist": { 136 | "type": "zip", 137 | "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754", 138 | "reference": "3dbf8a8e914634c48d389c1234552666b3d43754", 139 | "shasum": "" 140 | }, 141 | "require": { 142 | "php": "^7.3|^8.0" 143 | }, 144 | "require-dev": { 145 | "nesbot/carbon": "^2.61", 146 | "pestphp/pest": "^1.21.3", 147 | "phpstan/phpstan": "^1.8.2", 148 | "symfony/var-dumper": "^5.4.11" 149 | }, 150 | "type": "library", 151 | "extra": { 152 | "branch-alias": { 153 | "dev-master": "1.x-dev" 154 | } 155 | }, 156 | "autoload": { 157 | "psr-4": { 158 | "Laravel\\SerializableClosure\\": "src/" 159 | } 160 | }, 161 | "notification-url": "https://packagist.org/downloads/", 162 | "license": [ 163 | "MIT" 164 | ], 165 | "authors": [ 166 | { 167 | "name": "Taylor Otwell", 168 | "email": "taylor@laravel.com" 169 | }, 170 | { 171 | "name": "Nuno Maduro", 172 | "email": "nuno@laravel.com" 173 | } 174 | ], 175 | "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", 176 | "keywords": [ 177 | "closure", 178 | "laravel", 179 | "serializable" 180 | ], 181 | "support": { 182 | "issues": "https://github.com/laravel/serializable-closure/issues", 183 | "source": "https://github.com/laravel/serializable-closure" 184 | }, 185 | "time": "2023-11-08T14:08:06+00:00" 186 | }, 187 | { 188 | "name": "nikic/fast-route", 189 | "version": "v1.3.0", 190 | "source": { 191 | "type": "git", 192 | "url": "https://github.com/nikic/FastRoute.git", 193 | "reference": "181d480e08d9476e61381e04a71b34dc0432e812" 194 | }, 195 | "dist": { 196 | "type": "zip", 197 | "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", 198 | "reference": "181d480e08d9476e61381e04a71b34dc0432e812", 199 | "shasum": "" 200 | }, 201 | "require": { 202 | "php": ">=5.4.0" 203 | }, 204 | "require-dev": { 205 | "phpunit/phpunit": "^4.8.35|~5.7" 206 | }, 207 | "type": "library", 208 | "autoload": { 209 | "files": [ 210 | "src/functions.php" 211 | ], 212 | "psr-4": { 213 | "FastRoute\\": "src/" 214 | } 215 | }, 216 | "notification-url": "https://packagist.org/downloads/", 217 | "license": [ 218 | "BSD-3-Clause" 219 | ], 220 | "authors": [ 221 | { 222 | "name": "Nikita Popov", 223 | "email": "nikic@php.net" 224 | } 225 | ], 226 | "description": "Fast request router for PHP", 227 | "keywords": [ 228 | "router", 229 | "routing" 230 | ], 231 | "support": { 232 | "issues": "https://github.com/nikic/FastRoute/issues", 233 | "source": "https://github.com/nikic/FastRoute/tree/master" 234 | }, 235 | "time": "2018-02-13T20:26:39+00:00" 236 | }, 237 | { 238 | "name": "php-di/invoker", 239 | "version": "2.3.4", 240 | "source": { 241 | "type": "git", 242 | "url": "https://github.com/PHP-DI/Invoker.git", 243 | "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" 244 | }, 245 | "dist": { 246 | "type": "zip", 247 | "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", 248 | "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", 249 | "shasum": "" 250 | }, 251 | "require": { 252 | "php": ">=7.3", 253 | "psr/container": "^1.0|^2.0" 254 | }, 255 | "require-dev": { 256 | "athletic/athletic": "~0.1.8", 257 | "mnapoli/hard-mode": "~0.3.0", 258 | "phpunit/phpunit": "^9.0" 259 | }, 260 | "type": "library", 261 | "autoload": { 262 | "psr-4": { 263 | "Invoker\\": "src/" 264 | } 265 | }, 266 | "notification-url": "https://packagist.org/downloads/", 267 | "license": [ 268 | "MIT" 269 | ], 270 | "description": "Generic and extensible callable invoker", 271 | "homepage": "https://github.com/PHP-DI/Invoker", 272 | "keywords": [ 273 | "callable", 274 | "dependency", 275 | "dependency-injection", 276 | "injection", 277 | "invoke", 278 | "invoker" 279 | ], 280 | "support": { 281 | "issues": "https://github.com/PHP-DI/Invoker/issues", 282 | "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" 283 | }, 284 | "funding": [ 285 | { 286 | "url": "https://github.com/mnapoli", 287 | "type": "github" 288 | } 289 | ], 290 | "time": "2023-09-08T09:24:21+00:00" 291 | }, 292 | { 293 | "name": "php-di/php-di", 294 | "version": "7.0.6", 295 | "source": { 296 | "type": "git", 297 | "url": "https://github.com/PHP-DI/PHP-DI.git", 298 | "reference": "8097948a89f6ec782839b3e958432f427cac37fd" 299 | }, 300 | "dist": { 301 | "type": "zip", 302 | "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/8097948a89f6ec782839b3e958432f427cac37fd", 303 | "reference": "8097948a89f6ec782839b3e958432f427cac37fd", 304 | "shasum": "" 305 | }, 306 | "require": { 307 | "laravel/serializable-closure": "^1.0", 308 | "php": ">=8.0", 309 | "php-di/invoker": "^2.0", 310 | "psr/container": "^1.1 || ^2.0" 311 | }, 312 | "provide": { 313 | "psr/container-implementation": "^1.0" 314 | }, 315 | "require-dev": { 316 | "friendsofphp/php-cs-fixer": "^3", 317 | "friendsofphp/proxy-manager-lts": "^1", 318 | "mnapoli/phpunit-easymock": "^1.3", 319 | "phpunit/phpunit": "^9.5", 320 | "vimeo/psalm": "^4.6" 321 | }, 322 | "suggest": { 323 | "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)" 324 | }, 325 | "type": "library", 326 | "autoload": { 327 | "files": [ 328 | "src/functions.php" 329 | ], 330 | "psr-4": { 331 | "DI\\": "src/" 332 | } 333 | }, 334 | "notification-url": "https://packagist.org/downloads/", 335 | "license": [ 336 | "MIT" 337 | ], 338 | "description": "The dependency injection container for humans", 339 | "homepage": "https://php-di.org/", 340 | "keywords": [ 341 | "PSR-11", 342 | "container", 343 | "container-interop", 344 | "dependency injection", 345 | "di", 346 | "ioc", 347 | "psr11" 348 | ], 349 | "support": { 350 | "issues": "https://github.com/PHP-DI/PHP-DI/issues", 351 | "source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.6" 352 | }, 353 | "funding": [ 354 | { 355 | "url": "https://github.com/mnapoli", 356 | "type": "github" 357 | }, 358 | { 359 | "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", 360 | "type": "tidelift" 361 | } 362 | ], 363 | "time": "2023-11-02T10:04:50+00:00" 364 | }, 365 | { 366 | "name": "phpoption/phpoption", 367 | "version": "1.9.2", 368 | "source": { 369 | "type": "git", 370 | "url": "https://github.com/schmittjoh/php-option.git", 371 | "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820" 372 | }, 373 | "dist": { 374 | "type": "zip", 375 | "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/80735db690fe4fc5c76dfa7f9b770634285fa820", 376 | "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820", 377 | "shasum": "" 378 | }, 379 | "require": { 380 | "php": "^7.2.5 || ^8.0" 381 | }, 382 | "require-dev": { 383 | "bamarni/composer-bin-plugin": "^1.8.2", 384 | "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" 385 | }, 386 | "type": "library", 387 | "extra": { 388 | "bamarni-bin": { 389 | "bin-links": true, 390 | "forward-command": true 391 | }, 392 | "branch-alias": { 393 | "dev-master": "1.9-dev" 394 | } 395 | }, 396 | "autoload": { 397 | "psr-4": { 398 | "PhpOption\\": "src/PhpOption/" 399 | } 400 | }, 401 | "notification-url": "https://packagist.org/downloads/", 402 | "license": [ 403 | "Apache-2.0" 404 | ], 405 | "authors": [ 406 | { 407 | "name": "Johannes M. Schmitt", 408 | "email": "schmittjoh@gmail.com", 409 | "homepage": "https://github.com/schmittjoh" 410 | }, 411 | { 412 | "name": "Graham Campbell", 413 | "email": "hello@gjcampbell.co.uk", 414 | "homepage": "https://github.com/GrahamCampbell" 415 | } 416 | ], 417 | "description": "Option Type for PHP", 418 | "keywords": [ 419 | "language", 420 | "option", 421 | "php", 422 | "type" 423 | ], 424 | "support": { 425 | "issues": "https://github.com/schmittjoh/php-option/issues", 426 | "source": "https://github.com/schmittjoh/php-option/tree/1.9.2" 427 | }, 428 | "funding": [ 429 | { 430 | "url": "https://github.com/GrahamCampbell", 431 | "type": "github" 432 | }, 433 | { 434 | "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", 435 | "type": "tidelift" 436 | } 437 | ], 438 | "time": "2023-11-12T21:59:55+00:00" 439 | }, 440 | { 441 | "name": "psr/container", 442 | "version": "2.0.2", 443 | "source": { 444 | "type": "git", 445 | "url": "https://github.com/php-fig/container.git", 446 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" 447 | }, 448 | "dist": { 449 | "type": "zip", 450 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", 451 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", 452 | "shasum": "" 453 | }, 454 | "require": { 455 | "php": ">=7.4.0" 456 | }, 457 | "type": "library", 458 | "extra": { 459 | "branch-alias": { 460 | "dev-master": "2.0.x-dev" 461 | } 462 | }, 463 | "autoload": { 464 | "psr-4": { 465 | "Psr\\Container\\": "src/" 466 | } 467 | }, 468 | "notification-url": "https://packagist.org/downloads/", 469 | "license": [ 470 | "MIT" 471 | ], 472 | "authors": [ 473 | { 474 | "name": "PHP-FIG", 475 | "homepage": "https://www.php-fig.org/" 476 | } 477 | ], 478 | "description": "Common Container Interface (PHP FIG PSR-11)", 479 | "homepage": "https://github.com/php-fig/container", 480 | "keywords": [ 481 | "PSR-11", 482 | "container", 483 | "container-interface", 484 | "container-interop", 485 | "psr" 486 | ], 487 | "support": { 488 | "issues": "https://github.com/php-fig/container/issues", 489 | "source": "https://github.com/php-fig/container/tree/2.0.2" 490 | }, 491 | "time": "2021-11-05T16:47:00+00:00" 492 | }, 493 | { 494 | "name": "psr/http-factory", 495 | "version": "1.0.2", 496 | "source": { 497 | "type": "git", 498 | "url": "https://github.com/php-fig/http-factory.git", 499 | "reference": "e616d01114759c4c489f93b099585439f795fe35" 500 | }, 501 | "dist": { 502 | "type": "zip", 503 | "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", 504 | "reference": "e616d01114759c4c489f93b099585439f795fe35", 505 | "shasum": "" 506 | }, 507 | "require": { 508 | "php": ">=7.0.0", 509 | "psr/http-message": "^1.0 || ^2.0" 510 | }, 511 | "type": "library", 512 | "extra": { 513 | "branch-alias": { 514 | "dev-master": "1.0.x-dev" 515 | } 516 | }, 517 | "autoload": { 518 | "psr-4": { 519 | "Psr\\Http\\Message\\": "src/" 520 | } 521 | }, 522 | "notification-url": "https://packagist.org/downloads/", 523 | "license": [ 524 | "MIT" 525 | ], 526 | "authors": [ 527 | { 528 | "name": "PHP-FIG", 529 | "homepage": "https://www.php-fig.org/" 530 | } 531 | ], 532 | "description": "Common interfaces for PSR-7 HTTP message factories", 533 | "keywords": [ 534 | "factory", 535 | "http", 536 | "message", 537 | "psr", 538 | "psr-17", 539 | "psr-7", 540 | "request", 541 | "response" 542 | ], 543 | "support": { 544 | "source": "https://github.com/php-fig/http-factory/tree/1.0.2" 545 | }, 546 | "time": "2023-04-10T20:10:41+00:00" 547 | }, 548 | { 549 | "name": "psr/http-message", 550 | "version": "1.1", 551 | "source": { 552 | "type": "git", 553 | "url": "https://github.com/php-fig/http-message.git", 554 | "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" 555 | }, 556 | "dist": { 557 | "type": "zip", 558 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", 559 | "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", 560 | "shasum": "" 561 | }, 562 | "require": { 563 | "php": "^7.2 || ^8.0" 564 | }, 565 | "type": "library", 566 | "extra": { 567 | "branch-alias": { 568 | "dev-master": "1.1.x-dev" 569 | } 570 | }, 571 | "autoload": { 572 | "psr-4": { 573 | "Psr\\Http\\Message\\": "src/" 574 | } 575 | }, 576 | "notification-url": "https://packagist.org/downloads/", 577 | "license": [ 578 | "MIT" 579 | ], 580 | "authors": [ 581 | { 582 | "name": "PHP-FIG", 583 | "homepage": "http://www.php-fig.org/" 584 | } 585 | ], 586 | "description": "Common interface for HTTP messages", 587 | "homepage": "https://github.com/php-fig/http-message", 588 | "keywords": [ 589 | "http", 590 | "http-message", 591 | "psr", 592 | "psr-7", 593 | "request", 594 | "response" 595 | ], 596 | "support": { 597 | "source": "https://github.com/php-fig/http-message/tree/1.1" 598 | }, 599 | "time": "2023-04-04T09:50:52+00:00" 600 | }, 601 | { 602 | "name": "psr/http-server-handler", 603 | "version": "1.0.2", 604 | "source": { 605 | "type": "git", 606 | "url": "https://github.com/php-fig/http-server-handler.git", 607 | "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" 608 | }, 609 | "dist": { 610 | "type": "zip", 611 | "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", 612 | "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", 613 | "shasum": "" 614 | }, 615 | "require": { 616 | "php": ">=7.0", 617 | "psr/http-message": "^1.0 || ^2.0" 618 | }, 619 | "type": "library", 620 | "extra": { 621 | "branch-alias": { 622 | "dev-master": "1.0.x-dev" 623 | } 624 | }, 625 | "autoload": { 626 | "psr-4": { 627 | "Psr\\Http\\Server\\": "src/" 628 | } 629 | }, 630 | "notification-url": "https://packagist.org/downloads/", 631 | "license": [ 632 | "MIT" 633 | ], 634 | "authors": [ 635 | { 636 | "name": "PHP-FIG", 637 | "homepage": "https://www.php-fig.org/" 638 | } 639 | ], 640 | "description": "Common interface for HTTP server-side request handler", 641 | "keywords": [ 642 | "handler", 643 | "http", 644 | "http-interop", 645 | "psr", 646 | "psr-15", 647 | "psr-7", 648 | "request", 649 | "response", 650 | "server" 651 | ], 652 | "support": { 653 | "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" 654 | }, 655 | "time": "2023-04-10T20:06:20+00:00" 656 | }, 657 | { 658 | "name": "psr/http-server-middleware", 659 | "version": "1.0.2", 660 | "source": { 661 | "type": "git", 662 | "url": "https://github.com/php-fig/http-server-middleware.git", 663 | "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" 664 | }, 665 | "dist": { 666 | "type": "zip", 667 | "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", 668 | "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", 669 | "shasum": "" 670 | }, 671 | "require": { 672 | "php": ">=7.0", 673 | "psr/http-message": "^1.0 || ^2.0", 674 | "psr/http-server-handler": "^1.0" 675 | }, 676 | "type": "library", 677 | "extra": { 678 | "branch-alias": { 679 | "dev-master": "1.0.x-dev" 680 | } 681 | }, 682 | "autoload": { 683 | "psr-4": { 684 | "Psr\\Http\\Server\\": "src/" 685 | } 686 | }, 687 | "notification-url": "https://packagist.org/downloads/", 688 | "license": [ 689 | "MIT" 690 | ], 691 | "authors": [ 692 | { 693 | "name": "PHP-FIG", 694 | "homepage": "https://www.php-fig.org/" 695 | } 696 | ], 697 | "description": "Common interface for HTTP server-side middleware", 698 | "keywords": [ 699 | "http", 700 | "http-interop", 701 | "middleware", 702 | "psr", 703 | "psr-15", 704 | "psr-7", 705 | "request", 706 | "response" 707 | ], 708 | "support": { 709 | "issues": "https://github.com/php-fig/http-server-middleware/issues", 710 | "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" 711 | }, 712 | "time": "2023-04-11T06:14:47+00:00" 713 | }, 714 | { 715 | "name": "psr/log", 716 | "version": "3.0.0", 717 | "source": { 718 | "type": "git", 719 | "url": "https://github.com/php-fig/log.git", 720 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" 721 | }, 722 | "dist": { 723 | "type": "zip", 724 | "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", 725 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", 726 | "shasum": "" 727 | }, 728 | "require": { 729 | "php": ">=8.0.0" 730 | }, 731 | "type": "library", 732 | "extra": { 733 | "branch-alias": { 734 | "dev-master": "3.x-dev" 735 | } 736 | }, 737 | "autoload": { 738 | "psr-4": { 739 | "Psr\\Log\\": "src" 740 | } 741 | }, 742 | "notification-url": "https://packagist.org/downloads/", 743 | "license": [ 744 | "MIT" 745 | ], 746 | "authors": [ 747 | { 748 | "name": "PHP-FIG", 749 | "homepage": "https://www.php-fig.org/" 750 | } 751 | ], 752 | "description": "Common interface for logging libraries", 753 | "homepage": "https://github.com/php-fig/log", 754 | "keywords": [ 755 | "log", 756 | "psr", 757 | "psr-3" 758 | ], 759 | "support": { 760 | "source": "https://github.com/php-fig/log/tree/3.0.0" 761 | }, 762 | "time": "2021-07-14T16:46:02+00:00" 763 | }, 764 | { 765 | "name": "ralouphie/getallheaders", 766 | "version": "3.0.3", 767 | "source": { 768 | "type": "git", 769 | "url": "https://github.com/ralouphie/getallheaders.git", 770 | "reference": "120b605dfeb996808c31b6477290a714d356e822" 771 | }, 772 | "dist": { 773 | "type": "zip", 774 | "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", 775 | "reference": "120b605dfeb996808c31b6477290a714d356e822", 776 | "shasum": "" 777 | }, 778 | "require": { 779 | "php": ">=5.6" 780 | }, 781 | "require-dev": { 782 | "php-coveralls/php-coveralls": "^2.1", 783 | "phpunit/phpunit": "^5 || ^6.5" 784 | }, 785 | "type": "library", 786 | "autoload": { 787 | "files": [ 788 | "src/getallheaders.php" 789 | ] 790 | }, 791 | "notification-url": "https://packagist.org/downloads/", 792 | "license": [ 793 | "MIT" 794 | ], 795 | "authors": [ 796 | { 797 | "name": "Ralph Khattar", 798 | "email": "ralph.khattar@gmail.com" 799 | } 800 | ], 801 | "description": "A polyfill for getallheaders.", 802 | "support": { 803 | "issues": "https://github.com/ralouphie/getallheaders/issues", 804 | "source": "https://github.com/ralouphie/getallheaders/tree/develop" 805 | }, 806 | "time": "2019-03-08T08:55:37+00:00" 807 | }, 808 | { 809 | "name": "slim/psr7", 810 | "version": "1.6.1", 811 | "source": { 812 | "type": "git", 813 | "url": "https://github.com/slimphp/Slim-Psr7.git", 814 | "reference": "72d2b2bac94ab4575d369f605dbfafbe168d3163" 815 | }, 816 | "dist": { 817 | "type": "zip", 818 | "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/72d2b2bac94ab4575d369f605dbfafbe168d3163", 819 | "reference": "72d2b2bac94ab4575d369f605dbfafbe168d3163", 820 | "shasum": "" 821 | }, 822 | "require": { 823 | "fig/http-message-util": "^1.1.5", 824 | "php": "^7.4 || ^8.0", 825 | "psr/http-factory": "^1.0", 826 | "psr/http-message": "^1.0", 827 | "ralouphie/getallheaders": "^3.0", 828 | "symfony/polyfill-php80": "^1.26" 829 | }, 830 | "provide": { 831 | "psr/http-factory-implementation": "1.0", 832 | "psr/http-message-implementation": "1.0" 833 | }, 834 | "require-dev": { 835 | "adriansuter/php-autoload-override": "^1.3", 836 | "ext-json": "*", 837 | "http-interop/http-factory-tests": "^0.9.0", 838 | "php-http/psr7-integration-tests": "1.1", 839 | "phpspec/prophecy": "^1.15", 840 | "phpspec/prophecy-phpunit": "^2.0", 841 | "phpstan/phpstan": "^1.8", 842 | "phpunit/phpunit": "^9.5", 843 | "squizlabs/php_codesniffer": "^3.7" 844 | }, 845 | "type": "library", 846 | "autoload": { 847 | "psr-4": { 848 | "Slim\\Psr7\\": "src" 849 | } 850 | }, 851 | "notification-url": "https://packagist.org/downloads/", 852 | "license": [ 853 | "MIT" 854 | ], 855 | "authors": [ 856 | { 857 | "name": "Josh Lockhart", 858 | "email": "hello@joshlockhart.com", 859 | "homepage": "http://joshlockhart.com" 860 | }, 861 | { 862 | "name": "Andrew Smith", 863 | "email": "a.smith@silentworks.co.uk", 864 | "homepage": "http://silentworks.co.uk" 865 | }, 866 | { 867 | "name": "Rob Allen", 868 | "email": "rob@akrabat.com", 869 | "homepage": "http://akrabat.com" 870 | }, 871 | { 872 | "name": "Pierre Berube", 873 | "email": "pierre@lgse.com", 874 | "homepage": "http://www.lgse.com" 875 | } 876 | ], 877 | "description": "Strict PSR-7 implementation", 878 | "homepage": "https://www.slimframework.com", 879 | "keywords": [ 880 | "http", 881 | "psr-7", 882 | "psr7" 883 | ], 884 | "support": { 885 | "issues": "https://github.com/slimphp/Slim-Psr7/issues", 886 | "source": "https://github.com/slimphp/Slim-Psr7/tree/1.6.1" 887 | }, 888 | "time": "2023-04-17T16:02:20+00:00" 889 | }, 890 | { 891 | "name": "slim/slim", 892 | "version": "4.12.0", 893 | "source": { 894 | "type": "git", 895 | "url": "https://github.com/slimphp/Slim.git", 896 | "reference": "e9e99c2b24398b967841c6c4c3048622cc7e2b18" 897 | }, 898 | "dist": { 899 | "type": "zip", 900 | "url": "https://api.github.com/repos/slimphp/Slim/zipball/e9e99c2b24398b967841c6c4c3048622cc7e2b18", 901 | "reference": "e9e99c2b24398b967841c6c4c3048622cc7e2b18", 902 | "shasum": "" 903 | }, 904 | "require": { 905 | "ext-json": "*", 906 | "nikic/fast-route": "^1.3", 907 | "php": "^7.4 || ^8.0", 908 | "psr/container": "^1.0 || ^2.0", 909 | "psr/http-factory": "^1.0", 910 | "psr/http-message": "^1.1", 911 | "psr/http-server-handler": "^1.0", 912 | "psr/http-server-middleware": "^1.0", 913 | "psr/log": "^1.1 || ^2.0 || ^3.0" 914 | }, 915 | "require-dev": { 916 | "adriansuter/php-autoload-override": "^1.4", 917 | "ext-simplexml": "*", 918 | "guzzlehttp/psr7": "^2.5", 919 | "httpsoft/http-message": "^1.1", 920 | "httpsoft/http-server-request": "^1.1", 921 | "laminas/laminas-diactoros": "^2.17", 922 | "nyholm/psr7": "^1.8", 923 | "nyholm/psr7-server": "^1.0", 924 | "phpspec/prophecy": "^1.17", 925 | "phpspec/prophecy-phpunit": "^2.0", 926 | "phpstan/phpstan": "^1.10", 927 | "phpunit/phpunit": "^9.6", 928 | "slim/http": "^1.3", 929 | "slim/psr7": "^1.6", 930 | "squizlabs/php_codesniffer": "^3.7" 931 | }, 932 | "suggest": { 933 | "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", 934 | "ext-xml": "Needed to support XML format in BodyParsingMiddleware", 935 | "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", 936 | "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." 937 | }, 938 | "type": "library", 939 | "autoload": { 940 | "psr-4": { 941 | "Slim\\": "Slim" 942 | } 943 | }, 944 | "notification-url": "https://packagist.org/downloads/", 945 | "license": [ 946 | "MIT" 947 | ], 948 | "authors": [ 949 | { 950 | "name": "Josh Lockhart", 951 | "email": "hello@joshlockhart.com", 952 | "homepage": "https://joshlockhart.com" 953 | }, 954 | { 955 | "name": "Andrew Smith", 956 | "email": "a.smith@silentworks.co.uk", 957 | "homepage": "http://silentworks.co.uk" 958 | }, 959 | { 960 | "name": "Rob Allen", 961 | "email": "rob@akrabat.com", 962 | "homepage": "http://akrabat.com" 963 | }, 964 | { 965 | "name": "Pierre Berube", 966 | "email": "pierre@lgse.com", 967 | "homepage": "http://www.lgse.com" 968 | }, 969 | { 970 | "name": "Gabriel Manricks", 971 | "email": "gmanricks@me.com", 972 | "homepage": "http://gabrielmanricks.com" 973 | } 974 | ], 975 | "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", 976 | "homepage": "https://www.slimframework.com", 977 | "keywords": [ 978 | "api", 979 | "framework", 980 | "micro", 981 | "router" 982 | ], 983 | "support": { 984 | "docs": "https://www.slimframework.com/docs/v4/", 985 | "forum": "https://discourse.slimframework.com/", 986 | "irc": "irc://irc.freenode.net:6667/slimphp", 987 | "issues": "https://github.com/slimphp/Slim/issues", 988 | "rss": "https://www.slimframework.com/blog/feed.rss", 989 | "slack": "https://slimphp.slack.com/", 990 | "source": "https://github.com/slimphp/Slim", 991 | "wiki": "https://github.com/slimphp/Slim/wiki" 992 | }, 993 | "funding": [ 994 | { 995 | "url": "https://opencollective.com/slimphp", 996 | "type": "open_collective" 997 | }, 998 | { 999 | "url": "https://tidelift.com/funding/github/packagist/slim/slim", 1000 | "type": "tidelift" 1001 | } 1002 | ], 1003 | "time": "2023-07-23T04:54:29+00:00" 1004 | }, 1005 | { 1006 | "name": "symfony/polyfill-ctype", 1007 | "version": "v1.29.0", 1008 | "source": { 1009 | "type": "git", 1010 | "url": "https://github.com/symfony/polyfill-ctype.git", 1011 | "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" 1012 | }, 1013 | "dist": { 1014 | "type": "zip", 1015 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", 1016 | "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", 1017 | "shasum": "" 1018 | }, 1019 | "require": { 1020 | "php": ">=7.1" 1021 | }, 1022 | "provide": { 1023 | "ext-ctype": "*" 1024 | }, 1025 | "suggest": { 1026 | "ext-ctype": "For best performance" 1027 | }, 1028 | "type": "library", 1029 | "extra": { 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.29.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": "2024-01-29T20:11:03+00:00" 1083 | }, 1084 | { 1085 | "name": "symfony/polyfill-mbstring", 1086 | "version": "v1.29.0", 1087 | "source": { 1088 | "type": "git", 1089 | "url": "https://github.com/symfony/polyfill-mbstring.git", 1090 | "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" 1091 | }, 1092 | "dist": { 1093 | "type": "zip", 1094 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", 1095 | "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", 1096 | "shasum": "" 1097 | }, 1098 | "require": { 1099 | "php": ">=7.1" 1100 | }, 1101 | "provide": { 1102 | "ext-mbstring": "*" 1103 | }, 1104 | "suggest": { 1105 | "ext-mbstring": "For best performance" 1106 | }, 1107 | "type": "library", 1108 | "extra": { 1109 | "thanks": { 1110 | "name": "symfony/polyfill", 1111 | "url": "https://github.com/symfony/polyfill" 1112 | } 1113 | }, 1114 | "autoload": { 1115 | "files": [ 1116 | "bootstrap.php" 1117 | ], 1118 | "psr-4": { 1119 | "Symfony\\Polyfill\\Mbstring\\": "" 1120 | } 1121 | }, 1122 | "notification-url": "https://packagist.org/downloads/", 1123 | "license": [ 1124 | "MIT" 1125 | ], 1126 | "authors": [ 1127 | { 1128 | "name": "Nicolas Grekas", 1129 | "email": "p@tchwork.com" 1130 | }, 1131 | { 1132 | "name": "Symfony Community", 1133 | "homepage": "https://symfony.com/contributors" 1134 | } 1135 | ], 1136 | "description": "Symfony polyfill for the Mbstring extension", 1137 | "homepage": "https://symfony.com", 1138 | "keywords": [ 1139 | "compatibility", 1140 | "mbstring", 1141 | "polyfill", 1142 | "portable", 1143 | "shim" 1144 | ], 1145 | "support": { 1146 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" 1147 | }, 1148 | "funding": [ 1149 | { 1150 | "url": "https://symfony.com/sponsor", 1151 | "type": "custom" 1152 | }, 1153 | { 1154 | "url": "https://github.com/fabpot", 1155 | "type": "github" 1156 | }, 1157 | { 1158 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1159 | "type": "tidelift" 1160 | } 1161 | ], 1162 | "time": "2024-01-29T20:11:03+00:00" 1163 | }, 1164 | { 1165 | "name": "symfony/polyfill-php80", 1166 | "version": "v1.28.0", 1167 | "source": { 1168 | "type": "git", 1169 | "url": "https://github.com/symfony/polyfill-php80.git", 1170 | "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" 1171 | }, 1172 | "dist": { 1173 | "type": "zip", 1174 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", 1175 | "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", 1176 | "shasum": "" 1177 | }, 1178 | "require": { 1179 | "php": ">=7.1" 1180 | }, 1181 | "type": "library", 1182 | "extra": { 1183 | "branch-alias": { 1184 | "dev-main": "1.28-dev" 1185 | }, 1186 | "thanks": { 1187 | "name": "symfony/polyfill", 1188 | "url": "https://github.com/symfony/polyfill" 1189 | } 1190 | }, 1191 | "autoload": { 1192 | "files": [ 1193 | "bootstrap.php" 1194 | ], 1195 | "psr-4": { 1196 | "Symfony\\Polyfill\\Php80\\": "" 1197 | }, 1198 | "classmap": [ 1199 | "Resources/stubs" 1200 | ] 1201 | }, 1202 | "notification-url": "https://packagist.org/downloads/", 1203 | "license": [ 1204 | "MIT" 1205 | ], 1206 | "authors": [ 1207 | { 1208 | "name": "Ion Bazan", 1209 | "email": "ion.bazan@gmail.com" 1210 | }, 1211 | { 1212 | "name": "Nicolas Grekas", 1213 | "email": "p@tchwork.com" 1214 | }, 1215 | { 1216 | "name": "Symfony Community", 1217 | "homepage": "https://symfony.com/contributors" 1218 | } 1219 | ], 1220 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", 1221 | "homepage": "https://symfony.com", 1222 | "keywords": [ 1223 | "compatibility", 1224 | "polyfill", 1225 | "portable", 1226 | "shim" 1227 | ], 1228 | "support": { 1229 | "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" 1230 | }, 1231 | "funding": [ 1232 | { 1233 | "url": "https://symfony.com/sponsor", 1234 | "type": "custom" 1235 | }, 1236 | { 1237 | "url": "https://github.com/fabpot", 1238 | "type": "github" 1239 | }, 1240 | { 1241 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1242 | "type": "tidelift" 1243 | } 1244 | ], 1245 | "time": "2023-01-26T09:26:14+00:00" 1246 | }, 1247 | { 1248 | "name": "vlucas/phpdotenv", 1249 | "version": "v5.6.0", 1250 | "source": { 1251 | "type": "git", 1252 | "url": "https://github.com/vlucas/phpdotenv.git", 1253 | "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4" 1254 | }, 1255 | "dist": { 1256 | "type": "zip", 1257 | "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", 1258 | "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", 1259 | "shasum": "" 1260 | }, 1261 | "require": { 1262 | "ext-pcre": "*", 1263 | "graham-campbell/result-type": "^1.1.2", 1264 | "php": "^7.2.5 || ^8.0", 1265 | "phpoption/phpoption": "^1.9.2", 1266 | "symfony/polyfill-ctype": "^1.24", 1267 | "symfony/polyfill-mbstring": "^1.24", 1268 | "symfony/polyfill-php80": "^1.24" 1269 | }, 1270 | "require-dev": { 1271 | "bamarni/composer-bin-plugin": "^1.8.2", 1272 | "ext-filter": "*", 1273 | "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" 1274 | }, 1275 | "suggest": { 1276 | "ext-filter": "Required to use the boolean validator." 1277 | }, 1278 | "type": "library", 1279 | "extra": { 1280 | "bamarni-bin": { 1281 | "bin-links": true, 1282 | "forward-command": true 1283 | }, 1284 | "branch-alias": { 1285 | "dev-master": "5.6-dev" 1286 | } 1287 | }, 1288 | "autoload": { 1289 | "psr-4": { 1290 | "Dotenv\\": "src/" 1291 | } 1292 | }, 1293 | "notification-url": "https://packagist.org/downloads/", 1294 | "license": [ 1295 | "BSD-3-Clause" 1296 | ], 1297 | "authors": [ 1298 | { 1299 | "name": "Graham Campbell", 1300 | "email": "hello@gjcampbell.co.uk", 1301 | "homepage": "https://github.com/GrahamCampbell" 1302 | }, 1303 | { 1304 | "name": "Vance Lucas", 1305 | "email": "vance@vancelucas.com", 1306 | "homepage": "https://github.com/vlucas" 1307 | } 1308 | ], 1309 | "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", 1310 | "keywords": [ 1311 | "dotenv", 1312 | "env", 1313 | "environment" 1314 | ], 1315 | "support": { 1316 | "issues": "https://github.com/vlucas/phpdotenv/issues", 1317 | "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.0" 1318 | }, 1319 | "funding": [ 1320 | { 1321 | "url": "https://github.com/GrahamCampbell", 1322 | "type": "github" 1323 | }, 1324 | { 1325 | "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", 1326 | "type": "tidelift" 1327 | } 1328 | ], 1329 | "time": "2023-11-12T22:43:29+00:00" 1330 | }, 1331 | { 1332 | "name": "vlucas/valitron", 1333 | "version": "v1.4.11", 1334 | "source": { 1335 | "type": "git", 1336 | "url": "https://github.com/vlucas/valitron.git", 1337 | "reference": "fadce39f5f235755bb9794b2573af2d5bfcba85f" 1338 | }, 1339 | "dist": { 1340 | "type": "zip", 1341 | "url": "https://api.github.com/repos/vlucas/valitron/zipball/fadce39f5f235755bb9794b2573af2d5bfcba85f", 1342 | "reference": "fadce39f5f235755bb9794b2573af2d5bfcba85f", 1343 | "shasum": "" 1344 | }, 1345 | "require": { 1346 | "php": ">=5.3.2" 1347 | }, 1348 | "require-dev": { 1349 | "phpunit/phpunit": ">=4.8.35" 1350 | }, 1351 | "suggest": { 1352 | "ext-mbstring": "It can support the multiple bytes string length." 1353 | }, 1354 | "type": "library", 1355 | "autoload": { 1356 | "psr-4": { 1357 | "Valitron\\": "src/Valitron" 1358 | } 1359 | }, 1360 | "notification-url": "https://packagist.org/downloads/", 1361 | "license": [ 1362 | "BSD-3-Clause" 1363 | ], 1364 | "authors": [ 1365 | { 1366 | "name": "Vance Lucas", 1367 | "email": "vance@vancelucas.com", 1368 | "homepage": "https://www.vancelucas.com" 1369 | } 1370 | ], 1371 | "description": "Simple, elegant, stand-alone validation library with NO dependencies", 1372 | "homepage": "https://github.com/vlucas/valitron", 1373 | "keywords": [ 1374 | "valid", 1375 | "validation", 1376 | "validator" 1377 | ], 1378 | "support": { 1379 | "issues": "https://github.com/vlucas/valitron/issues", 1380 | "source": "https://github.com/vlucas/valitron/tree/v1.4.11" 1381 | }, 1382 | "funding": [ 1383 | { 1384 | "url": "https://tidelift.com/funding/github/packagist/vlucas/valitron", 1385 | "type": "tidelift" 1386 | } 1387 | ], 1388 | "time": "2022-10-14T11:54:24+00:00" 1389 | } 1390 | ], 1391 | "packages-dev": [], 1392 | "aliases": [], 1393 | "minimum-stability": "stable", 1394 | "stability-flags": [], 1395 | "prefer-stable": false, 1396 | "prefer-lowest": false, 1397 | "platform": [], 1398 | "platform-dev": [], 1399 | "plugin-api-version": "2.3.0" 1400 | } 1401 | -------------------------------------------------------------------------------- /config/definitions.php: -------------------------------------------------------------------------------- 1 | function() { 8 | 9 | return new Database(host: $_ENV['DB_HOST'], 10 | name: $_ENV['DB_NAME'], 11 | user: $_ENV['DB_USER'], 12 | password: $_ENV['DB_PASS']); 13 | } 14 | ]; 15 | -------------------------------------------------------------------------------- /database.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `product` ( 2 | `id` int(11) NOT NULL, 3 | `name` varchar(128) NOT NULL, 4 | `description` text DEFAULT NULL, 5 | `size` int(11) NOT NULL 6 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; 7 | 8 | ALTER TABLE `product` 9 | ADD PRIMARY KEY (`id`), 10 | ADD KEY `name` (`name`); 11 | 12 | ALTER TABLE `product` 13 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5; 14 | 15 | INSERT INTO `product` (`name`, `description`, `size`) VALUES 16 | ('Product One', NULL, 10), 17 | ('Product Two', 'example', 20); 18 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | RewriteCond %{REQUEST_FILENAME} !-f 3 | RewriteCond %{REQUEST_FILENAME} !-d 4 | RewriteRule ^ index.php [QSA,L] -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | load(); 21 | 22 | $builder = new ContainerBuilder; 23 | 24 | $container = $builder->addDefinitions(APP_ROOT . '/config/definitions.php') 25 | ->build(); 26 | 27 | AppFactory::setContainer($container); 28 | 29 | $app = AppFactory::create(); 30 | 31 | $collector = $app->getRouteCollector(); 32 | 33 | $collector->setDefaultInvocationStrategy(new RequestResponseArgs); 34 | 35 | $app->addBodyParsingMiddleware(); 36 | 37 | $error_middleware = $app->addErrorMiddleware(true, true, true); 38 | 39 | $error_handler = $error_middleware->getDefaultErrorHandler(); 40 | 41 | $error_handler->forceContentType('application/json'); 42 | 43 | $app->add(new AddJsonResponseHeader); 44 | 45 | $app->group('/api', function (RouteCollectorProxy $group) { 46 | 47 | $group->get('/products', ProductIndex::class); 48 | 49 | $group->post('/products', [Products::class, 'create']); 50 | 51 | $group->group('', function (RouteCollectorProxy $group) { 52 | 53 | $group->get('/products/{id:[0-9]+}', Products::class . ':show'); 54 | 55 | $group->patch('/products/{id:[0-9]+}', Products::class . ':update'); 56 | 57 | $group->delete('/products/{id:[0-9]+}', Products::class . ':delete'); 58 | 59 | })->add(GetProduct::class); 60 | 61 | }); 62 | 63 | $app->run(); 64 | -------------------------------------------------------------------------------- /src/App/Controllers/ProductIndex.php: -------------------------------------------------------------------------------- 1 | repository->getAll(); 20 | 21 | $body = json_encode($data); 22 | 23 | $response->getBody()->write($body); 24 | 25 | return $response; 26 | } 27 | } -------------------------------------------------------------------------------- /src/App/Controllers/Products.php: -------------------------------------------------------------------------------- 1 | validator->mapFieldsRules([ 18 | 'name' => ['required'], 19 | 'size' => ['required', 'integer', ['min', 1]] 20 | ]); 21 | } 22 | 23 | public function show(Request $request, Response $response, string $id): Response 24 | { 25 | $product = $request->getAttribute('product'); 26 | 27 | $body = json_encode($product); 28 | 29 | $response->getBody()->write($body); 30 | 31 | return $response; 32 | } 33 | 34 | public function create(Request $request, Response $response): Response 35 | { 36 | $body = $request->getParsedBody(); 37 | 38 | $this->validator = $this->validator->withData($body); 39 | 40 | if ( ! $this->validator->validate()) { 41 | 42 | $response->getBody() 43 | ->write(json_encode($this->validator->errors())); 44 | 45 | return $response->withStatus(422); 46 | 47 | } 48 | 49 | $id = $this->repository->create($body); 50 | 51 | $body = json_encode([ 52 | 'message' => 'Product created', 53 | 'id' => $id 54 | ]); 55 | 56 | $response->getBody()->write($body); 57 | 58 | return $response->withStatus(201); 59 | } 60 | 61 | public function update(Request $request, Response $response, string $id): Response 62 | { 63 | $body = $request->getParsedBody(); 64 | 65 | $this->validator = $this->validator->withData($body); 66 | 67 | if ( ! $this->validator->validate()) { 68 | 69 | $response->getBody() 70 | ->write(json_encode($this->validator->errors())); 71 | 72 | return $response->withStatus(422); 73 | 74 | } 75 | 76 | $rows = $this->repository->update((int) $id, $body); 77 | 78 | $body = json_encode([ 79 | 'message' => 'Product updated', 80 | 'rows' => $rows 81 | ]); 82 | 83 | $response->getBody()->write($body); 84 | 85 | return $response; 86 | } 87 | 88 | public function delete(Request $request, Response $response, string $id): Response 89 | { 90 | $rows = $this->repository->delete($id); 91 | 92 | $body = json_encode([ 93 | 'message' => 'Product deleted', 94 | 'rows' => $rows 95 | ]); 96 | 97 | $response->getBody()->write($body); 98 | 99 | return $response; 100 | } 101 | } -------------------------------------------------------------------------------- /src/App/Database.php: -------------------------------------------------------------------------------- 1 | host;dbname=$this->name;charset=utf8"; 21 | 22 | $pdo = new PDO($dsn, $this->user, $this->password, [ 23 | PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION 24 | ]); 25 | 26 | return $pdo; 27 | } 28 | } -------------------------------------------------------------------------------- /src/App/Middleware/AddJsonResponseHeader.php: -------------------------------------------------------------------------------- 1 | handle($request); 16 | 17 | return $response->withHeader('Content-Type', 'application/json'); 18 | } 19 | } -------------------------------------------------------------------------------- /src/App/Middleware/GetProduct.php: -------------------------------------------------------------------------------- 1 | getRoute(); 25 | 26 | $id = $route->getArgument('id'); 27 | 28 | $product = $this->repository->getById((int) $id); 29 | 30 | if ($product === false) { 31 | 32 | throw new HttpNotFoundException($request,message: 'product not found'); 33 | 34 | } 35 | 36 | $request = $request->withAttribute('product', $product); 37 | 38 | return $handler->handle($request); 39 | } 40 | } -------------------------------------------------------------------------------- /src/App/Repositories/ProductRepository.php: -------------------------------------------------------------------------------- 1 | database->getConnection(); 19 | 20 | $stmt = $pdo->query('SELECT * FROM product'); 21 | 22 | return $stmt->fetchAll(PDO::FETCH_ASSOC); 23 | } 24 | 25 | public function getById(int $id): array|bool 26 | { 27 | $sql = 'SELECT * 28 | FROM product 29 | WHERE id = :id'; 30 | 31 | $pdo = $this->database->getConnection(); 32 | 33 | $stmt = $pdo->prepare($sql); 34 | 35 | $stmt->bindValue(':id', $id, PDO::PARAM_INT); 36 | 37 | $stmt->execute(); 38 | 39 | return $stmt->fetch(PDO::FETCH_ASSOC); 40 | } 41 | 42 | public function create(array $data): string 43 | { 44 | $sql = 'INSERT INTO product (name, description, size) 45 | VALUES (:name, :description, :size)'; 46 | 47 | $pdo = $this->database->getConnection(); 48 | 49 | $stmt = $pdo->prepare($sql); 50 | 51 | $stmt->bindValue(':name', $data['name'], PDO::PARAM_STR); 52 | 53 | if (empty($data['description'])) { 54 | 55 | $stmt->bindValue(':description', null, PDO::PARAM_NULL); 56 | 57 | } else { 58 | 59 | $stmt->bindValue(':description', $data['description'], PDO::PARAM_STR); 60 | 61 | } 62 | 63 | $stmt->bindValue(':size', $data['size'], PDO::PARAM_INT); 64 | 65 | $stmt->execute(); 66 | 67 | return $pdo->lastInsertId(); 68 | } 69 | 70 | public function update(int $id, array $data): int 71 | { 72 | $sql = 'UPDATE product 73 | SET name = :name, 74 | description = :description, 75 | size = :size 76 | WHERE id = :id'; 77 | 78 | $pdo = $this->database->getConnection(); 79 | 80 | $stmt = $pdo->prepare($sql); 81 | 82 | $stmt->bindValue(':name', $data['name'], PDO::PARAM_STR); 83 | 84 | if (empty($data['description'])) { 85 | 86 | $stmt->bindValue(':description', null, PDO::PARAM_NULL); 87 | 88 | } else { 89 | 90 | $stmt->bindValue(':description', $data['description'], PDO::PARAM_STR); 91 | 92 | } 93 | 94 | $stmt->bindValue(':size', $data['size'], PDO::PARAM_INT); 95 | 96 | $stmt->bindValue(':id', $id, PDO::PARAM_INT); 97 | 98 | $stmt->execute(); 99 | 100 | return $stmt->rowCount(); 101 | } 102 | 103 | public function delete(string $id): int 104 | { 105 | $sql = 'DELETE FROM product 106 | WHERE id = :id'; 107 | 108 | $pdo = $this->database->getConnection(); 109 | 110 | $stmt = $pdo->prepare($sql); 111 | 112 | $stmt->bindValue(':id', $id, PDO::PARAM_INT); 113 | 114 | $stmt->execute(); 115 | 116 | return $stmt->rowCount(); 117 | } 118 | } --------------------------------------------------------------------------------