From e817592556f31445b2edf46fe1550376a47b61c9 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Thu, 6 Jul 2023 06:24:21 +0000
Subject: [PATCH 001/119] adapters and refactor request and response
---
composer.json | 6 +-
composer.lock | 224 +++++++++++--------
src/Adapter.php | 11 +
src/Adapter/FPM/Request.php | 374 ++++++++++++++++++++++++++++++++
src/Adapter/FPM/Response.php | 82 +++++++
src/Adapter/FPM/Server.php | 29 +++
src/Adapter/Swoole/Files.php | 200 +++++++++++++++++
src/Adapter/Swoole/Request.php | 359 ++++++++++++++++++++++++++++++
src/Adapter/Swoole/Response.php | 94 ++++++++
src/Adapter/Swoole/Server.php | 32 +++
src/Request.php | 195 +++--------------
src/Response.php | 34 +--
12 files changed, 1349 insertions(+), 291 deletions(-)
create mode 100644 src/Adapter.php
create mode 100644 src/Adapter/FPM/Request.php
create mode 100644 src/Adapter/FPM/Response.php
create mode 100644 src/Adapter/FPM/Server.php
create mode 100644 src/Adapter/Swoole/Files.php
create mode 100644 src/Adapter/Swoole/Request.php
create mode 100644 src/Adapter/Swoole/Response.php
create mode 100644 src/Adapter/Swoole/Server.php
diff --git a/composer.json b/composer.json
index 3fb769b5..6e48d875 100644
--- a/composer.json
+++ b/composer.json
@@ -14,12 +14,14 @@
"check": "./vendor/bin/phpstan analyse -l 5 src tests"
},
"require": {
- "php": ">=8.0"
+ "php": ">=8.0",
+ "ext-swoole": "*"
},
"require-dev": {
"phpunit/phpunit": "^9.5.25",
"vimeo/psalm": "4.27.0",
"laravel/pint": "^1.2",
- "phpstan/phpstan": "1.9.x-dev"
+ "phpstan/phpstan": "1.9.x-dev",
+ "swoole/ide-helper": "4.8.3"
}
}
diff --git a/composer.lock b/composer.lock
index 6f8a74f3..091b638d 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "f89715e407bde4aecfdff0a0961815de",
+ "content-hash": "9a19af61f8406123b58e57360d1b802f",
"packages": [],
"packages-dev": [
{
@@ -503,25 +503,29 @@
},
{
"name": "doctrine/deprecations",
- "version": "v1.0.0",
+ "version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
- "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
+ "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
- "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
+ "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
+ "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
"shasum": ""
},
"require": {
- "php": "^7.1|^8.0"
+ "php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9",
- "phpunit/phpunit": "^7.5|^8.5|^9.5",
- "psr/log": "^1|^2|^3"
+ "phpstan/phpstan": "1.4.10 || 1.10.15",
+ "phpstan/phpstan-phpunit": "^1.0",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+ "psalm/plugin-phpunit": "0.18.4",
+ "psr/log": "^1 || ^2 || ^3",
+ "vimeo/psalm": "4.30.0 || 5.12.0"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
@@ -540,9 +544,9 @@
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
- "source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
+ "source": "https://github.com/doctrine/deprecations/tree/v1.1.1"
},
- "time": "2022-05-02T15:47:09+00:00"
+ "time": "2023-06-03T09:27:29+00:00"
},
{
"name": "doctrine/instantiator",
@@ -717,16 +721,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.8.0",
+ "version": "v1.10.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "4b8f2ef22bfcddd1d163cfd282e3f42ee1a5cce2"
+ "reference": "c472786bca01e4812a9bb7933b23edfc5b6877b7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/4b8f2ef22bfcddd1d163cfd282e3f42ee1a5cce2",
- "reference": "4b8f2ef22bfcddd1d163cfd282e3f42ee1a5cce2",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/c472786bca01e4812a9bb7933b23edfc5b6877b7",
+ "reference": "c472786bca01e4812a9bb7933b23edfc5b6877b7",
"shasum": ""
},
"require": {
@@ -737,7 +741,7 @@
"php": "^8.1.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.16.0",
+ "friendsofphp/php-cs-fixer": "^3.18.0",
"illuminate/view": "^10.5.1",
"laravel-zero/framework": "^10.0.2",
"mockery/mockery": "^1.5.1",
@@ -779,7 +783,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2023-04-04T13:08:09+00:00"
+ "time": "2023-06-20T15:55:03+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -842,16 +846,16 @@
},
{
"name": "netresearch/jsonmapper",
- "version": "v4.1.0",
+ "version": "v4.2.0",
"source": {
"type": "git",
"url": "https://github.com/cweiske/jsonmapper.git",
- "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f"
+ "reference": "f60565f8c0566a31acf06884cdaa591867ecc956"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
- "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
+ "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956",
+ "reference": "f60565f8c0566a31acf06884cdaa591867ecc956",
"shasum": ""
},
"require": {
@@ -887,22 +891,22 @@
"support": {
"email": "cweiske@cweiske.de",
"issues": "https://github.com/cweiske/jsonmapper/issues",
- "source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0"
+ "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0"
},
- "time": "2022-12-08T20:46:14+00:00"
+ "time": "2023-04-09T17:37:40+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v4.15.4",
+ "version": "v4.16.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290"
+ "reference": "19526a33fb561ef417e822e85f08a00db4059c17"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
- "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17",
+ "reference": "19526a33fb561ef417e822e85f08a00db4059c17",
"shasum": ""
},
"require": {
@@ -943,9 +947,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0"
},
- "time": "2023-03-05T19:49:14+00:00"
+ "time": "2023-06-25T14:52:30+00:00"
},
{
"name": "openlss/lib-array2xml",
@@ -1223,16 +1227,16 @@
},
{
"name": "phpdocumentor/type-resolver",
- "version": "1.7.1",
+ "version": "1.7.2",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "dfc078e8af9c99210337325ff5aa152872c98714"
+ "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714",
- "reference": "dfc078e8af9c99210337325ff5aa152872c98714",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d",
+ "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d",
"shasum": ""
},
"require": {
@@ -1275,28 +1279,30 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
- "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1"
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2"
},
- "time": "2023-03-27T19:02:04+00:00"
+ "time": "2023-05-30T18:13:47+00:00"
},
{
"name": "phpstan/phpdoc-parser",
- "version": "1.18.0",
+ "version": "1.22.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
- "reference": "882eabc9b6a12e25c27091a261397f9c8792e722"
+ "reference": "65c39594fbd8c67abfc68bb323f86447bab79cc0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/882eabc9b6a12e25c27091a261397f9c8792e722",
- "reference": "882eabc9b6a12e25c27091a261397f9c8792e722",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/65c39594fbd8c67abfc68bb323f86447bab79cc0",
+ "reference": "65c39594fbd8c67abfc68bb323f86447bab79cc0",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
+ "doctrine/annotations": "^2.0",
+ "nikic/php-parser": "^4.15",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.5",
@@ -1320,9 +1326,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
- "source": "https://github.com/phpstan/phpdoc-parser/tree/1.18.0"
+ "source": "https://github.com/phpstan/phpdoc-parser/tree/1.22.1"
},
- "time": "2023-04-06T07:26:43+00:00"
+ "time": "2023-06-29T20:46:06+00:00"
},
{
"name": "phpstan/phpstan",
@@ -1703,16 +1709,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.6",
+ "version": "9.6.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115"
+ "reference": "a9aceaf20a682aeacf28d582654a1670d8826778"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115",
- "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a9aceaf20a682aeacf28d582654a1670d8826778",
+ "reference": "a9aceaf20a682aeacf28d582654a1670d8826778",
"shasum": ""
},
"require": {
@@ -1786,7 +1792,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.9"
},
"funding": [
{
@@ -1802,7 +1808,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-27T11:43:46+00:00"
+ "time": "2023-06-11T06:13:56+00:00"
},
{
"name": "psr/container",
@@ -2207,16 +2213,16 @@
},
{
"name": "sebastian/diff",
- "version": "4.0.4",
+ "version": "4.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
+ "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
- "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
+ "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
"shasum": ""
},
"require": {
@@ -2261,7 +2267,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
- "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
+ "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
},
"funding": [
{
@@ -2269,7 +2275,7 @@
"type": "github"
}
],
- "time": "2020-10-26T13:10:38+00:00"
+ "time": "2023-05-07T05:35:17+00:00"
},
{
"name": "sebastian/environment",
@@ -2871,25 +2877,67 @@
],
"time": "2020-09-28T06:39:44+00:00"
},
+ {
+ "name": "swoole/ide-helper",
+ "version": "4.8.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/swoole/ide-helper.git",
+ "reference": "3ac4971814273889933b871e03b2a6b340e58f79"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/swoole/ide-helper/zipball/3ac4971814273889933b871e03b2a6b340e58f79",
+ "reference": "3ac4971814273889933b871e03b2a6b340e58f79",
+ "shasum": ""
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Team Swoole",
+ "email": "team@swoole.com"
+ }
+ ],
+ "description": "IDE help files for Swoole.",
+ "support": {
+ "issues": "https://github.com/swoole/ide-helper/issues",
+ "source": "https://github.com/swoole/ide-helper/tree/4.8.3"
+ },
+ "funding": [
+ {
+ "url": "https://gitee.com/swoole/swoole?donate=true",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/swoole",
+ "type": "github"
+ }
+ ],
+ "time": "2021-12-01T08:11:40+00:00"
+ },
{
"name": "symfony/console",
- "version": "v6.2.8",
+ "version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "3582d68a64a86ec25240aaa521ec8bc2342b369b"
+ "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/3582d68a64a86ec25240aaa521ec8bc2342b369b",
- "reference": "3582d68a64a86ec25240aaa521ec8bc2342b369b",
+ "url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
+ "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
"shasum": ""
},
"require": {
"php": ">=8.1",
- "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
- "symfony/service-contracts": "^1.1|^2|^3",
+ "symfony/service-contracts": "^2.5|^3",
"symfony/string": "^5.4|^6.0"
},
"conflict": {
@@ -2911,12 +2959,6 @@
"symfony/process": "^5.4|^6.0",
"symfony/var-dumper": "^5.4|^6.0"
},
- "suggest": {
- "psr/log": "For using the console logger",
- "symfony/event-dispatcher": "",
- "symfony/lock": "",
- "symfony/process": ""
- },
"type": "library",
"autoload": {
"psr-4": {
@@ -2949,7 +2991,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v6.2.8"
+ "source": "https://github.com/symfony/console/tree/v6.3.0"
},
"funding": [
{
@@ -2965,20 +3007,20 @@
"type": "tidelift"
}
],
- "time": "2023-03-29T21:42:15+00:00"
+ "time": "2023-05-29T12:49:39+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.2.1",
+ "version": "v3.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e"
+ "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
- "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
+ "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
"shasum": ""
},
"require": {
@@ -2987,7 +3029,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "3.3-dev"
+ "dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -3016,7 +3058,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0"
},
"funding": [
{
@@ -3032,7 +3074,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-01T10:25:55+00:00"
+ "time": "2023-05-23T14:45:45+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -3449,16 +3491,16 @@
},
{
"name": "symfony/service-contracts",
- "version": "v3.2.1",
+ "version": "v3.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "a8c9cedf55f314f3a186041d19537303766df09a"
+ "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a8c9cedf55f314f3a186041d19537303766df09a",
- "reference": "a8c9cedf55f314f3a186041d19537303766df09a",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4",
+ "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4",
"shasum": ""
},
"require": {
@@ -3468,13 +3510,10 @@
"conflict": {
"ext-psr": "<1.1|>=2"
},
- "suggest": {
- "symfony/service-implementation": ""
- },
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "3.3-dev"
+ "dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -3514,7 +3553,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.2.1"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.3.0"
},
"funding": [
{
@@ -3530,20 +3569,20 @@
"type": "tidelift"
}
],
- "time": "2023-03-01T10:32:47+00:00"
+ "time": "2023-05-23T14:45:45+00:00"
},
{
"name": "symfony/string",
- "version": "v6.2.8",
+ "version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef"
+ "reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/193e83bbd6617d6b2151c37fff10fa7168ebddef",
- "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef",
+ "url": "https://api.github.com/repos/symfony/string/zipball/f2e190ee75ff0f5eced645ec0be5c66fac81f51f",
+ "reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f",
"shasum": ""
},
"require": {
@@ -3554,13 +3593,13 @@
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
- "symfony/translation-contracts": "<2.0"
+ "symfony/translation-contracts": "<2.5"
},
"require-dev": {
"symfony/error-handler": "^5.4|^6.0",
"symfony/http-client": "^5.4|^6.0",
"symfony/intl": "^6.2",
- "symfony/translation-contracts": "^2.0|^3.0",
+ "symfony/translation-contracts": "^2.5|^3.0",
"symfony/var-exporter": "^5.4|^6.0"
},
"type": "library",
@@ -3600,7 +3639,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v6.2.8"
+ "source": "https://github.com/symfony/string/tree/v6.3.0"
},
"funding": [
{
@@ -3616,7 +3655,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-20T16:06:02+00:00"
+ "time": "2023-03-21T21:06:29+00:00"
},
{
"name": "theseer/tokenizer",
@@ -3893,7 +3932,8 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": ">=8.0"
+ "php": ">=8.0",
+ "ext-swoole": "*"
},
"platform-dev": [],
"plugin-api-version": "2.3.0"
diff --git a/src/Adapter.php b/src/Adapter.php
new file mode 100644
index 00000000..bdd28b7e
--- /dev/null
+++ b/src/Adapter.php
@@ -0,0 +1,11 @@
+generateInput();
+
+ return $this->rawPayload;
+ }
+
+ /**
+ * Get server
+ *
+ * Method for querying server parameters. If $key is not found $default value will be returned.
+ *
+ * @param string $key
+ * @param string|null $default
+ * @return string|null
+ */
+ public function getServer(string $key, string $default = null): ?string
+ {
+ return $_SERVER[$key] ?? $default;
+ }
+
+ /**
+ * Set server
+ *
+ * Method for setting server parameters.
+ *
+ * @param string $key
+ * @param string $value
+ * @return static
+ */
+ public function setServer(string $key, string $value): static
+ {
+ $_SERVER[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get IP
+ *
+ * Returns users IP address.
+ * Support HTTP_X_FORWARDED_FOR header usually return
+ * from different proxy servers or PHP default REMOTE_ADDR
+ *
+ * @return string
+ */
+ public function getIP(): string
+ {
+ $ips = explode(',', $this->getHeader('HTTP_X_FORWARDED_FOR', $this->getServer('REMOTE_ADDR') ?? '0.0.0.0'));
+
+ return trim($ips[0] ?? '');
+ }
+
+ /**
+ * Get Protocol
+ *
+ * Returns request protocol.
+ * Support HTTP_X_FORWARDED_PROTO header usually return
+ * from different proxy servers or PHP default REQUEST_SCHEME
+ *
+ * @return string
+ */
+ public function getProtocol(): string
+ {
+ return $this->getServer('HTTP_X_FORWARDED_PROTO', $this->getServer('REQUEST_SCHEME')) ?? 'https';
+ }
+
+ /**
+ * Get Port
+ *
+ * Returns request port.
+ *
+ * @return string
+ */
+ public function getPort(): string
+ {
+ return (string) \parse_url($this->getProtocol().'://'.$this->getServer('HTTP_HOST', ''), PHP_URL_PORT);
+ }
+
+ /**
+ * Get Hostname
+ *
+ * Returns request hostname.
+ *
+ * @return string
+ */
+ public function getHostname(): string
+ {
+ return (string) \parse_url($this->getProtocol().'://'.$this->getServer('HTTP_HOST', ''), PHP_URL_HOST);
+ }
+
+ /**
+ * Get Method
+ *
+ * Return HTTP request method
+ *
+ * @return string
+ */
+ public function getMethod(): string
+ {
+ return $this->getServer('REQUEST_METHOD') ?? 'UNKNOWN';
+ }
+
+ /**
+ * Set Method
+ *
+ * Set HTTP request method
+ *
+ * @param string $method
+ * @return static
+ */
+ public function setMethod(string $method): static
+ {
+ $this->setServer('REQUEST_METHOD', $method);
+
+ return $this;
+ }
+
+ /**
+ * Get URI
+ *
+ * Return HTTP request URI
+ *
+ * @return string
+ */
+ public function getURI(): string
+ {
+ return $this->getServer('REQUEST_URI') ?? '';
+ }
+
+ /**
+ * Get Path
+ *
+ * Return HTTP request path
+ *
+ * @param string $uri
+ * @return static
+ */
+ public function setURI(string $uri): static
+ {
+ $this->setServer('REQUEST_URI', $uri);
+
+ return $this;
+ }
+
+ /**
+ * Get files
+ *
+ * Method for querying upload files data. If $key is not found empty array will be returned.
+ *
+ * @param string $key
+ * @return array
+ */
+ public function getFiles(string $key): array
+ {
+ return (isset($_FILES[$key])) ? $_FILES[$key] : [];
+ }
+
+ /**
+ * Get Referer
+ *
+ * Return HTTP referer header
+ *
+ * @param string $default
+ * @return string
+ */
+ public function getReferer(string $default = ''): string
+ {
+ return (string) $this->getServer('HTTP_REFERER', $default);
+ }
+
+ /**
+ * Get Origin
+ *
+ * Return HTTP origin header
+ *
+ * @param string $default
+ * @return string
+ */
+ public function getOrigin(string $default = ''): string
+ {
+ return (string) $this->getServer('HTTP_ORIGIN', $default);
+ }
+
+ /**
+ * Get User Agent
+ *
+ * Return HTTP user agent header
+ *
+ * @param string $default
+ * @return string
+ */
+ public function getUserAgent(string $default = ''): string
+ {
+ return (string) $this->getServer('HTTP_USER_AGENT', $default);
+ }
+
+ /**
+ * Get Accept
+ *
+ * Return HTTP accept header
+ *
+ * @param string $default
+ * @return string
+ */
+ public function getAccept(string $default = ''): string
+ {
+ return (string) $this->getServer('HTTP_ACCEPT', $default);
+ }
+
+ /**
+ * Get cookie
+ *
+ * Method for querying HTTP cookie parameters. If $key is not found $default value will be returned.
+ *
+ * @param string $key
+ * @param string $default
+ * @return string
+ */
+ public function getCookie(string $key, string $default = ''): string
+ {
+ return (isset($_COOKIE[$key])) ? $_COOKIE[$key] : $default;
+ }
+
+ /**
+ * Get header
+ *
+ * Method for querying HTTP header parameters. If $key is not found $default value will be returned.
+ *
+ * @param string $key
+ * @param string $default
+ * @return string
+ */
+ public function getHeader(string $key, string $default = ''): string
+ {
+ $headers = $this->generateHeaders();
+
+ return (isset($headers[$key])) ? $headers[$key] : $default;
+ }
+
+ /**
+ * Set header
+ *
+ * Method for adding HTTP header parameters.
+ *
+ * @param string $key
+ * @param string $value
+ * @return static
+ */
+ public function addHeader(string $key, string $value): static
+ {
+ $this->headers[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Remvoe header
+ *
+ * Method for removing HTTP header parameters.
+ *
+ * @param string $key
+ * @return static
+ */
+ public function removeHeader(string $key): static
+ {
+ if (isset($this->headers[$key])) {
+ unset($this->headers[$key]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Generate input
+ *
+ * Generate PHP input stream and parse it as an array in order to handle different content type of requests
+ *
+ * @return array
+ */
+ protected function generateInput(): array
+ {
+ if (null === $this->queryString) {
+ $this->queryString = $_GET;
+ }
+ if (null === $this->payload) {
+ $contentType = $this->getHeader('content-type');
+
+ // Get content-type without the charset
+ $length = \strpos($contentType, ';');
+ $length = (empty($length)) ? \strlen($contentType) : $length;
+ $contentType = \substr($contentType, 0, $length);
+
+ $this->rawPayload = \file_get_contents('php://input');
+
+ switch ($contentType) {
+ case 'application/json':
+ $this->payload = \json_decode($this->rawPayload, true);
+ break;
+ default:
+ $this->payload = $_POST;
+ break;
+ }
+
+ if (empty($this->payload)) { // Make sure we return same data type even if json payload is empty or failed
+ $this->payload = [];
+ }
+ }
+
+ return match ($this->getServer('REQUEST_METHOD', '')) {
+ self::METHOD_POST,
+ self::METHOD_PUT,
+ self::METHOD_PATCH,
+ self::METHOD_DELETE => $this->payload,
+ default => $this->queryString
+ };
+ }
+
+ /**
+ * Generate headers
+ *
+ * Parse request headers as an array for easy querying using the getHeader method
+ *
+ * @return array
+ */
+ protected function generateHeaders(): array
+ {
+ if (null === $this->headers) {
+ /**
+ * Fallback for older PHP versions
+ * that do not support generateHeaders
+ */
+ if (! \function_exists('getallheaders')) {
+ $headers = [];
+
+ foreach ($_SERVER as $name => $value) {
+ if (\substr($name, 0, 5) == 'HTTP_') {
+ $headers[\str_replace(' ', '-', \strtolower(\str_replace('_', ' ', \substr($name, 5))))] = $value;
+ }
+ }
+
+ $this->headers = $headers;
+
+ return $this->headers;
+ }
+
+ $this->headers = array_change_key_case(getallheaders());
+ }
+
+ return $this->headers;
+ }
+}
\ No newline at end of file
diff --git a/src/Adapter/FPM/Response.php b/src/Adapter/FPM/Response.php
new file mode 100644
index 00000000..dce7c7fd
--- /dev/null
+++ b/src/Adapter/FPM/Response.php
@@ -0,0 +1,82 @@
+
+ */
+ protected static array $loaded = [];
+
+ /**
+ * @var int
+ */
+ protected static int $count = 0;
+
+ /**
+ * @var array
+ */
+ protected static array $mimeTypes = [];
+
+ /**
+ * @var array
+ */
+ const EXTENSIONS = [
+ 'css' => 'text/css',
+ 'js' => 'text/javascript',
+ 'svg' => 'image/svg+xml',
+ ];
+
+ /**
+ * Add MIME type.
+ *
+ * @param string $mimeType
+ * @return void
+ */
+ public static function addMimeType(string $mimeType): void
+ {
+ self::$mimeTypes[$mimeType] = true;
+ }
+
+ /**
+ * Remove MIME type.
+ *
+ * @param string $mimeType
+ * @return void
+ */
+ public static function removeMimeType(string $mimeType): void
+ {
+ if (isset(self::$mimeTypes[$mimeType])) {
+ unset(self::$mimeTypes[$mimeType]);
+ }
+ }
+
+ /**
+ * Get MimeType List
+ *
+ * @return array
+ */
+ public static function getMimeTypes(): array
+ {
+ return self::$mimeTypes;
+ }
+
+ /**
+ * Get Files Loaded Count
+ *
+ * @return int
+ */
+ public static function getCount(): int
+ {
+ return self::$count;
+ }
+
+ /**
+ * Load directory.
+ *
+ * @param string $directory
+ * @param string|null $root
+ * @return void
+ *
+ * @throws \Exception
+ */
+ public static function load(string $directory, string $root = null): void
+ {
+ if (! is_readable($directory)) {
+ throw new Exception("Failed to load directory: {$directory}");
+ }
+
+ $directory = realpath($directory);
+
+ $root ??= $directory;
+
+ $handle = opendir(strval($directory));
+
+ while ($path = readdir($handle)) {
+ $extension = pathinfo($path, PATHINFO_EXTENSION);
+
+ if (in_array($path, ['.', '..'])) {
+ continue;
+ }
+
+ if (in_array($extension, ['php', 'phtml'])) {
+ continue;
+ }
+
+ if (substr($path, 0, 1) === '.') {
+ continue;
+ }
+
+ $dirPath = $directory.'/'.$path;
+
+ if (is_dir($dirPath)) {
+ self::load($dirPath, strval($root));
+
+ continue;
+ }
+
+ $key = substr($dirPath, strlen(strval($root)));
+
+ if (array_key_exists($key, self::$loaded)) {
+ continue;
+ }
+
+ self::$loaded[$key] = [
+ 'contents' => file_get_contents($dirPath),
+ 'mimeType' => (array_key_exists($extension, self::EXTENSIONS))
+ ? self::EXTENSIONS[$extension]
+ : mime_content_type($dirPath),
+ ];
+
+ self::$count++;
+ }
+
+ closedir($handle);
+ }
+
+ /**
+ * Is file loaded.
+ *
+ * @param string $uri
+ * @return bool
+ */
+ public static function isFileLoaded(string $uri): bool
+ {
+ if (! array_key_exists($uri, self::$loaded)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Get file contents.
+ *
+ * @param string $uri
+ * @return string
+ *
+ * @throws \Exception
+ */
+ public static function getFileContents(string $uri): mixed
+ {
+ if (! array_key_exists($uri, self::$loaded)) {
+ throw new Exception('File not found or not loaded: '.$uri);
+ }
+
+ return self::$loaded[$uri]['contents'];
+ }
+
+ /**
+ * Get file MIME type.
+ *
+ * @param string $uri
+ * @return string
+ *
+ * @throws \Exception
+ */
+ public static function getFileMimeType(string $uri): mixed
+ {
+ if (! array_key_exists($uri, self::$loaded)) {
+ throw new Exception('File not found or not loaded: '.$uri);
+ }
+
+ return self::$loaded[$uri]['mimeType'];
+ }
+
+ /**
+ * Reset.
+ *
+ * @return void
+ */
+ public static function reset(): void
+ {
+ self::$count = 0;
+ self::$loaded = [];
+ self::$mimeTypes = [];
+ }
+}
\ No newline at end of file
diff --git a/src/Adapter/Swoole/Request.php b/src/Adapter/Swoole/Request.php
new file mode 100644
index 00000000..eda02858
--- /dev/null
+++ b/src/Adapter/Swoole/Request.php
@@ -0,0 +1,359 @@
+swoole = $request;
+ }
+
+ /**
+ * Get raw payload
+ *
+ * Method for getting the HTTP request payload as a raw string.
+ *
+ * @return string
+ */
+ public function getRawPayload(): string
+ {
+ return $this->swoole->rawContent();
+ }
+
+ /**
+ * Get server
+ *
+ * Method for querying server parameters. If $key is not found $default value will be returned.
+ *
+ * @param string $key
+ * @param string|null $default
+ * @return string|null
+ */
+ public function getServer(string $key, string $default = null): ?string
+ {
+ return $this->swoole->server[$key] ?? $default;
+ }
+
+ /**
+ * Set server
+ *
+ * Method for setting server parameters.
+ *
+ * @param string $key
+ * @param string $value
+ * @return static
+ */
+ public function setServer(string $key, string $value): static
+ {
+ $this->swoole->server[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get IP
+ *
+ * Returns users IP address.
+ * Support HTTP_X_FORWARDED_FOR header usually return
+ * from different proxy servers or PHP default REMOTE_ADDR
+ */
+ public function getIP(): string
+ {
+ $ips = explode(',', $this->getHeader('x-forwarded-for', $this->getServer('remote_addr') ?? '0.0.0.0'));
+
+ return trim($ips[0] ?? '');
+ }
+
+ /**
+ * Get Protocol
+ *
+ * Returns request protocol.
+ * Support HTTP_X_FORWARDED_PROTO header usually return
+ * from different proxy servers or PHP default REQUEST_SCHEME
+ *
+ * @return string
+ */
+ public function getProtocol(): string
+ {
+ $protocol = $this->getHeader('x-forwarded-proto', $this->getServer('server_protocol') ?? 'https');
+
+ if ($protocol === 'HTTP/1.1') {
+ return 'http';
+ }
+
+ return match ($protocol) {
+ 'http', 'https', 'ws', 'wss' => $protocol,
+ default => 'https'
+ };
+ }
+
+ /**
+ * Get Port
+ *
+ * Returns request port.
+ *
+ * @return string
+ */
+ public function getPort(): string
+ {
+ return $this->getHeader('x-forwarded-port', (string) \parse_url($this->getProtocol().'://'.$this->getHeader('x-forwarded-host', $this->getHeader('host')), PHP_URL_PORT));
+ }
+
+ /**
+ * Get Hostname
+ *
+ * Returns request hostname.
+ *
+ * @return string
+ */
+ public function getHostname(): string
+ {
+ return strval(\parse_url($this->getProtocol().'://'.$this->getHeader('x-forwarded-host', $this->getHeader('host')), PHP_URL_HOST));
+ }
+
+ /**
+ * Get Method
+ *
+ * Return HTTP request method
+ *
+ * @return string
+ */
+ public function getMethod(): string
+ {
+ return $this->getServer('request_method') ?? 'UNKNOWN';
+ }
+
+ /**
+ * Set method
+ *
+ * Set HTTP request method
+ *
+ * @param string $method
+ * @return static
+ */
+ public function setMethod(string $method): static
+ {
+ $this->setServer('request_method', $method);
+
+ return $this;
+ }
+
+ /**
+ * Get URI
+ *
+ * Return HTTP request URI
+ *
+ * @return string
+ */
+ public function getURI(): string
+ {
+ return $this->getServer('request_uri') ?? '';
+ }
+
+ /**
+ * Set URI
+ *
+ * Set HTTP request URI
+ *
+ * @param string $uri
+ * @return static
+ */
+ public function setURI(string $uri): static
+ {
+ $this->setServer('request_uri', $uri);
+
+ return $this;
+ }
+
+ /**
+ * Get Referer
+ *
+ * Return HTTP referer header
+ *
+ * @return string
+ */
+ public function getReferer(string $default = ''): string
+ {
+ return $this->getHeader('referer', '');
+ }
+
+ /**
+ * Get Origin
+ *
+ * Return HTTP origin header
+ *
+ * @return string
+ */
+ public function getOrigin(string $default = ''): string
+ {
+ return $this->getHeader('origin', $default);
+ }
+
+ /**
+ * Get User Agent
+ *
+ * Return HTTP user agent header
+ *
+ * @return string
+ */
+ public function getUserAgent(string $default = ''): string
+ {
+ return $this->getHeader('user-agent', $default);
+ }
+
+ /**
+ * Get Accept
+ *
+ * Return HTTP accept header
+ *
+ * @return string
+ */
+ public function getAccept(string $default = ''): string
+ {
+ return $this->getHeader('accept', $default);
+ }
+
+ /**
+ * Get files
+ *
+ * Method for querying upload files data. If $key is not found empty array will be returned.
+ *
+ * @param string $key
+ * @return array
+ */
+ public function getFiles($key): array
+ {
+ $key = strtolower($key);
+
+ return $this->swoole->files[$key] ?? [];
+ }
+
+ /**
+ * Get cookie
+ *
+ * Method for querying HTTP cookie parameters. If $key is not found $default value will be returned.
+ *
+ * @param string $key
+ * @param string $default
+ * @return string
+ */
+ public function getCookie(string $key, string $default = ''): string
+ {
+ $key = strtolower($key);
+
+ return $this->swoole->cookie[$key] ?? $default;
+ }
+
+ /**
+ * Get header
+ *
+ * Method for querying HTTP header parameters. If $key is not found $default value will be returned.
+ *
+ * @param string $key
+ * @param string $default
+ * @return string
+ */
+ public function getHeader(string $key, string $default = ''): string
+ {
+ return $this->swoole->header[$key] ?? $default;
+ }
+
+ /**
+ * Method for adding HTTP header parameters.
+ *
+ * @param string $key
+ * @param string $value
+ * @return static
+ */
+ public function addHeader(string $key, string $value): static
+ {
+ $this->swoole->header[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Method for removing HTTP header parameters.
+ *
+ * @param string $key
+ * @return static
+ */
+ public function removeHeader(string $key): static
+ {
+ if (isset($this->swoole->header[$key])) {
+ unset($this->swoole->header[$key]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Generate input
+ *
+ * Generate PHP input stream and parse it as an array in order to handle different content type of requests
+ *
+ * @return array
+ */
+ protected function generateInput(): array
+ {
+ if (null === $this->queryString) {
+ $this->queryString = $this->swoole->get ?? [];
+ }
+ if (null === $this->payload) {
+ $contentType = $this->getHeader('content-type');
+
+ // Get content-type without the charset
+ $length = strpos($contentType, ';');
+ $length = (empty($length)) ? strlen($contentType) : $length;
+ $contentType = substr($contentType, 0, $length);
+
+ switch ($contentType) {
+ case 'application/json':
+ $this->payload = json_decode(strval($this->swoole->rawContent()), true);
+ break;
+
+ default:
+ $this->payload = $this->swoole->post;
+ break;
+ }
+
+ if (empty($this->payload)) { // Make sure we return same data type even if json payload is empty or failed
+ $this->payload = [];
+ }
+ }
+
+ return match ($this->getMethod()) {
+ self::METHOD_POST,
+ self::METHOD_PUT,
+ self::METHOD_PATCH,
+ self::METHOD_DELETE => $this->payload,
+ default => $this->queryString
+ };
+ }
+
+ /**
+ * Generate headers
+ *
+ * Parse request headers as an array for easy querying using the getHeader method
+ *
+ * @return array
+ */
+ protected function generateHeaders(): array
+ {
+ return $this->swoole->header;
+ }
+}
\ No newline at end of file
diff --git a/src/Adapter/Swoole/Response.php b/src/Adapter/Swoole/Response.php
new file mode 100644
index 00000000..3cf83cd1
--- /dev/null
+++ b/src/Adapter/Swoole/Response.php
@@ -0,0 +1,94 @@
+swoole = $response;
+ parent::__construct(\microtime(true));
+ }
+
+ /**
+ * Write
+ *
+ * @param string $content
+ * @return void
+ */
+ protected function write(string $content): void
+ {
+ $this->swoole->write($content);
+ }
+
+ /**
+ * End
+ *
+ * @param string|null $content
+ * @return void
+ */
+ protected function end(string $content = null): void
+ {
+ $this->swoole->end($content);
+ }
+
+ /**
+ * Send Status Code
+ *
+ * @param int $statusCode
+ * @return void
+ */
+ protected function sendStatus(int $statusCode): void
+ {
+ $this->swoole->status((string) $statusCode);
+ }
+
+ /**
+ * Send Header
+ *
+ * @param string $key
+ * @param string $value
+ * @return void
+ */
+ protected function sendHeader(string $key, string $value): void
+ {
+ $this->swoole->header($key, $value);
+ }
+
+ /**
+ * Send Cookie
+ *
+ * Send a cookie
+ *
+ * @param string $name
+ * @param string $value
+ * @param array $options
+ * @return void
+ */
+ protected function sendCookie(string $name, string $value, array $options): void
+ {
+ $this->swoole->cookie(
+ name: $name,
+ value: $value,
+ expires: $options['expire'] ?? 0,
+ path: $options['path'] ?? '',
+ domain: $options['domain'] ?? '',
+ secure: $options['secure'] ?? false,
+ httponly: $options['httponly'] ?? false,
+ samesite: $options['samesite'] ?? false,
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/Adapter/Swoole/Server.php b/src/Adapter/Swoole/Server.php
new file mode 100644
index 00000000..a0b0ce21
--- /dev/null
+++ b/src/Adapter/Swoole/Server.php
@@ -0,0 +1,32 @@
+server = new SwooleServer($host, $port);
+ }
+
+ public function getRequest(): UtopiaRequest
+ {
+ return new Request(new SwooleRequest());
+ }
+
+ public function getResponse(): UtopiaResponse
+ {
+ return new Response(new SwooleResponse());
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/Request.php b/src/Request.php
index a1e4bd2a..9c2bdb0e 100755
--- a/src/Request.php
+++ b/src/Request.php
@@ -2,7 +2,7 @@
namespace Utopia;
-class Request
+abstract class Request
{
/**
* HTTP methods
@@ -25,13 +25,6 @@ class Request
const METHOD_CONNECT = 'CONNECT';
- /**
- * Container for raw php://input parsed stream
- *
- * @var string
- */
- private $rawPayload = '';
-
/**
* Container for php://input parsed stream as an associative array
*
@@ -120,12 +113,7 @@ public function getPayload(string $key, mixed $default = null): mixed
*
* @return string
*/
- public function getRawPayload(): string
- {
- $this->generateInput();
-
- return $this->rawPayload;
- }
+ abstract public function getRawPayload(): string;
/**
* Get server
@@ -136,10 +124,7 @@ public function getRawPayload(): string
* @param string|null $default
* @return string|null
*/
- public function getServer(string $key, string $default = null): ?string
- {
- return $_SERVER[$key] ?? $default;
- }
+ abstract public function getServer(string $key, string $default = null): ?string;
/**
* Set server
@@ -150,12 +135,7 @@ public function getServer(string $key, string $default = null): ?string
* @param string $value
* @return static
*/
- public function setServer(string $key, string $value): static
- {
- $_SERVER[$key] = $value;
-
- return $this;
- }
+ abstract public function setServer(string $key, string $value): static;
/**
* Get IP
@@ -166,12 +146,7 @@ public function setServer(string $key, string $value): static
*
* @return string
*/
- public function getIP(): string
- {
- $ips = explode(',', $this->getHeader('HTTP_X_FORWARDED_FOR', $this->getServer('REMOTE_ADDR') ?? '0.0.0.0'));
-
- return trim($ips[0] ?? '');
- }
+ abstract public function getIP(): string;
/**
* Get Protocol
@@ -182,10 +157,7 @@ public function getIP(): string
*
* @return string
*/
- public function getProtocol(): string
- {
- return $this->getServer('HTTP_X_FORWARDED_PROTO', $this->getServer('REQUEST_SCHEME')) ?? 'https';
- }
+ abstract public function getProtocol(): string;
/**
* Get Port
@@ -194,10 +166,7 @@ public function getProtocol(): string
*
* @return string
*/
- public function getPort(): string
- {
- return (string) \parse_url($this->getProtocol().'://'.$this->getServer('HTTP_HOST', ''), PHP_URL_PORT);
- }
+ abstract public function getPort(): string;
/**
* Get Hostname
@@ -206,10 +175,7 @@ public function getPort(): string
*
* @return string
*/
- public function getHostname(): string
- {
- return (string) \parse_url($this->getProtocol().'://'.$this->getServer('HTTP_HOST', ''), PHP_URL_HOST);
- }
+ abstract public function getHostname(): string;
/**
* Get Method
@@ -218,10 +184,7 @@ public function getHostname(): string
*
* @return string
*/
- public function getMethod(): string
- {
- return $this->getServer('REQUEST_METHOD') ?? 'UNKNOWN';
- }
+ abstract public function getMethod(): string;
/**
* Set Method
@@ -231,12 +194,7 @@ public function getMethod(): string
* @param string $method
* @return static
*/
- public function setMethod(string $method): static
- {
- $this->setServer('REQUEST_METHOD', $method);
-
- return $this;
- }
+ abstract public function setMethod(string $method): static;
/**
* Get URI
@@ -258,12 +216,7 @@ public function getURI(): string
* @param string $uri
* @return static
*/
- public function setURI(string $uri): static
- {
- $this->setServer('REQUEST_URI', $uri);
-
- return $this;
- }
+ abstract public function setURI(string $uri): static;
/**
* Get files
@@ -273,10 +226,7 @@ public function setURI(string $uri): static
* @param string $key
* @return array
*/
- public function getFiles(string $key): array
- {
- return (isset($_FILES[$key])) ? $_FILES[$key] : [];
- }
+ abstract public function getFiles(string $key): array;
/**
* Get Referer
@@ -286,10 +236,7 @@ public function getFiles(string $key): array
* @param string $default
* @return string
*/
- public function getReferer(string $default = ''): string
- {
- return (string) $this->getServer('HTTP_REFERER', $default);
- }
+ abstract public function getReferer(string $default = ''): string;
/**
* Get Origin
@@ -299,10 +246,7 @@ public function getReferer(string $default = ''): string
* @param string $default
* @return string
*/
- public function getOrigin(string $default = ''): string
- {
- return (string) $this->getServer('HTTP_ORIGIN', $default);
- }
+ abstract public function getOrigin(string $default = ''): string;
/**
* Get User Agent
@@ -312,10 +256,7 @@ public function getOrigin(string $default = ''): string
* @param string $default
* @return string
*/
- public function getUserAgent(string $default = ''): string
- {
- return (string) $this->getServer('HTTP_USER_AGENT', $default);
- }
+ abstract public function getUserAgent(string $default = ''): string;
/**
* Get Accept
@@ -325,10 +266,7 @@ public function getUserAgent(string $default = ''): string
* @param string $default
* @return string
*/
- public function getAccept(string $default = ''): string
- {
- return (string) $this->getServer('HTTP_ACCEPT', $default);
- }
+ abstract public function getAccept(string $default = ''): string;
/**
* Get cookie
@@ -339,10 +277,7 @@ public function getAccept(string $default = ''): string
* @param string $default
* @return string
*/
- public function getCookie(string $key, string $default = ''): string
- {
- return (isset($_COOKIE[$key])) ? $_COOKIE[$key] : $default;
- }
+ abstract public function getCookie(string $key, string $default = ''): string;
/**
* Get header
@@ -353,12 +288,7 @@ public function getCookie(string $key, string $default = ''): string
* @param string $default
* @return string
*/
- public function getHeader(string $key, string $default = ''): string
- {
- $headers = $this->generateHeaders();
-
- return (isset($headers[$key])) ? $headers[$key] : $default;
- }
+ abstract public function getHeader(string $key, string $default = ''): string;
/**
* Get headers
@@ -381,12 +311,7 @@ public function getHeaders(): array
* @param string $value
* @return static
*/
- public function addHeader(string $key, string $value): static
- {
- $this->headers[$key] = $value;
-
- return $this;
- }
+ abstract public function addHeader(string $key, string $value): static;
/**
* Remvoe header
@@ -396,14 +321,7 @@ public function addHeader(string $key, string $value): static
* @param string $key
* @return static
*/
- public function removeHeader(string $key): static
- {
- if (isset($this->headers[$key])) {
- unset($this->headers[$key]);
- }
-
- return $this;
- }
+ abstract public function removeHeader(string $key): static;
/**
* Get Request Size
@@ -563,83 +481,22 @@ public function setPayload(array $params): static
}
/**
- * Generate input
+ * Generate headers
*
- * Generate PHP input stream and parse it as an array in order to handle different content type of requests
+ * Parse request headers as an array for easy querying using the getHeader method
*
* @return array
*/
- protected function generateInput(): array
- {
- if (null === $this->queryString) {
- $this->queryString = $_GET;
- }
- if (null === $this->payload) {
- $contentType = $this->getHeader('content-type');
-
- // Get content-type without the charset
- $length = \strpos($contentType, ';');
- $length = (empty($length)) ? \strlen($contentType) : $length;
- $contentType = \substr($contentType, 0, $length);
-
- $this->rawPayload = \file_get_contents('php://input');
-
- switch ($contentType) {
- case 'application/json':
- $this->payload = \json_decode($this->rawPayload, true);
- break;
- default:
- $this->payload = $_POST;
- break;
- }
-
- if (empty($this->payload)) { // Make sure we return same data type even if json payload is empty or failed
- $this->payload = [];
- }
- }
-
- return match ($this->getServer('REQUEST_METHOD', '')) {
- self::METHOD_POST,
- self::METHOD_PUT,
- self::METHOD_PATCH,
- self::METHOD_DELETE => $this->payload,
- default => $this->queryString
- };
- }
+ abstract protected function generateHeaders(): array;
/**
- * Generate headers
+ * Generate input
*
- * Parse request headers as an array for easy querying using the getHeader method
+ * Generate PHP input stream and parse it as an array in order to handle different content type of requests
*
* @return array
*/
- protected function generateHeaders(): array
- {
- if (null === $this->headers) {
- /**
- * Fallback for older PHP versions
- * that do not support generateHeaders
- */
- if (! \function_exists('getallheaders')) {
- $headers = [];
-
- foreach ($_SERVER as $name => $value) {
- if (\substr($name, 0, 5) == 'HTTP_') {
- $headers[\str_replace(' ', '-', \strtolower(\str_replace('_', ' ', \substr($name, 5))))] = $value;
- }
- }
-
- $this->headers = $headers;
-
- return $this->headers;
- }
-
- $this->headers = array_change_key_case(getallheaders());
- }
-
- return $this->headers;
- }
+ abstract protected function generateInput(): array;
/**
* Content Range Parser
diff --git a/src/Response.php b/src/Response.php
index 826a2b07..26c59db6 100755
--- a/src/Response.php
+++ b/src/Response.php
@@ -2,7 +2,7 @@
namespace Utopia;
-class Response
+abstract class Response
{
/**
* HTTP content types
@@ -499,10 +499,7 @@ public function send(string $body = ''): void
* @param string $content
* @return void
*/
- protected function write(string $content): void
- {
- echo $content;
- }
+ abstract protected function write(string $content): void;
/**
* End
@@ -512,12 +509,7 @@ protected function write(string $content): void
* @param string $content
* @return void
*/
- protected function end(string $content = null): void
- {
- if (! is_null($content)) {
- echo $content;
- }
- }
+ abstract protected function end(string $content = null): void;
/**
* Output response
@@ -586,10 +578,7 @@ protected function appendHeaders(): static
* @param int $statusCode
* @return void
*/
- protected function sendStatus(int $statusCode): void
- {
- http_response_code($statusCode);
- }
+ abstract protected function sendStatus(int $statusCode): void;
/**
* Send Header
@@ -600,10 +589,7 @@ protected function sendStatus(int $statusCode): void
* @param string $value
* @return void
*/
- protected function sendHeader(string $key, string $value): void
- {
- \header($key.': '.$value);
- }
+ abstract protected function sendHeader(string $key, string $value): void;
/**
* Send Cookie
@@ -615,15 +601,7 @@ protected function sendHeader(string $key, string $value): void
* @param array $options
* @return void
*/
- protected function sendCookie(string $name, string $value, array $options): void
- {
- // Use proper PHP keyword name
- $options['expires'] = $options['expire'];
- unset($options['expire']);
-
- // Set the cookie
- \setcookie($name, $value, $options);
- }
+ abstract protected function sendCookie(string $name, string $value, array $options): void;
/**
* Append cookies
From 02006b218cf5f63f7b4ba4e1abfcf36359c818d5 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 05:32:52 +0000
Subject: [PATCH 002/119] update test and fix
---
src/Adapter.php | 8 +++-----
src/Adapter/FPM/Request.php | 2 +-
src/Adapter/FPM/Server.php | 8 +++-----
src/Adapter/Swoole/Files.php | 4 ++--
src/Adapter/Swoole/Request.php | 2 +-
src/Adapter/Swoole/Response.php | 2 +-
src/Adapter/Swoole/Server.php | 15 ++++++++++++---
src/App.php | 14 ++++++++++++--
tests/e2e/server.php | 9 ++++-----
9 files changed, 39 insertions(+), 25 deletions(-)
diff --git a/src/Adapter.php b/src/Adapter.php
index bdd28b7e..f490c0bb 100644
--- a/src/Adapter.php
+++ b/src/Adapter.php
@@ -2,10 +2,8 @@
namespace Utopia;
-use Utopia\Request;
-use Utopia\Response;
-
-abstract class Adapter {
+abstract class Adapter
+{
abstract public function getRequest(): Request;
abstract public function getResponse(): Response;
-}
\ No newline at end of file
+}
diff --git a/src/Adapter/FPM/Request.php b/src/Adapter/FPM/Request.php
index b7617c5f..e6e342ea 100644
--- a/src/Adapter/FPM/Request.php
+++ b/src/Adapter/FPM/Request.php
@@ -371,4 +371,4 @@ protected function generateHeaders(): array
return $this->headers;
}
-}
\ No newline at end of file
+}
diff --git a/src/Adapter/FPM/Server.php b/src/Adapter/FPM/Server.php
index e184f4f5..67e1fba4 100644
--- a/src/Adapter/FPM/Server.php
+++ b/src/Adapter/FPM/Server.php
@@ -7,9 +7,8 @@
use Utopia\Request as UtopiaRequest;
use Utopia\Response as UtopiaResponse;
-
-class Server extends Adapter {
-
+class Server extends Adapter
+{
protected SwooleServer $server;
public function __construct()
@@ -25,5 +24,4 @@ public function getResponse(): UtopiaResponse
{
return new Response();
}
-
-}
\ No newline at end of file
+}
diff --git a/src/Adapter/Swoole/Files.php b/src/Adapter/Swoole/Files.php
index e0e2ecac..707b3435 100644
--- a/src/Adapter/Swoole/Files.php
+++ b/src/Adapter/Swoole/Files.php
@@ -24,7 +24,7 @@ class Files
/**
* @var array
*/
- const EXTENSIONS = [
+ public const EXTENSIONS = [
'css' => 'text/css',
'js' => 'text/javascript',
'svg' => 'image/svg+xml',
@@ -197,4 +197,4 @@ public static function reset(): void
self::$loaded = [];
self::$mimeTypes = [];
}
-}
\ No newline at end of file
+}
diff --git a/src/Adapter/Swoole/Request.php b/src/Adapter/Swoole/Request.php
index eda02858..302e5476 100644
--- a/src/Adapter/Swoole/Request.php
+++ b/src/Adapter/Swoole/Request.php
@@ -356,4 +356,4 @@ protected function generateHeaders(): array
{
return $this->swoole->header;
}
-}
\ No newline at end of file
+}
diff --git a/src/Adapter/Swoole/Response.php b/src/Adapter/Swoole/Response.php
index 3cf83cd1..921e43f5 100644
--- a/src/Adapter/Swoole/Response.php
+++ b/src/Adapter/Swoole/Response.php
@@ -91,4 +91,4 @@ protected function sendCookie(string $name, string $value, array $options): void
samesite: $options['samesite'] ?? false,
);
}
-}
\ No newline at end of file
+}
diff --git a/src/Adapter/Swoole/Server.php b/src/Adapter/Swoole/Server.php
index a0b0ce21..59470568 100644
--- a/src/Adapter/Swoole/Server.php
+++ b/src/Adapter/Swoole/Server.php
@@ -9,8 +9,8 @@
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
-class Server extends Adapter {
-
+class Server extends Adapter
+{
protected SwooleServer $server;
public function __construct(string $host, string $port = null)
@@ -29,4 +29,13 @@ public function getResponse(): UtopiaResponse
}
-}
\ No newline at end of file
+ public function setConfig(array $configs)
+ {
+ $this->server->set($configs);
+ }
+
+ public function onWorkerStart(callable $callback)
+ {
+ $this->server->on('WorkerStart', $callback);
+ }
+}
diff --git a/src/App.php b/src/App.php
index d4e7bfa7..47a7a386 100755
--- a/src/App.php
+++ b/src/App.php
@@ -102,14 +102,21 @@ class App
*/
protected static ?Route $wildcardRoute = null;
+ /**
+ * @var Adapter
+ */
+ protected Adapter $server;
+
/**
* App
*
* @param string $timezone
+ * @param Adapter $server
*/
- public function __construct(string $timezone)
+ public function __construct(string $timezone, Adapter $server)
{
\date_default_timezone_set($timezone);
+ $this->server = $server;
}
/**
@@ -605,8 +612,11 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
* @param Request $request
* @param Response $response
*/
- public function run(Request $request, Response $response): static
+ public function run(): static
{
+ $request = $this->server->getRequest();
+ $response = $this->server->getResponse();
+
$this->resources['request'] = $request;
$this->resources['response'] = $response;
diff --git a/tests/e2e/server.php b/tests/e2e/server.php
index cef864ee..5305bef7 100644
--- a/tests/e2e/server.php
+++ b/tests/e2e/server.php
@@ -2,8 +2,8 @@
require_once __DIR__.'/../../vendor/autoload.php';
+use Utopia\Adapter\FPM\Server;
use Utopia\App;
-use Utopia\Request;
use Utopia\Response;
use Utopia\Validator\Text;
@@ -46,8 +46,7 @@
$response->noContent();
});
-$request = new Request();
-$response = new Response();
+$server = new Server();
-$app = new App('UTC');
-$app->run($request, $response);
+$app = new App('UTC', $server);
+$app->run();
From 151434c9c4bacdd85c326ce4f4b78a7c22d953e2 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 05:35:23 +0000
Subject: [PATCH 003/119] fix lint
---
.github/workflows/lint.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index bcb85b66..e976a4f1 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -16,7 +16,7 @@ jobs:
php-version: '8.0'
- name: Install dependencies
- run: composer install --prefer-dist
+ run: composer install --prefer-dist --ignore-platform-reqs
- name: Run Linter
run: composer lint
\ No newline at end of file
From af837133acc288955b0fc6ff829ec9658afd9309 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 05:44:03 +0000
Subject: [PATCH 004/119] fix tests
---
tests/AppTest.php | 18 ++++++++++--------
tests/RequestTest.php | 2 +-
tests/ResponseTest.php | 3 ++-
tests/UtopiaRequestTest.php | 4 ++--
4 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/tests/AppTest.php b/tests/AppTest.php
index 2236fd75..ef8fe763 100755
--- a/tests/AppTest.php
+++ b/tests/AppTest.php
@@ -3,8 +3,10 @@
namespace Utopia;
use PHPUnit\Framework\TestCase;
-use Utopia\Tests\UtopiaRequestTest;
+use Utopia\Tests\UtopiaFPMRequestTest;
use Utopia\Validator\Text;
+use Utopia\Adapter\FPM\Request;
+use Utopia\Adapter\FPM\Server;
class AppTest extends TestCase
{
@@ -17,7 +19,7 @@ class AppTest extends TestCase
public function setUp(): void
{
App::reset();
- $this->app = new App('Asia/Tel_Aviv');
+ $this->app = new App('Asia/Tel_Aviv', new Server());
$this->saveRequest();
}
@@ -159,7 +161,7 @@ public function testCanExecuteRoute(): void
});
\ob_start();
- $request = new UtopiaRequestTest();
+ $request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y', 'z' => 'param-z']);
$this->app->execute($route, $request);
$result = \ob_get_contents();
@@ -179,7 +181,7 @@ public function testCanExecuteRoute(): void
});
\ob_start();
- $request = new UtopiaRequestTest();
+ $request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
$this->app->execute($route, $request);
$result = \ob_get_contents();
@@ -251,7 +253,7 @@ public function testCanExecuteRoute(): void
});
\ob_start();
- $request = new UtopiaRequestTest();
+ $request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
$this->app->execute($route, $request);
$result = \ob_get_contents();
@@ -260,7 +262,7 @@ public function testCanExecuteRoute(): void
$this->assertEquals('init-'.$resource.'-(init-api)-param-x-param-y-(shutdown-api)-shutdown', $result);
\ob_start();
- $request = new UtopiaRequestTest();
+ $request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
$this->app->execute($homepage, $request);
$result = \ob_get_contents();
@@ -498,7 +500,7 @@ public function testCanRunRequest(): void
});
\ob_start();
- $this->app->run(new Request(), new Response());
+ $this->app->run();
$result = \ob_get_contents();
\ob_end_clean();
@@ -523,7 +525,7 @@ public function testWildcardRoute(): void
});
\ob_start();
- @$this->app->run(new Request(), new Response());
+ @$this->app->run();
$result = \ob_get_contents();
\ob_end_clean();
diff --git a/tests/RequestTest.php b/tests/RequestTest.php
index 727d534a..a71bf12d 100755
--- a/tests/RequestTest.php
+++ b/tests/RequestTest.php
@@ -3,7 +3,7 @@
namespace Utopia\Tests;
use PHPUnit\Framework\TestCase;
-use Utopia\Request;
+use Utopia\Adapter\FPM\Request;
class RequestTest extends TestCase
{
diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php
index 30b20477..e2f1a48e 100755
--- a/tests/ResponseTest.php
+++ b/tests/ResponseTest.php
@@ -3,8 +3,9 @@
namespace Utopia;
use PHPUnit\Framework\TestCase;
+use Utopia\Adapter\FPM\Response;
-class ResponseTest extends TestCase
+class FPMResponseTest extends TestCase
{
protected ?Response $response;
diff --git a/tests/UtopiaRequestTest.php b/tests/UtopiaRequestTest.php
index 19ae0f6b..5cd71f16 100644
--- a/tests/UtopiaRequestTest.php
+++ b/tests/UtopiaRequestTest.php
@@ -2,9 +2,9 @@
namespace Utopia\Tests;
-use Utopia\Request as UtopiaRequest;
+use Utopia\Adapter\FPM\Request as UtopiaFPMRequest;
-class UtopiaRequestTest extends UtopiaRequest
+class UtopiaFPMRequestTest extends UtopiaFPMRequest
{
private static ?array $params;
From 4260458195e5c31bcd461cf7eb5c8d95d0956cb0 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 06:08:57 +0000
Subject: [PATCH 005/119] fixes
---
.github/workflows/bench.yml | 2 +-
composer.lock | 24 ++++++++++++------------
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml
index 3098877a..4cecb0e0 100644
--- a/.github/workflows/bench.yml
+++ b/.github/workflows/bench.yml
@@ -16,7 +16,7 @@ jobs:
php-version: '8.0'
- name: Install dependencies
- run: composer install --prefer-dist
+ run: composer install --prefer-dist --ignore-platform-reqs
- name: Run Benchmarks
run: composer bench -- --progress=plain
\ No newline at end of file
diff --git a/composer.lock b/composer.lock
index f7e27a72..34df0946 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "f27d5bb02390ce6b9a8268d4fffb1e87",
+ "content-hash": "84ebb005355cb22a8a5cc3c3b36ce609",
"packages": [],
"packages-dev": [
{
@@ -232,16 +232,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.10.3",
+ "version": "v1.5.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "c472786bca01e4812a9bb7933b23edfc5b6877b7"
+ "reference": "e0a8cef58b74662f27355be9cdea0e726bbac362"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/c472786bca01e4812a9bb7933b23edfc5b6877b7",
- "reference": "c472786bca01e4812a9bb7933b23edfc5b6877b7",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/e0a8cef58b74662f27355be9cdea0e726bbac362",
+ "reference": "e0a8cef58b74662f27355be9cdea0e726bbac362",
"shasum": ""
},
"require": {
@@ -249,16 +249,16 @@
"ext-mbstring": "*",
"ext-tokenizer": "*",
"ext-xml": "*",
- "php": "^8.1.0"
+ "php": "^8.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.18.0",
- "illuminate/view": "^10.5.1",
- "laravel-zero/framework": "^10.0.2",
+ "friendsofphp/php-cs-fixer": "^3.14.4",
+ "illuminate/view": "^9.51.0",
+ "laravel-zero/framework": "^9.2.0",
"mockery/mockery": "^1.5.1",
- "nunomaduro/larastan": "^2.5.1",
+ "nunomaduro/larastan": "^2.4.0",
"nunomaduro/termwind": "^1.15.1",
- "pestphp/pest": "^2.4.0"
+ "pestphp/pest": "^1.22.4"
},
"bin": [
"builds/pint"
@@ -294,7 +294,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2023-06-20T15:55:03+00:00"
+ "time": "2023-02-14T16:31:02+00:00"
},
{
"name": "myclabs/deep-copy",
From 4355dfad2940e1ef8f0a0ab0d3c3d56eefc6d151 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 06:27:30 +0000
Subject: [PATCH 006/119] fix param reference
---
src/App.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/App.php b/src/App.php
index 47a7a386..810c2a15 100755
--- a/src/App.php
+++ b/src/App.php
@@ -609,8 +609,6 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
* This is the place to initialize any pre routing logic.
* This is where you might want to parse the application current URL by any desired logic
*
- * @param Request $request
- * @param Response $response
*/
public function run(): static
{
From 29909dab1bfe2e3192e0dfbb429a31d2c23a92c7 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 06:33:03 +0000
Subject: [PATCH 007/119] downgrade symfony console
---
composer.lock | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/composer.lock b/composer.lock
index 34df0946..cad616d6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -2421,23 +2421,22 @@
},
{
"name": "symfony/console",
- "version": "v6.3.0",
+ "version": "v6.0.19",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7"
+ "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
- "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
+ "url": "https://api.github.com/repos/symfony/console/zipball/c3ebc83d031b71c39da318ca8b7a07ecc67507ed",
+ "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed",
"shasum": ""
},
"require": {
- "php": ">=8.1",
- "symfony/deprecation-contracts": "^2.5|^3",
+ "php": ">=8.0.2",
"symfony/polyfill-mbstring": "~1.0",
- "symfony/service-contracts": "^2.5|^3",
+ "symfony/service-contracts": "^1.1|^2|^3",
"symfony/string": "^5.4|^6.0"
},
"conflict": {
@@ -2459,6 +2458,12 @@
"symfony/process": "^5.4|^6.0",
"symfony/var-dumper": "^5.4|^6.0"
},
+ "suggest": {
+ "psr/log": "For using the console logger",
+ "symfony/event-dispatcher": "",
+ "symfony/lock": "",
+ "symfony/process": ""
+ },
"type": "library",
"autoload": {
"psr-4": {
@@ -2486,12 +2491,12 @@
"homepage": "https://symfony.com",
"keywords": [
"cli",
- "command-line",
+ "command line",
"console",
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v6.3.0"
+ "source": "https://github.com/symfony/console/tree/v6.0.19"
},
"funding": [
{
@@ -2507,7 +2512,7 @@
"type": "tidelift"
}
],
- "time": "2023-05-29T12:49:39+00:00"
+ "time": "2023-01-01T08:36:10+00:00"
},
{
"name": "symfony/deprecation-contracts",
From 63121c891baa8cede7f28a7565ad7f11d0f5dc10 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 06:37:35 +0000
Subject: [PATCH 008/119] downgrade phpbench
---
composer.lock | 39 +++++++++++++++++----------------------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/composer.lock b/composer.lock
index cad616d6..54b588dd 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "84ebb005355cb22a8a5cc3c3b36ce609",
+ "content-hash": "d3095212dd091713ce6091c108534af9",
"packages": [],
"packages-dev": [
{
@@ -626,16 +626,16 @@
},
{
"name": "phpbench/phpbench",
- "version": "1.2.14",
+ "version": "1.2.10",
"source": {
"type": "git",
"url": "https://github.com/phpbench/phpbench.git",
- "reference": "edbd1b7ecf704eb01f7a2bcd1b8aa8c189f9fa4e"
+ "reference": "95206f92479674599a75e02b74b9933e2d9883aa"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpbench/phpbench/zipball/edbd1b7ecf704eb01f7a2bcd1b8aa8c189f9fa4e",
- "reference": "edbd1b7ecf704eb01f7a2bcd1b8aa8c189f9fa4e",
+ "url": "https://api.github.com/repos/phpbench/phpbench/zipball/95206f92479674599a75e02b74b9933e2d9883aa",
+ "reference": "95206f92479674599a75e02b74b9933e2d9883aa",
"shasum": ""
},
"require": {
@@ -704,7 +704,7 @@
"description": "PHP Benchmarking Framework",
"support": {
"issues": "https://github.com/phpbench/phpbench/issues",
- "source": "https://github.com/phpbench/phpbench/tree/1.2.14"
+ "source": "https://github.com/phpbench/phpbench/tree/1.2.10"
},
"funding": [
{
@@ -712,7 +712,7 @@
"type": "github"
}
],
- "time": "2023-07-09T09:16:08+00:00"
+ "time": "2023-03-24T08:52:55+00:00"
},
{
"name": "phpstan/phpstan",
@@ -2421,22 +2421,23 @@
},
{
"name": "symfony/console",
- "version": "v6.0.19",
+ "version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed"
+ "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/c3ebc83d031b71c39da318ca8b7a07ecc67507ed",
- "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed",
+ "url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
+ "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
"shasum": ""
},
"require": {
- "php": ">=8.0.2",
+ "php": ">=8.1",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
- "symfony/service-contracts": "^1.1|^2|^3",
+ "symfony/service-contracts": "^2.5|^3",
"symfony/string": "^5.4|^6.0"
},
"conflict": {
@@ -2458,12 +2459,6 @@
"symfony/process": "^5.4|^6.0",
"symfony/var-dumper": "^5.4|^6.0"
},
- "suggest": {
- "psr/log": "For using the console logger",
- "symfony/event-dispatcher": "",
- "symfony/lock": "",
- "symfony/process": ""
- },
"type": "library",
"autoload": {
"psr-4": {
@@ -2491,12 +2486,12 @@
"homepage": "https://symfony.com",
"keywords": [
"cli",
- "command line",
+ "command-line",
"console",
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v6.0.19"
+ "source": "https://github.com/symfony/console/tree/v6.3.0"
},
"funding": [
{
@@ -2512,7 +2507,7 @@
"type": "tidelift"
}
],
- "time": "2023-01-01T08:36:10+00:00"
+ "time": "2023-05-29T12:49:39+00:00"
},
{
"name": "symfony/deprecation-contracts",
From b6d83d59e9324169645808ff3a7d9742dcf08b92 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 06:38:59 +0000
Subject: [PATCH 009/119] remove leftover code
---
src/Adapter/FPM/Server.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/Adapter/FPM/Server.php b/src/Adapter/FPM/Server.php
index 67e1fba4..122ab8fa 100644
--- a/src/Adapter/FPM/Server.php
+++ b/src/Adapter/FPM/Server.php
@@ -3,13 +3,11 @@
namespace Utopia\Adapter\FPM;
use Utopia\Adapter;
-use Swoole\Http\Server as SwooleServer;
use Utopia\Request as UtopiaRequest;
use Utopia\Response as UtopiaResponse;
class Server extends Adapter
{
- protected SwooleServer $server;
public function __construct()
{
From 9fbb07574c051f87cb5bc073f59d9e9b639454d5 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 06:40:44 +0000
Subject: [PATCH 010/119] move namespace
---
src/{Adapter/Swoole => }/Files.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename src/{Adapter/Swoole => }/Files.php (99%)
diff --git a/src/Adapter/Swoole/Files.php b/src/Files.php
similarity index 99%
rename from src/Adapter/Swoole/Files.php
rename to src/Files.php
index 707b3435..2c21a3f7 100644
--- a/src/Adapter/Swoole/Files.php
+++ b/src/Files.php
@@ -1,6 +1,6 @@
Date: Tue, 11 Jul 2023 06:42:13 +0000
Subject: [PATCH 011/119] fix formatting
---
src/Adapter/FPM/Server.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/Adapter/FPM/Server.php b/src/Adapter/FPM/Server.php
index 122ab8fa..e053278a 100644
--- a/src/Adapter/FPM/Server.php
+++ b/src/Adapter/FPM/Server.php
@@ -8,7 +8,6 @@
class Server extends Adapter
{
-
public function __construct()
{
}
From 45beee6eaa1876b8346e1c729610ef931bf2520d Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 06:44:35 +0000
Subject: [PATCH 012/119] update constructor
---
src/App.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/App.php b/src/App.php
index 810c2a15..06e745fe 100755
--- a/src/App.php
+++ b/src/App.php
@@ -110,10 +110,10 @@ class App
/**
* App
*
- * @param string $timezone
* @param Adapter $server
+ * @param string $timezone
*/
- public function __construct(string $timezone, Adapter $server)
+ public function __construct(Adapter $server, string $timezone)
{
\date_default_timezone_set($timezone);
$this->server = $server;
From d8350d1d49c9f4983685f9435a6ec1796ead0c86 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 12:30:25 +0545
Subject: [PATCH 013/119] Update src/Adapter/Swoole/Server.php
Co-authored-by: Eldad A. Fux
---
src/Adapter/Swoole/Server.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/Adapter/Swoole/Server.php b/src/Adapter/Swoole/Server.php
index 59470568..d7937e08 100644
--- a/src/Adapter/Swoole/Server.php
+++ b/src/Adapter/Swoole/Server.php
@@ -28,7 +28,6 @@ public function getResponse(): UtopiaResponse
return new Response(new SwooleResponse());
}
-
public function setConfig(array $configs)
{
$this->server->set($configs);
From 146ae35ae4124909babbd94406148409b3c3a612 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 06:48:05 +0000
Subject: [PATCH 014/119] fix test
---
tests/AppTest.php | 2 +-
tests/e2e/server.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/AppTest.php b/tests/AppTest.php
index ef8fe763..7301c530 100755
--- a/tests/AppTest.php
+++ b/tests/AppTest.php
@@ -19,7 +19,7 @@ class AppTest extends TestCase
public function setUp(): void
{
App::reset();
- $this->app = new App('Asia/Tel_Aviv', new Server());
+ $this->app = new App(new Server(), 'Asia/Tel_Aviv');
$this->saveRequest();
}
diff --git a/tests/e2e/server.php b/tests/e2e/server.php
index 5305bef7..12ad4c0d 100644
--- a/tests/e2e/server.php
+++ b/tests/e2e/server.php
@@ -48,5 +48,5 @@
$server = new Server();
-$app = new App('UTC', $server);
+$app = new App( $server, 'UTC');
$app->run();
From 4eeddf71f78ce6a739f7eaa7ad8232fb7d34b6c6 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 06:49:27 +0000
Subject: [PATCH 015/119] update readme
---
README.md | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index ac3fc084..d89fb04b 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,7 @@ require_once __DIR__ . '/../../vendor/autoload.php';
use Utopia\App;
use Utopia\Request;
use Utopia\Response;
+use Utopia\Adapter\FPM\Server;
App::get('/hello-world') // Define Route
->inject('request')
@@ -40,11 +41,8 @@ App::get('/hello-world') // Define Route
App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
-$app = new App('America/New_York');
-$request = new Request();
-$response = new Response();
-
-$app->run($request, $response);
+$app = new App(new Server(), 'America/New_York');
+$app->run();
```
### Hooks
@@ -57,6 +55,7 @@ require_once __DIR__ . '/../../vendor/autoload.php';
use Utopia\App;
use Utopia\Request;
use Utopia\Response;
+use Utopia\Adapter\FPM\Server;
App::init()
->inject('response')
@@ -88,11 +87,8 @@ App::get('/hello-world') // Define Route
App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
-$app = new App('America/New_York');
-$request = new Request();
-$response = new Response();
-
-$app->run($request, $response);
+$app = new App(new Server(), 'America/New_York');
+$app->run();
```
## System Requirements
From 803dddcb3ff81268bf0444869cb92814af5f3431 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 07:07:10 +0000
Subject: [PATCH 016/119] file loading support in servers
---
src/Adapter.php | 43 ++++++++++++++++++++++++++++++++
src/Files.php | 58 ++++++++++++++++++++++----------------------
tests/e2e/server.php | 2 +-
3 files changed, 73 insertions(+), 30 deletions(-)
diff --git a/src/Adapter.php b/src/Adapter.php
index f490c0bb..58bebb9a 100644
--- a/src/Adapter.php
+++ b/src/Adapter.php
@@ -4,6 +4,49 @@
abstract class Adapter
{
+ protected Files $files;
+
+ public function __construct()
+ {
+ $this->files = new Files();
+ }
abstract public function getRequest(): Request;
abstract public function getResponse(): Response;
+ /**
+ * Load directory.
+ *
+ * @param string $directory
+ * @param string|null $root
+ * @return void
+ *
+ * @throws \Exception
+ */
+ public function loadfiles(string $diectory, string $root = null): void
+ {
+ $this->files->load($diectory, $root);
+ }
+
+ /**
+ * Is file loaded.
+ *
+ * @param string $uri
+ * @return bool
+ */
+ public function isFileLoaded(string $uri): bool
+ {
+ return $this->files->isFileLoaded($uri);
+ }
+
+ /**
+ * Get file contents.
+ *
+ * @param string $uri
+ * @return string
+ *
+ * @throws \Exception
+ */
+ public function getFileContents(string $uri): mixed
+ {
+ return $this->files->getFileContents($uri);
+ }
}
diff --git a/src/Files.php b/src/Files.php
index 2c21a3f7..a9b29ec7 100644
--- a/src/Files.php
+++ b/src/Files.php
@@ -9,17 +9,17 @@ class Files
/**
* @var array
*/
- protected static array $loaded = [];
+ protected array $loaded = [];
/**
* @var int
*/
- protected static int $count = 0;
+ protected int $count = 0;
/**
* @var array
*/
- protected static array $mimeTypes = [];
+ protected array $mimeTypes = [];
/**
* @var array
@@ -36,9 +36,9 @@ class Files
* @param string $mimeType
* @return void
*/
- public static function addMimeType(string $mimeType): void
+ public function addMimeType(string $mimeType): void
{
- self::$mimeTypes[$mimeType] = true;
+ $this->mimeTypes[$mimeType] = true;
}
/**
@@ -47,10 +47,10 @@ public static function addMimeType(string $mimeType): void
* @param string $mimeType
* @return void
*/
- public static function removeMimeType(string $mimeType): void
+ public function removeMimeType(string $mimeType): void
{
- if (isset(self::$mimeTypes[$mimeType])) {
- unset(self::$mimeTypes[$mimeType]);
+ if (isset($this->mimeTypes[$mimeType])) {
+ unset($this->mimeTypes[$mimeType]);
}
}
@@ -59,9 +59,9 @@ public static function removeMimeType(string $mimeType): void
*
* @return array
*/
- public static function getMimeTypes(): array
+ public function getMimeTypes(): array
{
- return self::$mimeTypes;
+ return $this->mimeTypes;
}
/**
@@ -69,9 +69,9 @@ public static function getMimeTypes(): array
*
* @return int
*/
- public static function getCount(): int
+ public function getCount(): int
{
- return self::$count;
+ return $this->count;
}
/**
@@ -83,7 +83,7 @@ public static function getCount(): int
*
* @throws \Exception
*/
- public static function load(string $directory, string $root = null): void
+ public function load(string $directory, string $root = null): void
{
if (! is_readable($directory)) {
throw new Exception("Failed to load directory: {$directory}");
@@ -113,25 +113,25 @@ public static function load(string $directory, string $root = null): void
$dirPath = $directory.'/'.$path;
if (is_dir($dirPath)) {
- self::load($dirPath, strval($root));
+ $this->load($dirPath, strval($root));
continue;
}
$key = substr($dirPath, strlen(strval($root)));
- if (array_key_exists($key, self::$loaded)) {
+ if (array_key_exists($key, $this->loaded)) {
continue;
}
- self::$loaded[$key] = [
+ $this->loaded[$key] = [
'contents' => file_get_contents($dirPath),
'mimeType' => (array_key_exists($extension, self::EXTENSIONS))
? self::EXTENSIONS[$extension]
: mime_content_type($dirPath),
];
- self::$count++;
+ $this->count++;
}
closedir($handle);
@@ -143,9 +143,9 @@ public static function load(string $directory, string $root = null): void
* @param string $uri
* @return bool
*/
- public static function isFileLoaded(string $uri): bool
+ public function isFileLoaded(string $uri): bool
{
- if (! array_key_exists($uri, self::$loaded)) {
+ if (! array_key_exists($uri, $this->loaded)) {
return false;
}
@@ -160,13 +160,13 @@ public static function isFileLoaded(string $uri): bool
*
* @throws \Exception
*/
- public static function getFileContents(string $uri): mixed
+ public function getFileContents(string $uri): mixed
{
- if (! array_key_exists($uri, self::$loaded)) {
+ if (! array_key_exists($uri, $this->loaded)) {
throw new Exception('File not found or not loaded: '.$uri);
}
- return self::$loaded[$uri]['contents'];
+ return $this->loaded[$uri]['contents'];
}
/**
@@ -177,13 +177,13 @@ public static function getFileContents(string $uri): mixed
*
* @throws \Exception
*/
- public static function getFileMimeType(string $uri): mixed
+ public function getFileMimeType(string $uri): mixed
{
- if (! array_key_exists($uri, self::$loaded)) {
+ if (! array_key_exists($uri, $this->loaded)) {
throw new Exception('File not found or not loaded: '.$uri);
}
- return self::$loaded[$uri]['mimeType'];
+ return $this->loaded[$uri]['mimeType'];
}
/**
@@ -191,10 +191,10 @@ public static function getFileMimeType(string $uri): mixed
*
* @return void
*/
- public static function reset(): void
+ public function reset(): void
{
- self::$count = 0;
- self::$loaded = [];
- self::$mimeTypes = [];
+ $this->count = 0;
+ $this->loaded = [];
+ $this->mimeTypes = [];
}
}
diff --git a/tests/e2e/server.php b/tests/e2e/server.php
index 12ad4c0d..d0840f7e 100644
--- a/tests/e2e/server.php
+++ b/tests/e2e/server.php
@@ -48,5 +48,5 @@
$server = new Server();
-$app = new App( $server, 'UTC');
+$app = new App($server, 'UTC');
$app->run();
From 1876af80da04738b8ca8a2bbd766072453db74fb Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 11 Jul 2023 09:28:49 +0000
Subject: [PATCH 017/119] fix and update test for both server adapters
---
Dockerfile.swoole | 29 ++++++++++++++++
docker-compose.yml | 21 ++++++++++--
src/Adapter.php | 18 ++++++++--
src/Adapter/FPM/Server.php | 11 +++---
src/Adapter/Swoole/Server.php | 36 ++++++++++++++------
src/App.php | 7 ++--
tests/AppTest.php | 5 +--
tests/docker/nginx.conf | 6 ++--
tests/e2e/{ResponseTest.php => BaseTest.php} | 10 +-----
tests/e2e/Client.php | 5 +--
tests/e2e/ResponseFPMTest.php | 17 +++++++++
tests/e2e/ResponseSwooleTest.php | 17 +++++++++
tests/e2e/{server.php => init.php} | 6 ----
tests/e2e/server_fpm.php | 14 ++++++++
tests/e2e/server_swoole.php | 21 ++++++++++++
15 files changed, 177 insertions(+), 46 deletions(-)
create mode 100644 Dockerfile.swoole
rename tests/e2e/{ResponseTest.php => BaseTest.php} (84%)
create mode 100644 tests/e2e/ResponseFPMTest.php
create mode 100644 tests/e2e/ResponseSwooleTest.php
rename tests/e2e/{server.php => init.php} (91%)
create mode 100644 tests/e2e/server_fpm.php
create mode 100644 tests/e2e/server_swoole.php
diff --git a/Dockerfile.swoole b/Dockerfile.swoole
new file mode 100644
index 00000000..55ca84fe
--- /dev/null
+++ b/Dockerfile.swoole
@@ -0,0 +1,29 @@
+FROM composer:2.0 AS step0
+
+
+ARG TESTING=true
+
+ENV TESTING=$TESTING
+
+WORKDIR /usr/local/src/
+
+COPY composer.* /usr/local/src/
+
+RUN composer install --ignore-platform-reqs --optimize-autoloader \
+ --no-plugins --no-scripts --prefer-dist \
+ `if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
+
+FROM appwrite/base:0.2.2 as final
+LABEL maintainer="team@appwrite.io"
+
+WORKDIR /usr/src/code
+
+COPY ./src /usr/src/code/src
+COPY ./tests /usr/src/code/tests
+COPY ./phpunit.xml /usr/src/code/phpunit.xml
+COPY ./phpbench.json /usr/src/code/phpbench.json
+COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor
+
+EXPOSE 80
+
+CMD ["php", "tests/e2e/server_swoole.php"]
diff --git a/docker-compose.yml b/docker-compose.yml
index 849fa5ec..41d0f057 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,10 +1,27 @@
version: '3'
services:
- web:
+ fpm:
build: .
ports:
- "9020:80"
volumes:
- ./src:/usr/share/nginx/html/src
- - ./tests:/usr/share/nginx/html/tests
\ No newline at end of file
+ - ./tests:/usr/share/nginx/html/tests
+ networks:
+ - testing
+ depends_on:
+ - swoole
+ swoole:
+ build:
+ context: .
+ dockerfile: Dockerfile.swoole
+ ports:
+ - "9501:80"
+ volumes:
+ - ./src:/usr/src/code/src
+ - ./tests:/usr/src/code/tests
+ networks:
+ - testing
+networks:
+ testing:
\ No newline at end of file
diff --git a/src/Adapter.php b/src/Adapter.php
index 58bebb9a..64b407f5 100644
--- a/src/Adapter.php
+++ b/src/Adapter.php
@@ -10,8 +10,9 @@ public function __construct()
{
$this->files = new Files();
}
- abstract public function getRequest(): Request;
- abstract public function getResponse(): Response;
+
+ abstract public function onRequest(callable $callback);
+ abstract public function start();
/**
* Load directory.
*
@@ -49,4 +50,17 @@ public function getFileContents(string $uri): mixed
{
return $this->files->getFileContents($uri);
}
+
+ /**
+ * Get file MIME type.
+ *
+ * @param string $uri
+ * @return string
+ *
+ * @throws \Exception
+ */
+ public function getFileMimeType(string $uri): mixed
+ {
+ return $this->files->getFileMimeType($uri);
+ }
}
diff --git a/src/Adapter/FPM/Server.php b/src/Adapter/FPM/Server.php
index e053278a..bdc60175 100644
--- a/src/Adapter/FPM/Server.php
+++ b/src/Adapter/FPM/Server.php
@@ -3,22 +3,21 @@
namespace Utopia\Adapter\FPM;
use Utopia\Adapter;
-use Utopia\Request as UtopiaRequest;
-use Utopia\Response as UtopiaResponse;
class Server extends Adapter
{
public function __construct()
{
+ parent::__construct();
}
- public function getRequest(): UtopiaRequest
+ public function onRequest(callable $callback)
{
- return new Request();
+ call_user_func($callback, new Request(), new Response());
}
- public function getResponse(): UtopiaResponse
+ public function start()
{
- return new Response();
+ return;
}
}
diff --git a/src/Adapter/Swoole/Server.php b/src/Adapter/Swoole/Server.php
index d7937e08..1aff61cf 100644
--- a/src/Adapter/Swoole/Server.php
+++ b/src/Adapter/Swoole/Server.php
@@ -4,8 +4,6 @@
use Utopia\Adapter;
use Swoole\Http\Server as SwooleServer;
-use Utopia\Request as UtopiaRequest;
-use Utopia\Response as UtopiaResponse;
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
@@ -15,26 +13,44 @@ class Server extends Adapter
public function __construct(string $host, string $port = null)
{
+ parent::__construct();
$this->server = new SwooleServer($host, $port);
}
- public function getRequest(): UtopiaRequest
+ public function setConfig(array $configs)
{
- return new Request(new SwooleRequest());
+ $this->server->set($configs);
}
- public function getResponse(): UtopiaResponse
+ public function onRequest(callable $callback)
{
- return new Response(new SwooleResponse());
+ $this->server->on('request', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
+ call_user_func($callback, new Request($request), new Response($response));
+ });
}
- public function setConfig(array $configs)
+ public function onWorkerStart(callable $callback)
{
- $this->server->set($configs);
+ $this->server->on('WorkerStart', $callback);
}
- public function onWorkerStart(callable $callback)
+ public function onBeforeReload(callable $callback)
{
- $this->server->on('WorkerStart', $callback);
+ $this->server->on('BeforeReload', $callback);
+ }
+
+ public function onAfterReload(callable $callback)
+ {
+ $this->server->on('AfterReload', $callback);
+ }
+
+ public function onStart(callable $callback)
+ {
+ $this->server->on('start', $callback);
+ }
+
+ public function start()
+ {
+ $this->server->start();
}
}
diff --git a/src/App.php b/src/App.php
index 06e745fe..851741f5 100755
--- a/src/App.php
+++ b/src/App.php
@@ -609,12 +609,11 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
* This is the place to initialize any pre routing logic.
* This is where you might want to parse the application current URL by any desired logic
*
+ * @param Request $request
+ * @param Response $response;
*/
- public function run(): static
+ public function run(Request $request, Response $response): static
{
- $request = $this->server->getRequest();
- $response = $this->server->getResponse();
-
$this->resources['request'] = $request;
$this->resources['response'] = $response;
diff --git a/tests/AppTest.php b/tests/AppTest.php
index 7301c530..bdb80e44 100755
--- a/tests/AppTest.php
+++ b/tests/AppTest.php
@@ -6,6 +6,7 @@
use Utopia\Tests\UtopiaFPMRequestTest;
use Utopia\Validator\Text;
use Utopia\Adapter\FPM\Request;
+use Utopia\Adapter\FPM\Response;
use Utopia\Adapter\FPM\Server;
class AppTest extends TestCase
@@ -500,7 +501,7 @@ public function testCanRunRequest(): void
});
\ob_start();
- $this->app->run();
+ $this->app->run(new Request(), new Response());
$result = \ob_get_contents();
\ob_end_clean();
@@ -525,7 +526,7 @@ public function testWildcardRoute(): void
});
\ob_start();
- @$this->app->run();
+ @$this->app->run(new Request(), new Response());
$result = \ob_get_contents();
\ob_end_clean();
diff --git a/tests/docker/nginx.conf b/tests/docker/nginx.conf
index 978f1c03..54fdf4ae 100644
--- a/tests/docker/nginx.conf
+++ b/tests/docker/nginx.conf
@@ -33,7 +33,7 @@ http {
listen [::]:80 ipv6only=on; ## listen for ipv6
root /usr/share/nginx/html/tests/e2e;
- index index.php server.php index.html index.htm;
+ index index.php server_fpm.php index.html index.htm;
server_tokens off;
@@ -53,7 +53,7 @@ http {
location / {
# First attempt to serve request as file, then
# as directory, then fall back to index.html
- try_files $uri $uri/ /server.php?q=$uri&$args;
+ try_files $uri $uri/ /server_fpm.php?q=$uri&$args;
}
@@ -74,7 +74,7 @@ http {
fastcgi_param HTTP_IF_NONE_MATCH $http_if_none_match;
fastcgi_param HTTP_IF_MODIFIED_SINCE $http_if_modified_since;
fastcgi_read_timeout 600;
- fastcgi_index server.php;
+ fastcgi_index server_fpm.php;
include fastcgi_params;
}
diff --git a/tests/e2e/ResponseTest.php b/tests/e2e/BaseTest.php
similarity index 84%
rename from tests/e2e/ResponseTest.php
rename to tests/e2e/BaseTest.php
index 878cc23f..81fcde4c 100644
--- a/tests/e2e/ResponseTest.php
+++ b/tests/e2e/BaseTest.php
@@ -2,18 +2,10 @@
namespace Utopia\Tests;
-use PHPUnit\Framework\TestCase;
use Tests\E2E\Client;
-class ResponseTest extends TestCase
+trait BaseTest
{
- protected Client $client;
-
- public function setUp(): void
- {
- $this->client = new Client();
- }
-
public function testResponse()
{
$response = $this->client->call(Client::METHOD_GET, '/');
diff --git a/tests/e2e/Client.php b/tests/e2e/Client.php
index 662d860d..8edff5de 100644
--- a/tests/e2e/Client.php
+++ b/tests/e2e/Client.php
@@ -29,13 +29,14 @@ class Client
*
* @var string
*/
- protected $baseUrl = 'http://web';
+ protected $baseUrl;
/**
* SDK constructor.
*/
- public function __construct()
+ public function __construct(string $baseUrl = 'http://fpm')
{
+ $this->baseUrl = $baseUrl;
}
/**
diff --git a/tests/e2e/ResponseFPMTest.php b/tests/e2e/ResponseFPMTest.php
new file mode 100644
index 00000000..a1c21538
--- /dev/null
+++ b/tests/e2e/ResponseFPMTest.php
@@ -0,0 +1,17 @@
+client = new Client();
+ }
+}
diff --git a/tests/e2e/ResponseSwooleTest.php b/tests/e2e/ResponseSwooleTest.php
new file mode 100644
index 00000000..f212faee
--- /dev/null
+++ b/tests/e2e/ResponseSwooleTest.php
@@ -0,0 +1,17 @@
+client = new Client('http://swoole');
+ }
+}
diff --git a/tests/e2e/server.php b/tests/e2e/init.php
similarity index 91%
rename from tests/e2e/server.php
rename to tests/e2e/init.php
index d0840f7e..cf877865 100644
--- a/tests/e2e/server.php
+++ b/tests/e2e/init.php
@@ -2,7 +2,6 @@
require_once __DIR__.'/../../vendor/autoload.php';
-use Utopia\Adapter\FPM\Server;
use Utopia\App;
use Utopia\Response;
use Utopia\Validator\Text;
@@ -45,8 +44,3 @@
->action(function (Response $response) {
$response->noContent();
});
-
-$server = new Server();
-
-$app = new App($server, 'UTC');
-$app->run();
diff --git a/tests/e2e/server_fpm.php b/tests/e2e/server_fpm.php
new file mode 100644
index 00000000..04d76b13
--- /dev/null
+++ b/tests/e2e/server_fpm.php
@@ -0,0 +1,14 @@
+onRequest(function ($request, $response) use ($app) {
+ $app->run($request, $response);
+});
diff --git a/tests/e2e/server_swoole.php b/tests/e2e/server_swoole.php
new file mode 100644
index 00000000..1d445b85
--- /dev/null
+++ b/tests/e2e/server_swoole.php
@@ -0,0 +1,21 @@
+onRequest(function (Request $request, Response $response) use ($server) {
+ $app = new App($server, 'UTC');
+ $app->run($request, $response);
+});
+
+$server->onWorkerStart(function ($swooleServer, $workerId) {
+ \fwrite(STDOUT, "Worker " . ++$workerId . " started successfully\n");
+});
+
+$server->start();
From cbe0901ab350f493a552b5fd4c53f022ea323b69 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 02:19:07 +0000
Subject: [PATCH 018/119] fix test flow
---
.github/workflows/test.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index cc41aa6f..4ce331e1 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -22,4 +22,4 @@ jobs:
run: sleep 10
- name: Run Tests
- run: docker compose exec web vendor/bin/phpunit --configuration phpunit.xml
\ No newline at end of file
+ run: docker compose exec fpm vendor/bin/phpunit --configuration phpunit.xml
\ No newline at end of file
From c2e70abb9933b0515cd2df2166a026260de87a61 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 02:23:35 +0000
Subject: [PATCH 019/119] fix parameter name
---
src/Adapter.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Adapter.php b/src/Adapter.php
index 64b407f5..7dedd39b 100644
--- a/src/Adapter.php
+++ b/src/Adapter.php
@@ -22,9 +22,9 @@ abstract public function start();
*
* @throws \Exception
*/
- public function loadfiles(string $diectory, string $root = null): void
+ public function loadfiles(string $directory, string $root = null): void
{
- $this->files->load($diectory, $root);
+ $this->files->load($directory, $root);
}
/**
From 136c318c1f5043e9594ca213b1432fc0f10f07ef Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 10:10:22 +0545
Subject: [PATCH 020/119] Update src/Adapter.php
Co-authored-by: Eldad A. Fux
---
src/Adapter.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/Adapter.php b/src/Adapter.php
index 7dedd39b..5a29b989 100644
--- a/src/Adapter.php
+++ b/src/Adapter.php
@@ -13,6 +13,7 @@ public function __construct()
abstract public function onRequest(callable $callback);
abstract public function start();
+
/**
* Load directory.
*
From a3bdb494ef639d69beac9761c2e8eca00cc37399 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 10:10:29 +0545
Subject: [PATCH 021/119] Update src/Adapter.php
Co-authored-by: Eldad A. Fux
---
src/Adapter.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Adapter.php b/src/Adapter.php
index 5a29b989..0ca9644e 100644
--- a/src/Adapter.php
+++ b/src/Adapter.php
@@ -23,7 +23,7 @@ abstract public function start();
*
* @throws \Exception
*/
- public function loadfiles(string $directory, string $root = null): void
+ public function loadFiles(string $directory, string $root = null): void
{
$this->files->load($directory, $root);
}
From ab04d1526bbeb96778d2b282614fa4ea8dd899bf Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 04:28:16 +0000
Subject: [PATCH 022/119] update dockerfile name
---
Dockerfile => Dockerfile.fpm | 0
docker-compose.yml | 4 +++-
2 files changed, 3 insertions(+), 1 deletion(-)
rename Dockerfile => Dockerfile.fpm (100%)
diff --git a/Dockerfile b/Dockerfile.fpm
similarity index 100%
rename from Dockerfile
rename to Dockerfile.fpm
diff --git a/docker-compose.yml b/docker-compose.yml
index 41d0f057..0c4e0011 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,7 +2,9 @@ version: '3'
services:
fpm:
- build: .
+ build:
+ context: .
+ dockerfile: Dockerfile.fpm
ports:
- "9020:80"
volumes:
From 8b448f621e5708bea33ddb12a10cb52988f5db78 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 04:39:45 +0000
Subject: [PATCH 023/119] update readme
---
README.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/README.md b/README.md
index d89fb04b..cb8d1593 100644
--- a/README.md
+++ b/README.md
@@ -45,6 +45,74 @@ $app = new App(new Server(), 'America/New_York');
$app->run();
```
+### Server Adapters
+
+Library now supports server adapters and currently there are two servers implemented. You can use the PHP FPM server or the swoole server.
+
+**Use PHP FPM server**
+
+```php
+require_once __DIR__ . '/../../vendor/autoload.php';
+
+use Utopia\App;
+use Utopia\Adapter\FPM\Request;
+use Utopia\Adapter\FPM\Response;
+use Utopia\Adapter\FPM\Server;
+
+App::get('/hello-world') // Define Route
+ ->inject('request')
+ ->inject('response')
+ ->action(
+ function($request, $response) {
+ $response
+ ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
+ ->addHeader('Expires', '0')
+ ->addHeader('Pragma', 'no-cache')
+ ->json(['Hello' => 'World']);
+ }
+ );
+
+App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
+
+$app = new App(new Server(), 'America/New_York');
+$app->run(new Request(), new Response());
+```
+
+**Using swoole server**
+
+```php
+require_once __DIR__ . '/../../vendor/autoload.php';
+
+use Utopia\App;
+use Utopia\Adapter\Swoole\Request;
+use Utopia\Adapter\Swoole\Response;
+use Utopia\Adapter\Swoole\Server;
+
+App::get('/hello-world') // Define Route
+ ->inject('request')
+ ->inject('response')
+ ->action(
+ function($request, $response) {
+ $response
+ ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
+ ->addHeader('Expires', '0')
+ ->addHeader('Pragma', 'no-cache')
+ ->json(['Hello' => 'World']);
+ }
+ );
+
+App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
+
+$server = new Server('0.0.0.0', '80');
+
+$server->onRequest(function (Request $request, Response $response) use ($server) {
+ $app = new App($server, 'UTC');
+ $app->run($request, $response);
+});
+
+$server->start();
+```
+
### Hooks
There are three types of hooks, init hooks, shutdown hooks and error hooks. Init hooks are executed before the route action is executed. Shutdown hook is executed after route action is executed before application shuts down. Finally error hooks are executed whenever there's an error in the application lifecycle. You can provide multiple hooks for each stage. If you do not assign groups to the hook, by default the hook will be executed for every route.
From eaf63bde82b88c0a605da03bbad0fc9a2d392c3f Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 05:16:59 +0000
Subject: [PATCH 024/119] abstract away app start
---
src/App.php | 8 +++++++-
tests/AppTest.php | 2 +-
tests/e2e/server_fpm.php | 6 +-----
tests/e2e/server_swoole.php | 10 ++--------
4 files changed, 11 insertions(+), 15 deletions(-)
diff --git a/src/App.php b/src/App.php
index 851741f5..e971c696 100755
--- a/src/App.php
+++ b/src/App.php
@@ -453,6 +453,12 @@ public static function addRoute(string $method, string $url): Route
return $route;
}
+ public function start()
+ {
+ $this->server->onRequest(fn($request, $response ) => $this->run($request, $response));
+ $this->server->start();
+ }
+
/**
* Match
*
@@ -462,7 +468,7 @@ public static function addRoute(string $method, string $url): Route
* @param bool $fresh If true, will not match any cached route
* @return null|Route
*/
- public function match(Request $request, bool $fresh = false): ?Route
+ public function match(Request $request, bool $fresh = true): ?Route
{
if (null !== $this->route && !$fresh) {
return $this->route;
diff --git a/tests/AppTest.php b/tests/AppTest.php
index bdb80e44..254ba907 100755
--- a/tests/AppTest.php
+++ b/tests/AppTest.php
@@ -471,7 +471,7 @@ public function testCanMatchFreshRoute(): void
$_SERVER['REQUEST_METHOD'] = 'HEAD';
$_SERVER['REQUEST_URI'] = '/path2';
$request2 = new Request();
- $matched = $this->app->match($request2);
+ $matched = $this->app->match($request2, fresh: false);
$this->assertEquals($route1, $matched);
$this->assertEquals($route1, $this->app->getRoute());
diff --git a/tests/e2e/server_fpm.php b/tests/e2e/server_fpm.php
index 04d76b13..9395442f 100644
--- a/tests/e2e/server_fpm.php
+++ b/tests/e2e/server_fpm.php
@@ -6,9 +6,5 @@
use Utopia\App;
$server = new Server();
-
$app = new App($server, 'UTC');
-
-$server->onRequest(function ($request, $response) use ($app) {
- $app->run($request, $response);
-});
+$app->start();
diff --git a/tests/e2e/server_swoole.php b/tests/e2e/server_swoole.php
index 1d445b85..2a91f126 100644
--- a/tests/e2e/server_swoole.php
+++ b/tests/e2e/server_swoole.php
@@ -2,20 +2,14 @@
require_once __DIR__.'/init.php';
-use Utopia\Adapter\Swoole\Request;
-use Utopia\Adapter\Swoole\Response;
use Utopia\Adapter\Swoole\Server;
use Utopia\App;
$server = new Server('0.0.0.0', '80');
-
-$server->onRequest(function (Request $request, Response $response) use ($server) {
- $app = new App($server, 'UTC');
- $app->run($request, $response);
-});
+$app = new App($server, 'UTC');
$server->onWorkerStart(function ($swooleServer, $workerId) {
\fwrite(STDOUT, "Worker " . ++$workerId . " started successfully\n");
});
-$server->start();
+$app->start();
From bd9ff87d8589b72f1c670e51d6d39d620fd2d622 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 05:17:09 +0000
Subject: [PATCH 025/119] rename dockerfile
---
Dockerfile.fpm => Dockerfile | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename Dockerfile.fpm => Dockerfile (100%)
diff --git a/Dockerfile.fpm b/Dockerfile
similarity index 100%
rename from Dockerfile.fpm
rename to Dockerfile
From c8de4cc569506adfbcc1efd776be8c2b40ab6952 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 05:24:08 +0000
Subject: [PATCH 026/119] rename App -> Http
---
Dockerfile => Dockerfile.fpm | 0
README.md | 44 +++---
docs/Getting-Starting-Guide.md | 38 +++---
src/{App.php => Http.php} | 10 +-
src/Router.php | 20 +--
tests/{AppTest.php => HttpTest.php} | 204 ++++++++++++++--------------
tests/RouterBench.php | 14 +-
tests/RouterTest.php | 68 +++++-----
tests/e2e/init.php | 12 +-
tests/e2e/server_fpm.php | 6 +-
tests/e2e/server_swoole.php | 6 +-
11 files changed, 211 insertions(+), 211 deletions(-)
rename Dockerfile => Dockerfile.fpm (100%)
rename src/{App.php => Http.php} (99%)
rename tests/{AppTest.php => HttpTest.php} (68%)
diff --git a/Dockerfile b/Dockerfile.fpm
similarity index 100%
rename from Dockerfile
rename to Dockerfile.fpm
diff --git a/README.md b/README.md
index cb8d1593..7ea97cd0 100644
--- a/README.md
+++ b/README.md
@@ -21,12 +21,12 @@ Init your first application:
```php
require_once __DIR__ . '/../../vendor/autoload.php';
-use Utopia\App;
+use Utopia\Http;
use Utopia\Request;
use Utopia\Response;
use Utopia\Adapter\FPM\Server;
-App::get('/hello-world') // Define Route
+Http::get('/hello-world') // Define Route
->inject('request')
->inject('response')
->action(
@@ -39,10 +39,10 @@ App::get('/hello-world') // Define Route
}
);
-App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
+Http::setMode(Http::MODE_TYPE_PRODUCTION); // Define Mode
-$app = new App(new Server(), 'America/New_York');
-$app->run();
+$http = new Http(new Server(), 'America/New_York');
+$http->run();
```
### Server Adapters
@@ -54,12 +54,12 @@ Library now supports server adapters and currently there are two servers impleme
```php
require_once __DIR__ . '/../../vendor/autoload.php';
-use Utopia\App;
+use Utopia\Http;
use Utopia\Adapter\FPM\Request;
use Utopia\Adapter\FPM\Response;
use Utopia\Adapter\FPM\Server;
-App::get('/hello-world') // Define Route
+Http::get('/hello-world') // Define Route
->inject('request')
->inject('response')
->action(
@@ -72,10 +72,10 @@ App::get('/hello-world') // Define Route
}
);
-App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
+Http::setMode(Http::MODE_TYPE_PRODUCTION); // Define Mode
-$app = new App(new Server(), 'America/New_York');
-$app->run(new Request(), new Response());
+$http = new Http(new Server(), 'America/New_York');
+$http->run(new Request(), new Response());
```
**Using swoole server**
@@ -83,12 +83,12 @@ $app->run(new Request(), new Response());
```php
require_once __DIR__ . '/../../vendor/autoload.php';
-use Utopia\App;
+use Utopia\Http;
use Utopia\Adapter\Swoole\Request;
use Utopia\Adapter\Swoole\Response;
use Utopia\Adapter\Swoole\Server;
-App::get('/hello-world') // Define Route
+Http::get('/hello-world') // Define Route
->inject('request')
->inject('response')
->action(
@@ -101,13 +101,13 @@ App::get('/hello-world') // Define Route
}
);
-App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
+Http::setMode(Http::MODE_TYPE_PRODUCTION); // Define Mode
$server = new Server('0.0.0.0', '80');
$server->onRequest(function (Request $request, Response $response) use ($server) {
- $app = new App($server, 'UTC');
- $app->run($request, $response);
+ $http = new Http($server, 'UTC');
+ $http->run($request, $response);
});
$server->start();
@@ -120,18 +120,18 @@ There are three types of hooks, init hooks, shutdown hooks and error hooks. Init
```php
require_once __DIR__ . '/../../vendor/autoload.php';
-use Utopia\App;
+use Utopia\Http;
use Utopia\Request;
use Utopia\Response;
use Utopia\Adapter\FPM\Server;
-App::init()
+Http::init()
->inject('response')
->action(function($response) {
$response->addHeader('content-type', 'application/json');
});
-App::error()
+Http::error()
->inject('error')
->inject('response')
->action(function($error, $response) {
@@ -140,7 +140,7 @@ App::error()
->send('Error occurred ' . $error);
});
-App::get('/hello-world') // Define Route
+Http::get('/hello-world') // Define Route
->inject('request')
->inject('response')
->action(
@@ -153,10 +153,10 @@ App::get('/hello-world') // Define Route
}
);
-App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
+Http::setMode(Http::MODE_TYPE_PRODUCTION); // Define Mode
-$app = new App(new Server(), 'America/New_York');
-$app->run();
+$http = new Http(new Server(), 'America/New_York');
+$http->run();
```
## System Requirements
diff --git a/docs/Getting-Starting-Guide.md b/docs/Getting-Starting-Guide.md
index ab1779ac..a1a5c2a2 100644
--- a/docs/Getting-Starting-Guide.md
+++ b/docs/Getting-Starting-Guide.md
@@ -9,7 +9,7 @@ If you’re new to Utopia, let’s get started by looking at an example of a bas
## Basic GET Route
```php
-use Utopia\App;
+use Utopia\Http;
use Utopia\Swoole\Request;
use Utopia\Swoole\Response;
use Swoole\Http\Server;
@@ -18,7 +18,7 @@ use Swoole\Http\Response as SwooleResponse;
$http = new Server("0.0.0.0", 8080);
-App::get('/')
+Http::get('/')
->inject('request')
->inject('response')
->action(
@@ -27,14 +27,14 @@ App::get('/')
$response->send(" Hello World!
");
}
/*
- Configure your HTTP server to respond with the Utopia app.
+ Configure your HTTP server to respond with the Utopia http.
*/
$http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) {
$request = new Request($swooleRequest);
$response = new Response($swooleResponse);
- $app = new App('America/Toronto');
- $app->run($request, $response);
+ $http = new Http('America/Toronto');
+ $http->run($request, $response);
});
$http->start();
@@ -59,14 +59,14 @@ You can perform basic CRUD operations like GET, POST, PUT and DELETE using Utopi
You can create a PUT request to update a todo by passing it’s reference `id` along with the values to be updated as follows:
```php
-App::put('/todos/:id')
+Http::put('/todos/:id')
->param('id', "", new Wildcard(), 'id of the todo')
->param('task', "", new Wildcard(), 'name of the todo')
->param('is_complete', true, new Wildcard(), 'task complete or not')
->inject('response')
->action(
function($id, $task, $is_complete, $response) {
- $path = \realpath('/app/app/todos.json');
+ $path = \realpath('/http/http/todos.json');
$data = json_decode(file_get_contents($path));
foreach($data as $object){
if($object->id == $id){
@@ -138,7 +138,7 @@ You can find the details of other status codes by visiting our [GitHub repositor
Let's make the above example slightly advanced by adding more properties.
```php
-use Utopia\App;
+use Utopia\Http;
use Utopia\Swoole\Request;
use Utopia\Swoole\Response;
use Swoole\Http\Server;
@@ -148,28 +148,28 @@ use Utopia\Validator\Wildcard;
$http = new Server("0.0.0.0", 8080);
-App::init(function($response) {
+Http::init(function($response) {
/*
Example of global init method. Do stuff that is common to all your endpoints in all groups.
This can include things like authentication and authorisation checks, implementing rate limits and so on..
*/
}, ['response']);
-App::init(function($response) {
+Http::init(function($response) {
/*
Example of init method for group1. Do stuff that is common to all your endpoints in group1.
This can include things like authentication and authorisation checks, implementing rate limits and so on..
*/
}, ['response'], 'group1');
-App::init(function($response) {
+Http::init(function($response) {
/*
Example of init method for group2. Do stuff that is common to all your endpoints in group2.
This can include things like authentication and authorisation checks, implementing rate limits and so on..
*/
}, ['response'], 'group2');
-App::shutdown(function($request) {
+Http::shutdown(function($request) {
/*
Example of global shutdown method. Do stuff that needs to be performed at the end of each request for all groups.
'*' (Wildcard validator) is optional.
@@ -178,7 +178,7 @@ App::shutdown(function($request) {
}, ['request'], '*');
-App::shutdown(function($request) {
+Http::shutdown(function($request) {
/*
Example of shutdown method of group1. Do stuff that needs to be performed at the end of each request for all groups.
This can include cleanups, logging information, recording usage stats, closing database connections and so on..
@@ -186,7 +186,7 @@ App::shutdown(function($request) {
}, ['request'], 'group1');
-App::put('/todos/:id')
+Http::put('/todos/:id')
->desc('Update todo')
->groups(['group1', 'group2'])
->label('scope', 'public')
@@ -197,7 +197,7 @@ App::put('/todos/:id')
->inject('response')
->action(
function($id, $task, $is_complete, $response) {
- $path = \realpath('/app/app/todos.json');
+ $path = \realpath('/http/http/todos.json');
$data = json_decode(file_get_contents($path));
foreach($data as $object){
if($object->id == $id){
@@ -227,7 +227,7 @@ For each endpoint, you can add the following properties described below. Let’s
`label` can be used to store metadata that is related to your endpoint. It’s a key-value store. Some use-cases can be using label to generate the documentation or the swagger specifications.
* #### Injections
-Since each action in Utopia depends on certain resources, `inject` is used to add the dependencies. `$response` and `$request` can be injected into the service. Utopia provides the app static functions to make global resources available to all utopia endpoints.
+Since each action in Utopia depends on certain resources, `inject` is used to add the dependencies. `$response` and `$request` can be injected into the service. Utopia provides the http static functions to make global resources available to all utopia endpoints.
* #### Action
`action` contains the callback function that needs to be executed when an endpoint is called. The `param` and `inject` variables need to be passed as parameters in the callback function in the same order. The callback function defines the logic and also returns the `$response` back.
@@ -239,7 +239,7 @@ Now that you’re familiar with routing in Utopia, let’s dive into the lifecyc
## Init and Shutdown Methods
-The Utopia app goes through the following lifecycle whenever it receives any request:
+The Utopia http goes through the following lifecycle whenever it receives any request:

@@ -255,7 +255,7 @@ The init and shutdown methods take three params:
init method is executed in the beginning when the program execution begins. Here’s an example of the init method, where the init method is executed for all groups indicated by the wildcard symbol `'*'`.
```php
-App::init(function($response) {
+Http::init(function($response) {
/*
Do stuff that is common to all your endpoints.
This can include things like authentication and authorisation checks, implementing rate limits and so on..
@@ -268,7 +268,7 @@ App::init(function($response) {
Utopia's shutdown callback is used to perform cleanup tasks after a request. This could include closing any open database connections, resetting certain flags, triggering analytics events (if any) and similar tasks.
```php
-App::shutdown(function($request) {
+Http::shutdown(function($request) {
/*
Do stuff that needs to be performed at the end of each request.
This can include cleanups, logging information, recording usage stats, closing database connections and so on..
diff --git a/src/App.php b/src/Http.php
similarity index 99%
rename from src/App.php
rename to src/Http.php
index e971c696..08a85443 100755
--- a/src/App.php
+++ b/src/Http.php
@@ -2,7 +2,7 @@
namespace Utopia;
-class App
+class Http
{
/**
* Request method constants
@@ -108,7 +108,7 @@ class App
protected Adapter $server;
/**
- * App
+ * Http
*
* @param Adapter $server
* @param string $timezone
@@ -372,7 +372,7 @@ public static function setResource(string $name, callable $callback, array $inje
}
/**
- * Is app in production mode?
+ * Is http in production mode?
*
* @return bool
*/
@@ -382,7 +382,7 @@ public static function isProduction(): bool
}
/**
- * Is app in development mode?
+ * Is http in development mode?
*
* @return bool
*/
@@ -392,7 +392,7 @@ public static function isDevelopment(): bool
}
/**
- * Is app in stage mode?
+ * Is http in stage mode?
*
* @return bool
*/
diff --git a/src/Router.php b/src/Router.php
index 8748c253..f0c5b14e 100644
--- a/src/Router.php
+++ b/src/Router.php
@@ -16,11 +16,11 @@ class Router
* @var array
*/
protected static array $routes = [
- App::REQUEST_METHOD_GET => [],
- App::REQUEST_METHOD_POST => [],
- App::REQUEST_METHOD_PUT => [],
- App::REQUEST_METHOD_PATCH => [],
- App::REQUEST_METHOD_DELETE => [],
+ Http::REQUEST_METHOD_GET => [],
+ Http::REQUEST_METHOD_POST => [],
+ Http::REQUEST_METHOD_PUT => [],
+ Http::REQUEST_METHOD_PATCH => [],
+ Http::REQUEST_METHOD_DELETE => [],
];
/**
@@ -177,11 +177,11 @@ public static function reset(): void
{
self::$params = [];
self::$routes = [
- App::REQUEST_METHOD_GET => [],
- App::REQUEST_METHOD_POST => [],
- App::REQUEST_METHOD_PUT => [],
- App::REQUEST_METHOD_PATCH => [],
- App::REQUEST_METHOD_DELETE => [],
+ Http::REQUEST_METHOD_GET => [],
+ Http::REQUEST_METHOD_POST => [],
+ Http::REQUEST_METHOD_PUT => [],
+ Http::REQUEST_METHOD_PATCH => [],
+ Http::REQUEST_METHOD_DELETE => [],
];
}
}
diff --git a/tests/AppTest.php b/tests/HttpTest.php
similarity index 68%
rename from tests/AppTest.php
rename to tests/HttpTest.php
index 254ba907..4347e084 100755
--- a/tests/AppTest.php
+++ b/tests/HttpTest.php
@@ -9,9 +9,9 @@
use Utopia\Adapter\FPM\Response;
use Utopia\Adapter\FPM\Server;
-class AppTest extends TestCase
+class HttpTest extends TestCase
{
- protected ?App $app;
+ protected ?Http $http;
protected ?string $method;
@@ -19,14 +19,14 @@ class AppTest extends TestCase
public function setUp(): void
{
- App::reset();
- $this->app = new App(new Server(), 'Asia/Tel_Aviv');
+ Http::reset();
+ $this->http = new Http(new Server(), 'Asia/Tel_Aviv');
$this->saveRequest();
}
public function tearDown(): void
{
- $this->app = null;
+ $this->http = null;
$this->restoreRequest();
}
@@ -44,31 +44,31 @@ protected function restoreRequest(): void
public function testCanGetDifferentModes(): void
{
- $this->assertEmpty(App::getMode());
- $this->assertFalse(App::isProduction());
- $this->assertFalse(App::isDevelopment());
- $this->assertFalse(App::isStage());
+ $this->assertEmpty(Http::getMode());
+ $this->assertFalse(Http::isProduction());
+ $this->assertFalse(Http::isDevelopment());
+ $this->assertFalse(Http::isStage());
- App::setMode(App::MODE_TYPE_PRODUCTION);
+ Http::setMode(Http::MODE_TYPE_PRODUCTION);
- $this->assertEquals(App::MODE_TYPE_PRODUCTION, App::getMode());
- $this->assertTrue(App::isProduction());
- $this->assertFalse(App::isDevelopment());
- $this->assertFalse(App::isStage());
+ $this->assertEquals(Http::MODE_TYPE_PRODUCTION, Http::getMode());
+ $this->assertTrue(Http::isProduction());
+ $this->assertFalse(Http::isDevelopment());
+ $this->assertFalse(Http::isStage());
- App::setMode(App::MODE_TYPE_DEVELOPMENT);
+ Http::setMode(Http::MODE_TYPE_DEVELOPMENT);
- $this->assertEquals(App::MODE_TYPE_DEVELOPMENT, App::getMode());
- $this->assertFalse(App::isProduction());
- $this->assertTrue(App::isDevelopment());
- $this->assertFalse(App::isStage());
+ $this->assertEquals(Http::MODE_TYPE_DEVELOPMENT, Http::getMode());
+ $this->assertFalse(Http::isProduction());
+ $this->assertTrue(Http::isDevelopment());
+ $this->assertFalse(Http::isStage());
- App::setMode(App::MODE_TYPE_STAGE);
+ Http::setMode(Http::MODE_TYPE_STAGE);
- $this->assertEquals(App::MODE_TYPE_STAGE, App::getMode());
- $this->assertFalse(App::isProduction());
- $this->assertFalse(App::isDevelopment());
- $this->assertTrue(App::isStage());
+ $this->assertEquals(Http::MODE_TYPE_STAGE, Http::getMode());
+ $this->assertFalse(Http::isProduction());
+ $this->assertFalse(Http::isDevelopment());
+ $this->assertTrue(Http::isStage());
}
public function testCanGetEnvironmentVariable(): void
@@ -76,27 +76,27 @@ public function testCanGetEnvironmentVariable(): void
// Mock
$_SERVER['key'] = 'value';
- $this->assertEquals(App::getEnv('key'), 'value');
- $this->assertEquals(App::getEnv('unknown', 'test'), 'test');
+ $this->assertEquals(Http::getEnv('key'), 'value');
+ $this->assertEquals(Http::getEnv('unknown', 'test'), 'test');
}
public function testCanGetResources(): void
{
- App::setResource('rand', fn () => rand());
- App::setResource('first', fn ($second) => "first-{$second}", ['second']);
- App::setResource('second', fn () => 'second');
+ Http::setResource('rand', fn () => rand());
+ Http::setResource('first', fn ($second) => "first-{$second}", ['second']);
+ Http::setResource('second', fn () => 'second');
- $second = $this->app->getResource('second');
- $first = $this->app->getResource('first');
+ $second = $this->http->getResource('second');
+ $first = $this->http->getResource('first');
$this->assertEquals('second', $second);
$this->assertEquals('first-second', $first);
- $resource = $this->app->getResource('rand');
+ $resource = $this->http->getResource('rand');
$this->assertNotEmpty($resource);
- $this->assertEquals($resource, $this->app->getResource('rand'));
- $this->assertEquals($resource, $this->app->getResource('rand'));
- $this->assertEquals($resource, $this->app->getResource('rand'));
+ $this->assertEquals($resource, $this->http->getResource('rand'));
+ $this->assertEquals($resource, $this->http->getResource('rand'));
+ $this->assertEquals($resource, $this->http->getResource('rand'));
// Default Params
$route = new Route('GET', '/path');
@@ -110,7 +110,7 @@ public function testCanGetResources(): void
});
\ob_start();
- $this->app->execute($route, new Request());
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -119,10 +119,10 @@ public function testCanGetResources(): void
public function testCanExecuteRoute(): void
{
- App::setResource('rand', fn () => rand());
- $resource = $this->app->getResource('rand');
+ Http::setResource('rand', fn () => rand());
+ $resource = $this->http->getResource('rand');
- $this->app
+ $this->http
->error()
->inject('error')
->action(function ($error) {
@@ -140,7 +140,7 @@ public function testCanExecuteRoute(): void
});
\ob_start();
- $this->app->execute($route, new Request());
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -164,7 +164,7 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y', 'z' => 'param-z']);
- $this->app->execute($route, $request);
+ $this->http->execute($route, $request);
$result = \ob_get_contents();
\ob_end_clean();
@@ -184,7 +184,7 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->app->execute($route, $request);
+ $this->http->execute($route, $request);
$result = \ob_get_contents();
\ob_end_clean();
@@ -192,41 +192,41 @@ public function testCanExecuteRoute(): void
// With Hooks
- $this->app
+ $this->http
->init()
->inject('rand')
->action(function ($rand) {
echo 'init-'.$rand.'-';
});
- $this->app
+ $this->http
->shutdown()
->action(function () {
echo '-shutdown';
});
- $this->app
+ $this->http
->init()
->groups(['api'])
->action(function () {
echo '(init-api)-';
});
- $this->app
+ $this->http
->shutdown()
->groups(['api'])
->action(function () {
echo '-(shutdown-api)';
});
- $this->app
+ $this->http
->init()
->groups(['homepage'])
->action(function () {
echo '(init-homepage)-';
});
- $this->app
+ $this->http
->shutdown()
->groups(['homepage'])
->action(function () {
@@ -256,7 +256,7 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->app->execute($route, $request);
+ $this->http->execute($route, $request);
$result = \ob_get_contents();
\ob_end_clean();
@@ -265,7 +265,7 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->app->execute($homepage, $request);
+ $this->http->execute($homepage, $request);
$result = \ob_get_contents();
\ob_end_clean();
@@ -274,13 +274,13 @@ public function testCanExecuteRoute(): void
public function testCanAddAndExecuteHooks()
{
- $this->app
+ $this->http
->init()
->action(function () {
echo '(init)-';
});
- $this->app
+ $this->http
->shutdown()
->action(function () {
echo '-(shutdown)';
@@ -295,7 +295,7 @@ public function testCanAddAndExecuteHooks()
});
\ob_start();
- $this->app->execute($route, new Request());
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -311,7 +311,7 @@ public function testCanAddAndExecuteHooks()
});
\ob_start();
- $this->app->execute($route, new Request());
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -320,21 +320,21 @@ public function testCanAddAndExecuteHooks()
public function testCanHookThrowExceptions()
{
- $this->app
+ $this->http
->init()
->param('y', '', new Text(5), 'y param', false)
->action(function ($y) {
echo '(init)-'.$y.'-';
});
- $this->app
+ $this->http
->error()
->inject('error')
->action(function ($error) {
echo 'error-'.$error->getMessage();
});
- $this->app
+ $this->http
->shutdown()
->action(function () {
echo '-(shutdown)';
@@ -349,7 +349,7 @@ public function testCanHookThrowExceptions()
});
\ob_start();
- $this->app->execute($route, new Request());
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -357,7 +357,7 @@ public function testCanHookThrowExceptions()
\ob_start();
$_GET['y'] = 'y-def';
- $this->app->execute($route, new Request());
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -368,26 +368,26 @@ public function testCanSetRoute()
{
$route = new Route('GET', '/path');
- $this->assertEquals($this->app->getRoute(), null);
- $this->app->setRoute($route);
- $this->assertEquals($this->app->getRoute(), $route);
+ $this->assertEquals($this->http->getRoute(), null);
+ $this->http->setRoute($route);
+ $this->assertEquals($this->http->getRoute(), $route);
}
public function providerRouteMatching(): array
{
return [
- 'GET request' => [App::REQUEST_METHOD_GET, '/path1'],
- 'GET request on different route' => [App::REQUEST_METHOD_GET, '/path2'],
- 'GET request with trailing slash #1' => [App::REQUEST_METHOD_GET, '/path3', '/path3/'],
- 'GET request with trailing slash #2' => [App::REQUEST_METHOD_GET, '/path3/', '/path3/'],
- 'GET request with trailing slash #3' => [App::REQUEST_METHOD_GET, '/path3/', '/path3'],
- 'POST request' => [App::REQUEST_METHOD_POST, '/path1'],
- 'PUT request' => [App::REQUEST_METHOD_PUT, '/path1'],
- 'PATCH request' => [App::REQUEST_METHOD_PATCH, '/path1'],
- 'DELETE request' => [App::REQUEST_METHOD_DELETE, '/path1'],
- '1 separators' => [App::REQUEST_METHOD_GET, '/a/'],
- '2 separators' => [App::REQUEST_METHOD_GET, '/a/b'],
- '3 separators' => [App::REQUEST_METHOD_GET, '/a/b/c']
+ 'GET request' => [Http::REQUEST_METHOD_GET, '/path1'],
+ 'GET request on different route' => [Http::REQUEST_METHOD_GET, '/path2'],
+ 'GET request with trailing slash #1' => [Http::REQUEST_METHOD_GET, '/path3', '/path3/'],
+ 'GET request with trailing slash #2' => [Http::REQUEST_METHOD_GET, '/path3/', '/path3/'],
+ 'GET request with trailing slash #3' => [Http::REQUEST_METHOD_GET, '/path3/', '/path3'],
+ 'POST request' => [Http::REQUEST_METHOD_POST, '/path1'],
+ 'PUT request' => [Http::REQUEST_METHOD_PUT, '/path1'],
+ 'PATCH request' => [Http::REQUEST_METHOD_PATCH, '/path1'],
+ 'DELETE request' => [Http::REQUEST_METHOD_DELETE, '/path1'],
+ '1 separators' => [Http::REQUEST_METHOD_GET, '/a/'],
+ '2 separators' => [Http::REQUEST_METHOD_GET, '/a/b'],
+ '3 separators' => [Http::REQUEST_METHOD_GET, '/a/b/c']
];
}
@@ -400,28 +400,28 @@ public function testCanMatchRoute(string $method, string $path, string $url = nu
$expected = null;
switch ($method) {
- case App::REQUEST_METHOD_GET:
- $expected = App::get($path);
+ case Http::REQUEST_METHOD_GET:
+ $expected = Http::get($path);
break;
- case App::REQUEST_METHOD_POST:
- $expected = App::post($path);
+ case Http::REQUEST_METHOD_POST:
+ $expected = Http::post($path);
break;
- case App::REQUEST_METHOD_PUT:
- $expected = App::put($path);
+ case Http::REQUEST_METHOD_PUT:
+ $expected = Http::put($path);
break;
- case App::REQUEST_METHOD_PATCH:
- $expected = App::patch($path);
+ case Http::REQUEST_METHOD_PATCH:
+ $expected = Http::patch($path);
break;
- case App::REQUEST_METHOD_DELETE:
- $expected = App::delete($path);
+ case Http::REQUEST_METHOD_DELETE:
+ $expected = Http::delete($path);
break;
}
$_SERVER['REQUEST_METHOD'] = $method;
$_SERVER['REQUEST_URI'] = $url;
- $this->assertEquals($expected, $this->app->match(new Request()));
- $this->assertEquals($expected, $this->app->getRoute());
+ $this->assertEquals($expected, $this->http->match(new Request()));
+ $this->assertEquals($expected, $this->http->getRoute());
}
public function testNoMismatchRoute(): void
@@ -442,43 +442,43 @@ public function testNoMismatchRoute(): void
];
foreach ($requests as $request) {
- App::get($request['path']);
+ Http::get($request['path']);
- $_SERVER['REQUEST_METHOD'] = App::REQUEST_METHOD_GET;
+ $_SERVER['REQUEST_METHOD'] = Http::REQUEST_METHOD_GET;
$_SERVER['REQUEST_URI'] = $request['url'];
- $route = $this->app->match(new Request(), fresh: true);
+ $route = $this->http->match(new Request(), fresh: true);
$this->assertEquals(null, $route);
- $this->assertEquals(null, $this->app->getRoute());
+ $this->assertEquals(null, $this->http->getRoute());
}
}
public function testCanMatchFreshRoute(): void
{
- $route1 = App::get('/path1');
- $route2 = App::get('/path2');
+ $route1 = Http::get('/path1');
+ $route2 = Http::get('/path2');
try {
// Match first request
$_SERVER['REQUEST_METHOD'] = 'HEAD';
$_SERVER['REQUEST_URI'] = '/path1';
- $matched = $this->app->match(new Request());
+ $matched = $this->http->match(new Request());
$this->assertEquals($route1, $matched);
- $this->assertEquals($route1, $this->app->getRoute());
+ $this->assertEquals($route1, $this->http->getRoute());
// Second request match returns cached route
$_SERVER['REQUEST_METHOD'] = 'HEAD';
$_SERVER['REQUEST_URI'] = '/path2';
$request2 = new Request();
- $matched = $this->app->match($request2, fresh: false);
+ $matched = $this->http->match($request2, fresh: false);
$this->assertEquals($route1, $matched);
- $this->assertEquals($route1, $this->app->getRoute());
+ $this->assertEquals($route1, $this->http->getRoute());
// Fresh match returns new route
- $matched = $this->app->match($request2, fresh: true);
+ $matched = $this->http->match($request2, fresh: true);
$this->assertEquals($route2, $matched);
- $this->assertEquals($route2, $this->app->getRoute());
+ $this->assertEquals($route2, $this->http->getRoute());
} catch (\Exception $e) {
$this->fail($e->getMessage());
}
@@ -494,14 +494,14 @@ public function testCanRunRequest(): void
$_SERVER['REQUEST_METHOD'] = 'HEAD';
$_SERVER['REQUEST_URI'] = '/path';
- App::get('/path')
+ Http::get('/path')
->inject('response')
->action(function ($response) {
$response->send('HELLO');
});
\ob_start();
- $this->app->run(new Request(), new Response());
+ $this->http->run(new Request(), new Response());
$result = \ob_get_contents();
\ob_end_clean();
@@ -519,14 +519,14 @@ public function testWildcardRoute(): void
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['REQUEST_URI'] = '/unknown_path';
- App::wildcard()
+ Http::wildcard()
->inject('response')
->action(function ($response) {
$response->send('HELLO');
});
\ob_start();
- @$this->app->run(new Request(), new Response());
+ @$this->http->run(new Request(), new Response());
$result = \ob_get_contents();
\ob_end_clean();
diff --git a/tests/RouterBench.php b/tests/RouterBench.php
index 466506d6..7163c86c 100644
--- a/tests/RouterBench.php
+++ b/tests/RouterBench.php
@@ -17,12 +17,12 @@ public function tearDown(): void
public function setUpRouter(): void
{
- $routeBlog = new Route(App::REQUEST_METHOD_GET, '/blog');
- $routeBlogAuthors = new Route(App::REQUEST_METHOD_GET, '/blog/authors');
- $routeBlogPost = new Route(App::REQUEST_METHOD_GET, '/blog/:post');
- $routeBlogPostComments = new Route(App::REQUEST_METHOD_GET, '/blog/:post/comments');
- $routeBlogPostCommentsSingle = new Route(App::REQUEST_METHOD_GET, '/blog/:post/comments/:comment');
- $routeBlogLongUrl = new Route(App::REQUEST_METHOD_GET, '/blog/lorem/ipsum/dolor/sit/amet/consectetur/adipiscing/elit/Quisque/dolor/nisi/gravida/non/malesuada/eget/tincidunt/vitae/eros/Donec/hendrerit/mollis/purus/non/efficitur/augue/efficitur/sed/Praesent/a/tempus/felis/et/elementum/lorem/Vestibulum/ante/ipsum/primis/in/faucibus/orci/luctus/et/ultrices/posuere/cubilia/curae/Ut/luctus/ultrices/ligula/vulputate/malesuada/magna/pellentesque/eget/Mauris/at/sodales/orci/Mauris/efficitur/volutpat/est/in/faucibus/Donec/non/eleifend/nibh/Nunc/cursus/ornare/sollicitudin/Nullam/pellentesque/placerat/justo/ac/eleifend/tortor/imperdiet/quis/Nullam/tincidunt/non/justo/ut/pulvinar/Suspendisse/laoreet/tempus/nulla/eu/aliquet/Proin/metus/erat/facilisis/in/euismod/sit/amet/mollis/ac/nisi/Nulla/facilisi');
+ $routeBlog = new Route(Http::REQUEST_METHOD_GET, '/blog');
+ $routeBlogAuthors = new Route(Http::REQUEST_METHOD_GET, '/blog/authors');
+ $routeBlogPost = new Route(Http::REQUEST_METHOD_GET, '/blog/:post');
+ $routeBlogPostComments = new Route(Http::REQUEST_METHOD_GET, '/blog/:post/comments');
+ $routeBlogPostCommentsSingle = new Route(Http::REQUEST_METHOD_GET, '/blog/:post/comments/:comment');
+ $routeBlogLongUrl = new Route(Http::REQUEST_METHOD_GET, '/blog/lorem/ipsum/dolor/sit/amet/consectetur/adipiscing/elit/Quisque/dolor/nisi/gravida/non/malesuada/eget/tincidunt/vitae/eros/Donec/hendrerit/mollis/purus/non/efficitur/augue/efficitur/sed/Praesent/a/tempus/felis/et/elementum/lorem/Vestibulum/ante/ipsum/primis/in/faucibus/orci/luctus/et/ultrices/posuere/cubilia/curae/Ut/luctus/ultrices/ligula/vulputate/malesuada/magna/pellentesque/eget/Mauris/at/sodales/orci/Mauris/efficitur/volutpat/est/in/faucibus/Donec/non/eleifend/nibh/Nunc/cursus/ornare/sollicitudin/Nullam/pellentesque/placerat/justo/ac/eleifend/tortor/imperdiet/quis/Nullam/tincidunt/non/justo/ut/pulvinar/Suspendisse/laoreet/tempus/nulla/eu/aliquet/Proin/metus/erat/facilisis/in/euismod/sit/amet/mollis/ac/nisi/Nulla/facilisi');
Router::addRoute($routeBlog);
Router::addRoute($routeBlogAuthors);
@@ -53,6 +53,6 @@ public function provideRoutesToMatch(): iterable
#[ParamProviders('provideRoutesToMatch')]
public function benchRouter(array $data): void
{
- Router::match(App::REQUEST_METHOD_GET, $data['route']);
+ Router::match(Http::REQUEST_METHOD_GET, $data['route']);
}
}
diff --git a/tests/RouterTest.php b/tests/RouterTest.php
index 072d7693..8539d1c3 100644
--- a/tests/RouterTest.php
+++ b/tests/RouterTest.php
@@ -13,27 +13,27 @@ public function tearDown(): void
public function testCanMatchUrl(): void
{
- $routeIndex = new Route(App::REQUEST_METHOD_GET, '/');
- $routeAbout = new Route(App::REQUEST_METHOD_GET, '/about');
- $routeAboutMe = new Route(App::REQUEST_METHOD_GET, '/about/me');
+ $routeIndex = new Route(Http::REQUEST_METHOD_GET, '/');
+ $routeAbout = new Route(Http::REQUEST_METHOD_GET, '/about');
+ $routeAboutMe = new Route(Http::REQUEST_METHOD_GET, '/about/me');
Router::addRoute($routeIndex);
Router::addRoute($routeAbout);
Router::addRoute($routeAboutMe);
- $this->assertEquals($routeIndex, Router::match(App::REQUEST_METHOD_GET, '/'));
- $this->assertEquals($routeAbout, Router::match(App::REQUEST_METHOD_GET, '/about'));
- $this->assertEquals($routeAboutMe, Router::match(App::REQUEST_METHOD_GET, '/about/me'));
+ $this->assertEquals($routeIndex, Router::match(Http::REQUEST_METHOD_GET, '/'));
+ $this->assertEquals($routeAbout, Router::match(Http::REQUEST_METHOD_GET, '/about'));
+ $this->assertEquals($routeAboutMe, Router::match(Http::REQUEST_METHOD_GET, '/about/me'));
}
public function testCanMatchUrlWithPlaceholder(): void
{
- $routeBlog = new Route(App::REQUEST_METHOD_GET, '/blog');
- $routeBlogAuthors = new Route(App::REQUEST_METHOD_GET, '/blog/authors');
- $routeBlogAuthorsComments = new Route(App::REQUEST_METHOD_GET, '/blog/authors/comments');
- $routeBlogPost = new Route(App::REQUEST_METHOD_GET, '/blog/:post');
- $routeBlogPostComments = new Route(App::REQUEST_METHOD_GET, '/blog/:post/comments');
- $routeBlogPostCommentsSingle = new Route(App::REQUEST_METHOD_GET, '/blog/:post/comments/:comment');
+ $routeBlog = new Route(Http::REQUEST_METHOD_GET, '/blog');
+ $routeBlogAuthors = new Route(Http::REQUEST_METHOD_GET, '/blog/authors');
+ $routeBlogAuthorsComments = new Route(Http::REQUEST_METHOD_GET, '/blog/authors/comments');
+ $routeBlogPost = new Route(Http::REQUEST_METHOD_GET, '/blog/:post');
+ $routeBlogPostComments = new Route(Http::REQUEST_METHOD_GET, '/blog/:post/comments');
+ $routeBlogPostCommentsSingle = new Route(Http::REQUEST_METHOD_GET, '/blog/:post/comments/:comment');
Router::addRoute($routeBlog);
Router::addRoute($routeBlogAuthors);
@@ -42,12 +42,12 @@ public function testCanMatchUrlWithPlaceholder(): void
Router::addRoute($routeBlogPostComments);
Router::addRoute($routeBlogPostCommentsSingle);
- $this->assertEquals($routeBlog, Router::match(App::REQUEST_METHOD_GET, '/blog'));
- $this->assertEquals($routeBlogAuthors, Router::match(App::REQUEST_METHOD_GET, '/blog/authors'));
- $this->assertEquals($routeBlogAuthorsComments, Router::match(App::REQUEST_METHOD_GET, '/blog/authors/comments'));
- $this->assertEquals($routeBlogPost, Router::match(App::REQUEST_METHOD_GET, '/blog/test'));
- $this->assertEquals($routeBlogPostComments, Router::match(App::REQUEST_METHOD_GET, '/blog/test/comments'));
- $this->assertEquals($routeBlogPostCommentsSingle, Router::match(App::REQUEST_METHOD_GET, '/blog/test/comments/:comment'));
+ $this->assertEquals($routeBlog, Router::match(Http::REQUEST_METHOD_GET, '/blog'));
+ $this->assertEquals($routeBlogAuthors, Router::match(Http::REQUEST_METHOD_GET, '/blog/authors'));
+ $this->assertEquals($routeBlogAuthorsComments, Router::match(Http::REQUEST_METHOD_GET, '/blog/authors/comments'));
+ $this->assertEquals($routeBlogPost, Router::match(Http::REQUEST_METHOD_GET, '/blog/test'));
+ $this->assertEquals($routeBlogPostComments, Router::match(Http::REQUEST_METHOD_GET, '/blog/test/comments'));
+ $this->assertEquals($routeBlogPostCommentsSingle, Router::match(Http::REQUEST_METHOD_GET, '/blog/test/comments/:comment'));
}
public function testCanMatchUrlWithWildcard(): void
@@ -69,52 +69,52 @@ public function testCanMatchUrlWithWildcard(): void
public function testCanMatchHttpMethod(): void
{
- $routeGET = new Route(App::REQUEST_METHOD_GET, '/');
- $routePOST = new Route(App::REQUEST_METHOD_POST, '/');
+ $routeGET = new Route(Http::REQUEST_METHOD_GET, '/');
+ $routePOST = new Route(Http::REQUEST_METHOD_POST, '/');
Router::addRoute($routeGET);
Router::addRoute($routePOST);
- $this->assertEquals($routeGET, Router::match(App::REQUEST_METHOD_GET, '/'));
- $this->assertEquals($routePOST, Router::match(App::REQUEST_METHOD_POST, '/'));
+ $this->assertEquals($routeGET, Router::match(Http::REQUEST_METHOD_GET, '/'));
+ $this->assertEquals($routePOST, Router::match(Http::REQUEST_METHOD_POST, '/'));
- $this->assertNotEquals($routeGET, Router::match(App::REQUEST_METHOD_POST, '/'));
- $this->assertNotEquals($routePOST, Router::match(App::REQUEST_METHOD_GET, '/'));
+ $this->assertNotEquals($routeGET, Router::match(Http::REQUEST_METHOD_POST, '/'));
+ $this->assertNotEquals($routePOST, Router::match(Http::REQUEST_METHOD_GET, '/'));
}
public function testCanMatchAlias(): void
{
- $routeGET = new Route(App::REQUEST_METHOD_GET, '/target');
+ $routeGET = new Route(Http::REQUEST_METHOD_GET, '/target');
$routeGET->alias('/alias')->alias('/alias2');
Router::addRoute($routeGET);
- $this->assertEquals($routeGET, Router::match(App::REQUEST_METHOD_GET, '/target'));
- $this->assertEquals($routeGET, Router::match(App::REQUEST_METHOD_GET, '/alias'));
- $this->assertEquals($routeGET, Router::match(App::REQUEST_METHOD_GET, '/alias2'));
+ $this->assertEquals($routeGET, Router::match(Http::REQUEST_METHOD_GET, '/target'));
+ $this->assertEquals($routeGET, Router::match(Http::REQUEST_METHOD_GET, '/alias'));
+ $this->assertEquals($routeGET, Router::match(Http::REQUEST_METHOD_GET, '/alias2'));
}
public function testCanMatchFilename(): void
{
- $routeGET = new Route(App::REQUEST_METHOD_GET, '/robots.txt');
+ $routeGET = new Route(Http::REQUEST_METHOD_GET, '/robots.txt');
Router::addRoute($routeGET);
- $this->assertEquals($routeGET, Router::match(App::REQUEST_METHOD_GET, '/robots.txt'));
+ $this->assertEquals($routeGET, Router::match(Http::REQUEST_METHOD_GET, '/robots.txt'));
}
public function testCannotFindUnknownRouteByPath(): void
{
- $this->assertNull(Router::match(App::REQUEST_METHOD_GET, '/404'));
+ $this->assertNull(Router::match(Http::REQUEST_METHOD_GET, '/404'));
}
public function testCannotFindUnknownRouteByMethod(): void
{
- $route = new Route(App::REQUEST_METHOD_GET, '/404');
+ $route = new Route(Http::REQUEST_METHOD_GET, '/404');
Router::addRoute($route);
- $this->assertEquals($route, Router::match(App::REQUEST_METHOD_GET, '/404'));
+ $this->assertEquals($route, Router::match(Http::REQUEST_METHOD_GET, '/404'));
- $this->assertNull(Router::match(App::REQUEST_METHOD_POST, '/404'));
+ $this->assertNull(Router::match(Http::REQUEST_METHOD_POST, '/404'));
}
}
diff --git a/tests/e2e/init.php b/tests/e2e/init.php
index cf877865..c4cb4749 100644
--- a/tests/e2e/init.php
+++ b/tests/e2e/init.php
@@ -2,7 +2,7 @@
require_once __DIR__.'/../../vendor/autoload.php';
-use Utopia\App;
+use Utopia\Http;
use Utopia\Response;
use Utopia\Validator\Text;
@@ -12,20 +12,20 @@
ini_set('display_socket_timeout', '-1');
error_reporting(E_ALL);
-App::get('/')
+Http::get('/')
->inject('response')
->action(function (Response $response) {
$response->send('Hello World!');
});
-App::get('/value/:value')
+Http::get('/value/:value')
->param('value', '', new Text(64))
->inject('response')
->action(function (string $value, Response $response) {
$response->send($value);
});
-App::get('/chunked')
+Http::get('/chunked')
->inject('response')
->action(function (Response $response) {
foreach (['Hello ', 'World!'] as $key => $word) {
@@ -33,13 +33,13 @@
}
});
-App::get('/redirect')
+Http::get('/redirect')
->inject('response')
->action(function (Response $response) {
$response->redirect('/');
});
-App::get('/humans.txt')
+Http::get('/humans.txt')
->inject('response')
->action(function (Response $response) {
$response->noContent();
diff --git a/tests/e2e/server_fpm.php b/tests/e2e/server_fpm.php
index 9395442f..7ea1036e 100644
--- a/tests/e2e/server_fpm.php
+++ b/tests/e2e/server_fpm.php
@@ -3,8 +3,8 @@
require_once __DIR__.'/init.php';
use Utopia\Adapter\FPM\Server;
-use Utopia\App;
+use Utopia\Http;
$server = new Server();
-$app = new App($server, 'UTC');
-$app->start();
+$http = new Http($server, 'UTC');
+$http->start();
diff --git a/tests/e2e/server_swoole.php b/tests/e2e/server_swoole.php
index 2a91f126..52a7d08c 100644
--- a/tests/e2e/server_swoole.php
+++ b/tests/e2e/server_swoole.php
@@ -3,13 +3,13 @@
require_once __DIR__.'/init.php';
use Utopia\Adapter\Swoole\Server;
-use Utopia\App;
+use Utopia\Http;
$server = new Server('0.0.0.0', '80');
-$app = new App($server, 'UTC');
+$http = new Http($server, 'UTC');
$server->onWorkerStart(function ($swooleServer, $workerId) {
\fwrite(STDOUT, "Worker " . ++$workerId . " started successfully\n");
});
-$app->start();
+$http->start();
From 644687b8e2e1a73c09a4dd01f519477d8b6d4105 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 05:28:09 +0000
Subject: [PATCH 027/119] fix formatting
---
src/Adapter.php | 2 +-
src/Http.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Adapter.php b/src/Adapter.php
index 0ca9644e..1b275e6f 100644
--- a/src/Adapter.php
+++ b/src/Adapter.php
@@ -13,7 +13,7 @@ public function __construct()
abstract public function onRequest(callable $callback);
abstract public function start();
-
+
/**
* Load directory.
*
diff --git a/src/Http.php b/src/Http.php
index 08a85443..4bae79d2 100755
--- a/src/Http.php
+++ b/src/Http.php
@@ -455,7 +455,7 @@ public static function addRoute(string $method, string $url): Route
public function start()
{
- $this->server->onRequest(fn($request, $response ) => $this->run($request, $response));
+ $this->server->onRequest(fn ($request, $response) => $this->run($request, $response));
$this->server->start();
}
From 4bcf45857ab3473ba7f074f81a3eda66251b2da9 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 06:46:58 +0000
Subject: [PATCH 028/119] update namespace
---
README.md | 32 ++++++++++-----------
composer.json | 2 +-
docs/Getting-Starting-Guide.md | 14 ++++-----
src/{ => Http}/Adapter.php | 2 +-
src/{ => Http}/Adapter/FPM/Request.php | 4 +--
src/{ => Http}/Adapter/FPM/Response.php | 4 +--
src/{ => Http}/Adapter/FPM/Server.php | 4 +--
src/{ => Http}/Adapter/Swoole/Request.php | 4 +--
src/{ => Http}/Adapter/Swoole/Response.php | 4 +--
src/{ => Http}/Adapter/Swoole/Server.php | 4 +--
src/{ => Http}/Exception.php | 2 +-
src/{ => Http}/Files.php | 2 +-
src/{ => Http}/Hook.php | 2 +-
src/{ => Http}/Http.php | 2 +-
src/{ => Http}/Request.php | 2 +-
src/{ => Http}/Response.php | 2 +-
src/{ => Http}/Route.php | 4 +--
src/{ => Http}/Router.php | 6 ++--
src/{ => Http}/Validator.php | 2 +-
src/{ => Http}/Validator/ArrayList.php | 4 +--
src/{ => Http}/Validator/Assoc.php | 4 +--
src/{ => Http}/Validator/Boolean.php | 4 +--
src/{ => Http}/Validator/Domain.php | 4 +--
src/{ => Http}/Validator/FloatValidator.php | 4 +--
src/{ => Http}/Validator/HexColor.php | 4 +--
src/{ => Http}/Validator/Host.php | 4 +--
src/{ => Http}/Validator/Hostname.php | 4 +--
src/{ => Http}/Validator/IP.php | 4 +--
src/{ => Http}/Validator/Integer.php | 4 +--
src/{ => Http}/Validator/JSON.php | 4 +--
src/{ => Http}/Validator/Nullable.php | 4 +--
src/{ => Http}/Validator/Numeric.php | 4 +--
src/{ => Http}/Validator/Range.php | 2 +-
src/{ => Http}/Validator/Text.php | 4 +--
src/{ => Http}/Validator/URL.php | 4 +--
src/{ => Http}/Validator/WhiteList.php | 4 +--
src/{ => Http}/Validator/Wildcard.php | 4 +--
src/{ => Http}/View.php | 2 +-
tests/HookTest.php | 6 ++--
tests/HttpTest.php | 12 ++++----
tests/RequestTest.php | 4 +--
tests/ResponseTest.php | 10 +++----
tests/RouteTest.php | 4 +--
tests/RouterBench.php | 2 +-
tests/RouterTest.php | 2 +-
tests/UtopiaRequestTest.php | 4 +--
tests/Validator/ArrayListTest.php | 8 +++---
tests/Validator/AssocTest.php | 4 +--
tests/Validator/BooleanTest.php | 6 ++--
tests/Validator/DomainTest.php | 2 +-
tests/Validator/FloatValidatorTest.php | 6 ++--
tests/Validator/HexColorTest.php | 4 +--
tests/Validator/HostTest.php | 2 +-
tests/Validator/HostnameTest.php | 4 +--
tests/Validator/IPTest.php | 2 +-
tests/Validator/IntegerTest.php | 6 ++--
tests/Validator/JSONTest.php | 4 +--
tests/Validator/NullableTest.php | 2 +-
tests/Validator/NumericTest.php | 4 +--
tests/Validator/RangeTest.php | 18 ++++++------
tests/Validator/TextTest.php | 4 +--
tests/Validator/URLTest.php | 2 +-
tests/Validator/WhiteListTest.php | 4 +--
tests/Validator/WildcardTest.php | 4 +--
tests/ViewTest.php | 6 ++--
tests/e2e/BaseTest.php | 2 +-
tests/e2e/ResponseFPMTest.php | 2 +-
tests/e2e/ResponseSwooleTest.php | 2 +-
tests/e2e/init.php | 6 ++--
tests/e2e/server_fpm.php | 4 +--
tests/e2e/server_swoole.php | 4 +--
71 files changed, 163 insertions(+), 163 deletions(-)
rename src/{ => Http}/Adapter.php (98%)
rename src/{ => Http}/Adapter/FPM/Request.php (99%)
rename src/{ => Http}/Adapter/FPM/Response.php (94%)
rename src/{ => Http}/Adapter/FPM/Server.php (83%)
rename src/{ => Http}/Adapter/Swoole/Request.php (99%)
rename src/{ => Http}/Adapter/Swoole/Response.php (95%)
rename src/{ => Http}/Adapter/Swoole/Server.php (95%)
rename src/{ => Http}/Exception.php (67%)
rename src/{ => Http}/Files.php (99%)
rename src/{ => Http}/Hook.php (99%)
rename src/{ => Http}/Http.php (99%)
rename src/{ => Http}/Request.php (99%)
rename src/{ => Http}/Response.php (99%)
rename src/{ => Http}/Route.php (97%)
rename src/{ => Http}/Router.php (97%)
rename src/{ => Http}/Validator.php (97%)
rename src/{ => Http}/Validator/ArrayList.php (97%)
rename src/{ => Http}/Validator/Assoc.php (95%)
rename src/{ => Http}/Validator/Boolean.php (96%)
rename src/{ => Http}/Validator/Domain.php (95%)
rename src/{ => Http}/Validator/FloatValidator.php (96%)
rename src/{ => Http}/Validator/HexColor.php (93%)
rename src/{ => Http}/Validator/Host.php (96%)
rename src/{ => Http}/Validator/Hostname.php (97%)
rename src/{ => Http}/Validator/IP.php (97%)
rename src/{ => Http}/Validator/Integer.php (96%)
rename src/{ => Http}/Validator/JSON.php (93%)
rename src/{ => Http}/Validator/Nullable.php (95%)
rename src/{ => Http}/Validator/Numeric.php (94%)
rename src/{ => Http}/Validator/Range.php (98%)
rename src/{ => Http}/Validator/Text.php (98%)
rename src/{ => Http}/Validator/URL.php (96%)
rename src/{ => Http}/Validator/WhiteList.php (97%)
rename src/{ => Http}/Validator/Wildcard.php (93%)
rename src/{ => Http}/View.php (99%)
diff --git a/README.md b/README.md
index 7ea97cd0..c88a094c 100644
--- a/README.md
+++ b/README.md
@@ -21,10 +21,10 @@ Init your first application:
```php
require_once __DIR__ . '/../../vendor/autoload.php';
-use Utopia\Http;
-use Utopia\Request;
-use Utopia\Response;
-use Utopia\Adapter\FPM\Server;
+use Utopia\Http\Http;
+use Utopia\Http\Request;
+use Utopia\Http\Response;
+use Utopia\Http\Adapter\FPM\Server;
Http::get('/hello-world') // Define Route
->inject('request')
@@ -54,10 +54,10 @@ Library now supports server adapters and currently there are two servers impleme
```php
require_once __DIR__ . '/../../vendor/autoload.php';
-use Utopia\Http;
-use Utopia\Adapter\FPM\Request;
-use Utopia\Adapter\FPM\Response;
-use Utopia\Adapter\FPM\Server;
+use Utopia\Http\Http;
+use Utopia\Http\Adapter\FPM\Request;
+use Utopia\Http\Adapter\FPM\Response;
+use Utopia\Http\Adapter\FPM\Server;
Http::get('/hello-world') // Define Route
->inject('request')
@@ -83,10 +83,10 @@ $http->run(new Request(), new Response());
```php
require_once __DIR__ . '/../../vendor/autoload.php';
-use Utopia\Http;
-use Utopia\Adapter\Swoole\Request;
-use Utopia\Adapter\Swoole\Response;
-use Utopia\Adapter\Swoole\Server;
+use Utopia\Http\Http;
+use Utopia\Http\Adapter\Swoole\Request;
+use Utopia\Http\Adapter\Swoole\Response;
+use Utopia\Http\Adapter\Swoole\Server;
Http::get('/hello-world') // Define Route
->inject('request')
@@ -120,10 +120,10 @@ There are three types of hooks, init hooks, shutdown hooks and error hooks. Init
```php
require_once __DIR__ . '/../../vendor/autoload.php';
-use Utopia\Http;
-use Utopia\Request;
-use Utopia\Response;
-use Utopia\Adapter\FPM\Server;
+use Utopia\Http\Http;
+use Utopia\Http\Request;
+use Utopia\Http\Response;
+use Utopia\Http\Adapter\FPM\Server;
Http::init()
->inject('response')
diff --git a/composer.json b/composer.json
index 03211d27..1c9edc09 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,7 @@
"minimum-stability": "stable",
"autoload": {
"psr-4": {
- "Utopia\\": "src/"
+ "Utopia\\Http": "src/Http"
}
},
"scripts": {
diff --git a/docs/Getting-Starting-Guide.md b/docs/Getting-Starting-Guide.md
index a1a5c2a2..272a6b4a 100644
--- a/docs/Getting-Starting-Guide.md
+++ b/docs/Getting-Starting-Guide.md
@@ -9,9 +9,9 @@ If you’re new to Utopia, let’s get started by looking at an example of a bas
## Basic GET Route
```php
-use Utopia\Http;
-use Utopia\Swoole\Request;
-use Utopia\Swoole\Response;
+use Utopia\Http\Http;
+use Utopia\Http\Swoole\Request;
+use Utopia\Http\Swoole\Response;
use Swoole\Http\Server;
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
@@ -138,13 +138,13 @@ You can find the details of other status codes by visiting our [GitHub repositor
Let's make the above example slightly advanced by adding more properties.
```php
-use Utopia\Http;
-use Utopia\Swoole\Request;
-use Utopia\Swoole\Response;
+use Utopia\Http\Http;
+use Utopia\Http\Swoole\Request;
+use Utopia\Http\Swoole\Response;
use Swoole\Http\Server;
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
-use Utopia\Validator\Wildcard;
+use Utopia\Http\Validator\Wildcard;
$http = new Server("0.0.0.0", 8080);
diff --git a/src/Adapter.php b/src/Http/Adapter.php
similarity index 98%
rename from src/Adapter.php
rename to src/Http/Adapter.php
index 1b275e6f..63c13f65 100644
--- a/src/Adapter.php
+++ b/src/Http/Adapter.php
@@ -1,6 +1,6 @@
response->setContentType(Response::CONTENT_TYPE_HTML, Response::CHARSET_UTF8);
// Assertions
- $this->assertInstanceOf('Utopia\Response', $contentType);
+ $this->assertInstanceOf('Utopia\Http\Response', $contentType);
}
public function testCanSetStatus()
@@ -32,7 +32,7 @@ public function testCanSetStatus()
$status = $this->response->setStatusCode(Response::STATUS_CODE_OK);
// Assertions
- $this->assertInstanceOf('Utopia\Response', $status);
+ $this->assertInstanceOf('Utopia\Http\Response', $status);
try {
$this->response->setStatusCode(0); // Unknown status code
@@ -50,7 +50,7 @@ public function testCanGetStatus()
$status = $this->response->setStatusCode(Response::STATUS_CODE_OK);
// Assertions
- $this->assertInstanceOf('Utopia\Response', $status);
+ $this->assertInstanceOf('Utopia\Http\Response', $status);
$this->assertEquals(Response::STATUS_CODE_OK, $this->response->getStatusCode());
}
diff --git a/tests/RouteTest.php b/tests/RouteTest.php
index cbdea1c3..4a966b87 100755
--- a/tests/RouteTest.php
+++ b/tests/RouteTest.php
@@ -1,9 +1,9 @@
assertFalse($arrayList->isValid(['string', 'string', 3]));
$this->assertFalse($arrayList->isValid('string'));
$this->assertFalse($arrayList->isValid('string'));
- $this->assertEquals(\Utopia\Validator::TYPE_STRING, $arrayList->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $arrayList->getType());
$this->assertInstanceOf(Text::class, $arrayList->getValidator());
}
@@ -25,7 +25,7 @@ public function testCanValidateNumericValues(): void
$this->assertTrue($arrayList->isValid([1, 2, 3]));
$this->assertFalse($arrayList->isValid(1));
$this->assertFalse($arrayList->isValid('string'));
- $this->assertEquals(\Utopia\Validator::TYPE_MIXED, $arrayList->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_MIXED, $arrayList->getType());
$this->assertInstanceOf(Numeric::class, $arrayList->getValidator());
}
@@ -35,7 +35,7 @@ public function testCanValidateNumericValuesWithBoundaries(): void
$this->assertTrue($arrayList->isValid([1]));
$this->assertTrue($arrayList->isValid([1, 2]));
$this->assertFalse($arrayList->isValid([1, 2, 3]));
- $this->assertEquals($arrayList->getType(), \Utopia\Validator::TYPE_MIXED);
+ $this->assertEquals($arrayList->getType(), \Utopia\Http\Validator::TYPE_MIXED);
$this->assertInstanceOf(Numeric::class, $arrayList->getValidator());
}
}
diff --git a/tests/Validator/AssocTest.php b/tests/Validator/AssocTest.php
index 8bf1c96e..2036998b 100755
--- a/tests/Validator/AssocTest.php
+++ b/tests/Validator/AssocTest.php
@@ -1,6 +1,6 @@
assertTrue($this->assoc->isValid([]));
$this->assertTrue($this->assoc->isValid(['value' => str_repeat('-', 62000)]));
$this->assertTrue($this->assoc->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_ARRAY, $this->assoc->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_ARRAY, $this->assoc->getType());
}
public function testCantValidateSequentialArray(): void
diff --git a/tests/Validator/BooleanTest.php b/tests/Validator/BooleanTest.php
index b1742918..bda71580 100755
--- a/tests/Validator/BooleanTest.php
+++ b/tests/Validator/BooleanTest.php
@@ -1,6 +1,6 @@
assertFalse($boolean->isValid('string'));
$this->assertFalse($boolean->isValid(1.2));
$this->assertFalse($boolean->isArray());
- $this->assertEquals($boolean->getType(), \Utopia\Validator::TYPE_BOOLEAN);
+ $this->assertEquals($boolean->getType(), \Utopia\Http\Validator::TYPE_BOOLEAN);
}
public function testCanValidateLoosely()
@@ -41,6 +41,6 @@ public function testCanValidateLoosely()
$this->assertFalse($boolean->isValid('string'));
$this->assertFalse($boolean->isValid(1.2));
$this->assertFalse($boolean->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_BOOLEAN, $boolean->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_BOOLEAN, $boolean->getType());
}
}
diff --git a/tests/Validator/DomainTest.php b/tests/Validator/DomainTest.php
index ca14a20e..d8fa4de4 100644
--- a/tests/Validator/DomainTest.php
+++ b/tests/Validator/DomainTest.php
@@ -11,7 +11,7 @@
* @license The MIT License (MIT)
*/
-namespace Utopia\Validator;
+namespace Utopia\Http\Validator;
use PHPUnit\Framework\TestCase;
diff --git a/tests/Validator/FloatValidatorTest.php b/tests/Validator/FloatValidatorTest.php
index 80d8f4dd..be905b68 100755
--- a/tests/Validator/FloatValidatorTest.php
+++ b/tests/Validator/FloatValidatorTest.php
@@ -1,6 +1,6 @@
assertFalse($validator->isValid('23.5'));
$this->assertFalse($validator->isValid('23'));
$this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_FLOAT, $validator->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_FLOAT, $validator->getType());
}
public function testCanValidateLoosely(): void
@@ -34,6 +34,6 @@ public function testCanValidateLoosely(): void
$this->assertFalse($validator->isValid('abc'));
$this->assertFalse($validator->isValid(true));
$this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_FLOAT, $validator->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_FLOAT, $validator->getType());
}
}
diff --git a/tests/Validator/HexColorTest.php b/tests/Validator/HexColorTest.php
index 93b7aa64..f90d92fe 100755
--- a/tests/Validator/HexColorTest.php
+++ b/tests/Validator/HexColorTest.php
@@ -1,6 +1,6 @@
assertFalse($hexColor->isValid('ffff'));
$this->assertFalse($hexColor->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_STRING, $hexColor->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $hexColor->getType());
}
}
diff --git a/tests/Validator/HostTest.php b/tests/Validator/HostTest.php
index 6ad38299..7d845f33 100644
--- a/tests/Validator/HostTest.php
+++ b/tests/Validator/HostTest.php
@@ -11,7 +11,7 @@
* @license The MIT License (MIT)
*/
-namespace Utopia\Validator;
+namespace Utopia\Http\Validator;
use PHPUnit\Framework\TestCase;
diff --git a/tests/Validator/HostnameTest.php b/tests/Validator/HostnameTest.php
index a1e492e0..2760648d 100755
--- a/tests/Validator/HostnameTest.php
+++ b/tests/Validator/HostnameTest.php
@@ -1,6 +1,6 @@
assertEquals(\Utopia\Validator::TYPE_STRING, $validator->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $validator->getType());
$this->assertFalse($validator->isArray());
$this->assertTrue($validator->isValid('myweb.com'));
diff --git a/tests/Validator/IPTest.php b/tests/Validator/IPTest.php
index 124be488..88c71994 100644
--- a/tests/Validator/IPTest.php
+++ b/tests/Validator/IPTest.php
@@ -11,7 +11,7 @@
* @license The MIT License (MIT)
*/
-namespace Utopia\Validator;
+namespace Utopia\Http\Validator;
use PHPUnit\Framework\TestCase;
diff --git a/tests/Validator/IntegerTest.php b/tests/Validator/IntegerTest.php
index 4161b3ad..faddca2c 100755
--- a/tests/Validator/IntegerTest.php
+++ b/tests/Validator/IntegerTest.php
@@ -1,6 +1,6 @@
assertFalse($validator->isValid(true));
$this->assertFalse($validator->isValid(false));
$this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_INTEGER, $validator->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_INTEGER, $validator->getType());
}
public function testCanValidateLoosely()
@@ -31,6 +31,6 @@ public function testCanValidateLoosely()
$this->assertFalse($validator->isValid(true));
$this->assertFalse($validator->isValid(false));
$this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_INTEGER, $validator->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_INTEGER, $validator->getType());
}
}
diff --git a/tests/Validator/JSONTest.php b/tests/Validator/JSONTest.php
index bafce37c..d4a4e358 100755
--- a/tests/Validator/JSONTest.php
+++ b/tests/Validator/JSONTest.php
@@ -1,6 +1,6 @@
assertFalse($json->isValid(1.2));
$this->assertFalse($json->isValid("{'test': 'demo'}"));
$this->assertFalse($json->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_OBJECT, $json->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_OBJECT, $json->getType());
}
}
diff --git a/tests/Validator/NullableTest.php b/tests/Validator/NullableTest.php
index fa15c530..ebd24834 100755
--- a/tests/Validator/NullableTest.php
+++ b/tests/Validator/NullableTest.php
@@ -1,6 +1,6 @@
assertFalse($numeric->isValid('not numeric'));
$this->assertFalse($numeric->isValid([]));
$this->assertFalse($numeric->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_MIXED, $numeric->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_MIXED, $numeric->getType());
}
}
diff --git a/tests/Validator/RangeTest.php b/tests/Validator/RangeTest.php
index 2bd1ee68..aafbab4a 100755
--- a/tests/Validator/RangeTest.php
+++ b/tests/Validator/RangeTest.php
@@ -1,6 +1,6 @@
assertTrue($range->isValid(0));
@@ -22,13 +22,13 @@ public function testCanValidateIntegerRange()
$this->assertEquals(0, $range->getMin());
$this->assertEquals(5, $range->getMax());
$this->assertFalse($range->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_INTEGER, $range->getFormat());
- $this->assertEquals(\Utopia\Validator::TYPE_INTEGER, $range->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_INTEGER, $range->getFormat());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_INTEGER, $range->getType());
}
public function testCanValidateFloatRange()
{
- $range = new Range(0, 1, \Utopia\Validator::TYPE_FLOAT);
+ $range = new Range(0, 1, \Utopia\Http\Validator::TYPE_FLOAT);
$this->assertTrue($range->isValid(0.0));
$this->assertTrue($range->isValid(1.0));
@@ -41,14 +41,14 @@ public function testCanValidateFloatRange()
$this->assertEquals(0, $range->getMin());
$this->assertEquals(1, $range->getMax());
$this->assertFalse($range->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_FLOAT, $range->getFormat());
- $this->assertEquals(\Utopia\Validator::TYPE_FLOAT, $range->getType(), \Utopia\Validator::TYPE_FLOAT);
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_FLOAT, $range->getFormat());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_FLOAT, $range->getType(), \Utopia\Http\Validator::TYPE_FLOAT);
}
public function canValidateInfinityRange()
{
- $integer = new Range(5, INF, \Utopia\Validator::TYPE_INTEGER);
- $float = new Range(-INF, 45.6, \Utopia\Validator::TYPE_FLOAT);
+ $integer = new Range(5, INF, \Utopia\Http\Validator::TYPE_INTEGER);
+ $float = new Range(-INF, 45.6, \Utopia\Http\Validator::TYPE_FLOAT);
$this->assertTrue($integer->isValid(25));
$this->assertFalse($integer->isValid(3));
diff --git a/tests/Validator/TextTest.php b/tests/Validator/TextTest.php
index cb987043..476cfd8a 100755
--- a/tests/Validator/TextTest.php
+++ b/tests/Validator/TextTest.php
@@ -1,6 +1,6 @@
assertFalse($validator->isValid(['seven', 8, 9.0]));
$this->assertFalse($validator->isValid(false));
$this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_STRING, $validator->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $validator->getType());
}
public function testCanValidateBoundaries(): void
diff --git a/tests/Validator/URLTest.php b/tests/Validator/URLTest.php
index e7bad1b5..f092890f 100644
--- a/tests/Validator/URLTest.php
+++ b/tests/Validator/URLTest.php
@@ -11,7 +11,7 @@
* @license The MIT License (MIT)
*/
-namespace Utopia\Validator;
+namespace Utopia\Http\Validator;
use PHPUnit\Framework\TestCase;
diff --git a/tests/Validator/WhiteListTest.php b/tests/Validator/WhiteListTest.php
index 9d88f75e..f024908c 100755
--- a/tests/Validator/WhiteListTest.php
+++ b/tests/Validator/WhiteListTest.php
@@ -1,6 +1,6 @@
assertFalse($whiteList->isValid(5));
$this->assertFalse($whiteList->isArray());
$this->assertEquals($whiteList->getList(), ['string1', 'string2', 3, 4]);
- $this->assertEquals(\Utopia\Validator::TYPE_STRING, $whiteList->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $whiteList->getType());
}
public function testCanValidateLoosely(): void
diff --git a/tests/Validator/WildcardTest.php b/tests/Validator/WildcardTest.php
index b79c3580..4de71475 100644
--- a/tests/Validator/WildcardTest.php
+++ b/tests/Validator/WildcardTest.php
@@ -1,6 +1,6 @@
assertTrue($validator->isValid(true));
$this->assertTrue($validator->isValid(false));
$this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Validator::TYPE_STRING, $validator->getType());
+ $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $validator->getType());
}
}
diff --git a/tests/ViewTest.php b/tests/ViewTest.php
index 9b18fb1e..6f4bcc6f 100755
--- a/tests/ViewTest.php
+++ b/tests/ViewTest.php
@@ -1,6 +1,6 @@
view->setParam('key', 'value');
- $this->assertInstanceOf('Utopia\View', $value);
+ $this->assertInstanceOf('Utopia\Http\View', $value);
}
public function testCanGetParam()
@@ -37,7 +37,7 @@ public function testCanSetPath()
{
$value = $this->view->setPath('mocks/View/fake.phtml');
- $this->assertInstanceOf('Utopia\View', $value);
+ $this->assertInstanceOf('Utopia\Http\View', $value);
}
public function testCanSetRendered()
diff --git a/tests/e2e/BaseTest.php b/tests/e2e/BaseTest.php
index 81fcde4c..3fbdef51 100644
--- a/tests/e2e/BaseTest.php
+++ b/tests/e2e/BaseTest.php
@@ -1,6 +1,6 @@
Date: Wed, 12 Jul 2023 06:54:47 +0000
Subject: [PATCH 029/119] static file handling
---
src/Http/Adapter.php | 58 -------------------------
src/Http/Adapter/FPM/Server.php | 4 +-
src/Http/Adapter/Swoole/Server.php | 1 -
src/Http/Http.php | 69 ++++++++++++++++++++++++++++++
4 files changed, 70 insertions(+), 62 deletions(-)
diff --git a/src/Http/Adapter.php b/src/Http/Adapter.php
index 63c13f65..bdfd2b43 100644
--- a/src/Http/Adapter.php
+++ b/src/Http/Adapter.php
@@ -4,64 +4,6 @@
abstract class Adapter
{
- protected Files $files;
-
- public function __construct()
- {
- $this->files = new Files();
- }
-
abstract public function onRequest(callable $callback);
abstract public function start();
-
- /**
- * Load directory.
- *
- * @param string $directory
- * @param string|null $root
- * @return void
- *
- * @throws \Exception
- */
- public function loadFiles(string $directory, string $root = null): void
- {
- $this->files->load($directory, $root);
- }
-
- /**
- * Is file loaded.
- *
- * @param string $uri
- * @return bool
- */
- public function isFileLoaded(string $uri): bool
- {
- return $this->files->isFileLoaded($uri);
- }
-
- /**
- * Get file contents.
- *
- * @param string $uri
- * @return string
- *
- * @throws \Exception
- */
- public function getFileContents(string $uri): mixed
- {
- return $this->files->getFileContents($uri);
- }
-
- /**
- * Get file MIME type.
- *
- * @param string $uri
- * @return string
- *
- * @throws \Exception
- */
- public function getFileMimeType(string $uri): mixed
- {
- return $this->files->getFileMimeType($uri);
- }
}
diff --git a/src/Http/Adapter/FPM/Server.php b/src/Http/Adapter/FPM/Server.php
index 7442caf2..ccfc3e9b 100644
--- a/src/Http/Adapter/FPM/Server.php
+++ b/src/Http/Adapter/FPM/Server.php
@@ -7,9 +7,7 @@
class Server extends Adapter
{
public function __construct()
- {
- parent::__construct();
- }
+ {}
public function onRequest(callable $callback)
{
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index de97b2aa..b14659bd 100644
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -13,7 +13,6 @@ class Server extends Adapter
public function __construct(string $host, string $port = null)
{
- parent::__construct();
$this->server = new SwooleServer($host, $port);
}
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 097e9c65..9b0dcbbc 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -37,6 +37,11 @@ class Http
'error' => null,
];
+ /**
+ * @var Files
+ */
+ protected Files $files;
+
/**
* @var array
*/
@@ -116,6 +121,7 @@ class Http
public function __construct(Adapter $server, string $timezone)
{
\date_default_timezone_set($timezone);
+ $this->files = new Files();
$this->server = $server;
}
@@ -453,6 +459,57 @@ public static function addRoute(string $method, string $url): Route
return $route;
}
+ /**
+ * Load directory.
+ *
+ * @param string $directory
+ * @param string|null $root
+ * @return void
+ *
+ * @throws \Exception
+ */
+ public function loadFiles(string $directory, string $root = null): void
+ {
+ $this->files->load($directory, $root);
+ }
+
+ /**
+ * Is file loaded.
+ *
+ * @param string $uri
+ * @return bool
+ */
+ protected function isFileLoaded(string $uri): bool
+ {
+ return $this->files->isFileLoaded($uri);
+ }
+
+ /**
+ * Get file contents.
+ *
+ * @param string $uri
+ * @return string
+ *
+ * @throws \Exception
+ */
+ protected function getFileContents(string $uri): mixed
+ {
+ return $this->files->getFileContents($uri);
+ }
+
+ /**
+ * Get file MIME type.
+ *
+ * @param string $uri
+ * @return string
+ *
+ * @throws \Exception
+ */
+ protected function getFileMimeType(string $uri): mixed
+ {
+ return $this->files->getFileMimeType($uri);
+ }
+
public function start()
{
$this->server->onRequest(fn ($request, $response) => $this->run($request, $response));
@@ -620,6 +677,18 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
*/
public function run(Request $request, Response $response): static
{
+ if($this->isFileLoaded($request->getURI())) {
+ $time = (60 * 60 * 24 * 365 * 2); // 45 days cache
+
+ $response
+ ->setContentType($this->getFileMimeType($request->getURI()))
+ ->addHeader('Cache-Control', 'public, max-age=' . $time)
+ ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time) . ' GMT') // 45 days cache
+ ->send($this->getFileContents($request->getURI()));
+
+ return $this;
+ }
+
$this->resources['request'] = $request;
$this->resources['response'] = $response;
From 97f9320dc35a2577d585b2cc1e05b79628b647cc Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 12 Jul 2023 06:55:45 +0000
Subject: [PATCH 030/119] fix formatting
---
composer.json | 2 +-
src/Http/Adapter/FPM/Server.php | 3 ++-
src/Http/Http.php | 2 +-
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/composer.json b/composer.json
index 1c9edc09..043758fa 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,7 @@
"minimum-stability": "stable",
"autoload": {
"psr-4": {
- "Utopia\\Http": "src/Http"
+ "Utopia\\Http\\": "src/Http"
}
},
"scripts": {
diff --git a/src/Http/Adapter/FPM/Server.php b/src/Http/Adapter/FPM/Server.php
index ccfc3e9b..75ce2f64 100644
--- a/src/Http/Adapter/FPM/Server.php
+++ b/src/Http/Adapter/FPM/Server.php
@@ -7,7 +7,8 @@
class Server extends Adapter
{
public function __construct()
- {}
+ {
+ }
public function onRequest(callable $callback)
{
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 9b0dcbbc..c266d695 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -677,7 +677,7 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
*/
public function run(Request $request, Response $response): static
{
- if($this->isFileLoaded($request->getURI())) {
+ if ($this->isFileLoaded($request->getURI())) {
$time = (60 * 60 * 24 * 365 * 2); // 45 days cache
$response
From dc967650982de758e372ce543ee8f697165d4a64 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Thu, 13 Jul 2023 01:48:23 +0000
Subject: [PATCH 031/119] upate php version for test - dev dependencies now
require 8.1
---
.github/workflows/bench.yml | 2 +-
.github/workflows/lint.yml | 2 +-
.github/workflows/test.yml | 2 +-
composer.lock | 36 ++++++++++++++++++------------------
4 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml
index 4cecb0e0..7aee0312 100644
--- a/.github/workflows/bench.yml
+++ b/.github/workflows/bench.yml
@@ -13,7 +13,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
- php-version: '8.0'
+ php-version: '8.1'
- name: Install dependencies
run: composer install --prefer-dist --ignore-platform-reqs
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index e976a4f1..9b30f651 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -13,7 +13,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
- php-version: '8.0'
+ php-version: '8.1'
- name: Install dependencies
run: composer install --prefer-dist --ignore-platform-reqs
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4ce331e1..96667e1e 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -13,7 +13,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
- php-version: '8.0'
+ php-version: '8.1'
- name: Setup Docker
run: docker-compose up -d --build
diff --git a/composer.lock b/composer.lock
index 54b588dd..093012ef 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "d3095212dd091713ce6091c108534af9",
+ "content-hash": "f27d5bb02390ce6b9a8268d4fffb1e87",
"packages": [],
"packages-dev": [
{
@@ -232,16 +232,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.5.0",
+ "version": "v1.10.4",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "e0a8cef58b74662f27355be9cdea0e726bbac362"
+ "reference": "f56798088068af8bd75a8f2c4ecae022990fdf75"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/e0a8cef58b74662f27355be9cdea0e726bbac362",
- "reference": "e0a8cef58b74662f27355be9cdea0e726bbac362",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/f56798088068af8bd75a8f2c4ecae022990fdf75",
+ "reference": "f56798088068af8bd75a8f2c4ecae022990fdf75",
"shasum": ""
},
"require": {
@@ -249,16 +249,16 @@
"ext-mbstring": "*",
"ext-tokenizer": "*",
"ext-xml": "*",
- "php": "^8.0"
+ "php": "^8.1.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.14.4",
- "illuminate/view": "^9.51.0",
- "laravel-zero/framework": "^9.2.0",
+ "friendsofphp/php-cs-fixer": "^3.21.1",
+ "illuminate/view": "^10.5.1",
+ "laravel-zero/framework": "^10.0.2",
"mockery/mockery": "^1.5.1",
- "nunomaduro/larastan": "^2.4.0",
+ "nunomaduro/larastan": "^2.5.1",
"nunomaduro/termwind": "^1.15.1",
- "pestphp/pest": "^1.22.4"
+ "pestphp/pest": "^2.4.0"
},
"bin": [
"builds/pint"
@@ -294,7 +294,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2023-02-14T16:31:02+00:00"
+ "time": "2023-07-11T15:18:27+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -626,16 +626,16 @@
},
{
"name": "phpbench/phpbench",
- "version": "1.2.10",
+ "version": "1.2.14",
"source": {
"type": "git",
"url": "https://github.com/phpbench/phpbench.git",
- "reference": "95206f92479674599a75e02b74b9933e2d9883aa"
+ "reference": "edbd1b7ecf704eb01f7a2bcd1b8aa8c189f9fa4e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpbench/phpbench/zipball/95206f92479674599a75e02b74b9933e2d9883aa",
- "reference": "95206f92479674599a75e02b74b9933e2d9883aa",
+ "url": "https://api.github.com/repos/phpbench/phpbench/zipball/edbd1b7ecf704eb01f7a2bcd1b8aa8c189f9fa4e",
+ "reference": "edbd1b7ecf704eb01f7a2bcd1b8aa8c189f9fa4e",
"shasum": ""
},
"require": {
@@ -704,7 +704,7 @@
"description": "PHP Benchmarking Framework",
"support": {
"issues": "https://github.com/phpbench/phpbench/issues",
- "source": "https://github.com/phpbench/phpbench/tree/1.2.10"
+ "source": "https://github.com/phpbench/phpbench/tree/1.2.14"
},
"funding": [
{
@@ -712,7 +712,7 @@
"type": "github"
}
],
- "time": "2023-03-24T08:52:55+00:00"
+ "time": "2023-07-09T09:16:08+00:00"
},
{
"name": "phpstan/phpstan",
From 73d8f0b13a9b4721d1012af518a9cc054f29142c Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Thu, 13 Jul 2023 07:32:22 +0000
Subject: [PATCH 032/119] more server related callbacks
---
src/Http/Adapter.php | 2 ++
src/Http/Adapter/FPM/Server.php | 10 ++++++++++
src/Http/Http.php | 22 ++++++++++++++++++++++
3 files changed, 34 insertions(+)
diff --git a/src/Http/Adapter.php b/src/Http/Adapter.php
index bdfd2b43..c05f98f5 100644
--- a/src/Http/Adapter.php
+++ b/src/Http/Adapter.php
@@ -4,6 +4,8 @@
abstract class Adapter
{
+ abstract public function onStart(callable $callback);
+ abstract public function onWorkerStart(callable $callback);
abstract public function onRequest(callable $callback);
abstract public function start();
}
diff --git a/src/Http/Adapter/FPM/Server.php b/src/Http/Adapter/FPM/Server.php
index 75ce2f64..84e92289 100644
--- a/src/Http/Adapter/FPM/Server.php
+++ b/src/Http/Adapter/FPM/Server.php
@@ -15,6 +15,16 @@ public function onRequest(callable $callback)
call_user_func($callback, new Request(), new Response());
}
+ public function onStart(callable $callback)
+ {
+ call_user_func($callback, $this);
+ }
+
+ public function onWorkerStart(callable $callback)
+ {
+ return;
+ }
+
public function start()
{
return;
diff --git a/src/Http/Http.php b/src/Http/Http.php
index c266d695..49a8b45c 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -510,6 +510,28 @@ protected function getFileMimeType(string $uri): mixed
return $this->files->getFileMimeType($uri);
}
+ /**
+ * On worker start callback
+ *
+ * @param callable $callback
+ * @return void
+ */
+ public function onWorkerStart(callable $callback)
+ {
+ $this->server->onWorkerStart($callback);
+ }
+
+ /**
+ * On server start callback
+ *
+ * @param callable $callback
+ * @return void
+ */
+ public function onStart(callable $callback)
+ {
+ $this->server->onStart($callback);
+ }
+
public function start()
{
$this->server->onRequest(fn ($request, $response) => $this->run($request, $response));
From a912fab7a031bcedc4fdfc996a993624ca8dfebd Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Thu, 13 Jul 2023 08:24:05 +0000
Subject: [PATCH 033/119] start hook
---
src/Http/Http.php | 45 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 37 insertions(+), 8 deletions(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 49a8b45c..b79b9231 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -90,6 +90,13 @@ class Http
*/
protected static array $options = [];
+ /**
+ * Server Start hooks
+ *
+ * @var Hook[]
+ */
+ protected static array $startHooks = [];
+
/**
* Route
*
@@ -521,20 +528,42 @@ public function onWorkerStart(callable $callback)
$this->server->onWorkerStart($callback);
}
- /**
- * On server start callback
- *
- * @param callable $callback
- * @return void
- */
- public function onStart(callable $callback)
+
+ public static function onStart(): Hook
{
- $this->server->onStart($callback);
+ $hook = new Hook();
+ self::$startHooks[] = $hook;
+ return $hook;
}
public function start()
{
$this->server->onRequest(fn ($request, $response) => $this->run($request, $response));
+ $this->server->onStart(function ($server) {
+ $this->resources['server'] = $server;
+
+ try {
+
+ foreach (self::$startHooks as $hook) {
+ $arguments = $this->getArguments($hook, [], []);
+ \call_user_func_array($hook->getAction(), $arguments);
+ }
+ } catch(\Exception $e) {
+ self::setResource('error', fn () => $e);
+
+ foreach (self::$errors as $error) { // Global error hooks
+ if (in_array('*', $error->getGroups())) {
+ try {
+ $arguments = $this->getArguments($error, [], []);
+ \call_user_func_array($error->getAction(), $arguments);
+ } catch (\Throwable $e) {
+ throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
+ }
+ }
+ }
+ }
+ });
+
$this->server->start();
}
From ab4544aeecec6c931f4ffd464c1a77e1cae2d083 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Thu, 13 Jul 2023 08:29:03 +0000
Subject: [PATCH 034/119] worker start hooks
---
src/Http/Http.php | 46 +++++++++++++++++++++++++++++++++++++---------
1 file changed, 37 insertions(+), 9 deletions(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index b79b9231..2f7de5d3 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -97,6 +97,13 @@ class Http
*/
protected static array $startHooks = [];
+ /**
+ * Worker Start hooks
+ *
+ * @var Hook[]
+ */
+ protected static array $workerStartHooks = [];
+
/**
* Route
*
@@ -517,18 +524,13 @@ protected function getFileMimeType(string $uri): mixed
return $this->files->getFileMimeType($uri);
}
- /**
- * On worker start callback
- *
- * @param callable $callback
- * @return void
- */
- public function onWorkerStart(callable $callback)
+ public static function onWorkerStart(): Hook
{
- $this->server->onWorkerStart($callback);
+ $hook = new Hook();
+ self::$workerStartHooks[] = $hook;
+ return $hook;
}
-
public static function onStart(): Hook
{
$hook = new Hook();
@@ -564,6 +566,32 @@ public function start()
}
});
+ $this->server->onWorkerStart(function ($server, $workerId) {
+ $this->resources['server'] = $server;
+ $this->resources['workerId'] = $workerId;
+
+ try {
+
+ foreach (self::$workerStartHooks as $hook) {
+ $arguments = $this->getArguments($hook, [], []);
+ \call_user_func_array($hook->getAction(), $arguments);
+ }
+ } catch(\Exception $e) {
+ self::setResource('error', fn () => $e);
+
+ foreach (self::$errors as $error) { // Global error hooks
+ if (in_array('*', $error->getGroups())) {
+ try {
+ $arguments = $this->getArguments($error, [], []);
+ \call_user_func_array($error->getAction(), $arguments);
+ } catch (\Throwable $e) {
+ throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
+ }
+ }
+ }
+ }
+ });
+
$this->server->start();
}
From db4ae13e3da8466117983e1b116eba97182312b0 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Thu, 13 Jul 2023 08:36:49 +0000
Subject: [PATCH 035/119] fix setting resource
---
src/Http/Http.php | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 2f7de5d3..a009d71a 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -543,7 +543,9 @@ public function start()
$this->server->onRequest(fn ($request, $response) => $this->run($request, $response));
$this->server->onStart(function ($server) {
$this->resources['server'] = $server;
-
+ self::setResource('server', function () use ($server) {
+ return $server;
+ });
try {
foreach (self::$startHooks as $hook) {
@@ -570,6 +572,13 @@ public function start()
$this->resources['server'] = $server;
$this->resources['workerId'] = $workerId;
+ self::setResource('server', function () use ($server) {
+ return $server;
+ });
+ self::setResource('workerId', function () use ($workerId) {
+ return $workerId;
+ });
+
try {
foreach (self::$workerStartHooks as $hook) {
From 4eb05830afaf20e8a3a597945a91e34cd09d6cfb Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 16 Jul 2023 09:07:01 +0000
Subject: [PATCH 036/119] fix reset
---
src/Http/Http.php | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index a009d71a..5c03243b 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -891,5 +891,7 @@ public static function reset(): void
self::$init = [];
self::$shutdown = [];
self::$options = [];
+ self::$workerStartHooks = [];
+ self::$startHooks = [];
}
}
From 5a6d1711f053190e61b8e8719853ef379bef59b8 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 18 Jul 2023 07:36:40 +0545
Subject: [PATCH 037/119] swoole beforeShutdown callback
---
src/Http/Adapter/Swoole/Server.php | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index b14659bd..95afa0e6 100644
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -43,6 +43,11 @@ public function onAfterReload(callable $callback)
$this->server->on('AfterReload', $callback);
}
+ public function onBeforeShutdown(callable $callback)
+ {
+ $this->server->on('beforeShutdown', $callback);
+ }
+
public function onStart(callable $callback)
{
$this->server->on('start', $callback);
From 22bd6d6566b457172fb55ede59d485e2f4600e2c Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 18 Jul 2023 02:39:39 +0000
Subject: [PATCH 038/119] support request hooks
---
src/Http/Http.php | 57 ++++++++++++++++++++++++++++++++++++++---------
1 file changed, 46 insertions(+), 11 deletions(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 5c03243b..6df78813 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -104,6 +104,13 @@ class Http
*/
protected static array $workerStartHooks = [];
+ /**
+ * Request hooks
+ *
+ * @var Hook[]
+ */
+ protected static array $requestHooks = [];
+
/**
* Route
*
@@ -538,6 +545,13 @@ public static function onStart(): Hook
return $hook;
}
+ public static function onRequest(): Hook
+ {
+ $hook = new Hook();
+ self::$requestHooks[] = $hook;
+ return $hook;
+ }
+
public function start()
{
$this->server->onRequest(fn ($request, $response) => $this->run($request, $response));
@@ -765,6 +779,38 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
*/
public function run(Request $request, Response $response): static
{
+ $this->resources['request'] = $request;
+ $this->resources['response'] = $response;
+
+ self::setResource('request', function () use ($request) {
+ return $request;
+ });
+
+ self::setResource('response', function () use ($response) {
+ return $response;
+ });
+
+ try {
+
+ foreach (self::$requestHooks as $hook) {
+ $arguments = $this->getArguments($hook, [], []);
+ \call_user_func_array($hook->getAction(), $arguments);
+ }
+ } catch(\Exception $e) {
+ self::setResource('error', fn () => $e);
+
+ foreach (self::$errors as $error) { // Global error hooks
+ if (in_array('*', $error->getGroups())) {
+ try {
+ $arguments = $this->getArguments($error, [], []);
+ \call_user_func_array($error->getAction(), $arguments);
+ } catch (\Throwable $e) {
+ throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
+ }
+ }
+ }
+ }
+
if ($this->isFileLoaded($request->getURI())) {
$time = (60 * 60 * 24 * 365 * 2); // 45 days cache
@@ -777,17 +823,6 @@ public function run(Request $request, Response $response): static
return $this;
}
- $this->resources['request'] = $request;
- $this->resources['response'] = $response;
-
- self::setResource('request', function () use ($request) {
- return $request;
- });
-
- self::setResource('response', function () use ($response) {
- return $response;
- });
-
$method = $request->getMethod();
$route = $this->match($request);
$groups = ($route instanceof Route) ? $route->getGroups() : [];
From f5a483a1dfe2061d8b7ccac0561b180ded944d0b Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 18 Jul 2023 12:11:26 +0545
Subject: [PATCH 039/119] add getter for swoole internal request
---
src/Http/Adapter/Swoole/Request.php | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/Http/Adapter/Swoole/Request.php b/src/Http/Adapter/Swoole/Request.php
index 9e319657..8a717730 100644
--- a/src/Http/Adapter/Swoole/Request.php
+++ b/src/Http/Adapter/Swoole/Request.php
@@ -301,6 +301,11 @@ public function removeHeader(string $key): static
return $this;
}
+ public function getSwooleRequest(): SwooleRequest
+ {
+ return $this->swoole;
+ }
+
/**
* Generate input
*
From 0e67327c92fd2db70771f9b7c65f8ecc508ccfdd Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 18 Jul 2023 12:14:40 +0545
Subject: [PATCH 040/119] getter for swoole response
---
src/Http/Adapter/Swoole/Response.php | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/Http/Adapter/Swoole/Response.php b/src/Http/Adapter/Swoole/Response.php
index 12b61027..d4ecdf91 100644
--- a/src/Http/Adapter/Swoole/Response.php
+++ b/src/Http/Adapter/Swoole/Response.php
@@ -23,6 +23,11 @@ public function __construct(SwooleResponse $response)
parent::__construct(\microtime(true));
}
+ public function getSwooleResponse(): SwooleResponse
+ {
+ return $this->swoole;
+ }
+
/**
* Write
*
From 552bccd2c576edd5f6ee9951ce484e3d3b26d490 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Thu, 20 Jul 2023 01:25:26 +0000
Subject: [PATCH 041/119] get fresh resource each time by default
---
src/Http/Http.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 6df78813..44cb56da 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -341,7 +341,7 @@ public static function setMode(string $value): void
*
* @throws Exception
*/
- public function getResource(string $name, bool $fresh = false): mixed
+ public function getResource(string $name, bool $fresh = true): mixed
{
if ($name === 'utopia') {
return $this;
From 50d4cd5c7fe97b3d653850b4b614614098734781 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 6 Aug 2023 00:43:20 +0000
Subject: [PATCH 042/119] enable context
---
src/Http/Adapter/FPM/Server.php | 2 +-
src/Http/Adapter/Swoole/Server.php | 7 ++-
src/Http/Http.php | 77 ++++++++++++++++--------------
3 files changed, 48 insertions(+), 38 deletions(-)
diff --git a/src/Http/Adapter/FPM/Server.php b/src/Http/Adapter/FPM/Server.php
index 84e92289..b8dd0f68 100644
--- a/src/Http/Adapter/FPM/Server.php
+++ b/src/Http/Adapter/FPM/Server.php
@@ -12,7 +12,7 @@ public function __construct()
public function onRequest(callable $callback)
{
- call_user_func($callback, new Request(), new Response());
+ call_user_func($callback, new Request(), new Response(), 100);
}
public function onStart(callable $callback)
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index 95afa0e6..19d48fb2 100644
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -2,6 +2,8 @@
namespace Utopia\Http\Adapter\Swoole;
+use Swoole\Constant;
+use Swoole\Coroutine;
use Utopia\Http\Adapter;
use Swoole\Http\Server as SwooleServer;
use Swoole\Http\Request as SwooleRequest;
@@ -18,13 +20,16 @@ public function __construct(string $host, string $port = null)
public function setConfig(array $configs)
{
+ $configs = array_merge($configs, [
+ Constant::OPTION_ENABLE_COROUTINE => true
+ ]);
$this->server->set($configs);
}
public function onRequest(callable $callback)
{
$this->server->on('request', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
- call_user_func($callback, new Request($request), new Response($response));
+ call_user_func($callback, new Request($request), new Response($response), Coroutine::getCid());
});
}
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 44cb56da..cd2237ca 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -341,26 +341,27 @@ public static function setMode(string $value): void
*
* @throws Exception
*/
- public function getResource(string $name, bool $fresh = true): mixed
+ public function getResource(string $name, int $context, bool $fresh = true): mixed
{
if ($name === 'utopia') {
return $this;
}
- if (!\array_key_exists($name, $this->resources) || $fresh || self::$resourcesCallbacks[$name]['reset']) {
+ if (!\array_key_exists($name, $this->resources[$context]) || $fresh || self::$resourcesCallbacks[$name]['reset']) {
if (!\array_key_exists($name, self::$resourcesCallbacks)) {
throw new Exception('Failed to find resource: "' . $name . '"');
}
- $this->resources[$name] = \call_user_func_array(
+ if(!\array_key_exists($context, $this->resources));
+ $this->resources[$context][$name] = \call_user_func_array(
self::$resourcesCallbacks[$name]['callback'],
- $this->getResources(self::$resourcesCallbacks[$name]['injections'])
+ $this->getResources(self::$resourcesCallbacks[$name]['injections'], $context)
);
}
self::$resourcesCallbacks[$name]['reset'] = false;
- return $this->resources[$name];
+ return $this->resources[$context][$name];
}
/**
@@ -369,12 +370,12 @@ public function getResource(string $name, bool $fresh = true): mixed
* @param array $list
* @return array
*/
- public function getResources(array $list): array
+ public function getResources(array $list, int $context): array
{
- $resources = [];
+ $resources[$context] = [];
foreach ($list as $name) {
- $resources[$name] = $this->getResource($name);
+ $resources[$name] = $this->getResource($name, $context);
}
return $resources;
@@ -554,7 +555,7 @@ public static function onRequest(): Hook
public function start()
{
- $this->server->onRequest(fn ($request, $response) => $this->run($request, $response));
+ $this->server->onRequest(fn ($request, $response, $context) => $this->run($request, $response, $context));
$this->server->onStart(function ($server) {
$this->resources['server'] = $server;
self::setResource('server', function () use ($server) {
@@ -563,7 +564,7 @@ public function start()
try {
foreach (self::$startHooks as $hook) {
- $arguments = $this->getArguments($hook, [], []);
+ $arguments = $this->getArguments($hook, 0, [], []);
\call_user_func_array($hook->getAction(), $arguments);
}
} catch(\Exception $e) {
@@ -572,7 +573,7 @@ public function start()
foreach (self::$errors as $error) { // Global error hooks
if (in_array('*', $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, [], []);
+ $arguments = $this->getArguments($error, 0, [], []);
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
@@ -596,7 +597,7 @@ public function start()
try {
foreach (self::$workerStartHooks as $hook) {
- $arguments = $this->getArguments($hook, [], []);
+ $arguments = $this->getArguments($hook, 0, [], []);
\call_user_func_array($hook->getAction(), $arguments);
}
} catch(\Exception $e) {
@@ -605,7 +606,7 @@ public function start()
foreach (self::$errors as $error) { // Global error hooks
if (in_array('*', $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, [], []);
+ $arguments = $this->getArguments($error, 0, [], []);
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
@@ -648,7 +649,7 @@ public function match(Request $request, bool $fresh = true): ?Route
* @param Route $route
* @param Request $request
*/
- public function execute(Route $route, Request $request): static
+ public function execute(Route $route, Request $request, int $context): static
{
$arguments = [];
$groups = $route->getGroups();
@@ -658,7 +659,7 @@ public function execute(Route $route, Request $request): static
if ($route->getHook()) {
foreach (self::$init as $hook) { // Global init hooks
if (in_array('*', $hook->getGroups())) {
- $arguments = $this->getArguments($hook, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($hook, $context, $pathValues, $request->getParams());
\call_user_func_array($hook->getAction(), $arguments);
}
}
@@ -667,13 +668,13 @@ public function execute(Route $route, Request $request): static
foreach ($groups as $group) {
foreach (self::$init as $hook) { // Group init hooks
if (in_array($group, $hook->getGroups())) {
- $arguments = $this->getArguments($hook, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($hook, $context, $pathValues, $request->getParams());
\call_user_func_array($hook->getAction(), $arguments);
}
}
}
- $arguments = $this->getArguments($route, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($route, $context, $pathValues, $request->getParams());
// Call the action callback with the matched positions as params
\call_user_func_array($route->getAction(), $arguments);
@@ -681,7 +682,7 @@ public function execute(Route $route, Request $request): static
foreach ($groups as $group) {
foreach (self::$shutdown as $hook) { // Group shutdown hooks
if (in_array($group, $hook->getGroups())) {
- $arguments = $this->getArguments($hook, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($hook, $context, $pathValues, $request->getParams());
\call_user_func_array($hook->getAction(), $arguments);
}
}
@@ -690,7 +691,7 @@ public function execute(Route $route, Request $request): static
if ($route->getHook()) {
foreach (self::$shutdown as $hook) { // Group shutdown hooks
if (in_array('*', $hook->getGroups())) {
- $arguments = $this->getArguments($hook, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($hook, $context, $pathValues, $request->getParams());
\call_user_func_array($hook->getAction(), $arguments);
}
}
@@ -702,7 +703,7 @@ public function execute(Route $route, Request $request): static
foreach (self::$errors as $error) { // Group error hooks
if (in_array($group, $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($error, $context, $pathValues, $request->getParams());
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
@@ -714,7 +715,7 @@ public function execute(Route $route, Request $request): static
foreach (self::$errors as $error) { // Global error hooks
if (in_array('*', $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($error, $context, $pathValues, $request->getParams());
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
@@ -723,6 +724,9 @@ public function execute(Route $route, Request $request): static
}
}
+ // Reset resources for the context
+ $this->resources[$context] = [];
+
return $this;
}
@@ -736,7 +740,7 @@ public function execute(Route $route, Request $request): static
*
* @throws Exception
*/
- protected function getArguments(Hook $hook, array $values, array $requestParams): array
+ protected function getArguments(Hook $hook, int $context, array $values, array $requestParams): array
{
$arguments = [];
foreach ($hook->getParams() as $key => $param) { // Get value from route or request object
@@ -753,7 +757,7 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
}
if ($paramExists) {
- $this->validate($key, $param, $value);
+ $this->validate($key, $param, $value, $context);
}
}
@@ -762,7 +766,7 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
}
foreach ($hook->getInjections() as $key => $injection) {
- $arguments[$injection['order']] = $this->getResource($injection['name']);
+ $arguments[$injection['order']] = $this->getResource($injection['name'], $context);
}
return $arguments;
@@ -777,10 +781,11 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
* @param Request $request
* @param Response $response;
*/
- public function run(Request $request, Response $response): static
+ public function run(Request $request, Response $response, int $context): static
{
- $this->resources['request'] = $request;
- $this->resources['response'] = $response;
+ $this->resources[$context] = [];
+ $this->resources[$context]['request'] = $request;
+ $this->resources[$context]['response'] = $response;
self::setResource('request', function () use ($request) {
return $request;
@@ -793,7 +798,7 @@ public function run(Request $request, Response $response): static
try {
foreach (self::$requestHooks as $hook) {
- $arguments = $this->getArguments($hook, [], []);
+ $arguments = $this->getArguments($hook, $context, [], []);
\call_user_func_array($hook->getAction(), $arguments);
}
} catch(\Exception $e) {
@@ -802,7 +807,7 @@ public function run(Request $request, Response $response): static
foreach (self::$errors as $error) { // Global error hooks
if (in_array('*', $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, [], []);
+ $arguments = $this->getArguments($error, $context, [], []);
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
@@ -839,20 +844,20 @@ public function run(Request $request, Response $response): static
}
if (null !== $route) {
- return $this->execute($route, $request);
+ return $this->execute($route, $request, $context);
} elseif (self::REQUEST_METHOD_OPTIONS == $method) {
try {
foreach ($groups as $group) {
foreach (self::$options as $option) { // Group options hooks
if (in_array($group, $option->getGroups())) {
- \call_user_func_array($option->getAction(), $this->getArguments($option, [], $request->getParams()));
+ \call_user_func_array($option->getAction(), $this->getArguments($option, $context, [], $request->getParams()));
}
}
}
foreach (self::$options as $option) { // Global options hooks
if (in_array('*', $option->getGroups())) {
- \call_user_func_array($option->getAction(), $this->getArguments($option, [], $request->getParams()));
+ \call_user_func_array($option->getAction(), $this->getArguments($option, $context, [], $request->getParams()));
}
}
} catch (\Throwable $e) {
@@ -861,7 +866,7 @@ public function run(Request $request, Response $response): static
self::setResource('error', function () use ($e) {
return $e;
});
- \call_user_func_array($error->getAction(), $this->getArguments($error, [], $request->getParams()));
+ \call_user_func_array($error->getAction(), $this->getArguments($error, $context, [], $request->getParams()));
}
}
}
@@ -871,7 +876,7 @@ public function run(Request $request, Response $response): static
self::setResource('error', function () {
return new Exception('Not Found', 404);
});
- \call_user_func_array($error->getAction(), $this->getArguments($error, [], $request->getParams()));
+ \call_user_func_array($error->getAction(), $this->getArguments($error, $context, [], $request->getParams()));
}
}
}
@@ -891,7 +896,7 @@ public function run(Request $request, Response $response): static
*
* @throws Exception
*/
- protected function validate(string $key, array $param, mixed $value): void
+ protected function validate(string $key, array $param, mixed $value, $context): void
{
if ($param['optional'] && \is_null($value)) {
return;
@@ -900,7 +905,7 @@ protected function validate(string $key, array $param, mixed $value): void
$validator = $param['validator']; // checking whether the class exists
if (\is_callable($validator)) {
- $validator = \call_user_func_array($validator, $this->getResources($param['injections']));
+ $validator = \call_user_func_array($validator, $this->getResources($param['injections'], $context));
}
if (!$validator instanceof Validator) { // is the validator object an instance of the Validator class
From c0b5d733a6dce30b715516b901225afd59a3198e Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 6 Aug 2023 00:43:58 +0000
Subject: [PATCH 043/119] fresh is now false by default
---
src/Http/Http.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index cd2237ca..5016a59f 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -341,7 +341,7 @@ public static function setMode(string $value): void
*
* @throws Exception
*/
- public function getResource(string $name, int $context, bool $fresh = true): mixed
+ public function getResource(string $name, int $context, bool $fresh = false): mixed
{
if ($name === 'utopia') {
return $this;
From 33698fc8aeb8f767c935ca14fe09255c15321a48 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 6 Aug 2023 00:50:40 +0000
Subject: [PATCH 044/119] fix resource for context null
---
src/Http/Http.php | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 5016a59f..4b7688e5 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -347,6 +347,10 @@ public function getResource(string $name, int $context, bool $fresh = false): mi
return $this;
}
+ if(!\array_key_exists($context, $this->resources)) {
+ $this->resources[$context] = [];
+ }
+
if (!\array_key_exists($name, $this->resources[$context]) || $fresh || self::$resourcesCallbacks[$name]['reset']) {
if (!\array_key_exists($name, self::$resourcesCallbacks)) {
throw new Exception('Failed to find resource: "' . $name . '"');
From cd3c30a9719f868b80f8ebb4affc933886abe136 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 6 Aug 2023 01:11:12 +0000
Subject: [PATCH 045/119] unused code
---
src/Http/Http.php | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 4b7688e5..285762fd 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -356,7 +356,6 @@ public function getResource(string $name, int $context, bool $fresh = false): mi
throw new Exception('Failed to find resource: "' . $name . '"');
}
- if(!\array_key_exists($context, $this->resources));
$this->resources[$context][$name] = \call_user_func_array(
self::$resourcesCallbacks[$name]['callback'],
$this->getResources(self::$resourcesCallbacks[$name]['injections'], $context)
@@ -761,7 +760,7 @@ protected function getArguments(Hook $hook, int $context, array $values, array $
}
if ($paramExists) {
- $this->validate($key, $param, $value, $context);
+ // $this->validate($key, $param, $value, $context);
}
}
From 0e4281d82de70d9c4e64a67c846b2516d263fbb7 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 6 Aug 2023 02:08:48 +0000
Subject: [PATCH 046/119] add swoole test
---
.github/workflows/test.yml | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 96667e1e..ce9d61c5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -21,5 +21,8 @@ jobs:
- name: Wait for Server to be ready
run: sleep 10
- - name: Run Tests
- run: docker compose exec fpm vendor/bin/phpunit --configuration phpunit.xml
\ No newline at end of file
+ - name: Run FPM Tests
+ run: docker compose exec fpm vendor/bin/phpunit --configuration phpunit.xml
+
+ - name: Run Swoole Tests
+ run: docker compose exec swoole vendor/bin/phpunit --configuration phpunit.xml
\ No newline at end of file
From 0f69480dbed9f4a9edf3c75990fb5885dd7552b8 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 6 Aug 2023 02:09:59 +0000
Subject: [PATCH 047/119] update tests
---
src/Http/Http.php | 2 +-
tests/HttpTest.php | 41 +++++++++++++++++++++--------------------
2 files changed, 22 insertions(+), 21 deletions(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 285762fd..3ffe80c9 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -760,7 +760,7 @@ protected function getArguments(Hook $hook, int $context, array $values, array $
}
if ($paramExists) {
- // $this->validate($key, $param, $value, $context);
+ $this->validate($key, $param, $value, $context);
}
}
diff --git a/tests/HttpTest.php b/tests/HttpTest.php
index b1cb376a..230345fb 100755
--- a/tests/HttpTest.php
+++ b/tests/HttpTest.php
@@ -86,17 +86,17 @@ public function testCanGetResources(): void
Http::setResource('first', fn ($second) => "first-{$second}", ['second']);
Http::setResource('second', fn () => 'second');
- $second = $this->http->getResource('second');
- $first = $this->http->getResource('first');
+ $second = $this->http->getResource('second', 1);
+ $first = $this->http->getResource('first', 1);
$this->assertEquals('second', $second);
$this->assertEquals('first-second', $first);
- $resource = $this->http->getResource('rand');
+ $resource = $this->http->getResource('rand', 1);
$this->assertNotEmpty($resource);
- $this->assertEquals($resource, $this->http->getResource('rand'));
- $this->assertEquals($resource, $this->http->getResource('rand'));
- $this->assertEquals($resource, $this->http->getResource('rand'));
+ $this->assertEquals($resource, $this->http->getResource('rand', 1));
+ $this->assertEquals($resource, $this->http->getResource('rand', 1));
+ $this->assertEquals($resource, $this->http->getResource('rand', 1));
// Default Params
$route = new Route('GET', '/path');
@@ -110,7 +110,7 @@ public function testCanGetResources(): void
});
\ob_start();
- $this->http->execute($route, new Request());
+ $this->http->execute($route, new Request(), 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -120,13 +120,14 @@ public function testCanGetResources(): void
public function testCanExecuteRoute(): void
{
Http::setResource('rand', fn () => rand());
- $resource = $this->http->getResource('rand');
+ $resource = $this->http->getResource('rand', 1);
$this->http
->error()
->inject('error')
- ->action(function ($error) {
+ ->action(function (\Throwable $error) {
echo 'error: '.$error->getMessage();
+ echo 'error: ' . $error->getTraceAsString();
});
// Default Params
@@ -140,7 +141,7 @@ public function testCanExecuteRoute(): void
});
\ob_start();
- $this->http->execute($route, new Request());
+ $this->http->execute($route, new Request(), 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -164,7 +165,7 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y', 'z' => 'param-z']);
- $this->http->execute($route, $request);
+ $this->http->execute($route, $request, 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -184,7 +185,7 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->http->execute($route, $request);
+ $this->http->execute($route, $request, 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -256,7 +257,7 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->http->execute($route, $request);
+ $this->http->execute($route, $request, 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -265,7 +266,7 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->http->execute($homepage, $request);
+ $this->http->execute($homepage, $request, 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -295,7 +296,7 @@ public function testCanAddAndExecuteHooks()
});
\ob_start();
- $this->http->execute($route, new Request());
+ $this->http->execute($route, new Request(), 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -311,7 +312,7 @@ public function testCanAddAndExecuteHooks()
});
\ob_start();
- $this->http->execute($route, new Request());
+ $this->http->execute($route, new Request(), 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -349,7 +350,7 @@ public function testCanHookThrowExceptions()
});
\ob_start();
- $this->http->execute($route, new Request());
+ $this->http->execute($route, new Request(), 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -357,7 +358,7 @@ public function testCanHookThrowExceptions()
\ob_start();
$_GET['y'] = 'y-def';
- $this->http->execute($route, new Request());
+ $this->http->execute($route, new Request(), 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -501,7 +502,7 @@ public function testCanRunRequest(): void
});
\ob_start();
- $this->http->run(new Request(), new Response());
+ $this->http->run(new Request(), new Response(), 1);
$result = \ob_get_contents();
\ob_end_clean();
@@ -526,7 +527,7 @@ public function testWildcardRoute(): void
});
\ob_start();
- @$this->http->run(new Request(), new Response());
+ @$this->http->run(new Request(), new Response(), 1);
$result = \ob_get_contents();
\ob_end_clean();
From 6dcef9af940b7bb87c8fac8cffab41f84ad2c2c9 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 6 Aug 2023 07:03:38 +0000
Subject: [PATCH 048/119] fix test with resource reset
---
src/Http/Http.php | 7 ++-----
tests/HttpTest.php | 8 ++++----
2 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 3ffe80c9..73ebbf20 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -347,9 +347,7 @@ public function getResource(string $name, int $context, bool $fresh = false): mi
return $this;
}
- if(!\array_key_exists($context, $this->resources)) {
- $this->resources[$context] = [];
- }
+ $this->resources[$context] ??= [];
if (!\array_key_exists($name, $this->resources[$context]) || $fresh || self::$resourcesCallbacks[$name]['reset']) {
if (!\array_key_exists($name, self::$resourcesCallbacks)) {
@@ -363,7 +361,6 @@ public function getResource(string $name, int $context, bool $fresh = false): mi
}
self::$resourcesCallbacks[$name]['reset'] = false;
-
return $this->resources[$context][$name];
}
@@ -375,7 +372,7 @@ public function getResource(string $name, int $context, bool $fresh = false): mi
*/
public function getResources(array $list, int $context): array
{
- $resources[$context] = [];
+ $resources = [];
foreach ($list as $name) {
$resources[$name] = $this->getResource($name, $context);
diff --git a/tests/HttpTest.php b/tests/HttpTest.php
index 230345fb..fe09c529 100755
--- a/tests/HttpTest.php
+++ b/tests/HttpTest.php
@@ -127,7 +127,6 @@ public function testCanExecuteRoute(): void
->inject('error')
->action(function (\Throwable $error) {
echo 'error: '.$error->getMessage();
- echo 'error: ' . $error->getTraceAsString();
});
// Default Params
@@ -146,7 +145,7 @@ public function testCanExecuteRoute(): void
\ob_end_clean();
// With Params
-
+ $resource = $this->http->getResource('rand', 1);
$route = new Route('GET', '/path');
$route
@@ -172,7 +171,7 @@ public function testCanExecuteRoute(): void
$this->assertEquals($resource.'-param-x-param-y', $result);
// With Error
-
+ $resource = $this->http->getResource('rand', 1);
$route = new Route('GET', '/path');
$route
@@ -192,7 +191,7 @@ public function testCanExecuteRoute(): void
$this->assertEquals('error: Invalid x: Value must be a valid string and no longer than 1 chars', $result);
// With Hooks
-
+ $resource = $this->http->getResource('rand', 1);
$this->http
->init()
->inject('rand')
@@ -263,6 +262,7 @@ public function testCanExecuteRoute(): void
$this->assertEquals('init-'.$resource.'-(init-api)-param-x-param-y-(shutdown-api)-shutdown', $result);
+ $resource = $this->http->getResource('rand', 1);
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
From 242a20f7177fdcfff4762a8a11fda7d937610ffc Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 6 Aug 2023 07:09:42 +0000
Subject: [PATCH 049/119] fix lint
---
src/Http/Router.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Http/Router.php b/src/Http/Router.php
index b484acb9..044ca786 100644
--- a/src/Http/Router.php
+++ b/src/Http/Router.php
@@ -66,7 +66,7 @@ public static function addRoute(Route $route): void
self::$routes[$route->getMethod()][$path] = $route;
}
- /**
+ /**
* Add route to router.
*
* @param \Utopia\Route $route
From 54074b9c23efa2fcca2bc004a9d9bc2050d77fd7 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 6 Aug 2023 08:10:07 +0000
Subject: [PATCH 050/119] set a default context and make context string
---
src/Http/Adapter/FPM/Server.php | 2 +-
src/Http/Adapter/Swoole/Server.php | 2 +-
src/Http/Http.php | 16 ++++++++--------
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/Http/Adapter/FPM/Server.php b/src/Http/Adapter/FPM/Server.php
index b8dd0f68..e5d2cf3d 100644
--- a/src/Http/Adapter/FPM/Server.php
+++ b/src/Http/Adapter/FPM/Server.php
@@ -12,7 +12,7 @@ public function __construct()
public function onRequest(callable $callback)
{
- call_user_func($callback, new Request(), new Response(), 100);
+ call_user_func($callback, new Request(), new Response(), 'fpm');
}
public function onStart(callable $callback)
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index 19d48fb2..adb5a8eb 100644
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -29,7 +29,7 @@ public function setConfig(array $configs)
public function onRequest(callable $callback)
{
$this->server->on('request', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
- call_user_func($callback, new Request($request), new Response($response), Coroutine::getCid());
+ call_user_func($callback, new Request($request), new Response($response), \strval(Coroutine::getCid()));
});
}
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 78b25fce..a5458811 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -341,7 +341,7 @@ public static function setMode(string $value): void
*
* @throws Exception
*/
- public function getResource(string $name, int $context, bool $fresh = false): mixed
+ public function getResource(string $name, string $context = 'utopia', bool $fresh = false): mixed
{
if ($name === 'utopia') {
return $this;
@@ -370,7 +370,7 @@ public function getResource(string $name, int $context, bool $fresh = false): mi
* @param array $list
* @return array
*/
- public function getResources(array $list, int $context): array
+ public function getResources(array $list, string $context): array
{
$resources = [];
@@ -649,7 +649,7 @@ public function match(Request $request, bool $fresh = true): ?Route
* @param Route $route
* @param Request $request
*/
- public function execute(Route $route, Request $request, int $context): static
+ public function execute(Route $route, Request $request, string $context): static
{
$arguments = [];
$groups = $route->getGroups();
@@ -740,7 +740,7 @@ public function execute(Route $route, Request $request, int $context): static
*
* @throws Exception
*/
- protected function getArguments(Hook $hook, int $context, array $values, array $requestParams): array
+ protected function getArguments(Hook $hook, string $context, array $values, array $requestParams): array
{
$arguments = [];
foreach ($hook->getParams() as $key => $param) { // Get value from route or request object
@@ -781,7 +781,7 @@ protected function getArguments(Hook $hook, int $context, array $values, array $
* @param Request $request
* @param Response $response;
*/
- public function run(Request $request, Response $response, int $context): static
+ public function run(Request $request, Response $response, string $context): static
{
$this->resources[$context] = [];
$this->resources[$context]['request'] = $request;
@@ -843,7 +843,7 @@ public function run(Request $request, Response $response, int $context): static
foreach (self::$options as $option) { // Group options hooks
/** @var Hook $option */
if (in_array($group, $option->getGroups())) {
- \call_user_func_array($option->getAction(), $this->getArguments($option, [], $request->getParams()));
+ \call_user_func_array($option->getAction(), $this->getArguments($option, $context, [], $request->getParams()));
}
}
}
@@ -851,7 +851,7 @@ public function run(Request $request, Response $response, int $context): static
foreach (self::$options as $option) { // Global options hooks
/** @var Hook $option */
if (in_array('*', $option->getGroups())) {
- \call_user_func_array($option->getAction(), $this->getArguments($option, [], $request->getParams()));
+ \call_user_func_array($option->getAction(), $this->getArguments($option, $context, [], $request->getParams()));
}
}
} catch (\Throwable $e) {
@@ -861,7 +861,7 @@ public function run(Request $request, Response $response, int $context): static
self::setResource('error', function () use ($e) {
return $e;
});
- \call_user_func_array($error->getAction(), $this->getArguments($error, [], $request->getParams()));
+ \call_user_func_array($error->getAction(), $this->getArguments($error, $context, [], $request->getParams()));
}
}
}
From 11488b15defd85f6bb460f7344eb63514e7e68b3 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 8 Aug 2023 09:18:57 +0000
Subject: [PATCH 051/119] make utopia default context
---
src/Http/Http.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index a5458811..951b620b 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -564,7 +564,7 @@ public function start()
try {
foreach (self::$startHooks as $hook) {
- $arguments = $this->getArguments($hook, 0, [], []);
+ $arguments = $this->getArguments($hook, 'utopia', [], []);
\call_user_func_array($hook->getAction(), $arguments);
}
} catch(\Exception $e) {
@@ -573,7 +573,7 @@ public function start()
foreach (self::$errors as $error) { // Global error hooks
if (in_array('*', $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, 0, [], []);
+ $arguments = $this->getArguments($error, 'utopia', [], []);
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
@@ -597,7 +597,7 @@ public function start()
try {
foreach (self::$workerStartHooks as $hook) {
- $arguments = $this->getArguments($hook, 0, [], []);
+ $arguments = $this->getArguments($hook, 'utopia', [], []);
\call_user_func_array($hook->getAction(), $arguments);
}
} catch(\Exception $e) {
@@ -606,7 +606,7 @@ public function start()
foreach (self::$errors as $error) { // Global error hooks
if (in_array('*', $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, 0, [], []);
+ $arguments = $this->getArguments($error, 'utopia', [], []);
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
From d2909e70a39a883b4f59d6513b2af4bfd4af62b5 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 8 Aug 2023 09:28:58 +0000
Subject: [PATCH 052/119] upgrade callback
---
src/Http/Http.php | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 951b620b..b122ff91 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -348,8 +348,9 @@ public function getResource(string $name, string $context = 'utopia', bool $fres
}
$this->resources[$context] ??= [];
+ self::$resourcesCallbacks[$name]['reset'] ??= [];
- if (!\array_key_exists($name, $this->resources[$context]) || $fresh || self::$resourcesCallbacks[$name]['reset']) {
+ if (!\array_key_exists($name, $this->resources[$context]) || $fresh || self::$resourcesCallbacks[$name]['reset'][$context]) {
if (!\array_key_exists($name, self::$resourcesCallbacks)) {
throw new Exception('Failed to find resource: "' . $name . '"');
}
@@ -360,7 +361,7 @@ public function getResource(string $name, string $context = 'utopia', bool $fres
);
}
- self::$resourcesCallbacks[$name]['reset'] = false;
+ self::$resourcesCallbacks[$name]['reset'][$context] = false;
return $this->resources[$context][$name];
}
From 52c1a06db614a8eb522fde707756244ee674984c Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Tue, 8 Aug 2023 09:38:53 +0000
Subject: [PATCH 053/119] fix callback reset type
---
src/Http/Http.php | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index b122ff91..ea75681b 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -348,9 +348,8 @@ public function getResource(string $name, string $context = 'utopia', bool $fres
}
$this->resources[$context] ??= [];
- self::$resourcesCallbacks[$name]['reset'] ??= [];
- if (!\array_key_exists($name, $this->resources[$context]) || $fresh || self::$resourcesCallbacks[$name]['reset'][$context]) {
+ if (!\array_key_exists($name, $this->resources[$context]) || $fresh || (self::$resourcesCallbacks[$name]['reset'][$context] ?? true)) {
if (!\array_key_exists($name, self::$resourcesCallbacks)) {
throw new Exception('Failed to find resource: "' . $name . '"');
}
@@ -397,7 +396,7 @@ public static function setResource(string $name, callable $callback, array $inje
if ($name === 'utopia') {
throw new Exception("'utopia' is a reserved keyword.", 500);
}
- self::$resourcesCallbacks[$name] = ['callback' => $callback, 'injections' => $injections, 'reset' => true];
+ self::$resourcesCallbacks[$name] = ['callback' => $callback, 'injections' => $injections, 'resets' => []];
}
/**
From b7ff4de50f33fe87928bf5a48fceb404ada09f30 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 9 Aug 2023 00:20:39 +0000
Subject: [PATCH 054/119] fix check and lint
---
src/Http/Adapter/Swoole/Server.php | 3 +-
src/Http/Router.php | 2 +-
tests/HttpTest.php | 52 +++++++++++++++---------------
3 files changed, 28 insertions(+), 29 deletions(-)
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index adb5a8eb..a78e34d9 100644
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -2,7 +2,6 @@
namespace Utopia\Http\Adapter\Swoole;
-use Swoole\Constant;
use Swoole\Coroutine;
use Utopia\Http\Adapter;
use Swoole\Http\Server as SwooleServer;
@@ -21,7 +20,7 @@ public function __construct(string $host, string $port = null)
public function setConfig(array $configs)
{
$configs = array_merge($configs, [
- Constant::OPTION_ENABLE_COROUTINE => true
+ 'enable_coroutine' => true
]);
$this->server->set($configs);
}
diff --git a/src/Http/Router.php b/src/Http/Router.php
index 044ca786..f0a38953 100644
--- a/src/Http/Router.php
+++ b/src/Http/Router.php
@@ -69,7 +69,7 @@ public static function addRoute(Route $route): void
/**
* Add route to router.
*
- * @param \Utopia\Route $route
+ * @param \Utopia\Http\Route $route
* @return void
* @throws \Exception
*/
diff --git a/tests/HttpTest.php b/tests/HttpTest.php
index b2c1918d..c00cfb14 100755
--- a/tests/HttpTest.php
+++ b/tests/HttpTest.php
@@ -86,17 +86,17 @@ public function testCanGetResources(): void
Http::setResource('first', fn ($second) => "first-{$second}", ['second']);
Http::setResource('second', fn () => 'second');
- $second = $this->http->getResource('second', 1);
- $first = $this->http->getResource('first', 1);
+ $second = $this->http->getResource('second', '1');
+ $first = $this->http->getResource('first', '1');
$this->assertEquals('second', $second);
$this->assertEquals('first-second', $first);
- $resource = $this->http->getResource('rand', 1);
+ $resource = $this->http->getResource('rand', '1');
$this->assertNotEmpty($resource);
- $this->assertEquals($resource, $this->http->getResource('rand', 1));
- $this->assertEquals($resource, $this->http->getResource('rand', 1));
- $this->assertEquals($resource, $this->http->getResource('rand', 1));
+ $this->assertEquals($resource, $this->http->getResource('rand', '1'));
+ $this->assertEquals($resource, $this->http->getResource('rand', '1'));
+ $this->assertEquals($resource, $this->http->getResource('rand', '1'));
// Default Params
$route = new Route('GET', '/path');
@@ -110,7 +110,7 @@ public function testCanGetResources(): void
});
\ob_start();
- $this->http->execute($route, new Request(), 1);
+ $this->http->execute($route, new Request(), '1');
$result = \ob_get_contents();
\ob_end_clean();
@@ -120,7 +120,7 @@ public function testCanGetResources(): void
public function testCanExecuteRoute(): void
{
Http::setResource('rand', fn () => rand());
- $resource = $this->http->getResource('rand', 1);
+ $resource = $this->http->getResource('rand', '1');
$this->http
->error()
@@ -140,12 +140,12 @@ public function testCanExecuteRoute(): void
});
\ob_start();
- $this->http->execute($route, new Request(), 1);
+ $this->http->execute($route, new Request(), '1');
$result = \ob_get_contents();
\ob_end_clean();
// With Params
- $resource = $this->http->getResource('rand', 1);
+ $resource = $this->http->getResource('rand', '1');
$route = new Route('GET', '/path');
$route
@@ -164,14 +164,14 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y', 'z' => 'param-z']);
- $this->http->execute($route, $request, 1);
+ $this->http->execute($route, $request, '1');
$result = \ob_get_contents();
\ob_end_clean();
$this->assertEquals($resource . '-param-x-param-y', $result);
// With Error
- $resource = $this->http->getResource('rand', 1);
+ $resource = $this->http->getResource('rand', '1');
$route = new Route('GET', '/path');
$route
@@ -184,14 +184,14 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->http->execute($route, $request, 1);
+ $this->http->execute($route, $request, '1');
$result = \ob_get_contents();
\ob_end_clean();
$this->assertEquals('error: Invalid x: Value must be a valid string and no longer than 1 chars', $result);
// With Hooks
- $resource = $this->http->getResource('rand', 1);
+ $resource = $this->http->getResource('rand', '1');
$this->http
->init()
->inject('rand')
@@ -256,17 +256,17 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->http->execute($route, $request, 1);
+ $this->http->execute($route, $request, '1');
$result = \ob_get_contents();
\ob_end_clean();
$this->assertEquals('init-' . $resource . '-(init-api)-param-x-param-y-(shutdown-api)-shutdown', $result);
- $resource = $this->http->getResource('rand', 1);
+ $resource = $this->http->getResource('rand', '1');
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->http->execute($homepage, $request, 1);
+ $this->http->execute($homepage, $request, '1');
$result = \ob_get_contents();
\ob_end_clean();
@@ -296,7 +296,7 @@ public function testCanAddAndExecuteHooks()
});
\ob_start();
- $this->http->execute($route, new Request(), 1);
+ $this->http->execute($route, new Request(), '1');
$result = \ob_get_contents();
\ob_end_clean();
@@ -312,7 +312,7 @@ public function testCanAddAndExecuteHooks()
});
\ob_start();
- $this->http->execute($route, new Request(), 1);
+ $this->http->execute($route, new Request(), '1');
$result = \ob_get_contents();
\ob_end_clean();
@@ -350,7 +350,7 @@ public function testCanHookThrowExceptions()
});
\ob_start();
- $this->http->execute($route, new Request(), 1);
+ $this->http->execute($route, new Request(), '1');
$result = \ob_get_contents();
\ob_end_clean();
@@ -358,7 +358,7 @@ public function testCanHookThrowExceptions()
\ob_start();
$_GET['y'] = 'y-def';
- $this->http->execute($route, new Request(), 1);
+ $this->http->execute($route, new Request(), '1');
$result = \ob_get_contents();
\ob_end_clean();
@@ -502,7 +502,7 @@ public function testCanRunRequest(): void
});
\ob_start();
- $this->http->run(new Request(), new Response(), 1);
+ $this->http->run(new Request(), new Response(), '1');
$result = \ob_get_contents();
\ob_end_clean();
@@ -523,7 +523,7 @@ public function testWildcardRoute(): void
Http::init()
->action(function () {
$route = $this->http->getRoute();
- http::setResource('myRoute', fn () => $route);
+ Http::setResource('myRoute', fn () => $route);
});
@@ -539,7 +539,7 @@ public function testWildcardRoute(): void
});
\ob_start();
- @$this->http->run(new Request(), new Response(), 1);
+ @$this->http->run(new Request(), new Response(), '1');
$result = \ob_get_contents();
\ob_end_clean();
@@ -548,7 +548,7 @@ public function testWildcardRoute(): void
\ob_start();
$req = new Request();
$req = $req->setMethod('OPTIONS');
- @$this->http->run($req, new Response(), 1);
+ @$this->http->run($req, new Response(), '1');
$result = \ob_get_contents();
\ob_end_clean();
@@ -558,7 +558,7 @@ public function testWildcardRoute(): void
$_SERVER['REQUEST_URI'] = '/init_response';
\ob_start();
- @$this->app->run(new Request(), new Response());
+ @$this->http->run(new Request(), new Response(), '1');
$result = \ob_get_contents();
\ob_end_clean();
From 1105527b4c754652461a39c02f1c5b95f828eff5 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Wed, 9 Aug 2023 01:42:19 +0000
Subject: [PATCH 055/119] fixes after merge
---
Dockerfile.swoole | 2 +-
src/Http/Adapter/Swoole/Server.php | 3 +++
src/Http/Http.php | 11 ++++++-----
tests/HttpTest.php | 10 ----------
4 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/Dockerfile.swoole b/Dockerfile.swoole
index 55ca84fe..58cb3a24 100644
--- a/Dockerfile.swoole
+++ b/Dockerfile.swoole
@@ -13,7 +13,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist \
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
-FROM appwrite/base:0.2.2 as final
+FROM appwrite/base:0.4.3 as final
LABEL maintainer="team@appwrite.io"
WORKDIR /usr/src/code
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index a78e34d9..f4055e80 100644
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -15,6 +15,9 @@ class Server extends Adapter
public function __construct(string $host, string $port = null)
{
$this->server = new SwooleServer($host, $port);
+ $this->server->set([
+ 'enable_coroutine' => true
+ ]);
}
public function setConfig(array $configs)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 4043dc13..8152fad4 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -557,7 +557,8 @@ public function start()
{
$this->server->onRequest(fn ($request, $response, $context) => $this->run($request, $response, $context));
$this->server->onStart(function ($server) {
- $this->resources['server'] = $server;
+ $this->resources['utopia'] ??= [];
+ $this->resources['utopia']['server'] = $server;
self::setResource('server', function () use ($server) {
return $server;
});
@@ -584,8 +585,9 @@ public function start()
});
$this->server->onWorkerStart(function ($server, $workerId) {
- $this->resources['server'] = $server;
- $this->resources['workerId'] = $workerId;
+ $this->resources['utopia'] ??= [];
+ $this->resources['utopia']['server'] = $server;
+ $this->resources['utopia']['workerId'] = $workerId;
self::setResource('server', function () use ($server) {
return $server;
@@ -675,7 +677,7 @@ public function execute(Route $route, Request $request, string $context): static
}
$arguments = $this->getArguments($route, $context, $pathValues, $request->getParams());
-
+ \call_user_func_array($route->getAction(), $arguments);
foreach ($groups as $group) {
foreach (self::$shutdown as $hook) { // Group shutdown hooks
@@ -825,7 +827,6 @@ public function run(Request $request, Response $response, string $context): stat
return $this;
}
-
$method = $request->getMethod();
$route = $this->match($request);
$groups = ($route instanceof Route) ? $route->getGroups() : [];
diff --git a/tests/HttpTest.php b/tests/HttpTest.php
index c00cfb14..bbd84cac 100755
--- a/tests/HttpTest.php
+++ b/tests/HttpTest.php
@@ -554,16 +554,6 @@ public function testWildcardRoute(): void
$this->assertEquals('', $result);
- $_SERVER['REQUEST_METHOD'] = 'GET';
- $_SERVER['REQUEST_URI'] = '/init_response';
-
- \ob_start();
- @$this->http->run(new Request(), new Response(), '1');
- $result = \ob_get_contents();
- \ob_end_clean();
-
- $this->assertEquals('THIS IS RESPONSE FROM INIT!', $result);
-
$_SERVER['REQUEST_METHOD'] = $method;
$_SERVER['REQUEST_URI'] = $uri;
}
From f3cb0415dd292bd0acc08464a365cc73299613d7 Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Thu, 10 Aug 2023 01:29:15 +0000
Subject: [PATCH 056/119] update missing resource
---
src/Http/Http.php | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 8152fad4..15e3d1bd 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -787,13 +787,11 @@ public function run(Request $request, Response $response, string $context): stat
$this->resources[$context]['request'] = $request;
$this->resources[$context]['response'] = $response;
- self::setResource('request', function () use ($request) {
- return $request;
- });
+ self::setResource('context', fn () => $context);
- self::setResource('response', function () use ($response) {
- return $response;
- });
+ self::setResource('request', fn () => $request);
+
+ self::setResource('response', fn () => $response);
try {
From d714fcbd12c864964d4e0329e623d0b18b84fb8f Mon Sep 17 00:00:00 2001
From: Damodar Lohani
Date: Sun, 10 Sep 2023 12:13:20 +0000
Subject: [PATCH 057/119] remove view from framework
---
src/Http/View.php | 338 --------------------------------
tests/ViewTest.php | 86 --------
tests/mocks/View/template.phtml | 1 -
3 files changed, 425 deletions(-)
delete mode 100755 src/Http/View.php
delete mode 100755 tests/ViewTest.php
delete mode 100755 tests/mocks/View/template.phtml
diff --git a/src/Http/View.php b/src/Http/View.php
deleted file mode 100755
index 87568f52..00000000
--- a/src/Http/View.php
+++ /dev/null
@@ -1,338 +0,0 @@
-setPath($path) method
- *
- * @param string $path
- *
- * @throws Exception
- */
- public function __construct(string $path = '')
- {
- $this->setPath($path);
-
- $this
- ->addFilter(self::FILTER_ESCAPE, function (string $value) {
- return \htmlentities($value, ENT_QUOTES, 'UTF-8');
- })
- ->addFilter(self::FILTER_NL2P, function (string $value) {
- $paragraphs = '';
-
- foreach (\explode("\n\n", $value) as $line) {
- if (\trim($line)) {
- $paragraphs .= ''.$line.'
';
- }
- }
-
- $paragraphs = \str_replace("\n", '
', $paragraphs);
-
- return $paragraphs;
- });
- }
-
- /**
- * Set param
- *
- * Assign a parameter by key
- *
- * @param string $key
- * @param mixed $value
- *
- * @throws Exception
- */
- public function setParam(string $key, mixed $value): static
- {
- if (\strpos($key, '.') !== false) {
- throw new Exception('$key can\'t contain a dot "." character');
- }
-
- $this->params[$key] = $value;
-
- return $this;
- }
-
- /**
- * Set parent View object conatining this object
- *
- * @param self $view
- */
- public function setParent(self $view): static
- {
- $this->parent = $view;
-
- return $this;
- }
-
- /**
- * Return a View instance of the parent view containing this view
- *
- * @return self|null
- */
- public function getParent(): ?self
- {
- if (! empty($this->parent)) {
- return $this->parent;
- }
-
- return null;
- }
-
- /**
- * Get param
- *
- * Returns an assigned parameter by its key or $default if param key doesn't exists
- *
- * @param string $path
- * @param mixed $default (optional)
- * @return mixed
- */
- public function getParam(string $path, mixed $default = null): mixed
- {
- $path = \explode('.', $path);
- $temp = $this->params;
-
- foreach ($path as $key) {
- $temp = (isset($temp[$key])) ? $temp[$key] : null;
-
- if (null !== $temp) {
- $value = $temp;
- } else {
- return $default;
- }
- }
-
- return $value;
- }
-
- /**
- * Set path
- *
- * Set object template path that will be used to render view output
- *
- * @param string $path
- *
- * @throws Exception
- */
- public function setPath(string $path): static
- {
- $this->path = $path;
-
- return $this;
- }
-
- /**
- * Set rendered
- *
- * By enabling rendered state to true, the object will not render its template and will return an empty string instead
- *
- * @param bool $state
- */
- public function setRendered(bool $state = true): static
- {
- $this->rendered = $state;
-
- return $this;
- }
-
- /**
- * Is rendered
- *
- * Return whether current View rendering state is set to true or false
- *
- * @return bool
- */
- public function isRendered(): bool
- {
- return $this->rendered;
- }
-
- /**
- * Add Filter
- *
- * @param string $name
- * @param callable $callback
- */
- public function addFilter(string $name, callable $callback): static
- {
- $this->filters[$name] = $callback;
-
- return $this;
- }
-
- /**
- * Output and filter value
- *
- * @param mixed $value
- * @param string|array $filter
- * @return mixed
- *
- * @throws Exception
- */
- public function print(mixed $value, string|array $filter = ''): mixed
- {
- if (! empty($filter)) {
- if (\is_array($filter)) {
- foreach ($filter as $callback) {
- if (! isset($this->filters[$callback])) {
- throw new Exception('Filter "'.$callback.'" is not registered');
- }
-
- $value = $this->filters[$callback]($value);
- }
- } else {
- if (! isset($this->filters[$filter])) {
- throw new Exception('Filter "'.$filter.'" is not registered');
- }
-
- $value = $this->filters[$filter]($value);
- }
- }
-
- return $value;
- }
-
- /**
- * Render
- *
- * Render view .phtml template file if template has not been set as rendered yet using $this->setRendered(true).
- * In case path is not readable throws Exception.
- *
- * @param bool $minify
- * @return string
- *
- * @throws Exception
- */
- public function render(bool $minify = true): string
- {
- if ($this->rendered) { // Don't render any template
- return '';
- }
-
- \ob_start(); //Start of build
-
- if (\is_readable($this->path)) {
- /**
- * Include template file
- *
- * @psalm-suppress UnresolvableInclude
- */
- include $this->path;
- } else {
- \ob_end_clean();
- throw new Exception('"'.$this->path.'" view template is not readable');
- }
-
- $html = \ob_get_contents();
-
- \ob_end_clean(); //End of build
-
- if ($minify) {
- // Searching textarea and pre
- \preg_match_all('#\.*\<\/textarea\>#Uis', $html, $foundTxt);
- \preg_match_all('#\.*\<\/pre\>#Uis', $html, $foundPre);
-
- // replacing both with / $index
- $html = \str_replace($foundTxt[0], \array_map(function ($el) {
- return '';
- }, \array_keys($foundTxt[0])), $html);
- $html = \str_replace($foundPre[0], \array_map(function ($el) {
- return ''.$el.'
';
- }, \array_keys($foundPre[0])), $html);
-
- // your stuff
- $search = [
- '/\>[^\S ]+/s', // strip whitespaces after tags, except space
- '/[^\S ]+\',
- '<',
- '\\1',
- ];
-
- $html = \preg_replace($search, $replace, $html);
-
- // Replacing back with content
- $html = \str_replace(\array_map(function ($el) {
- return '';
- }, \array_keys($foundTxt[0])), $foundTxt[0], $html);
- $html = \str_replace(\array_map(function ($el) {
- return ''.$el.'
';
- }, \array_keys($foundPre[0])), $foundPre[0], $html);
- }
-
- return $html;
- }
-
- /* View Helpers */
-
- /**
- * Exec
- *
- * Exec child View components
- *
- * @param array|self $view
- * @return string
- *
- * @throws Exception
- */
- public function exec($view): string
- {
- $output = '';
-
- if (\is_array($view)) {
- foreach ($view as $node) { /* @var $node self */
- if ($node instanceof self) {
- $node->setParent($this);
- $output .= $node->render();
- }
- }
- }
-
- if ($view instanceof self) {
- $view->setParent($this);
- $output = $view->render();
- }
-
- return $output;
- }
-}
diff --git a/tests/ViewTest.php b/tests/ViewTest.php
deleted file mode 100755
index 6f4bcc6f..00000000
--- a/tests/ViewTest.php
+++ /dev/null
@@ -1,86 +0,0 @@
-view = new View(__DIR__.'/mocks/View/template.phtml');
- }
-
- public function tearDown(): void
- {
- $this->view = null;
- }
-
- public function testCanSetParam()
- {
- $value = $this->view->setParam('key', 'value');
-
- $this->assertInstanceOf('Utopia\Http\View', $value);
- }
-
- public function testCanGetParam()
- {
- $this->view->setParam('key', 'value');
-
- $this->assertEquals('value', $this->view->getParam('key', 'default'));
- $this->assertEquals('default', $this->view->getParam('fake', 'default'));
- }
-
- public function testCanSetPath()
- {
- $value = $this->view->setPath('mocks/View/fake.phtml');
-
- $this->assertInstanceOf('Utopia\Http\View', $value);
- }
-
- public function testCanSetRendered()
- {
- $this->view->setRendered();
-
- $this->assertEquals(true, $this->view->isRendered());
- }
-
- public function testCanGetRendered()
- {
- $this->view->setRendered(false);
- $this->assertEquals(false, $this->view->isRendered());
-
- $this->view->setRendered(true);
- $this->assertEquals(true, $this->view->isRendered());
- }
-
- public function testCanRenderHtml()
- {
- $this->assertEquals('Test template mock
', $this->view->render());
-
- $this->view->setRendered();
- $this->assertEquals('', $this->view->render());
-
- try {
- $this->view->setRendered(false);
- $this->view->setPath('just-a-broken-string.phtml');
- $this->view->render();
- } catch(\Exception $e) {
- return;
- }
-
- $this->fail('An expected exception has not been raised.');
- }
-
- public function testCanEscapeUnicode()
- {
- $this->assertEquals('&"', $this->view->print('&"', View::FILTER_ESCAPE));
- }
-
- public function testCanFilterNewLinesToParagraphs()
- {
- $this->assertEquals('line1
line2
', $this->view->print("line1\n\nline2", View::FILTER_NL2P));
- }
-}
diff --git a/tests/mocks/View/template.phtml b/tests/mocks/View/template.phtml
deleted file mode 100755
index 51d1c6a4..00000000
--- a/tests/mocks/View/template.phtml
+++ /dev/null
@@ -1 +0,0 @@
-Test template mock
\ No newline at end of file
From 6c8ffb015840ff559685792df57bdf2eda4d2a7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Mon, 2 Oct 2023 12:49:31 +0000
Subject: [PATCH 058/119] Fix Swoole coroutine http server
---
src/Http/Adapter/Swoole/Server.php | 23 ++++-------------------
1 file changed, 4 insertions(+), 19 deletions(-)
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index f4055e80..1fa1e913 100644
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -4,7 +4,7 @@
use Swoole\Coroutine;
use Utopia\Http\Adapter;
-use Swoole\Http\Server as SwooleServer;
+use Swoole\Coroutine\Http\Server as SwooleServer;
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
@@ -30,34 +30,19 @@ public function setConfig(array $configs)
public function onRequest(callable $callback)
{
- $this->server->on('request', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
+ $this->server->handle('/', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
call_user_func($callback, new Request($request), new Response($response), \strval(Coroutine::getCid()));
});
}
public function onWorkerStart(callable $callback)
{
- $this->server->on('WorkerStart', $callback);
- }
-
- public function onBeforeReload(callable $callback)
- {
- $this->server->on('BeforeReload', $callback);
- }
-
- public function onAfterReload(callable $callback)
- {
- $this->server->on('AfterReload', $callback);
- }
-
- public function onBeforeShutdown(callable $callback)
- {
- $this->server->on('beforeShutdown', $callback);
+ return;
}
public function onStart(callable $callback)
{
- $this->server->on('start', $callback);
+ call_user_func($callback, $this);
}
public function start()
From a4916b4b83b04f43411ea51a34c6f40715e13d0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Mon, 2 Oct 2023 12:55:03 +0000
Subject: [PATCH 059/119] Disable forced type on onRequest
---
src/Http/Adapter/Swoole/Server.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index 1fa1e913..59ce4126 100644
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -31,7 +31,7 @@ public function setConfig(array $configs)
public function onRequest(callable $callback)
{
$this->server->handle('/', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
- call_user_func($callback, new Request($request), new Response($response), \strval(Coroutine::getCid()));
+ call_user_func($callback, $request, $response, \strval(Coroutine::getCid()));
});
}
From 69b83a3ffdb9ed8b5db4d44abe42fc8aeaa1215a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Mon, 2 Oct 2023 13:05:16 +0000
Subject: [PATCH 060/119] Add route resource
---
src/Http/Http.php | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 8d42fd37..aad8883b 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -829,6 +829,8 @@ public function run(Request $request, Response $response, string $context): stat
$route = $this->match($request);
$groups = ($route instanceof Route) ? $route->getGroups() : [];
+ self::setResource('route', fn () => $route);
+
if (self::REQUEST_METHOD_HEAD == $method) {
$method = self::REQUEST_METHOD_GET;
$response->disablePayload();
@@ -871,6 +873,8 @@ public function run(Request $request, Response $response, string $context): stat
$this->route = $route;
$path = \parse_url($request->getURI(), PHP_URL_PATH);
$route->path($path);
+
+ self::setResource('route', fn () => $route);
}
if (null !== $route) {
From 2213a3c8e67c92639e7a220900b525653ee0fade Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 3 Oct 2023 08:54:37 +0000
Subject: [PATCH 061/119] Fix tests
---
src/Http/Adapter/Swoole/Server.php | 8 +++++++-
tests/e2e/server_swoole.php | 8 ++++----
2 files changed, 11 insertions(+), 5 deletions(-)
mode change 100644 => 100755 src/Http/Adapter/Swoole/Server.php
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
old mode 100644
new mode 100755
index 59ce4126..4e79c949
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -7,6 +7,7 @@
use Swoole\Coroutine\Http\Server as SwooleServer;
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
+use Utopia\Http\Http;
class Server extends Adapter
{
@@ -31,7 +32,12 @@ public function setConfig(array $configs)
public function onRequest(callable $callback)
{
$this->server->handle('/', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
- call_user_func($callback, $request, $response, \strval(Coroutine::getCid()));
+ $context = \strval(Coroutine::getCid());
+
+ Http::setResource('swooleRequest', fn () => $request);
+ Http::setResource('swooleResponse', fn () => $response);
+
+ call_user_func($callback, new Request($request), new Response($response), $context);
});
}
diff --git a/tests/e2e/server_swoole.php b/tests/e2e/server_swoole.php
index cb9456ca..00ed43b0 100644
--- a/tests/e2e/server_swoole.php
+++ b/tests/e2e/server_swoole.php
@@ -5,11 +5,11 @@
use Utopia\Http\Adapter\Swoole\Server;
use Utopia\Http\Http;
+use function Swoole\Coroutine\run;
+
$server = new Server('0.0.0.0', '80');
$http = new Http($server, 'UTC');
-$server->onWorkerStart(function ($swooleServer, $workerId) {
- \fwrite(STDOUT, "Worker " . ++$workerId . " started successfully\n");
+run(function () use($http) {
+ $http->start();
});
-
-$http->start();
From 96e1f5805d178da0650ddeb0f5e36413b86bd107 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 3 Oct 2023 09:07:30 +0000
Subject: [PATCH 062/119] Tests fix
---
phpstan.neon | 2 ++
tests/e2e/server_swoole.php | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/phpstan.neon b/phpstan.neon
index a76a8329..d275a391 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,4 +1,6 @@
parameters:
+ scanDirectories:
+ - vendor/swoole/ide-helper
level: 5
paths:
- src
diff --git a/tests/e2e/server_swoole.php b/tests/e2e/server_swoole.php
index 00ed43b0..9de631cf 100644
--- a/tests/e2e/server_swoole.php
+++ b/tests/e2e/server_swoole.php
@@ -10,6 +10,6 @@
$server = new Server('0.0.0.0', '80');
$http = new Http($server, 'UTC');
-run(function () use($http) {
+run(function () use ($http) {
$http->start();
});
From c9ea90ea4326852ec530c0f17912c78cd2fceebf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 3 Oct 2023 12:56:31 +0000
Subject: [PATCH 063/119] Add swoole resources
---
src/Http/Adapter/Swoole/Server.php | 4 +--
src/Http/Http.php | 42 ++++++++++++++++++------------
tests/e2e/ResponseSwooleTest.php | 6 +++++
tests/e2e/server_swoole.php | 14 ++++++++++
4 files changed, 47 insertions(+), 19 deletions(-)
mode change 100644 => 100755 tests/e2e/ResponseSwooleTest.php
mode change 100644 => 100755 tests/e2e/server_swoole.php
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index 4e79c949..b13a522d 100755
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -34,8 +34,8 @@ public function onRequest(callable $callback)
$this->server->handle('/', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
$context = \strval(Coroutine::getCid());
- Http::setResource('swooleRequest', fn () => $request);
- Http::setResource('swooleResponse', fn () => $response);
+ Http::setResource('swooleRequest', fn () => $request, [], $context);
+ Http::setResource('swooleResponse', fn () => $response, [], $context);
call_user_func($callback, new Request($request), new Response($response), $context);
});
diff --git a/src/Http/Http.php b/src/Http/Http.php
index aad8883b..9d90b353 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -349,18 +349,23 @@ public function getResource(string $name, string $context = 'utopia', bool $fres
$this->resources[$context] ??= [];
- if (!\array_key_exists($name, $this->resources[$context]) || $fresh || (self::$resourcesCallbacks[$name]['reset'][$context] ?? true)) {
- if (!\array_key_exists($name, self::$resourcesCallbacks)) {
+ $resourcesCallback = &self::$resourcesCallbacks[$context] ?? [];
+ if(empty($resourcesCallback) || !\array_key_exists($name, $resourcesCallback)) {
+ $resourcesCallback = &self::$resourcesCallbacks['utopia'];
+ }
+
+ if (!\array_key_exists($name, $this->resources[$context]) || $fresh || ($resourcesCallback[$name]['reset'][$context] ?? true)) {
+ if (!\array_key_exists($name, $resourcesCallback)) {
throw new Exception('Failed to find resource: "' . $name . '"');
}
$this->resources[$context][$name] = \call_user_func_array(
- self::$resourcesCallbacks[$name]['callback'],
- $this->getResources(self::$resourcesCallbacks[$name]['injections'], $context)
+ $resourcesCallback[$name]['callback'],
+ $this->getResources($resourcesCallback[$name]['injections'], $context)
);
}
- self::$resourcesCallbacks[$name]['reset'][$context] = false;
+ $resourcesCallback[$name]['reset'][$context] = false;
return $this->resources[$context][$name];
}
@@ -391,12 +396,15 @@ public function getResources(array $list, string $context): array
*
* @throws Exception
*/
- public static function setResource(string $name, callable $callback, array $injections = []): void
+ public static function setResource(string $name, callable $callback, array $injections = [], string $context = 'utopia'): void
{
if ($name === 'utopia') {
throw new Exception("'utopia' is a reserved keyword.", 500);
}
- self::$resourcesCallbacks[$name] = ['callback' => $callback, 'injections' => $injections, 'resets' => []];
+
+ self::$resourcesCallbacks[$context] ??= [];
+
+ self::$resourcesCallbacks[$context][$name] = ['callback' => $callback, 'injections' => $injections, 'resets' => []];
}
/**
@@ -697,7 +705,7 @@ public function execute(Route $route, Request $request, string $context): static
}
}
} catch (\Throwable $e) {
- self::setResource('error', fn () => $e);
+ self::setResource('error', fn () => $e, [], $context);
foreach ($groups as $group) {
foreach (self::$errors as $error) { // Group error hooks
@@ -787,11 +795,11 @@ public function run(Request $request, Response $response, string $context): stat
$this->resources[$context]['request'] = $request;
$this->resources[$context]['response'] = $response;
- self::setResource('context', fn () => $context);
+ self::setResource('context', fn () => $context, [], $context);
- self::setResource('request', fn () => $request);
+ self::setResource('request', fn () => $request, [], $context);
- self::setResource('response', fn () => $response);
+ self::setResource('response', fn () => $response, [], $context);
try {
@@ -800,7 +808,7 @@ public function run(Request $request, Response $response, string $context): stat
\call_user_func_array($hook->getAction(), $arguments);
}
} catch(\Exception $e) {
- self::setResource('error', fn () => $e);
+ self::setResource('error', fn () => $e, [], $context);
foreach (self::$errors as $error) { // Global error hooks
if (in_array('*', $error->getGroups())) {
@@ -829,7 +837,7 @@ public function run(Request $request, Response $response, string $context): stat
$route = $this->match($request);
$groups = ($route instanceof Route) ? $route->getGroups() : [];
- self::setResource('route', fn () => $route);
+ self::setResource('route', fn () => $route, [], $context);
if (self::REQUEST_METHOD_HEAD == $method) {
$method = self::REQUEST_METHOD_GET;
@@ -859,7 +867,7 @@ public function run(Request $request, Response $response, string $context): stat
if (in_array('*', $error->getGroups())) {
self::setResource('error', function () use ($e) {
return $e;
- });
+ }, [], $context);
\call_user_func_array($error->getAction(), $this->getArguments($error, $context, [], $request->getParams()));
}
}
@@ -874,7 +882,7 @@ public function run(Request $request, Response $response, string $context): stat
$path = \parse_url($request->getURI(), PHP_URL_PATH);
$route->path($path);
- self::setResource('route', fn () => $route);
+ self::setResource('route', fn () => $route, [], $context);
}
if (null !== $route) {
@@ -899,7 +907,7 @@ public function run(Request $request, Response $response, string $context): stat
if (in_array('*', $error->getGroups())) {
self::setResource('error', function () use ($e) {
return $e;
- });
+ }, [], $context);
\call_user_func_array($error->getAction(), $this->getArguments($error, $context, [], $request->getParams()));
}
}
@@ -909,7 +917,7 @@ public function run(Request $request, Response $response, string $context): stat
if (in_array('*', $error->getGroups())) {
self::setResource('error', function () {
return new Exception('Not Found', 404);
- });
+ }, [], $context);
\call_user_func_array($error->getAction(), $this->getArguments($error, $context, [], $request->getParams()));
}
}
diff --git a/tests/e2e/ResponseSwooleTest.php b/tests/e2e/ResponseSwooleTest.php
old mode 100644
new mode 100755
index 6d793b90..0851554a
--- a/tests/e2e/ResponseSwooleTest.php
+++ b/tests/e2e/ResponseSwooleTest.php
@@ -14,4 +14,10 @@ public function setUp(): void
{
$this->client = new Client('http://swoole');
}
+
+ public function testSwooleResources(): void
+ {
+ $response = $this->client->call(Client::METHOD_DELETE, '/swoole-test');
+ $this->assertEquals('DELETE', $response['body']);
+ }
}
diff --git a/tests/e2e/server_swoole.php b/tests/e2e/server_swoole.php
old mode 100644
new mode 100755
index 9de631cf..e15e1be4
--- a/tests/e2e/server_swoole.php
+++ b/tests/e2e/server_swoole.php
@@ -2,11 +2,25 @@
require_once __DIR__.'/init.php';
+use Swoole\Http\Request as SwooleRequest;
+use Swoole\Http\Response as SwooleResponse;
use Utopia\Http\Adapter\Swoole\Server;
use Utopia\Http\Http;
use function Swoole\Coroutine\run;
+Http::delete('/swoole-test')
+ ->inject('swooleRequest')
+ ->inject('swooleResponse')
+ ->action(function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) {
+ $method = $swooleRequest->getMethod();
+ $swooleResponse->header('Content-Type', 'text/plain');
+ $swooleResponse->header('Cache-Control', 'no-cache');
+ $swooleResponse->setStatusCode(200);
+ $swooleResponse->write($method);
+ $swooleResponse->end();
+ });
+
$server = new Server('0.0.0.0', '80');
$http = new Http($server, 'UTC');
From e34ed9c34d50b64e997ab53fd4f486b6179ae6ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 4 Oct 2023 11:53:40 +0000
Subject: [PATCH 064/119] Add default context to getResources
---
src/Http/Http.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 9d90b353..49352ba0 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -375,7 +375,7 @@ public function getResource(string $name, string $context = 'utopia', bool $fres
* @param array $list
* @return array
*/
- public function getResources(array $list, string $context): array
+ public function getResources(array $list, string $context = 'utopia'): array
{
$resources = [];
From c68f74e633edfdc71c42d175c0505427d00848b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 11 Oct 2023 10:46:00 +0200
Subject: [PATCH 065/119] Fix memory leak
---
src/Http/Http.php | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 49352ba0..3fc1ea9f 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -2,6 +2,8 @@
namespace Utopia\Http;
+use Throwable;
+
class Http
{
/**
@@ -563,7 +565,15 @@ public static function onRequest(): Hook
public function start()
{
- $this->server->onRequest(fn ($request, $response, $context) => $this->run($request, $response, $context));
+ $this->server->onRequest(function ($request, $response, $context) {
+ try {
+ $this->run($request, $response, $context);
+ } finally {
+ if(isset(self::$resourcesCallbacks[$context])) {
+ unset(self::$resourcesCallbacks[$context]);
+ }
+ }
+ });
$this->server->onStart(function ($server) {
$this->resources['utopia'] ??= [];
$this->resources['utopia']['server'] = $server;
From a73f0a0eb8974245e409136d2024711413fbb329 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Mon, 16 Oct 2023 15:32:02 +0200
Subject: [PATCH 066/119] Linter fix
---
composer.lock | 80 +++++++++++++++++++++++------------------------
src/Http/Http.php | 2 --
2 files changed, 40 insertions(+), 42 deletions(-)
diff --git a/composer.lock b/composer.lock
index 7ae353eb..01568c0b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -232,16 +232,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.13.1",
+ "version": "v1.13.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "22f204242d68095b3ba7dab5d3ef0240454a4652"
+ "reference": "93b2d0d49719bc6e444ba21cd4dbbccec935413d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/22f204242d68095b3ba7dab5d3ef0240454a4652",
- "reference": "22f204242d68095b3ba7dab5d3ef0240454a4652",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/93b2d0d49719bc6e444ba21cd4dbbccec935413d",
+ "reference": "93b2d0d49719bc6e444ba21cd4dbbccec935413d",
"shasum": ""
},
"require": {
@@ -252,13 +252,13 @@
"php": "^8.1.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.21.1",
- "illuminate/view": "^10.5.1",
+ "friendsofphp/php-cs-fixer": "^3.34.1",
+ "illuminate/view": "^10.23.1",
"laravel-zero/framework": "^10.1.2",
- "mockery/mockery": "^1.5.1",
- "nunomaduro/larastan": "^2.5.1",
+ "mockery/mockery": "^1.6.6",
+ "nunomaduro/larastan": "^2.6.4",
"nunomaduro/termwind": "^1.15.1",
- "pestphp/pest": "^2.4.0"
+ "pestphp/pest": "^2.18.2"
},
"bin": [
"builds/pint"
@@ -294,7 +294,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2023-09-06T11:03:34+00:00"
+ "time": "2023-10-10T15:39:09+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -716,16 +716,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.10.33",
+ "version": "1.10.38",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1"
+ "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
- "reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5302bb402c57f00fb3c2c015bac86e0827e4b691",
+ "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691",
"shasum": ""
},
"require": {
@@ -774,20 +774,20 @@
"type": "tidelift"
}
],
- "time": "2023-09-04T12:20:53+00:00"
+ "time": "2023-10-06T14:19:14+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "9.2.27",
+ "version": "9.2.29",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1"
+ "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1",
- "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76",
+ "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76",
"shasum": ""
},
"require": {
@@ -844,7 +844,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29"
},
"funding": [
{
@@ -852,7 +852,7 @@
"type": "github"
}
],
- "time": "2023-07-26T13:44:30+00:00"
+ "time": "2023-09-19T04:57:46+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -1097,16 +1097,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.11",
+ "version": "9.6.13",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "810500e92855eba8a7a5319ae913be2da6f957b0"
+ "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0",
- "reference": "810500e92855eba8a7a5319ae913be2da6f957b0",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be",
+ "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be",
"shasum": ""
},
"require": {
@@ -1121,7 +1121,7 @@
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"php": ">=7.3",
- "phpunit/php-code-coverage": "^9.2.13",
+ "phpunit/php-code-coverage": "^9.2.28",
"phpunit/php-file-iterator": "^3.0.5",
"phpunit/php-invoker": "^3.1.1",
"phpunit/php-text-template": "^2.0.3",
@@ -1180,7 +1180,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13"
},
"funding": [
{
@@ -1196,7 +1196,7 @@
"type": "tidelift"
}
],
- "time": "2023-08-19T07:10:56+00:00"
+ "time": "2023-09-19T05:39:22+00:00"
},
{
"name": "psr/cache",
@@ -2642,16 +2642,16 @@
},
{
"name": "symfony/finder",
- "version": "v6.3.3",
+ "version": "v6.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e"
+ "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/9915db259f67d21eefee768c1abcf1cc61b1fc9e",
- "reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/a1b31d88c0e998168ca7792f222cbecee47428c4",
+ "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4",
"shasum": ""
},
"require": {
@@ -2686,7 +2686,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v6.3.3"
+ "source": "https://github.com/symfony/finder/tree/v6.3.5"
},
"funding": [
{
@@ -2702,7 +2702,7 @@
"type": "tidelift"
}
],
- "time": "2023-07-31T08:31:44+00:00"
+ "time": "2023-09-26T12:56:25+00:00"
},
{
"name": "symfony/options-resolver",
@@ -3246,16 +3246,16 @@
},
{
"name": "symfony/string",
- "version": "v6.3.2",
+ "version": "v6.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "53d1a83225002635bca3482fcbf963001313fb68"
+ "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68",
- "reference": "53d1a83225002635bca3482fcbf963001313fb68",
+ "url": "https://api.github.com/repos/symfony/string/zipball/13d76d0fb049051ed12a04bef4f9de8715bea339",
+ "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339",
"shasum": ""
},
"require": {
@@ -3312,7 +3312,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v6.3.2"
+ "source": "https://github.com/symfony/string/tree/v6.3.5"
},
"funding": [
{
@@ -3328,7 +3328,7 @@
"type": "tidelift"
}
],
- "time": "2023-07-05T08:41:27+00:00"
+ "time": "2023-09-18T10:38:32+00:00"
},
{
"name": "theseer/tokenizer",
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 3fc1ea9f..01ed4be7 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -2,8 +2,6 @@
namespace Utopia\Http;
-use Throwable;
-
class Http
{
/**
From 7405c1fea69443c9034c2f6494a7cbd2d6e6813f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 17 Oct 2023 13:16:05 +0200
Subject: [PATCH 067/119] Improve Assoc validator with length param
---
src/Http/Validator/Assoc.php | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/src/Http/Validator/Assoc.php b/src/Http/Validator/Assoc.php
index f8cd27b7..7a8d51c9 100644
--- a/src/Http/Validator/Assoc.php
+++ b/src/Http/Validator/Assoc.php
@@ -11,6 +11,21 @@
*/
class Assoc extends Validator
{
+ /**
+ * @var int
+ */
+ protected int $length;
+
+ /**
+ * Pass integer length to allow larger json objects
+ *
+ * @param int $length
+ */
+ public function __construct(int $length = 65535)
+ {
+ $this->length = $length;
+ }
+
/**
* Get Description
*
@@ -64,7 +79,7 @@ public function isValid($value): bool
$jsonString = \json_encode($value);
$jsonStringSize = \strlen($jsonString);
- if ($jsonStringSize > 65535) {
+ if ($jsonStringSize > $this->length) {
return false;
}
From 55792e017c87536f627ab89f3336807f3bdb4e86 Mon Sep 17 00:00:00 2001
From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com>
Date: Wed, 27 Dec 2023 19:44:12 +0530
Subject: [PATCH 068/119] Add multiple validator
---
src/Http/Validator/Multiple.php | 115 +++++++++++++++++++++++++++++++
tests/Validator/MultipleTest.php | 35 ++++++++++
2 files changed, 150 insertions(+)
create mode 100644 src/Http/Validator/Multiple.php
create mode 100644 tests/Validator/MultipleTest.php
diff --git a/src/Http/Validator/Multiple.php b/src/Http/Validator/Multiple.php
new file mode 100644
index 00000000..4c919377
--- /dev/null
+++ b/src/Http/Validator/Multiple.php
@@ -0,0 +1,115 @@
+addRule($rule);
+ }
+
+ $this->type = $type;
+ }
+ /**
+ * Add rule
+ *
+ * Add a new rule to the end of the rules containing array
+ *
+ * @param Validator $rule
+ * @return $this
+ */
+ public function addRule(Validator $rule)
+ {
+ $this->rules[] = $rule;
+
+ return $this;
+ }
+
+ /**
+ * Get Description
+ *
+ * Returns validator description
+ *
+ * @return string
+ */
+ public function getDescription(): string
+ {
+ $description = '';
+ foreach ($this->rules as $key => $rule) {
+ $description .= ++$key . '. ' . $rule->getDescription() . " \n";
+ }
+
+ return $description;
+ }
+
+ /**
+ * Is valid
+ *
+ * Validation will pass when all rules are valid if only one of the rules is invalid validation will fail.
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function isValid(mixed $value): bool
+ {
+ foreach ($this->rules as $rule) { /* @var $rule Validator */
+ if (false === $rule->isValid($value)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get Type
+ *
+ * Returns validator type.
+ *
+ * @return string
+ */
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ /**
+ * Is array
+ *
+ * Function will return true if object is array.
+ *
+ * @return bool
+ */
+ public function isArray(): bool
+ {
+ return true;
+ }
+}
diff --git a/tests/Validator/MultipleTest.php b/tests/Validator/MultipleTest.php
new file mode 100644
index 00000000..348c3244
--- /dev/null
+++ b/tests/Validator/MultipleTest.php
@@ -0,0 +1,35 @@
+validator = new Multiple([new Text(20), new URL()], Multiple::TYPE_STRING);
+ }
+
+ public function testIsValid()
+ {
+ $this->assertEquals('string', $this->validator->getType());
+ $this->assertEquals("1. Value must be a valid string and at least 1 chars and no longer than 20 chars \n2. Value must be a valid URL \n", $this->validator->getDescription());
+
+ // Valid URL but invalid text length
+ $this->assertFalse($this->validator->isValid('http://example.com/very-long-url'));
+
+ // Valid text within length, but invalid URL
+ $this->assertFalse($this->validator->isValid('hello world'));
+
+ // Both conditions satisfied
+ $this->assertTrue($this->validator->isValid('http://example.com'));
+ $this->assertTrue($this->validator->isValid('https://google.com'));
+
+ // Neither condition satisfied
+ $this->assertFalse($this->validator->isValid('example.com/hello-world'));
+ $this->assertFalse($this->validator->isValid(''));
+ }
+}
From dff85bd8e90b2b7c4052238bca13133b31234a7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 3 Jan 2024 09:15:44 +0000
Subject: [PATCH 069/119] CI/CD fixes
---
composer.lock | 185 +++++++++++++++---------------
src/Http/Adapter/FPM/Request.php | 2 +-
src/Http/Adapter/FPM/Response.php | 2 +-
src/Http/Files.php | 8 +-
src/Http/Validator/Multiple.php | 4 +-
tests/HttpTest.php | 16 +--
tests/Validator/MultipleTest.php | 2 +-
7 files changed, 111 insertions(+), 108 deletions(-)
diff --git a/composer.lock b/composer.lock
index a2f6346c..a388d0e9 100644
--- a/composer.lock
+++ b/composer.lock
@@ -232,16 +232,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.13.3",
+ "version": "v1.13.7",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "93b2d0d49719bc6e444ba21cd4dbbccec935413d"
+ "reference": "4157768980dbd977f1c4b4cc94997416d8b30ece"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/93b2d0d49719bc6e444ba21cd4dbbccec935413d",
- "reference": "93b2d0d49719bc6e444ba21cd4dbbccec935413d",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/4157768980dbd977f1c4b4cc94997416d8b30ece",
+ "reference": "4157768980dbd977f1c4b4cc94997416d8b30ece",
"shasum": ""
},
"require": {
@@ -252,13 +252,13 @@
"php": "^8.1.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.34.1",
- "illuminate/view": "^10.23.1",
- "laravel-zero/framework": "^10.1.2",
+ "friendsofphp/php-cs-fixer": "^3.38.0",
+ "illuminate/view": "^10.30.1",
+ "laravel-zero/framework": "^10.3.0",
"mockery/mockery": "^1.6.6",
"nunomaduro/larastan": "^2.6.4",
"nunomaduro/termwind": "^1.15.1",
- "pestphp/pest": "^2.18.2"
+ "pestphp/pest": "^2.24.2"
},
"bin": [
"builds/pint"
@@ -294,7 +294,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2023-10-10T15:39:09+00:00"
+ "time": "2023-12-05T19:43:12+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -724,16 +724,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.10.38",
+ "version": "1.10.50",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691"
+ "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5302bb402c57f00fb3c2c015bac86e0827e4b691",
- "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4",
+ "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4",
"shasum": ""
},
"require": {
@@ -782,20 +782,20 @@
"type": "tidelift"
}
],
- "time": "2023-10-06T14:19:14+00:00"
+ "time": "2023-12-13T10:59:42+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "9.2.29",
+ "version": "9.2.30",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76"
+ "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76",
- "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089",
+ "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089",
"shasum": ""
},
"require": {
@@ -852,7 +852,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30"
},
"funding": [
{
@@ -860,7 +860,7 @@
"type": "github"
}
],
- "time": "2023-09-19T04:57:46+00:00"
+ "time": "2023-12-22T06:47:57+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -1105,16 +1105,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.13",
+ "version": "9.6.15",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be"
+ "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be",
- "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1",
+ "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1",
"shasum": ""
},
"require": {
@@ -1188,7 +1188,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15"
},
"funding": [
{
@@ -1204,7 +1204,7 @@
"type": "tidelift"
}
],
- "time": "2023-09-19T05:39:22+00:00"
+ "time": "2023-12-01T16:55:19+00:00"
},
{
"name": "psr/cache",
@@ -2430,24 +2430,23 @@
},
{
"name": "symfony/console",
- "version": "v6.3.4",
+ "version": "v7.0.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6"
+ "reference": "f8587c4cdc5acad67af71c37db34ef03af91e59c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6",
- "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6",
+ "url": "https://api.github.com/repos/symfony/console/zipball/f8587c4cdc5acad67af71c37db34ef03af91e59c",
+ "reference": "f8587c4cdc5acad67af71c37db34ef03af91e59c",
"shasum": ""
},
"require": {
- "php": ">=8.1",
- "symfony/deprecation-contracts": "^2.5|^3",
+ "php": ">=8.2",
"symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^2.5|^3",
- "symfony/string": "^5.4|^6.0"
+ "symfony/string": "^6.4|^7.0"
},
"conflict": {
"symfony/dependency-injection": "<6.4",
@@ -2461,12 +2460,16 @@
},
"require-dev": {
"psr/log": "^1|^2|^3",
- "symfony/config": "^5.4|^6.0",
- "symfony/dependency-injection": "^5.4|^6.0",
- "symfony/event-dispatcher": "^5.4|^6.0",
- "symfony/lock": "^5.4|^6.0",
- "symfony/process": "^5.4|^6.0",
- "symfony/var-dumper": "^5.4|^6.0"
+ "symfony/config": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/event-dispatcher": "^6.4|^7.0",
+ "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/lock": "^6.4|^7.0",
+ "symfony/messenger": "^6.4|^7.0",
+ "symfony/process": "^6.4|^7.0",
+ "symfony/stopwatch": "^6.4|^7.0",
+ "symfony/var-dumper": "^6.4|^7.0"
},
"type": "library",
"autoload": {
@@ -2500,7 +2503,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v6.3.4"
+ "source": "https://github.com/symfony/console/tree/v7.0.2"
},
"funding": [
{
@@ -2516,11 +2519,11 @@
"type": "tidelift"
}
],
- "time": "2023-08-16T10:10:12+00:00"
+ "time": "2023-12-10T16:54:46+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.3.0",
+ "version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
@@ -2567,7 +2570,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
},
"funding": [
{
@@ -2587,20 +2590,20 @@
},
{
"name": "symfony/filesystem",
- "version": "v6.3.1",
+ "version": "v7.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae"
+ "reference": "7da8ea2362a283771478c5f7729cfcb43a76b8b7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae",
- "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/7da8ea2362a283771478c5f7729cfcb43a76b8b7",
+ "reference": "7da8ea2362a283771478c5f7729cfcb43a76b8b7",
"shasum": ""
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8"
},
@@ -2630,7 +2633,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v6.3.1"
+ "source": "https://github.com/symfony/filesystem/tree/v7.0.0"
},
"funding": [
{
@@ -2646,27 +2649,27 @@
"type": "tidelift"
}
],
- "time": "2023-06-01T08:30:39+00:00"
+ "time": "2023-07-27T06:33:22+00:00"
},
{
"name": "symfony/finder",
- "version": "v6.3.5",
+ "version": "v7.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4"
+ "reference": "6e5688d69f7cfc4ed4a511e96007e06c2d34ce56"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/a1b31d88c0e998168ca7792f222cbecee47428c4",
- "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/6e5688d69f7cfc4ed4a511e96007e06c2d34ce56",
+ "reference": "6e5688d69f7cfc4ed4a511e96007e06c2d34ce56",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.2"
},
"require-dev": {
- "symfony/filesystem": "^6.0"
+ "symfony/filesystem": "^6.4|^7.0"
},
"type": "library",
"autoload": {
@@ -2694,7 +2697,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v6.3.5"
+ "source": "https://github.com/symfony/finder/tree/v7.0.0"
},
"funding": [
{
@@ -2710,24 +2713,24 @@
"type": "tidelift"
}
],
- "time": "2023-09-26T12:56:25+00:00"
+ "time": "2023-10-31T17:59:56+00:00"
},
{
"name": "symfony/options-resolver",
- "version": "v6.3.0",
+ "version": "v7.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
- "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd"
+ "reference": "700ff4096e346f54cb628ea650767c8130f1001f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a10f19f5198d589d5c33333cffe98dc9820332dd",
- "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/700ff4096e346f54cb628ea650767c8130f1001f",
+ "reference": "700ff4096e346f54cb628ea650767c8130f1001f",
"shasum": ""
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3"
},
"type": "library",
@@ -2761,7 +2764,7 @@
"options"
],
"support": {
- "source": "https://github.com/symfony/options-resolver/tree/v6.3.0"
+ "source": "https://github.com/symfony/options-resolver/tree/v7.0.0"
},
"funding": [
{
@@ -2777,7 +2780,7 @@
"type": "tidelift"
}
],
- "time": "2023-05-12T14:21:09+00:00"
+ "time": "2023-08-08T10:20:21+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -3111,20 +3114,20 @@
},
{
"name": "symfony/process",
- "version": "v6.3.4",
+ "version": "v7.0.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54"
+ "reference": "acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/0b5c29118f2e980d455d2e34a5659f4579847c54",
- "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54",
+ "url": "https://api.github.com/repos/symfony/process/zipball/acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a",
+ "reference": "acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.2"
},
"type": "library",
"autoload": {
@@ -3152,7 +3155,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v6.3.4"
+ "source": "https://github.com/symfony/process/tree/v7.0.2"
},
"funding": [
{
@@ -3168,25 +3171,25 @@
"type": "tidelift"
}
],
- "time": "2023-08-07T10:39:22+00:00"
+ "time": "2023-12-24T09:15:37+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v3.3.0",
+ "version": "v3.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4"
+ "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4",
- "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0",
+ "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0",
"shasum": ""
},
"require": {
"php": ">=8.1",
- "psr/container": "^2.0"
+ "psr/container": "^1.1|^2.0"
},
"conflict": {
"ext-psr": "<1.1|>=2"
@@ -3234,7 +3237,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.3.0"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.4.1"
},
"funding": [
{
@@ -3250,24 +3253,24 @@
"type": "tidelift"
}
],
- "time": "2023-05-23T14:45:45+00:00"
+ "time": "2023-12-26T14:02:43+00:00"
},
{
"name": "symfony/string",
- "version": "v6.3.5",
+ "version": "v7.0.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339"
+ "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/13d76d0fb049051ed12a04bef4f9de8715bea339",
- "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339",
+ "url": "https://api.github.com/repos/symfony/string/zipball/cc78f14f91f5e53b42044d0620961c48028ff9f5",
+ "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5",
"shasum": ""
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-grapheme": "~1.0",
"symfony/polyfill-intl-normalizer": "~1.0",
@@ -3277,11 +3280,11 @@
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/error-handler": "^5.4|^6.0",
- "symfony/http-client": "^5.4|^6.0",
- "symfony/intl": "^6.2",
+ "symfony/error-handler": "^6.4|^7.0",
+ "symfony/http-client": "^6.4|^7.0",
+ "symfony/intl": "^6.4|^7.0",
"symfony/translation-contracts": "^2.5|^3.0",
- "symfony/var-exporter": "^5.4|^6.0"
+ "symfony/var-exporter": "^6.4|^7.0"
},
"type": "library",
"autoload": {
@@ -3320,7 +3323,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v6.3.5"
+ "source": "https://github.com/symfony/string/tree/v7.0.2"
},
"funding": [
{
@@ -3336,7 +3339,7 @@
"type": "tidelift"
}
],
- "time": "2023-09-18T10:38:32+00:00"
+ "time": "2023-12-10T16:54:46+00:00"
},
{
"name": "theseer/tokenizer",
@@ -3448,5 +3451,5 @@
"ext-swoole": "*"
},
"platform-dev": [],
- "plugin-api-version": "2.3.0"
+ "plugin-api-version": "2.6.0"
}
diff --git a/src/Http/Adapter/FPM/Request.php b/src/Http/Adapter/FPM/Request.php
index 957509da..ecabb457 100644
--- a/src/Http/Adapter/FPM/Request.php
+++ b/src/Http/Adapter/FPM/Request.php
@@ -352,7 +352,7 @@ protected function generateHeaders(): array
* Fallback for older PHP versions
* that do not support generateHeaders
*/
- if (! \function_exists('getallheaders')) {
+ if (!\function_exists('getallheaders')) {
$headers = [];
foreach ($_SERVER as $name => $value) {
diff --git a/src/Http/Adapter/FPM/Response.php b/src/Http/Adapter/FPM/Response.php
index 9d4dfc09..88c47716 100644
--- a/src/Http/Adapter/FPM/Response.php
+++ b/src/Http/Adapter/FPM/Response.php
@@ -29,7 +29,7 @@ protected function write(string $content): void
*/
protected function end(string $content = null): void
{
- if (! is_null($content)) {
+ if (!is_null($content)) {
echo $content;
}
}
diff --git a/src/Http/Files.php b/src/Http/Files.php
index 93a2410b..5ecd353f 100644
--- a/src/Http/Files.php
+++ b/src/Http/Files.php
@@ -85,7 +85,7 @@ public function getCount(): int
*/
public function load(string $directory, string $root = null): void
{
- if (! is_readable($directory)) {
+ if (!is_readable($directory)) {
throw new Exception("Failed to load directory: {$directory}");
}
@@ -145,7 +145,7 @@ public function load(string $directory, string $root = null): void
*/
public function isFileLoaded(string $uri): bool
{
- if (! array_key_exists($uri, $this->loaded)) {
+ if (!array_key_exists($uri, $this->loaded)) {
return false;
}
@@ -162,7 +162,7 @@ public function isFileLoaded(string $uri): bool
*/
public function getFileContents(string $uri): mixed
{
- if (! array_key_exists($uri, $this->loaded)) {
+ if (!array_key_exists($uri, $this->loaded)) {
throw new Exception('File not found or not loaded: '.$uri);
}
@@ -179,7 +179,7 @@ public function getFileContents(string $uri): mixed
*/
public function getFileMimeType(string $uri): mixed
{
- if (! array_key_exists($uri, $this->loaded)) {
+ if (!array_key_exists($uri, $this->loaded)) {
throw new Exception('File not found or not loaded: '.$uri);
}
diff --git a/src/Http/Validator/Multiple.php b/src/Http/Validator/Multiple.php
index bcc9205d..4c919377 100644
--- a/src/Http/Validator/Multiple.php
+++ b/src/Http/Validator/Multiple.php
@@ -1,8 +1,8 @@
assertFalse(App::getAllowOverride());
- App::get('/')->action(function () {
+ Http::setAllowOverride(false);
+ $this->assertFalse(Http::getAllowOverride());
+ Http::get('/')->action(function () {
echo 'Hello first';
});
try {
- App::get('/')->action(function () {
+ Http::get('/')->action(function () {
echo 'Hello second';
});
$this->fail('Failed to throw exception');
@@ -338,13 +338,13 @@ public function testAllowRouteOverrides()
}
// Test success
- App::setAllowOverride(true);
- $this->assertTrue(App::getAllowOverride());
- App::get('/')->action(function () {
+ Http::setAllowOverride(true);
+ $this->assertTrue(Http::getAllowOverride());
+ Http::get('/')->action(function () {
echo 'Hello first';
});
- App::get('/')->action(function () {
+ Http::get('/')->action(function () {
echo 'Hello second';
});
}
diff --git a/tests/Validator/MultipleTest.php b/tests/Validator/MultipleTest.php
index 8ef1ee59..348c3244 100644
--- a/tests/Validator/MultipleTest.php
+++ b/tests/Validator/MultipleTest.php
@@ -1,6 +1,6 @@
Date: Wed, 3 Jan 2024 10:19:54 +0000
Subject: [PATCH 070/119] Update README
---
CONTRIBUTING.md | 6 ++
README.md | 233 ++++++++++++++++++++++++++++++------------------
2 files changed, 153 insertions(+), 86 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7cc480d1..4701ba07 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -64,6 +64,12 @@ $ git push origin [name_of_your_new_branch]
8. After approval, merge your PR
9. GitHub will automatically delete the branch after the merge is done. (they can still be restored).
+### Testing
+
+- `docker-compose up -d`
+- `docker-compose exec web vendor/bin/phpunit --configuration phpunit.xml`
+- `docker-compose exec web vendor/bin/psalm --show-info=true`
+
## Introducing New Features
We would 💖 you to contribute to Framework, but we would also like to make sure Framework is as great as possible and loyal to its vision and mission statement 🙏.
diff --git a/README.md b/README.md
index c88a094c..a00d1fc1 100644
--- a/README.md
+++ b/README.md
@@ -17,9 +17,12 @@ Install using composer:
composer require utopia-php/framework
```
-Init your first application:
+Init your first application in `src/server.php`:
+
```php
-require_once __DIR__ . '/../../vendor/autoload.php';
+inject('request')
->inject('response')
->action(
- function($request, $response) {
+ function(Request $request, Response $response) {
$response
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
->addHeader('Expires', '0')
@@ -39,126 +42,206 @@ Http::get('/hello-world') // Define Route
}
);
-Http::setMode(Http::MODE_TYPE_PRODUCTION); // Define Mode
+Http::setMode(Http::MODE_TYPE_PRODUCTION);
+
+$http = new Http(new Server(), 'America/New_York');
+$http->start();
+```
+
+Run HTTP server:
+
+```bash
+php -S localhost:8000 src/server2.php
+```
+
+Send HTTP request:
-$http = new Http(new Server(), 'America/New_York');
-$http->run();
+```
+curl http://localhost:8000/hello-world
```
### Server Adapters
-Library now supports server adapters and currently there are two servers implemented. You can use the PHP FPM server or the swoole server.
+Library supports server adapters to be able to run on any PHP setup. For instance, you could use FPM server, or the Swoole server.
**Use PHP FPM server**
```php
-require_once __DIR__ . '/../../vendor/autoload.php';
-
use Utopia\Http\Http;
-use Utopia\Http\Adapter\FPM\Request;
-use Utopia\Http\Adapter\FPM\Response;
+use Utopia\Http\Response;
use Utopia\Http\Adapter\FPM\Server;
-Http::get('/hello-world') // Define Route
- ->inject('request')
+Http::get('/')
->inject('response')
->action(
- function($request, $response) {
- $response
- ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
- ->addHeader('Expires', '0')
- ->addHeader('Pragma', 'no-cache')
- ->json(['Hello' => 'World']);
+ function(Response $response) {
+ $response->send('Hello from PHP FPM');
}
);
-Http::setMode(Http::MODE_TYPE_PRODUCTION); // Define Mode
-
-$http = new Http(new Server(), 'America/New_York');
-$http->run(new Request(), new Response());
+$http = new Http(new Server(), 'America/New_York');
+$http->start();
```
-**Using swoole server**
+**Using Swoole server**
```php
-require_once __DIR__ . '/../../vendor/autoload.php';
-
use Utopia\Http\Http;
-use Utopia\Http\Adapter\Swoole\Request;
-use Utopia\Http\Adapter\Swoole\Response;
+use Utopia\Http\Request;
+use Utopia\Http\Response;
use Utopia\Http\Adapter\Swoole\Server;
+use function Swoole\Coroutine\run;
-Http::get('/hello-world') // Define Route
+Http::get('/')
->inject('request')
->inject('response')
->action(
- function($request, $response) {
- $response
- ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
- ->addHeader('Expires', '0')
- ->addHeader('Pragma', 'no-cache')
- ->json(['Hello' => 'World']);
+ function(Request $request, Response $response) {
+ $response->send('Hello from Swoole');
}
);
-Http::setMode(Http::MODE_TYPE_PRODUCTION); // Define Mode
+$http = new Http(new Server('0.0.0.0', '80'), 'America/New_York');
+run(fn() => $http->start());
+```
+
+### Parameters
-$server = new Server('0.0.0.0', '80');
+Parameters are used to recieve input into endpoint action from the HTTP request. Parameters could be defined as URL parameters, or could be defined in body with structure such as JSON.
-$server->onRequest(function (Request $request, Response $response) use ($server) {
- $http = new Http($server, 'UTC');
- $http->run($request, $response);
-});
+Every parameter must have a validator defined. Validators are simple classes that verify the input and ensure security of inputs. You can define your own validators, or use some of [built-in validators](https://github.com/utopia-php/framework/tree/master/src/Validator).
+
+Define an endpoint with params:
+
+```php
+Http::get('/')
+ ->param('name', 'World', new Text(256), 'Name to greet. Optional, max length 256.', true)
+ ->inject('response')
+ ->action(function(string $name, Response $response) {
+ $response->send('Hello ' . $name);
+ });
+```
+
+Send HTTP requests to ensure parameter works:
-$server->start();
+```bash
+curl http://localhost:8000/hello-world
+curl http://localhost:8000/hello-world?name=Utopia
+curl http://localhost:8000/hello-world?name=Appwrite
```
+It's always recommended to use params instead of getting params or body directly from the request resource. If you do that intentionally, always ensure to run validation right after fetching such a raw input.
+
### Hooks
-There are three types of hooks, init hooks, shutdown hooks and error hooks. Init hooks are executed before the route action is executed. Shutdown hook is executed after route action is executed before application shuts down. Finally error hooks are executed whenever there's an error in the application lifecycle. You can provide multiple hooks for each stage. If you do not assign groups to the hook, by default the hook will be executed for every route.
+There are three types of hooks:
-```php
-require_once __DIR__ . '/../../vendor/autoload.php';
+- **Init hooks** are executed before the route action is executed
+- **Shutdown hooks** are executed after route action is finished, but before application shuts down
+- **Error hooks** are executed whenever there's an error in the application lifecycle.
-use Utopia\Http\Http;
-use Utopia\Http\Request;
-use Utopia\Http\Response;
-use Utopia\Http\Adapter\FPM\Server;
+You can provide multiple hooks for each stage. If you do not assign groups to the hook, by default the hook will be executed for every route. If a group is defined on a hook, it will only run during lifecycle of a request with the same group name on the action.
+```php
Http::init()
+ ->inject('request')
+ ->action(function(Request $request) {
+ \var_dump("Recieved: " . $request->getMethod() . ' ' . $request->getURI());
+ });
+
+Http::shutdown()
->inject('response')
- ->action(function($response) {
- $response->addHeader('content-type', 'application/json');
+ ->action(function(Response $response) {
+ \var_dump('Responding with status code: ' . $response->getStatusCode());
});
Http::error()
->inject('error')
->inject('response')
- ->action(function($error, $response) {
+ ->action(function(\Throwable $error, Response $response) {
$response
->setStatusCode(500)
->send('Error occurred ' . $error);
});
+```
-Http::get('/hello-world') // Define Route
- ->inject('request')
+Hooks are designed to be actions ran during lifecycle of requests. Hooks should include functional logic. Hooks are not designed to prepare dependencies or context for the request. For such use case you should use resources.
+
+### Groups
+
+Groups allow you to define common behaviour for multiple endpoints.
+
+You can start by defining a group on an endpoint. Keep in mind you can also define multiple groups on a single endpoint.
+
+```php
+Http::get('/v1/health')
+ ->groups(['api', 'public'])
->inject('response')
->action(
- function($request, $response) {
- $response
- ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
- ->addHeader('Expires', '0')
- ->addHeader('Pragma', 'no-cache')
- ->json(['Hello' => 'World']);
+ function(Response $response) {
+ $response->send('OK');
}
);
+```
+
+Now you can define hooks that would apply only to specific groups. Remember, hooks can also be assigned to multiple groups.
-Http::setMode(Http::MODE_TYPE_PRODUCTION); // Define Mode
+```php
+Http::init()
+ ->groups(['api'])
+ ->inject('request')
+ ->inject('response')
+ ->action(function(Request $request, Response $response) {
+ $apiKey = $request->getHeader('x-api-key', '');
-$http = new Http(new Server(), 'America/New_York');
-$http->run();
+ if(empty($apiKey)) {
+ $response
+ ->setStatusCode(Response::STATUS_CODE_UNAUTHORIZED)
+ ->send('API key missing.');
+ }
+ });
```
+Groups are designed to be actions ran during lifecycle of requests to endpoints that got some logic incommon. Groups allow you to prevent code duplication, and are designed to be defined anywhere in your source code to allow flexibility.
+
+### Resources
+
+Resources allows you to prepare dependencies for requests such as database connection or user which sent the request. A new instance of a resource is created for every request.
+
+Define a resource:
+
+```php
+Http::setResource('timing', function() {
+ return \microtime(true);
+});
+```
+
+Inject resource into endpoint action:
+
+```php
+Http::get('/')
+ ->inject('timing')
+ ->inject('response')
+ ->action(function(float $timing, Response $response) {
+ $response->send('Request Unix timestamp: ' . \strval($timing));
+ });
+```
+
+Inject resource into hook:
+
+```php
+Http::shutdown()
+ ->inject('timing')
+ ->action(function(float $timing) {
+ $difference = \microtime(true) - $timing;
+ \var_dump("Request took: " . $difference . " seconds");
+ });
+```
+
+In advanced scenarios, resources can also be injected into other resources or endpoint params.
+
+Resources are designed to prepare dependencies or context for the request. Resources are not meant to do functional logic or return callbacks. For such use case you should use hooks.
+
## System Requirements
Utopia Framework requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible.
@@ -169,23 +252,7 @@ Our ecosystem support other thin PHP projects aiming to extend the core PHP Utop
Each project is focused on solving a single, very simple problem and you can use composer to include any of them in your next project.
-Library | Description
---- | ---
-**[Utopia AB](https://github.com/utopia-php/ab)** | Simple PHP library for managing AB testing on the server side.
-**[Utopia Abuse](https://github.com/utopia-php/abuse)** | Simple PHP library for rate limiting usage of different features in your app or API.
-**[Utopia Analytics](https://github.com/utopia-php/analytics)** | Simple PHP library to send information about events or pageviews to Google Analytics.
-**[Utopia Audit](https://github.com/utopia-php/audit)** | Simple PHP library for audit logging users actions and system events
-**[Utopia Cache](https://github.com/utopia-php/cache)** | Simple PHP library for managing cache with different storage adapters.
-**[Utopia CLI](https://github.com/utopia-php/cli)** | Simple PHP library for for building simple command line tools.
-**[Utopia Config](https://github.com/utopia-php/config)** | Simple PHP library for managing your app configuration.
-**[Utopia Database](https://github.com/utopia-php/database)** | Simple PHP library for managing application persistency. It supports multiple database adapters.
-**[Utopia Domains](https://github.com/utopia-php/domains)** | Simple PHP library for parsing domain names.
-**[Utopia Image](https://github.com/utopia-php/image)** | Simple PHP library for creating common image manipulations that is easy to use.
-**[Utopia Locale](https://github.com/utopia-php/locale)** | Simple PHP library for adding support to multiple locales in your app or API.
-**[Utopia Preloader](https://github.com/utopia-php/preloader)** | Simple PHP library for managing PHP preloading configuration.
-**[Utopia Registry](https://github.com/utopia-php/registry)** | Simple PHP library for dependency injection and lazy loading of objects or resources.
-**[Utopia System](https://github.com/utopia-php/system)** | Simple PHP library for obtaining information about the host's system.
-**[Utopia Storage](https://github.com/utopia-php/storage)** | Simple and lite PHP library for managing application storage. It supports multiple storage adapters.
+You can find all libraries in [GitHub Utopia organization](https://github.com/utopia-php).
## Contributing
@@ -197,12 +264,6 @@ You can refer to the [Contributing Guide](https://github.com/utopia-php/framewor
For security issues, please email security@appwrite.io instead of posting a public issue in GitHub.
-### Testing
-
- - `docker-compose up -d`
- - `docker-compose exec web vendor/bin/phpunit --configuration phpunit.xml`
- - `docker-compose exec web vendor/bin/psalm --show-info=true`
-
## Copyright and license
The MIT License (MIT) [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php)
From 8dfe731ac984e56c67ed185fd41ccbc3937c67ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 3 Jan 2024 10:24:26 +0000
Subject: [PATCH 071/119] Auto-add context to swoole
---
src/Http/Adapter/Swoole/Server.php | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index b13a522d..8423fade 100755
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -9,6 +9,8 @@
use Swoole\Http\Response as SwooleResponse;
use Utopia\Http\Http;
+use function Swoole\Coroutine\run;
+
class Server extends Adapter
{
protected SwooleServer $server;
@@ -53,6 +55,10 @@ public function onStart(callable $callback)
public function start()
{
- $this->server->start();
+ if(Coroutine::getCid() === -1) {
+ run(fn () => $this->server->start());
+ } else {
+ $this->server->start();
+ }
}
}
From 6cd323224e2504b9498cf07206e1fb91e201c22c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 3 Jan 2024 10:25:20 +0000
Subject: [PATCH 072/119] Update swoole README
---
README.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/README.md b/README.md
index a00d1fc1..c394a271 100644
--- a/README.md
+++ b/README.md
@@ -90,7 +90,6 @@ use Utopia\Http\Http;
use Utopia\Http\Request;
use Utopia\Http\Response;
use Utopia\Http\Adapter\Swoole\Server;
-use function Swoole\Coroutine\run;
Http::get('/')
->inject('request')
@@ -102,7 +101,7 @@ Http::get('/')
);
$http = new Http(new Server('0.0.0.0', '80'), 'America/New_York');
-run(fn() => $http->start());
+$http->start();
```
### Parameters
From ceae30ff3ab0ac45b07a2281b8fa6275d5e51164 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 3 Jan 2024 10:33:05 +0000
Subject: [PATCH 073/119] Improve readme, add example
---
README.md | 12 +++++++-----
example/.gitignore | 1 +
example/Dockerfile | 12 ++++++++++++
example/composer.json | 6 ++++++
example/docker-compose.yml | 10 ++++++++++
example/src/server.php | 18 ++++++++++++++++++
6 files changed, 54 insertions(+), 5 deletions(-)
create mode 100644 example/.gitignore
create mode 100644 example/Dockerfile
create mode 100644 example/composer.json
create mode 100644 example/docker-compose.yml
create mode 100644 example/src/server.php
diff --git a/README.md b/README.md
index c394a271..b7d8cdcd 100644
--- a/README.md
+++ b/README.md
@@ -20,8 +20,6 @@ composer require utopia-php/framework
Init your first application in `src/server.php`:
```php
-start();
```
-**Using Swoole server**
+> When using PHP FPM, you can use command `php -S localhost:80 src/server.php` to run HTTP server locally
+
+#### Using Swoole server
```php
use Utopia\Http\Http;
@@ -104,6 +104,8 @@ $http = new Http(new Server('0.0.0.0', '80'), 'America/New_York');
$http->start();
```
+> When using Swoole, you can use command `php src/server.php` to run HTTP server locally, but you need Swoole installed. For setup with Docker, check out our [example application](/example)
+
### Parameters
Parameters are used to recieve input into endpoint action from the HTTP request. Parameters could be defined as URL parameters, or could be defined in body with structure such as JSON.
diff --git a/example/.gitignore b/example/.gitignore
new file mode 100644
index 00000000..5657f6ea
--- /dev/null
+++ b/example/.gitignore
@@ -0,0 +1 @@
+vendor
\ No newline at end of file
diff --git a/example/Dockerfile b/example/Dockerfile
new file mode 100644
index 00000000..3abcbeed
--- /dev/null
+++ b/example/Dockerfile
@@ -0,0 +1,12 @@
+FROM composer:2.0 AS step0
+WORKDIR /usr/local/src/
+COPY composer.* /usr/local/src/
+RUN composer install --ignore-platform-reqs --optimize-autoloader --no-plugins --no-scripts --prefer-dist
+
+FROM appwrite/base:0.4.3 as final
+WORKDIR /usr/src/code
+COPY ./src /usr/src/code/src
+COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor
+
+EXPOSE 80
+CMD ["php", "src/server.php"]
diff --git a/example/composer.json b/example/composer.json
new file mode 100644
index 00000000..999df3c0
--- /dev/null
+++ b/example/composer.json
@@ -0,0 +1,6 @@
+{
+ "name": "utopia-php/http-app",
+ "require": {
+ "utopia-php/framework": "0.33.*"
+ }
+}
\ No newline at end of file
diff --git a/example/docker-compose.yml b/example/docker-compose.yml
new file mode 100644
index 00000000..6733d969
--- /dev/null
+++ b/example/docker-compose.yml
@@ -0,0 +1,10 @@
+version: '3'
+
+services:
+ server:
+ build:
+ context: .
+ ports:
+ - "80:80"
+ volumes:
+ - ./src:/usr/src/code/src
\ No newline at end of file
diff --git a/example/src/server.php b/example/src/server.php
new file mode 100644
index 00000000..b00f2b3e
--- /dev/null
+++ b/example/src/server.php
@@ -0,0 +1,18 @@
+param('name', 'World', new Text(256), 'Name to greet. Optional, max length 256.', true)
+ ->inject('response')
+ ->action(function(string $name, Response $response) {
+ $response->send('Hello ' . $name);
+ });
+
+$http = new Http(new Server('0.0.0.0', '80'), 'America/New_York');
+$http->start();
From 3ba0cd1cf3ff0ddb6f0bf8084234c0c876903534 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 3 Jan 2024 11:37:21 +0100
Subject: [PATCH 074/119] Grammar fixes
---
README.md | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/README.md b/README.md
index b7d8cdcd..319a8b95 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
Utopia Framework is a PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. This library is maintained by the [Appwrite team](https://appwrite.io).
-Utopia Framework is dependency free. Any extra features such as authentication, caching will be available as standalone models in order to keep the framework core as clean, light and easy to learn.
+Utopia Framework is dependency-free. Any extra features, such as authentication or caching, will be available as standalone models in order to keep the framework core clean, light, and easy to learn.
## Getting Started
@@ -60,7 +60,7 @@ curl http://localhost:8000/hello-world
### Server Adapters
-Library supports server adapters to be able to run on any PHP setup. For instance, you could use FPM server, or the Swoole server.
+The library supports server adapters to be able to run on any PHP setup. For instance, you could use the FPM server or the Swoole server.
#### Use PHP FPM server
@@ -81,7 +81,7 @@ $http = new Http(new Server(), 'America/New_York');
$http->start();
```
-> When using PHP FPM, you can use command `php -S localhost:80 src/server.php` to run HTTP server locally
+> When using PHP FPM, you can use the command `php -S localhost:80 src/server.php` to run the HTTP server locally
#### Using Swoole server
@@ -104,13 +104,13 @@ $http = new Http(new Server('0.0.0.0', '80'), 'America/New_York');
$http->start();
```
-> When using Swoole, you can use command `php src/server.php` to run HTTP server locally, but you need Swoole installed. For setup with Docker, check out our [example application](/example)
+> When using Swoole, you can use the command `php src/server.php` to run the HTTP server locally, but you need Swoole installed. For setup with Docker, check out our [example application](/example)
### Parameters
-Parameters are used to recieve input into endpoint action from the HTTP request. Parameters could be defined as URL parameters, or could be defined in body with structure such as JSON.
+Parameters are used to receive input into endpoint action from the HTTP request. Parameters could be defined as URL parameters or in a body with a structure such as JSON.
-Every parameter must have a validator defined. Validators are simple classes that verify the input and ensure security of inputs. You can define your own validators, or use some of [built-in validators](https://github.com/utopia-php/framework/tree/master/src/Validator).
+Every parameter must have a validator defined. Validators are simple classes that verify the input and ensure the security of inputs. You can define your own validators or use some of [built-in validators](https://github.com/utopia-php/framework/tree/master/src/Validator).
Define an endpoint with params:
@@ -123,7 +123,7 @@ Http::get('/')
});
```
-Send HTTP requests to ensure parameter works:
+Send HTTP requests to ensure the parameter works:
```bash
curl http://localhost:8000/hello-world
@@ -131,7 +131,7 @@ curl http://localhost:8000/hello-world?name=Utopia
curl http://localhost:8000/hello-world?name=Appwrite
```
-It's always recommended to use params instead of getting params or body directly from the request resource. If you do that intentionally, always ensure to run validation right after fetching such a raw input.
+It's always recommended to use params instead of getting params or body directly from the request resource. If you do that intentionally, always make sure to run validation right after fetching such a raw input.
### Hooks
@@ -141,7 +141,7 @@ There are three types of hooks:
- **Shutdown hooks** are executed after route action is finished, but before application shuts down
- **Error hooks** are executed whenever there's an error in the application lifecycle.
-You can provide multiple hooks for each stage. If you do not assign groups to the hook, by default the hook will be executed for every route. If a group is defined on a hook, it will only run during lifecycle of a request with the same group name on the action.
+You can provide multiple hooks for each stage. If you do not assign groups to the hook, by default, the hook will be executed for every route. If a group is defined on a hook, it will only run during the lifecycle of a request with the same group name on the action.
```php
Http::init()
@@ -166,11 +166,11 @@ Http::error()
});
```
-Hooks are designed to be actions ran during lifecycle of requests. Hooks should include functional logic. Hooks are not designed to prepare dependencies or context for the request. For such use case you should use resources.
+Hooks are designed to be actions that run during the lifecycle of requests. Hooks should include functional logic. Hooks are not designed to prepare dependencies or context for the request. For such a use case, you should use resources.
### Groups
-Groups allow you to define common behaviour for multiple endpoints.
+Groups allow you to define common behavior for multiple endpoints.
You can start by defining a group on an endpoint. Keep in mind you can also define multiple groups on a single endpoint.
@@ -203,11 +203,11 @@ Http::init()
});
```
-Groups are designed to be actions ran during lifecycle of requests to endpoints that got some logic incommon. Groups allow you to prevent code duplication, and are designed to be defined anywhere in your source code to allow flexibility.
+Groups are designed to be actions that run during the lifecycle of requests to endpoints that have some logic in common. Groups allow you to prevent code duplication and are designed to be defined anywhere in your source code to allow flexibility.
### Resources
-Resources allows you to prepare dependencies for requests such as database connection or user which sent the request. A new instance of a resource is created for every request.
+Resources allow you to prepare dependencies for requests such as database connection or the user who sent the request. A new instance of a resource is created for every request.
Define a resource:
@@ -228,7 +228,7 @@ Http::get('/')
});
```
-Inject resource into hook:
+Inject resource into a hook:
```php
Http::shutdown()
@@ -239,9 +239,9 @@ Http::shutdown()
});
```
-In advanced scenarios, resources can also be injected into other resources or endpoint params.
+In advanced scenarios, resources can also be injected into other resources or endpoint parameters.
-Resources are designed to prepare dependencies or context for the request. Resources are not meant to do functional logic or return callbacks. For such use case you should use hooks.
+Resources are designed to prepare dependencies or context for the request. Resources are not meant to do functional logic or return callbacks. For such a use case, you should use hooks.
## System Requirements
@@ -249,7 +249,7 @@ Utopia Framework requires PHP 8.0 or later. We recommend using the latest PHP ve
## More from Utopia
-Our ecosystem support other thin PHP projects aiming to extend the core PHP Utopia framework.
+Our ecosystem supports other thin PHP projects aiming to extend the core PHP Utopia framework.
Each project is focused on solving a single, very simple problem and you can use composer to include any of them in your next project.
From ecf9791295183b46fe30c9507c893ec0404bcb52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 3 Jan 2024 11:41:23 +0100
Subject: [PATCH 075/119] Update README.md
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 319a8b95..f0e7501b 100644
--- a/README.md
+++ b/README.md
@@ -243,6 +243,8 @@ In advanced scenarios, resources can also be injected into other resources or en
Resources are designed to prepare dependencies or context for the request. Resources are not meant to do functional logic or return callbacks. For such a use case, you should use hooks.
+To learn more about Framework architecture and features, check out more in-depth [Getting started guide](/docs/Getting-Starting-Guide.md).
+
## System Requirements
Utopia Framework requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible.
From 569428c020d766092a700fd9b17c4b0f9c422308 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 3 Jan 2024 11:42:13 +0100
Subject: [PATCH 076/119] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f0e7501b..fe37a60e 100644
--- a/README.md
+++ b/README.md
@@ -110,7 +110,7 @@ $http->start();
Parameters are used to receive input into endpoint action from the HTTP request. Parameters could be defined as URL parameters or in a body with a structure such as JSON.
-Every parameter must have a validator defined. Validators are simple classes that verify the input and ensure the security of inputs. You can define your own validators or use some of [built-in validators](https://github.com/utopia-php/framework/tree/master/src/Validator).
+Every parameter must have a validator defined. Validators are simple classes that verify the input and ensure the security of inputs. You can define your own validators or use some of [built-in validators](/src/Http/Validator).
Define an endpoint with params:
From f5e2ac03c824fd471f9f44a2e34c96b82d1f9379 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 3 Jan 2024 10:46:01 +0000
Subject: [PATCH 077/119] Add fpm resources
---
src/Http/Adapter/FPM/Server.php | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/Http/Adapter/FPM/Server.php b/src/Http/Adapter/FPM/Server.php
index e5d2cf3d..de5eb0c9 100644
--- a/src/Http/Adapter/FPM/Server.php
+++ b/src/Http/Adapter/FPM/Server.php
@@ -3,6 +3,7 @@
namespace Utopia\Http\Adapter\FPM;
use Utopia\Http\Adapter;
+use Utopia\Http\Http;
class Server extends Adapter
{
@@ -12,7 +13,13 @@ public function __construct()
public function onRequest(callable $callback)
{
- call_user_func($callback, new Request(), new Response(), 'fpm');
+ $request = new Request();
+ $response = new Response();
+
+ Http::setResource('fpmRequest', fn () => $request);
+ Http::setResource('fpmResponse', fn () => $response);
+
+ call_user_func($callback, $request, $response, 'fpm');
}
public function onStart(callable $callback)
From 8ef54825075334a912369c724773631d46a2e687 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 3 Jan 2024 10:46:25 +0000
Subject: [PATCH 078/119] Fix formatting
---
example/src/server.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/example/src/server.php b/example/src/server.php
index b00f2b3e..4eb07f71 100644
--- a/example/src/server.php
+++ b/example/src/server.php
@@ -10,7 +10,7 @@
Http::get('/')
->param('name', 'World', new Text(256), 'Name to greet. Optional, max length 256.', true)
->inject('response')
- ->action(function(string $name, Response $response) {
+ ->action(function (string $name, Response $response) {
$response->send('Hello ' . $name);
});
From d8ef76a5deb6dece0be25757931c4023f0f8fd99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Thu, 4 Jan 2024 11:01:50 +0000
Subject: [PATCH 079/119] PR review changes
---
Dockerfile.swoole | 2 +-
src/Http/Adapter/FPM/Server.php | 2 +-
src/Http/Adapter/Swoole/Server.php | 2 +-
tests/docker/nginx.conf | 6 +++---
tests/e2e/{server_fpm.php => server-fpm.php} | 0
tests/e2e/{server_swoole.php => server-swoole.php} | 0
6 files changed, 6 insertions(+), 6 deletions(-)
rename tests/e2e/{server_fpm.php => server-fpm.php} (100%)
rename tests/e2e/{server_swoole.php => server-swoole.php} (100%)
diff --git a/Dockerfile.swoole b/Dockerfile.swoole
index 58cb3a24..6e0fdba1 100644
--- a/Dockerfile.swoole
+++ b/Dockerfile.swoole
@@ -26,4 +26,4 @@ COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor
EXPOSE 80
-CMD ["php", "tests/e2e/server_swoole.php"]
+CMD ["php", "tests/e2e/server-swoole.php"]
diff --git a/src/Http/Adapter/FPM/Server.php b/src/Http/Adapter/FPM/Server.php
index de5eb0c9..7aeb06bb 100644
--- a/src/Http/Adapter/FPM/Server.php
+++ b/src/Http/Adapter/FPM/Server.php
@@ -29,7 +29,7 @@ public function onStart(callable $callback)
public function onWorkerStart(callable $callback)
{
- return;
+ call_user_func($callback, $this);
}
public function start()
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index 8423fade..f2fa6ef5 100755
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -45,7 +45,7 @@ public function onRequest(callable $callback)
public function onWorkerStart(callable $callback)
{
- return;
+ call_user_func($callback, $this);
}
public function onStart(callable $callback)
diff --git a/tests/docker/nginx.conf b/tests/docker/nginx.conf
index 54fdf4ae..f38e0e60 100644
--- a/tests/docker/nginx.conf
+++ b/tests/docker/nginx.conf
@@ -33,7 +33,7 @@ http {
listen [::]:80 ipv6only=on; ## listen for ipv6
root /usr/share/nginx/html/tests/e2e;
- index index.php server_fpm.php index.html index.htm;
+ index index.php server-fpm.php index.html index.htm;
server_tokens off;
@@ -53,7 +53,7 @@ http {
location / {
# First attempt to serve request as file, then
# as directory, then fall back to index.html
- try_files $uri $uri/ /server_fpm.php?q=$uri&$args;
+ try_files $uri $uri/ /server-fpm.php?q=$uri&$args;
}
@@ -74,7 +74,7 @@ http {
fastcgi_param HTTP_IF_NONE_MATCH $http_if_none_match;
fastcgi_param HTTP_IF_MODIFIED_SINCE $http_if_modified_since;
fastcgi_read_timeout 600;
- fastcgi_index server_fpm.php;
+ fastcgi_index server-fpm.php;
include fastcgi_params;
}
diff --git a/tests/e2e/server_fpm.php b/tests/e2e/server-fpm.php
similarity index 100%
rename from tests/e2e/server_fpm.php
rename to tests/e2e/server-fpm.php
diff --git a/tests/e2e/server_swoole.php b/tests/e2e/server-swoole.php
similarity index 100%
rename from tests/e2e/server_swoole.php
rename to tests/e2e/server-swoole.php
From d5e2929a62c754f58f6676f8ce9731c2e4b236d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Thu, 4 Jan 2024 11:03:12 +0000
Subject: [PATCH 080/119] Improve swoole constructor
---
src/Http/Adapter/Swoole/Server.php | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index f2fa6ef5..1c2cde72 100755
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -15,20 +15,12 @@ class Server extends Adapter
{
protected SwooleServer $server;
- public function __construct(string $host, string $port = null)
+ public function __construct(string $host, string $port = null, array $settings = [])
{
$this->server = new SwooleServer($host, $port);
- $this->server->set([
+ $this->server->set(\array_merge($settings, [
'enable_coroutine' => true
- ]);
- }
-
- public function setConfig(array $configs)
- {
- $configs = array_merge($configs, [
- 'enable_coroutine' => true
- ]);
- $this->server->set($configs);
+ ]));
}
public function onRequest(callable $callback)
From ee4fc6deb6444dd893f6f947ffb2033c364bcf85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Thu, 4 Jan 2024 11:18:06 +0000
Subject: [PATCH 081/119] Remove worker concept
---
src/Http/Adapter.php | 1 -
src/Http/Adapter/FPM/Server.php | 5 ---
src/Http/Adapter/Swoole/Server.php | 5 ---
src/Http/Http.php | 49 ------------------------------
4 files changed, 60 deletions(-)
mode change 100644 => 100755 src/Http/Adapter.php
mode change 100644 => 100755 src/Http/Adapter/FPM/Server.php
diff --git a/src/Http/Adapter.php b/src/Http/Adapter.php
old mode 100644
new mode 100755
index c05f98f5..082ca6ab
--- a/src/Http/Adapter.php
+++ b/src/Http/Adapter.php
@@ -5,7 +5,6 @@
abstract class Adapter
{
abstract public function onStart(callable $callback);
- abstract public function onWorkerStart(callable $callback);
abstract public function onRequest(callable $callback);
abstract public function start();
}
diff --git a/src/Http/Adapter/FPM/Server.php b/src/Http/Adapter/FPM/Server.php
old mode 100644
new mode 100755
index 7aeb06bb..e90f0cd7
--- a/src/Http/Adapter/FPM/Server.php
+++ b/src/Http/Adapter/FPM/Server.php
@@ -27,11 +27,6 @@ public function onStart(callable $callback)
call_user_func($callback, $this);
}
- public function onWorkerStart(callable $callback)
- {
- call_user_func($callback, $this);
- }
-
public function start()
{
return;
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index 1c2cde72..9fe73e98 100755
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -35,11 +35,6 @@ public function onRequest(callable $callback)
});
}
- public function onWorkerStart(callable $callback)
- {
- call_user_func($callback, $this);
- }
-
public function onStart(callable $callback)
{
call_user_func($callback, $this);
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 5a770abf..c203462f 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -97,13 +97,6 @@ class Http
*/
protected static array $startHooks = [];
- /**
- * Worker Start hooks
- *
- * @var Hook[]
- */
- protected static array $workerStartHooks = [];
-
/**
* Request hooks
*
@@ -563,13 +556,6 @@ protected function getFileMimeType(string $uri): mixed
return $this->files->getFileMimeType($uri);
}
- public static function onWorkerStart(): Hook
- {
- $hook = new Hook();
- self::$workerStartHooks[] = $hook;
- return $hook;
- }
-
public static function onStart(): Hook
{
$hook = new Hook();
@@ -623,40 +609,6 @@ public function start()
}
});
- $this->server->onWorkerStart(function ($server, $workerId) {
- $this->resources['utopia'] ??= [];
- $this->resources['utopia']['server'] = $server;
- $this->resources['utopia']['workerId'] = $workerId;
-
- self::setResource('server', function () use ($server) {
- return $server;
- });
- self::setResource('workerId', function () use ($workerId) {
- return $workerId;
- });
-
- try {
-
- foreach (self::$workerStartHooks as $hook) {
- $arguments = $this->getArguments($hook, 'utopia', [], []);
- \call_user_func_array($hook->getAction(), $arguments);
- }
- } catch(\Exception $e) {
- self::setResource('error', fn () => $e);
-
- foreach (self::$errors as $error) { // Global error hooks
- if (in_array('*', $error->getGroups())) {
- try {
- $arguments = $this->getArguments($error, 'utopia', [], []);
- \call_user_func_array($error->getAction(), $arguments);
- } catch (\Throwable $e) {
- throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
- }
- }
- }
- }
- });
-
$this->server->start();
}
@@ -1004,7 +956,6 @@ public static function reset(): void
self::$init = [];
self::$shutdown = [];
self::$options = [];
- self::$workerStartHooks = [];
self::$startHooks = [];
}
}
From 9cfeb169ddce087ca6da5c7e8992a20febda7e28 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Thu, 4 Jan 2024 13:24:25 +0000
Subject: [PATCH 082/119] Wildcard host validator
---
src/Validator/Host.php | 8 +++++---
tests/Validator/HostTest.php | 6 +++++-
2 files changed, 10 insertions(+), 4 deletions(-)
mode change 100644 => 100755 src/Validator/Host.php
diff --git a/src/Validator/Host.php b/src/Validator/Host.php
old mode 100644
new mode 100755
index 1f7fb06c..77078b2c
--- a/src/Validator/Host.php
+++ b/src/Validator/Host.php
@@ -51,11 +51,13 @@ public function isValid($value): bool
return false;
}
- if (\in_array(\parse_url($value, PHP_URL_HOST), $this->whitelist)) {
- return true;
+ $hostnameValidator = new Hostname($this->whitelist);
+
+ if (!$hostnameValidator->isValid(\parse_url($value, PHP_URL_HOST))) {
+ return false;
}
- return false;
+ return true;
}
/**
diff --git a/tests/Validator/HostTest.php b/tests/Validator/HostTest.php
index 6ad38299..de62d4bf 100644
--- a/tests/Validator/HostTest.php
+++ b/tests/Validator/HostTest.php
@@ -21,7 +21,7 @@ class HostTest extends TestCase
public function setUp(): void
{
- $this->host = new Host(['example.io', 'subdomain.example.test', 'localhost']);
+ $this->host = new Host(['example.io', 'subdomain.example.test', 'localhost', '*.appwrite.io']);
}
public function testIsValid()
@@ -32,6 +32,10 @@ public function testIsValid()
$this->assertEquals($this->host->isValid('localhost'), false);
$this->assertEquals($this->host->isValid('http://subdomain.example.test/path'), true);
$this->assertEquals($this->host->isValid('http://test.subdomain.example.test/path'), false);
+ $this->assertEquals($this->host->isValid('http://appwrite.io/path'), false);
+ $this->assertEquals($this->host->isValid('http://me.appwrite.io/path'), true);
+ $this->assertEquals($this->host->isValid('http://you.appwrite.io/path'), true);
+ $this->assertEquals($this->host->isValid('http://us.together.appwrite.io/path'), true);
$this->assertEquals($this->host->getType(), 'string');
}
}
From f5254a990db3b998edd84b42035cb2b025277df7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Fri, 5 Jan 2024 08:45:36 +0000
Subject: [PATCH 083/119] Improve readme
---
.github/ISSUE_TEMPLATE/bug.yaml | 2 +-
CONTRIBUTING.md | 24 ++++++++++++------------
README.md | 25 +++++++++++++------------
composer.json | 5 +++--
docs/Getting-Starting-Guide.md | 10 +++++-----
example/composer.json | 2 +-
tests/Validator/DomainTest.php | 11 -----------
tests/Validator/HostTest.php | 11 -----------
tests/Validator/IPTest.php | 11 -----------
tests/Validator/URLTest.php | 11 -----------
10 files changed, 35 insertions(+), 77 deletions(-)
diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml
index c034a667..0e676b25 100644
--- a/.github/ISSUE_TEMPLATE/bug.yaml
+++ b/.github/ISSUE_TEMPLATE/bug.yaml
@@ -34,7 +34,7 @@ body:
- type: dropdown
id: utopia-version
attributes:
- label: "🎲 Utopia Framework version"
+ label: "🎲 Utopia Http version"
description: "What version of Utopia are you running?"
options:
- Version 0.18.x
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4701ba07..8da3199b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,16 +1,16 @@
# Contributing
-We would ❤️ for you to contribute to Framework and help make it better! We want contributing to Framework to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, new docs as well as updates and tweaks, blog posts, workshops, and more.
+We would ❤️ for you to contribute to Utopia-PHP Http and help make it better! We want contributing to Http to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, new docs as well as updates and tweaks, blog posts, workshops, and more.
## How to Start?
If you are worried or don’t know where to start, check out our next section explaining what kind of help we could use and where can you get involved. You can reach out with questions to [Eldad Fux (@eldadfux)](https://twitter.com/eldadfux) or [@appwrite_io](https://twitter.com/appwrite_io) on Twitter, and anyone from the [Appwrite team on Discord](https://discord.gg/GSeTUeA). You can also submit an issue, and a maintainer can guide you!
-You can get an in-depth understanding of the Utopia-PHP framework in our [Getting Started](docs/Getting-Starting-Guide.md) guide.
+You can get an in-depth understanding of the Utopia-PHP Http in our [Getting Started](docs/Getting-Starting-Guide.md) guide.
## Code of Conduct
-Help us keep framework open and inclusive. Please read and follow our [Code of Conduct](/CODE_OF_CONDUCT.md).
+Help us keep Utopia-PHP Http open and inclusive. Please read and follow our [Code of Conduct](/CODE_OF_CONDUCT.md).
## Submit a Pull Request 🚀
@@ -72,33 +72,33 @@ $ git push origin [name_of_your_new_branch]
## Introducing New Features
-We would 💖 you to contribute to Framework, but we would also like to make sure Framework is as great as possible and loyal to its vision and mission statement 🙏.
+We would 💖 you to contribute to Utopia-PHP HTTP, but we would also like to make sure Http is as great as possible and loyal to its vision and mission statement 🙏.
For us to find the right balance, please open an issue explaining your ideas before introducing a new pull request.
-This will allow the Framework community to have sufficient discussion about the new feature value and how it fits in the product roadmap and vision.
+This will allow the Utopia-PHP Http community to have sufficient discussion about the new feature value and how it fits in the product roadmap and vision.
-This is also important for the Framework lead developers to be able to give technical input and different emphasis regarding the feature design and architecture. Some bigger features might need to go through our [RFC process](https://github.com/appwrite/rfc).
+This is also important for the Http lead developers to be able to give technical input and different emphasis regarding the feature design and architecture. Some bigger features might need to go through our [RFC process](https://github.com/appwrite/rfc).
## Other Ways to Help
-Pull requests are great, but there are many other areas where you can help Framework
+Pull requests are great, but there are many other areas where you can help Utopia-PHP Http
### Blogging & Speaking
-Blogging, speaking about, or creating tutorials about one of Framework's many features is great way to contribute and help our project grow.
+Blogging, speaking about, or creating tutorials about one of Http's many features is great way to contribute and help our project grow.
### Presenting at Meetups
-Presenting at meetups and conferences about your Framework projects. Your unique challenges and successes in building things with Framework can provide great speaking material. We’d love to review your talk abstract/CFP, so get in touch with us if you’d like some help!
+Presenting at meetups and conferences about your Http projects. Your unique challenges and successes in building things with Utopia-PHP Http can provide great speaking material. We’d love to review your talk abstract/CFP, so get in touch with us if you’d like some help!
### Sending Feedbacks & Reporting Bugs
-Sending feedback is a great way for us to understand your different use cases of Framework better. If you had any issues, bugs, or want to share about your experience, feel free to do so on our GitHub issues page or at our [Discord channel](https://discord.gg/GSeTUeA).
+Sending feedback is a great way for us to understand your different use cases of Utopia-PHP Http better. If you had any issues, bugs, or want to share about your experience, feel free to do so on our GitHub issues page or at our [Discord channel](https://discord.gg/GSeTUeA).
### Submitting New Ideas
-If you think Framework could use a new feature, please open an issue on our GitHub repository, stating as much information as you can think about your new idea and it's implications. We would also use this issue to gather more information, get more feedback from the community, and have a proper discussion about the new feature.
+If you think Utopia-PHP Http could use a new feature, please open an issue on our GitHub repository, stating as much information as you can think about your new idea and it's implications. We would also use this issue to gather more information, get more feedback from the community, and have a proper discussion about the new feature.
### Improving Documentation
@@ -106,4 +106,4 @@ Submitting documentation updates, enhancements, designs, or bug fixes. Spelling
### Helping Someone
-Searching for Framework on Discord, GitHub, or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to Framework's repo!
+Searching for Utopia-PHP Http on Discord, GitHub, or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to Http's repo!
diff --git a/README.md b/README.md
index fe37a60e..16429706 100644
--- a/README.md
+++ b/README.md
@@ -2,19 +2,20 @@
-[](https://travis-ci.org/utopia-php/framework)
-
+[](https://travis-ci.org/utopia-php/http)
+
[](https://discord.gg/GSeTUeA)
-Utopia Framework is a PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. This library is maintained by the [Appwrite team](https://appwrite.io).
+Utopia Http is a PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. This library is maintained by the [Appwrite team](https://appwrite.io).
-Utopia Framework is dependency-free. Any extra features, such as authentication or caching, will be available as standalone models in order to keep the framework core clean, light, and easy to learn.
+Utopia Http is dependency-free. Any extra features, such as authentication or caching are available as standalone models in order to keep the framework core clean, light, and easy to learn.
## Getting Started
-Install using composer:
+Install using Composer:
+
```bash
-composer require utopia-php/framework
+composer require utopia-php/http
```
Init your first application in `src/server.php`:
@@ -49,7 +50,7 @@ $http->start();
Run HTTP server:
```bash
-php -S localhost:8000 src/server2.php
+php -S localhost:8000 src/server.php
```
Send HTTP request:
@@ -60,7 +61,7 @@ curl http://localhost:8000/hello-world
### Server Adapters
-The library supports server adapters to be able to run on any PHP setup. For instance, you could use the FPM server or the Swoole server.
+The library supports server adapters to be able to run on any PHP setup. Youx1s could use the FPM server or the Swoole server.
#### Use PHP FPM server
@@ -243,15 +244,15 @@ In advanced scenarios, resources can also be injected into other resources or en
Resources are designed to prepare dependencies or context for the request. Resources are not meant to do functional logic or return callbacks. For such a use case, you should use hooks.
-To learn more about Framework architecture and features, check out more in-depth [Getting started guide](/docs/Getting-Starting-Guide.md).
+To learn more about Http architecture and features, check out more in-depth [Getting started guide](/docs/Getting-Starting-Guide.md).
## System Requirements
-Utopia Framework requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible.
+Utopia Http requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible.
## More from Utopia
-Our ecosystem supports other thin PHP projects aiming to extend the core PHP Utopia framework.
+Our ecosystem supports other thin PHP projects aiming to extend the core PHP Utopia Http.
Each project is focused on solving a single, very simple problem and you can use composer to include any of them in your next project.
@@ -263,7 +264,7 @@ All code contributions - including those of people having commit access - must g
Fork the project, create a feature branch, and send us a pull request.
-You can refer to the [Contributing Guide](https://github.com/utopia-php/framework/blob/master/CONTRIBUTING.md) for more info.
+You can refer to the [Contributing Guide](https://github.com/utopia-php/http/blob/master/CONTRIBUTING.md) for more info.
For security issues, please email security@appwrite.io instead of posting a public issue in GitHub.
diff --git a/composer.json b/composer.json
index 043758fa..8694ef5b 100644
--- a/composer.json
+++ b/composer.json
@@ -1,10 +1,11 @@
{
- "name": "utopia-php/framework",
- "description": "A simple, light and advanced PHP framework",
+ "name": "utopia-php/http",
+ "description": "A simple, light and advanced PHP HTTP framework",
"type": "library",
"keywords": [
"php",
"framework",
+ "http",
"upf"
],
"license": "MIT",
diff --git a/docs/Getting-Starting-Guide.md b/docs/Getting-Starting-Guide.md
index 272a6b4a..de0f1118 100644
--- a/docs/Getting-Starting-Guide.md
+++ b/docs/Getting-Starting-Guide.md
@@ -1,7 +1,7 @@
# Getting Started with Utopia-PHP
# Intro
-Utopia Framework is an easy-to-use PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. It follows an architecture like Express and is based on the declarative programming approach. Documenting and writing code are usually seen as two separate tasks and very often, documentation loses priority in the software development lifecycle. Utopia unifies the two with a flexible API that allows your code to be self-documenting. What’s interesting about Utopia is its ability to accept metadata along with it’s route definitions. This metadata can then be used for various purposes like generating documentation, swagger specifications and more.
+Utopia Http is an easy-to-use PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. It follows an architecture like Express and is based on the declarative programming approach. Documenting and writing code are usually seen as two separate tasks and very often, documentation loses priority in the software development lifecycle. Utopia unifies the two with a flexible API that allows your code to be self-documenting. What’s interesting about Utopia is its ability to accept metadata along with it’s route definitions. This metadata can then be used for various purposes like generating documentation, swagger specifications and more.
# Defining Routes
If you’re new to Utopia, let’s get started by looking at an example of a basic GET route for an application that you can create using Utopia. We'll be using a [Swoole server](https://github.com/swoole/swoole-src) in this example, but you should be able to extend it to any HTTP server.
@@ -130,7 +130,7 @@ $response
->send('')
```
-You can find the details of other status codes by visiting our [GitHub repository](https://github.com/utopia-php/framework/blob/master/src/Response.php).
+You can find the details of other status codes by visiting our [GitHub repository](https://github.com/utopia-php/http/blob/master/src/Response.php).
# Advanced Utopia
@@ -279,9 +279,9 @@ Http::shutdown(function($request) {
# Running Locally
-If you have PHP and Composer installed on your device, you can run Utopia apps locally by downloading the Utopia-PHP/framework dependency using `composer require utopia-php/framework` command.
+If you have PHP and Composer installed on your device, you can run Utopia apps locally by downloading the Utopia-PHP/http dependency using `composer require utopia-php/http` command.
-> Utopia Framework requires PHP 7.3 or later. We recommend using the latest PHP version whenever possible.
+> Utopia Http requires PHP 7.3 or later. We recommend using the latest PHP version whenever possible.
-Wonderful! 😄 You’re all set to create a basic demo app using the Utopia framework. If you have any issues or questions feel free to reach out to us on our [Discord Server](https://appwrite.io/discord).
+Wonderful! 😄 You’re all set to create a basic demo app using the Utopia Http. If you have any issues or questions feel free to reach out to us on our [Discord Server](https://appwrite.io/discord).
diff --git a/example/composer.json b/example/composer.json
index 999df3c0..8e35bc2e 100644
--- a/example/composer.json
+++ b/example/composer.json
@@ -1,6 +1,6 @@
{
"name": "utopia-php/http-app",
"require": {
- "utopia-php/framework": "0.33.*"
+ "utopia-php/http": "0.33.*"
}
}
\ No newline at end of file
diff --git a/tests/Validator/DomainTest.php b/tests/Validator/DomainTest.php
index d8fa4de4..85a346e1 100644
--- a/tests/Validator/DomainTest.php
+++ b/tests/Validator/DomainTest.php
@@ -1,15 +1,4 @@
- * @version 1.0 RC4
- * @license The MIT License (MIT)
- */
namespace Utopia\Http\Validator;
diff --git a/tests/Validator/HostTest.php b/tests/Validator/HostTest.php
index 7d845f33..9476ea6b 100644
--- a/tests/Validator/HostTest.php
+++ b/tests/Validator/HostTest.php
@@ -1,15 +1,4 @@
- * @version 1.0 RC4
- * @license The MIT License (MIT)
- */
namespace Utopia\Http\Validator;
diff --git a/tests/Validator/IPTest.php b/tests/Validator/IPTest.php
index 88c71994..074a8f68 100644
--- a/tests/Validator/IPTest.php
+++ b/tests/Validator/IPTest.php
@@ -1,15 +1,4 @@
- * @version 1.0 RC4
- * @license The MIT License (MIT)
- */
namespace Utopia\Http\Validator;
diff --git a/tests/Validator/URLTest.php b/tests/Validator/URLTest.php
index f092890f..de530cd1 100644
--- a/tests/Validator/URLTest.php
+++ b/tests/Validator/URLTest.php
@@ -1,15 +1,4 @@
- * @version 1.0 RC4
- * @license The MIT License (MIT)
- */
namespace Utopia\Http\Validator;
From 6b6ae760497ea692bdbf27e574a82e90aa5fcc1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Fri, 5 Jan 2024 08:47:00 +0000
Subject: [PATCH 084/119] Fix docs version
---
docs/Getting-Starting-Guide.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/Getting-Starting-Guide.md b/docs/Getting-Starting-Guide.md
index de0f1118..ab1ccb8c 100644
--- a/docs/Getting-Starting-Guide.md
+++ b/docs/Getting-Starting-Guide.md
@@ -281,7 +281,7 @@ Http::shutdown(function($request) {
# Running Locally
If you have PHP and Composer installed on your device, you can run Utopia apps locally by downloading the Utopia-PHP/http dependency using `composer require utopia-php/http` command.
-> Utopia Http requires PHP 7.3 or later. We recommend using the latest PHP version whenever possible.
+> Utopia Http requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible.
Wonderful! 😄 You’re all set to create a basic demo app using the Utopia Http. If you have any issues or questions feel free to reach out to us on our [Discord Server](https://appwrite.io/discord).
From 19e0eb1742467c6dcd5d52e97fb7b2c3801af8ac Mon Sep 17 00:00:00 2001
From: Torsten Dittmann
Date: Fri, 5 Jan 2024 11:44:20 +0100
Subject: [PATCH 085/119] chore: rename library to utopia-php/http
---
.github/workflows/test.yml | 5 +++-
README.md | 14 ++++-----
composer.json | 2 +-
composer.lock | 14 ++++-----
docs/Getting-Starting-Guide.md | 54 +++++++++++++++++-----------------
example/composer.json | 2 +-
tests/Validator/DomainTest.php | 2 +-
tests/Validator/HostTest.php | 2 +-
tests/Validator/IPTest.php | 2 +-
tests/Validator/URLTest.php | 2 +-
10 files changed, 51 insertions(+), 48 deletions(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ce9d61c5..e17e5507 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -15,6 +15,9 @@ jobs:
with:
php-version: '8.1'
+ - name: Validate composer.json and composer.lock
+ run: composer validate --strict
+
- name: Setup Docker
run: docker-compose up -d --build
@@ -23,6 +26,6 @@ jobs:
- name: Run FPM Tests
run: docker compose exec fpm vendor/bin/phpunit --configuration phpunit.xml
-
+
- name: Run Swoole Tests
run: docker compose exec swoole vendor/bin/phpunit --configuration phpunit.xml
\ No newline at end of file
diff --git a/README.md b/README.md
index fe37a60e..3fb0a525 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
-[](https://travis-ci.org/utopia-php/framework)
-
+[](https://travis-ci.org/utopia-php/http)
+
[](https://discord.gg/GSeTUeA)
Utopia Framework is a PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. This library is maintained by the [Appwrite team](https://appwrite.io).
@@ -14,7 +14,7 @@ Utopia Framework is dependency-free. Any extra features, such as authentication
Install using composer:
```bash
-composer require utopia-php/framework
+composer require utopia-php/http
```
Init your first application in `src/server.php`:
@@ -49,7 +49,7 @@ $http->start();
Run HTTP server:
```bash
-php -S localhost:8000 src/server2.php
+php -S localhost:8000 src/server2.php
```
Send HTTP request:
@@ -203,7 +203,7 @@ Http::init()
});
```
-Groups are designed to be actions that run during the lifecycle of requests to endpoints that have some logic in common. Groups allow you to prevent code duplication and are designed to be defined anywhere in your source code to allow flexibility.
+Groups are designed to be actions that run during the lifecycle of requests to endpoints that have some logic in common. Groups allow you to prevent code duplication and are designed to be defined anywhere in your source code to allow flexibility.
### Resources
@@ -253,7 +253,7 @@ Utopia Framework requires PHP 8.0 or later. We recommend using the latest PHP ve
Our ecosystem supports other thin PHP projects aiming to extend the core PHP Utopia framework.
-Each project is focused on solving a single, very simple problem and you can use composer to include any of them in your next project.
+Each project is focused on solving a single, very simple problem and you can use composer to include any of them in your next project.
You can find all libraries in [GitHub Utopia organization](https://github.com/utopia-php).
@@ -263,7 +263,7 @@ All code contributions - including those of people having commit access - must g
Fork the project, create a feature branch, and send us a pull request.
-You can refer to the [Contributing Guide](https://github.com/utopia-php/framework/blob/master/CONTRIBUTING.md) for more info.
+You can refer to the [Contributing Guide](https://github.com/utopia-php/http/blob/master/CONTRIBUTING.md) for more info.
For security issues, please email security@appwrite.io instead of posting a public issue in GitHub.
diff --git a/composer.json b/composer.json
index 043758fa..a2cf3cb2 100644
--- a/composer.json
+++ b/composer.json
@@ -1,5 +1,5 @@
{
- "name": "utopia-php/framework",
+ "name": "utopia-php/http",
"description": "A simple, light and advanced PHP framework",
"type": "library",
"keywords": [
diff --git a/composer.lock b/composer.lock
index a388d0e9..a5519ed2 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "f27d5bb02390ce6b9a8268d4fffb1e87",
+ "content-hash": "33b8cf270cfbd8f86cbd1338d81f5140",
"packages": [],
"packages-dev": [
{
@@ -724,16 +724,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.10.50",
+ "version": "1.10.52",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4"
+ "reference": "0cd0c330081d4f1e1d630701fe4f342c3b659685"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4",
- "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0cd0c330081d4f1e1d630701fe4f342c3b659685",
+ "reference": "0cd0c330081d4f1e1d630701fe4f342c3b659685",
"shasum": ""
},
"require": {
@@ -782,7 +782,7 @@
"type": "tidelift"
}
],
- "time": "2023-12-13T10:59:42+00:00"
+ "time": "2024-01-05T09:51:32+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -3451,5 +3451,5 @@
"ext-swoole": "*"
},
"platform-dev": [],
- "plugin-api-version": "2.6.0"
+ "plugin-api-version": "2.3.0"
}
diff --git a/docs/Getting-Starting-Guide.md b/docs/Getting-Starting-Guide.md
index 272a6b4a..0d44f140 100644
--- a/docs/Getting-Starting-Guide.md
+++ b/docs/Getting-Starting-Guide.md
@@ -4,7 +4,7 @@
Utopia Framework is an easy-to-use PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. It follows an architecture like Express and is based on the declarative programming approach. Documenting and writing code are usually seen as two separate tasks and very often, documentation loses priority in the software development lifecycle. Utopia unifies the two with a flexible API that allows your code to be self-documenting. What’s interesting about Utopia is its ability to accept metadata along with it’s route definitions. This metadata can then be used for various purposes like generating documentation, swagger specifications and more.
# Defining Routes
-If you’re new to Utopia, let’s get started by looking at an example of a basic GET route for an application that you can create using Utopia. We'll be using a [Swoole server](https://github.com/swoole/swoole-src) in this example, but you should be able to extend it to any HTTP server.
+If you’re new to Utopia, let’s get started by looking at an example of a basic GET route for an application that you can create using Utopia. We'll be using a [Swoole server](https://github.com/swoole/swoole-src) in this example, but you should be able to extend it to any HTTP server.
## Basic GET Route
@@ -17,7 +17,7 @@ use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
$http = new Server("0.0.0.0", 8080);
-
+
Http::get('/')
->inject('request')
->inject('response')
@@ -27,7 +27,7 @@ Http::get('/')
$response->send(" Hello World!
");
}
/*
- Configure your HTTP server to respond with the Utopia http.
+ Configure your HTTP server to respond with the Utopia http.
*/
$http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) {
@@ -39,12 +39,12 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
$http->start();
```
-
+
Any route in Utopia would require you to `inject` the dependencies ( `$request` and `$response` in this case ) and define the controller by passing a callback to the `action` function. As you might have already guessed, `$request` and `$response` refer to the objects of the HTTP server library you’re using, for example, Swoole in this case. `action` defines the callback function that would be called when the GET request is executed. In this case, raw HTML is returned as a `$response`.
## More Endpoints
-You can perform basic CRUD operations like GET, POST, PUT and DELETE using Utopia. Let’s assume there's a file `todos.json` that stores a list of todo objects with the following structure. In a real-world scenario, you would be fetching this information from a database.
+You can perform basic CRUD operations like GET, POST, PUT and DELETE using Utopia. Let’s assume there's a file `todos.json` that stores a list of todo objects with the following structure. In a real-world scenario, you would be fetching this information from a database.
```json
[
@@ -88,9 +88,9 @@ You might have noticed an additional property in the above example, i.e. `param`
All the parameters need to be defined using the `param` property which accepts the following - `$key`, `$default`, `$validator`, `$description`, `$optional` and `$injections`.
There are typically 3 types of parameters:
-1. Path params ( eg: `/api/users/` )
+1. Path params ( eg: `/api/users/` )
2. Query Params ( eg: `/api/users?userId=`)
-3. Body Params ( These are passed in the request body in POST and PUT requests. )
+3. Body Params ( These are passed in the request body in POST and PUT requests. )
Let's take a look at how these three types of params are taken care of by Utopia:
@@ -100,7 +100,7 @@ Let's take a look at how these three types of params are taken care of by Utopia
3. Body Parameters are specified using the `->param()` function as well.
-Each of these params then become available to the `->action()` callback function in the same order that they were declared in.
+Each of these params then become available to the `->action()` callback function in the same order that they were declared in.
### Returning a Response
Based on the type of the response you wish to return, multiple options can be used:
@@ -120,7 +120,7 @@ $response->json(['Goodbye' => 'World']);
JSON objects can be returned by passing the JSON object inside `$response->json()`.
-### Setting Response Status
+### Setting Response Status
You can set a status code for your response using the `setStatusCode()` function of utopia's response object.
@@ -130,7 +130,7 @@ $response
->send('')
```
-You can find the details of other status codes by visiting our [GitHub repository](https://github.com/utopia-php/framework/blob/master/src/Response.php).
+You can find the details of other status codes by visiting our [GitHub repository](https://github.com/utopia-php/http/blob/master/src/Response.php).
# Advanced Utopia
@@ -149,28 +149,28 @@ use Utopia\Http\Validator\Wildcard;
$http = new Server("0.0.0.0", 8080);
Http::init(function($response) {
- /*
- Example of global init method. Do stuff that is common to all your endpoints in all groups.
+ /*
+ Example of global init method. Do stuff that is common to all your endpoints in all groups.
This can include things like authentication and authorisation checks, implementing rate limits and so on..
*/
}, ['response']);
Http::init(function($response) {
- /*
+ /*
Example of init method for group1. Do stuff that is common to all your endpoints in group1.
This can include things like authentication and authorisation checks, implementing rate limits and so on..
*/
}, ['response'], 'group1');
Http::init(function($response) {
- /*
- Example of init method for group2. Do stuff that is common to all your endpoints in group2.
+ /*
+ Example of init method for group2. Do stuff that is common to all your endpoints in group2.
This can include things like authentication and authorisation checks, implementing rate limits and so on..
*/
}, ['response'], 'group2');
Http::shutdown(function($request) {
- /*
+ /*
Example of global shutdown method. Do stuff that needs to be performed at the end of each request for all groups.
'*' (Wildcard validator) is optional.
This can include cleanups, logging information, recording usage stats, closing database connections and so on..
@@ -179,7 +179,7 @@ Http::shutdown(function($request) {
}, ['request'], '*');
Http::shutdown(function($request) {
- /*
+ /*
Example of shutdown method of group1. Do stuff that needs to be performed at the end of each request for all groups.
This can include cleanups, logging information, recording usage stats, closing database connections and so on..
*/
@@ -211,7 +211,7 @@ Http::put('/todos/:id')
$response->json($data);
}
);
-
+
$http->start();
```
@@ -224,7 +224,7 @@ For each endpoint, you can add the following properties described below. Let’s
`groups` are used to define common functions that need to be executed. When you add a callback function to a group, the init hooks of the respective group are executed before the individual actions are executed.
* #### Labels
-`label` can be used to store metadata that is related to your endpoint. It’s a key-value store. Some use-cases can be using label to generate the documentation or the swagger specifications.
+`label` can be used to store metadata that is related to your endpoint. It’s a key-value store. Some use-cases can be using label to generate the documentation or the swagger specifications.
* #### Injections
Since each action in Utopia depends on certain resources, `inject` is used to add the dependencies. `$response` and `$request` can be injected into the service. Utopia provides the http static functions to make global resources available to all utopia endpoints.
@@ -238,7 +238,7 @@ Since each action in Utopia depends on certain resources, `inject` is used to ad
Now that you’re familiar with routing in Utopia, let’s dive into the lifecycle of a utopia request in detail and learn about some of the lifecycle methods.
## Init and Shutdown Methods
-
+
The Utopia http goes through the following lifecycle whenever it receives any request:

@@ -248,7 +248,7 @@ In case an error occurs anywhere during the execution, the workflow executes the
The init and shutdown methods take three params:
1. Callback function
- 2. Array of resources required by the callback
+ 2. Array of resources required by the callback
3. The endpoint group for which the callback is intended to run
* ### Init
@@ -256,9 +256,9 @@ The init and shutdown methods take three params:
init method is executed in the beginning when the program execution begins. Here’s an example of the init method, where the init method is executed for all groups indicated by the wildcard symbol `'*'`.
```php
Http::init(function($response) {
- /*
- Do stuff that is common to all your endpoints.
- This can include things like authentication and authorisation checks, implementing rate limits and so on..
+ /*
+ Do stuff that is common to all your endpoints.
+ This can include things like authentication and authorisation checks, implementing rate limits and so on..
*/
}, ['response'], '*');
```
@@ -269,8 +269,8 @@ Utopia's shutdown callback is used to perform cleanup tasks after a request. Thi
```php
Http::shutdown(function($request) {
- /*
- Do stuff that needs to be performed at the end of each request.
+ /*
+ Do stuff that needs to be performed at the end of each request.
This can include cleanups, logging information, recording usage stats, closing database connections and so on..
*/
@@ -279,7 +279,7 @@ Http::shutdown(function($request) {
# Running Locally
-If you have PHP and Composer installed on your device, you can run Utopia apps locally by downloading the Utopia-PHP/framework dependency using `composer require utopia-php/framework` command.
+If you have PHP and Composer installed on your device, you can run Utopia apps locally by downloading the utopia-php/http dependency using `composer require utopia-php/http` command.
> Utopia Framework requires PHP 7.3 or later. We recommend using the latest PHP version whenever possible.
diff --git a/example/composer.json b/example/composer.json
index 999df3c0..8e35bc2e 100644
--- a/example/composer.json
+++ b/example/composer.json
@@ -1,6 +1,6 @@
{
"name": "utopia-php/http-app",
"require": {
- "utopia-php/framework": "0.33.*"
+ "utopia-php/http": "0.33.*"
}
}
\ No newline at end of file
diff --git a/tests/Validator/DomainTest.php b/tests/Validator/DomainTest.php
index d8fa4de4..5e9e544f 100644
--- a/tests/Validator/DomainTest.php
+++ b/tests/Validator/DomainTest.php
@@ -5,7 +5,7 @@
* @package Framework
* @subpackage Tests
*
- * @link https://github.com/utopia-php/framework
+ * @link https://github.com/utopia-php/http
* @author Appwrite Team
* @version 1.0 RC4
* @license The MIT License (MIT)
diff --git a/tests/Validator/HostTest.php b/tests/Validator/HostTest.php
index 7d845f33..fc75907d 100644
--- a/tests/Validator/HostTest.php
+++ b/tests/Validator/HostTest.php
@@ -5,7 +5,7 @@
* @package Framework
* @subpackage Tests
*
- * @link https://github.com/utopia-php/framework
+ * @link https://github.com/utopia-php/http
* @author Appwrite Team
* @version 1.0 RC4
* @license The MIT License (MIT)
diff --git a/tests/Validator/IPTest.php b/tests/Validator/IPTest.php
index 88c71994..ea699feb 100644
--- a/tests/Validator/IPTest.php
+++ b/tests/Validator/IPTest.php
@@ -5,7 +5,7 @@
* @package Framework
* @subpackage Tests
*
- * @link https://github.com/utopia-php/framework
+ * @link https://github.com/utopia-php/http
* @author Appwrite Team
* @version 1.0 RC4
* @license The MIT License (MIT)
diff --git a/tests/Validator/URLTest.php b/tests/Validator/URLTest.php
index f092890f..5e8c94f6 100644
--- a/tests/Validator/URLTest.php
+++ b/tests/Validator/URLTest.php
@@ -5,7 +5,7 @@
* @package Framework
* @subpackage Tests
*
- * @link https://github.com/utopia-php/framework
+ * @link https://github.com/utopia-php/http
* @author Appwrite Team
* @version 1.0 RC4
* @license The MIT License (MIT)
From 43f884715e03b8aa4e87d8e77478ff032391c969 Mon Sep 17 00:00:00 2001
From: Torsten Dittmann
Date: Fri, 5 Jan 2024 11:49:09 +0100
Subject: [PATCH 086/119] fix: example version to latest
---
example/composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/example/composer.json b/example/composer.json
index 8e35bc2e..383d90aa 100644
--- a/example/composer.json
+++ b/example/composer.json
@@ -1,6 +1,6 @@
{
"name": "utopia-php/http-app",
"require": {
- "utopia-php/http": "0.33.*"
+ "utopia-php/http": "latest"
}
}
\ No newline at end of file
From 0ef2070db396cc1efc847d7490279c024414ff8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Fri, 5 Jan 2024 12:12:24 +0100
Subject: [PATCH 087/119] Update .github/ISSUE_TEMPLATE/bug.yaml
Co-authored-by: Torsten Dittmann
---
.github/ISSUE_TEMPLATE/bug.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml
index 0e676b25..0b6ca990 100644
--- a/.github/ISSUE_TEMPLATE/bug.yaml
+++ b/.github/ISSUE_TEMPLATE/bug.yaml
@@ -34,7 +34,7 @@ body:
- type: dropdown
id: utopia-version
attributes:
- label: "🎲 Utopia Http version"
+ label: "🎲 Utopia HTTP version"
description: "What version of Utopia are you running?"
options:
- Version 0.18.x
From f22cfa3e6693f1ff2b243a47960991be00dcb200 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Fri, 5 Jan 2024 12:12:35 +0100
Subject: [PATCH 088/119] Update CONTRIBUTING.md
Co-authored-by: Torsten Dittmann
---
CONTRIBUTING.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8da3199b..0e1eb142 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,6 +1,6 @@
# Contributing
-We would ❤️ for you to contribute to Utopia-PHP Http and help make it better! We want contributing to Http to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, new docs as well as updates and tweaks, blog posts, workshops, and more.
+We would ❤️ for you to contribute to `utopia-php/http` and help make it better! We want contributing to this library to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, new docs as well as updates and tweaks, blog posts, workshops, and more.
## How to Start?
From 5a996f6b070af27b3e862336c569fe7e0173e658 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Fri, 5 Jan 2024 12:15:21 +0100
Subject: [PATCH 089/119] Apply suggestions from code review
Co-authored-by: Torsten Dittmann
---
CONTRIBUTING.md | 22 +++++++++++-----------
README.md | 12 ++++++------
docs/Getting-Starting-Guide.md | 4 ++--
3 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0e1eb142..c01dbd27 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -6,11 +6,11 @@ We would ❤️ for you to contribute to `utopia-php/http` and help make it bett
If you are worried or don’t know where to start, check out our next section explaining what kind of help we could use and where can you get involved. You can reach out with questions to [Eldad Fux (@eldadfux)](https://twitter.com/eldadfux) or [@appwrite_io](https://twitter.com/appwrite_io) on Twitter, and anyone from the [Appwrite team on Discord](https://discord.gg/GSeTUeA). You can also submit an issue, and a maintainer can guide you!
-You can get an in-depth understanding of the Utopia-PHP Http in our [Getting Started](docs/Getting-Starting-Guide.md) guide.
+You can get an in-depth understanding of Utopia HTTP in our [Getting Started](docs/Getting-Starting-Guide.md) guide.
## Code of Conduct
-Help us keep Utopia-PHP Http open and inclusive. Please read and follow our [Code of Conduct](/CODE_OF_CONDUCT.md).
+Help us keep Utopia HTTP open and inclusive. Please read and follow our [Code of Conduct](/CODE_OF_CONDUCT.md).
## Submit a Pull Request 🚀
@@ -72,33 +72,33 @@ $ git push origin [name_of_your_new_branch]
## Introducing New Features
-We would 💖 you to contribute to Utopia-PHP HTTP, but we would also like to make sure Http is as great as possible and loyal to its vision and mission statement 🙏.
+We would 💖 you to contribute to Utopia HTTP, but we would also like to make sure this library is as great as possible and loyal to its vision and mission statement 🙏.
For us to find the right balance, please open an issue explaining your ideas before introducing a new pull request.
-This will allow the Utopia-PHP Http community to have sufficient discussion about the new feature value and how it fits in the product roadmap and vision.
+This will allow the community to have sufficient discussion about the new feature value and how it fits in the product roadmap and vision.
-This is also important for the Http lead developers to be able to give technical input and different emphasis regarding the feature design and architecture. Some bigger features might need to go through our [RFC process](https://github.com/appwrite/rfc).
+This is also important for the repository owners to be able to give technical input and different emphasis regarding the feature design and architecture. Some bigger features might need to go through our [RFC process](https://github.com/appwrite/rfc).
## Other Ways to Help
-Pull requests are great, but there are many other areas where you can help Utopia-PHP Http
+Pull requests are great, but there are many other areas where you can help:
### Blogging & Speaking
-Blogging, speaking about, or creating tutorials about one of Http's many features is great way to contribute and help our project grow.
+Creating blog posts, giving talks, or developing tutorials about one of this library's many features are excellent ways to contribute and help our project grow.
### Presenting at Meetups
-Presenting at meetups and conferences about your Http projects. Your unique challenges and successes in building things with Utopia-PHP Http can provide great speaking material. We’d love to review your talk abstract/CFP, so get in touch with us if you’d like some help!
+Presenting at meetups and conferences about your Utopia projects. Your unique challenges and successes in building things with this library can provide great speaking material. We’d love to review your conference talk abstract, so get in touch with us if you’d like some help!
### Sending Feedbacks & Reporting Bugs
-Sending feedback is a great way for us to understand your different use cases of Utopia-PHP Http better. If you had any issues, bugs, or want to share about your experience, feel free to do so on our GitHub issues page or at our [Discord channel](https://discord.gg/GSeTUeA).
+Sending feedback is a great way for us to understand your different use cases of this library better. If you had any issues, bugs, or want to share about your experience, feel free to do so on our GitHub issues page or at our [Discord channel](https://discord.gg/GSeTUeA).
### Submitting New Ideas
-If you think Utopia-PHP Http could use a new feature, please open an issue on our GitHub repository, stating as much information as you can think about your new idea and it's implications. We would also use this issue to gather more information, get more feedback from the community, and have a proper discussion about the new feature.
+If you think this library could use a new feature, please open an issue on our GitHub repository, stating as much information as you can think about your new idea and it's implications. We would also use this issue to gather more information, get more feedback from the community, and have a proper discussion about the new feature.
### Improving Documentation
@@ -106,4 +106,4 @@ Submitting documentation updates, enhancements, designs, or bug fixes. Spelling
### Helping Someone
-Searching for Utopia-PHP Http on Discord, GitHub, or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to Http's repo!
+Searching for Utopia-PHP on Discord, GitHub, or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to this repo!
diff --git a/README.md b/README.md
index 71f1504e..137e384c 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,9 @@

[](https://discord.gg/GSeTUeA)
-Utopia Http is a PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. This library is maintained by the [Appwrite team](https://appwrite.io).
+Utopia HTTP is a PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. This library is maintained by the [Appwrite team](https://appwrite.io).
-Utopia Http is dependency-free. Any extra features, such as authentication or caching are available as standalone models in order to keep the framework core clean, light, and easy to learn.
+Utopia HTTP is dependency-free. Any extra features, such as authentication or caching are available as standalone models in order to keep the framework core clean, light, and easy to learn.
## Getting Started
@@ -61,7 +61,7 @@ curl http://localhost:8000/hello-world
### Server Adapters
-The library supports server adapters to be able to run on any PHP setup. Youx1s could use the FPM server or the Swoole server.
+The library supports server adapters to be able to run on any PHP setup. You could use the FPM or Swoole server.
#### Use PHP FPM server
@@ -244,15 +244,15 @@ In advanced scenarios, resources can also be injected into other resources or en
Resources are designed to prepare dependencies or context for the request. Resources are not meant to do functional logic or return callbacks. For such a use case, you should use hooks.
-To learn more about Http architecture and features, check out more in-depth [Getting started guide](/docs/Getting-Starting-Guide.md).
+To learn more about architecture and features for this library, check out more in-depth [Getting started guide](/docs/Getting-Starting-Guide.md).
## System Requirements
-Utopia Http requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible.
+Utopia HTTP requires PHP 8.1 or later. We recommend using the latest PHP version whenever possible.
## More from Utopia
-Our ecosystem supports other thin PHP projects aiming to extend the core PHP Utopia Http.
+Our ecosystem supports other thin PHP projects aiming to extend the core PHP Utopia HTTP.
Each project is focused on solving a single, very simple problem and you can use composer to include any of them in your next project.
diff --git a/docs/Getting-Starting-Guide.md b/docs/Getting-Starting-Guide.md
index 2d5cf9c4..04a2aae9 100644
--- a/docs/Getting-Starting-Guide.md
+++ b/docs/Getting-Starting-Guide.md
@@ -1,7 +1,7 @@
# Getting Started with Utopia-PHP
# Intro
-Utopia Http is an easy-to-use PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. It follows an architecture like Express and is based on the declarative programming approach. Documenting and writing code are usually seen as two separate tasks and very often, documentation loses priority in the software development lifecycle. Utopia unifies the two with a flexible API that allows your code to be self-documenting. What’s interesting about Utopia is its ability to accept metadata along with it’s route definitions. This metadata can then be used for various purposes like generating documentation, swagger specifications and more.
+Utopia HTTP is an easy-to-use PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. It follows an architecture like Express and is based on the declarative programming approach. Documenting and writing code are usually seen as two separate tasks and very often, documentation loses priority in the software development lifecycle. Utopia unifies the two with a flexible API that allows your code to be self-documenting. What’s interesting about Utopia is its ability to accept metadata along with it’s route definitions. This metadata can then be used for various purposes like generating documentation, swagger specifications and more.
# Defining Routes
If you’re new to Utopia, let’s get started by looking at an example of a basic GET route for an application that you can create using Utopia. We'll be using a [Swoole server](https://github.com/swoole/swoole-src) in this example, but you should be able to extend it to any HTTP server.
@@ -281,7 +281,7 @@ Http::shutdown(function($request) {
# Running Locally
If you have PHP and Composer installed on your device, you can run Utopia apps locally by downloading the Utopia-PHP/http dependency using `composer require utopia-php/http` command.
-> Utopia Http requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible.
+> Utopia HTTP requires PHP 8.1 or later. We recommend using the latest PHP version whenever possible.
Wonderful! 😄 You’re all set to create a basic demo app using the Utopia Http. If you have any issues or questions feel free to reach out to us on our [Discord Server](https://appwrite.io/discord).
From 9c641f2a1f81fb27aa21e0dece9408ac6f351aa4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Fri, 5 Jan 2024 12:15:44 +0100
Subject: [PATCH 090/119] Update docs/Getting-Starting-Guide.md
Co-authored-by: Torsten Dittmann
---
docs/Getting-Starting-Guide.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/Getting-Starting-Guide.md b/docs/Getting-Starting-Guide.md
index 04a2aae9..e1aa0de2 100644
--- a/docs/Getting-Starting-Guide.md
+++ b/docs/Getting-Starting-Guide.md
@@ -279,7 +279,7 @@ Http::shutdown(function($request) {
# Running Locally
-If you have PHP and Composer installed on your device, you can run Utopia apps locally by downloading the Utopia-PHP/http dependency using `composer require utopia-php/http` command.
+If you have PHP and Composer installed on your device, you can run Utopia apps locally by downloading the `utopia-php/http` dependency using `composer require utopia-php/http` command.
> Utopia HTTP requires PHP 8.1 or later. We recommend using the latest PHP version whenever possible.
From ea29fe6c19edbaa73090141a81a51ae7ceb3dec4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Fri, 5 Jan 2024 11:17:35 +0000
Subject: [PATCH 091/119] PR review changes
---
CONTRIBUTING.md | 4 ++--
docs/Getting-Starting-Guide.md | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c01dbd27..3ab8893b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,6 +1,6 @@
# Contributing
-We would ❤️ for you to contribute to `utopia-php/http` and help make it better! We want contributing to this library to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, new docs as well as updates and tweaks, blog posts, workshops, and more.
+We would ❤️ for you to contribute to Utopia HTTP and help make it better! We want contributing to this library to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, new docs as well as updates and tweaks, blog posts, workshops, and more.
## How to Start?
@@ -106,4 +106,4 @@ Submitting documentation updates, enhancements, designs, or bug fixes. Spelling
### Helping Someone
-Searching for Utopia-PHP on Discord, GitHub, or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to this repo!
+Searching for Utopia HTTP on Discord, GitHub, or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to this repo!
diff --git a/docs/Getting-Starting-Guide.md b/docs/Getting-Starting-Guide.md
index e1aa0de2..b0f46a4b 100644
--- a/docs/Getting-Starting-Guide.md
+++ b/docs/Getting-Starting-Guide.md
@@ -1,4 +1,4 @@
-# Getting Started with Utopia-PHP
+# Getting Started with Utopia HTTP
# Intro
Utopia HTTP is an easy-to-use PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. It follows an architecture like Express and is based on the declarative programming approach. Documenting and writing code are usually seen as two separate tasks and very often, documentation loses priority in the software development lifecycle. Utopia unifies the two with a flexible API that allows your code to be self-documenting. What’s interesting about Utopia is its ability to accept metadata along with it’s route definitions. This metadata can then be used for various purposes like generating documentation, swagger specifications and more.
@@ -283,5 +283,5 @@ If you have PHP and Composer installed on your device, you can run Utopia apps l
> Utopia HTTP requires PHP 8.1 or later. We recommend using the latest PHP version whenever possible.
-Wonderful! 😄 You’re all set to create a basic demo app using the Utopia Http. If you have any issues or questions feel free to reach out to us on our [Discord Server](https://appwrite.io/discord).
+Wonderful! 😄 You’re all set to create a basic demo app using the Utopia HTTP. If you have any issues or questions feel free to reach out to us on our [Discord Server](https://appwrite.io/discord).
From 933ebc68309128a1978bf8c5aff276f8a63f0738 Mon Sep 17 00:00:00 2001
From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com>
Date: Wed, 31 Jan 2024 13:23:03 +0530
Subject: [PATCH 092/119] Add 451 status code
---
src/Http/Response.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/Http/Response.php b/src/Http/Response.php
index e6e7f2ad..c17fa52c 100755
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -115,6 +115,8 @@ abstract class Response
public const STATUS_CODE_TOO_MANY_REQUESTS = 429;
+ public const STATUS_CODE_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
+
public const STATUS_CODE_INTERNAL_SERVER_ERROR = 500;
public const STATUS_CODE_NOT_IMPLEMENTED = 501;
@@ -168,6 +170,7 @@ abstract class Response
self::STATUS_CODE_EXPECTATION_FAILED => 'Expectation Failed',
self::STATUS_CODE_TOO_EARLY => 'Too Early',
self::STATUS_CODE_TOO_MANY_REQUESTS => 'Too Many Requests',
+ self::STATUS_CODE_UNAVAILABLE_FOR_LEGAL_REASONS => 'Unavailable For Legal Reasons',
self::STATUS_CODE_INTERNAL_SERVER_ERROR => 'Internal Server Error',
self::STATUS_CODE_NOT_IMPLEMENTED => 'Not Implemented',
self::STATUS_CODE_BAD_GATEWAY => 'Bad Gateway',
From 0bba768d9ad73a0953a3938d9db42f87d553c14e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 20 Feb 2024 11:08:57 +0000
Subject: [PATCH 093/119] Mark methods public to allow chunk response
---
src/Http/Adapter/FPM/Response.php | 9 +++++----
src/Http/Adapter/Swoole/Response.php | 10 +++++-----
src/Http/Response.php | 13 ++++---------
3 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/src/Http/Adapter/FPM/Response.php b/src/Http/Adapter/FPM/Response.php
index 88c47716..e58cc3d4 100644
--- a/src/Http/Adapter/FPM/Response.php
+++ b/src/Http/Adapter/FPM/Response.php
@@ -12,11 +12,12 @@ class Response extends UtopiaResponse
* Send output
*
* @param string $content
- * @return void
+ * @return bool False if write cannot complete, such as request ended by client
*/
- protected function write(string $content): void
+ public function write(string $content): bool
{
echo $content;
+ return true;
}
/**
@@ -27,7 +28,7 @@ protected function write(string $content): void
* @param string $content
* @return void
*/
- protected function end(string $content = null): void
+ public function end(string $content = null): void
{
if (!is_null($content)) {
echo $content;
@@ -55,7 +56,7 @@ protected function sendStatus(int $statusCode): void
* @param string $value
* @return void
*/
- protected function sendHeader(string $key, string $value): void
+ public function sendHeader(string $key, string $value): void
{
\header($key.': '.$value);
}
diff --git a/src/Http/Adapter/Swoole/Response.php b/src/Http/Adapter/Swoole/Response.php
index d4ecdf91..4bb03926 100644
--- a/src/Http/Adapter/Swoole/Response.php
+++ b/src/Http/Adapter/Swoole/Response.php
@@ -32,11 +32,11 @@ public function getSwooleResponse(): SwooleResponse
* Write
*
* @param string $content
- * @return void
+ * @return bool False if write cannot complete, such as request ended by client
*/
- protected function write(string $content): void
+ public function write(string $content): bool
{
- $this->swoole->write($content);
+ return $this->swoole->write($content);
}
/**
@@ -45,7 +45,7 @@ protected function write(string $content): void
* @param string|null $content
* @return void
*/
- protected function end(string $content = null): void
+ public function end(string $content = null): void
{
$this->swoole->end($content);
}
@@ -68,7 +68,7 @@ protected function sendStatus(int $statusCode): void
* @param string $value
* @return void
*/
- protected function sendHeader(string $key, string $value): void
+ public function sendHeader(string $key, string $value): void
{
$this->swoole->header($key, $value);
}
diff --git a/src/Http/Response.php b/src/Http/Response.php
index c17fa52c..8d085d63 100755
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -511,9 +511,9 @@ public function send(string $body = ''): void
* Send output
*
* @param string $content
- * @return void
+ * @return bool False if write cannot complete, such as request ended by client
*/
- abstract protected function write(string $content): void;
+ abstract public function write(string $content): bool;
/**
* End
@@ -523,12 +523,7 @@ abstract protected function write(string $content): void;
* @param string $content
* @return void
*/
- protected function end(string $content = null): void
- {
- if (!is_null($content)) {
- echo $content;
- }
- }
+ abstract public function end(string $content = null): void;
/**
* Output response
@@ -608,7 +603,7 @@ abstract protected function sendStatus(int $statusCode): void;
* @param string $value
* @return void
*/
- abstract protected function sendHeader(string $key, string $value): void;
+ abstract public function sendHeader(string $key, string $value): void;
/**
* Send Cookie
From a92c7356ebb226c0d0aacc7a2596c0cb6f895cc2 Mon Sep 17 00:00:00 2001
From: Christy Jacob
Date: Thu, 7 Mar 2024 16:54:04 +0000
Subject: [PATCH 094/119] chore: test default param with function
---
composer.json | 3 +-
composer.lock | 337 ++++++++++++++++++++-------------------------
src/Http/Http.php | 3 +
tests/HttpTest.php | 43 ++++++
4 files changed, 194 insertions(+), 192 deletions(-)
diff --git a/composer.json b/composer.json
index 8694ef5b..b5c168bc 100644
--- a/composer.json
+++ b/composer.json
@@ -12,7 +12,8 @@
"minimum-stability": "stable",
"autoload": {
"psr-4": {
- "Utopia\\Http\\": "src/Http"
+ "Utopia\\": "src/",
+ "Tests\\E2E\\": "tests/e2e"
}
},
"scripts": {
diff --git a/composer.lock b/composer.lock
index a5519ed2..bc775e43 100644
--- a/composer.lock
+++ b/composer.lock
@@ -155,27 +155,27 @@
},
{
"name": "doctrine/lexer",
- "version": "3.0.0",
+ "version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
- "reference": "84a527db05647743d50373e0ec53a152f2cde568"
+ "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568",
- "reference": "84a527db05647743d50373e0ec53a152f2cde568",
+ "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd",
+ "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd",
"shasum": ""
},
"require": {
"php": "^8.1"
},
"require-dev": {
- "doctrine/coding-standard": "^10",
- "phpstan/phpstan": "^1.9",
- "phpunit/phpunit": "^9.5",
+ "doctrine/coding-standard": "^12",
+ "phpstan/phpstan": "^1.10",
+ "phpunit/phpunit": "^10.5",
"psalm/plugin-phpunit": "^0.18.3",
- "vimeo/psalm": "^5.0"
+ "vimeo/psalm": "^5.21"
},
"type": "library",
"autoload": {
@@ -212,7 +212,7 @@
],
"support": {
"issues": "https://github.com/doctrine/lexer/issues",
- "source": "https://github.com/doctrine/lexer/tree/3.0.0"
+ "source": "https://github.com/doctrine/lexer/tree/3.0.1"
},
"funding": [
{
@@ -228,20 +228,20 @@
"type": "tidelift"
}
],
- "time": "2022-12-15T16:57:16+00:00"
+ "time": "2024-02-05T11:56:58+00:00"
},
{
"name": "laravel/pint",
- "version": "v1.13.7",
+ "version": "v1.14.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "4157768980dbd977f1c4b4cc94997416d8b30ece"
+ "reference": "6b127276e3f263f7bb17d5077e9e0269e61b2a0e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/4157768980dbd977f1c4b4cc94997416d8b30ece",
- "reference": "4157768980dbd977f1c4b4cc94997416d8b30ece",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/6b127276e3f263f7bb17d5077e9e0269e61b2a0e",
+ "reference": "6b127276e3f263f7bb17d5077e9e0269e61b2a0e",
"shasum": ""
},
"require": {
@@ -252,13 +252,13 @@
"php": "^8.1.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.38.0",
- "illuminate/view": "^10.30.1",
+ "friendsofphp/php-cs-fixer": "^3.49.0",
+ "illuminate/view": "^10.43.0",
+ "larastan/larastan": "^2.8.1",
"laravel-zero/framework": "^10.3.0",
- "mockery/mockery": "^1.6.6",
- "nunomaduro/larastan": "^2.6.4",
+ "mockery/mockery": "^1.6.7",
"nunomaduro/termwind": "^1.15.1",
- "pestphp/pest": "^2.24.2"
+ "pestphp/pest": "^2.33.6"
},
"bin": [
"builds/pint"
@@ -294,7 +294,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2023-12-05T19:43:12+00:00"
+ "time": "2024-02-20T17:38:05+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -357,25 +357,27 @@
},
{
"name": "nikic/php-parser",
- "version": "v4.18.0",
+ "version": "v5.0.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999"
+ "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999",
- "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13",
+ "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13",
"shasum": ""
},
"require": {
+ "ext-ctype": "*",
+ "ext-json": "*",
"ext-tokenizer": "*",
- "php": ">=7.0"
+ "php": ">=7.4"
},
"require-dev": {
"ircmaxell/php-yacc": "^0.0.7",
- "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
+ "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
},
"bin": [
"bin/php-parse"
@@ -383,7 +385,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.9-dev"
+ "dev-master": "5.0-dev"
}
},
"autoload": {
@@ -407,26 +409,27 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2"
},
- "time": "2023-12-10T21:03:43+00:00"
+ "time": "2024-03-05T20:51:40+00:00"
},
{
"name": "phar-io/manifest",
- "version": "2.0.3",
+ "version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/phar-io/manifest.git",
- "reference": "97803eca37d319dfa7826cc2437fc020857acb53"
+ "reference": "54750ef60c58e43759730615a392c31c80e23176"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
- "reference": "97803eca37d319dfa7826cc2437fc020857acb53",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176",
"shasum": ""
},
"require": {
"ext-dom": "*",
+ "ext-libxml": "*",
"ext-phar": "*",
"ext-xmlwriter": "*",
"phar-io/version": "^3.0.1",
@@ -467,9 +470,15 @@
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
"support": {
"issues": "https://github.com/phar-io/manifest/issues",
- "source": "https://github.com/phar-io/manifest/tree/2.0.3"
+ "source": "https://github.com/phar-io/manifest/tree/2.0.4"
},
- "time": "2021-07-20T11:28:43+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:33:53+00:00"
},
{
"name": "phar-io/version",
@@ -724,16 +733,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.10.52",
+ "version": "1.10.60",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "0cd0c330081d4f1e1d630701fe4f342c3b659685"
+ "reference": "95dcea7d6c628a3f2f56d091d8a0219485a86bbe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0cd0c330081d4f1e1d630701fe4f342c3b659685",
- "reference": "0cd0c330081d4f1e1d630701fe4f342c3b659685",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/95dcea7d6c628a3f2f56d091d8a0219485a86bbe",
+ "reference": "95dcea7d6c628a3f2f56d091d8a0219485a86bbe",
"shasum": ""
},
"require": {
@@ -782,20 +791,20 @@
"type": "tidelift"
}
],
- "time": "2024-01-05T09:51:32+00:00"
+ "time": "2024-03-07T13:30:19+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "9.2.30",
+ "version": "9.2.31",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089"
+ "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089",
- "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965",
+ "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965",
"shasum": ""
},
"require": {
@@ -852,7 +861,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31"
},
"funding": [
{
@@ -860,7 +869,7 @@
"type": "github"
}
],
- "time": "2023-12-22T06:47:57+00:00"
+ "time": "2024-03-02T06:37:42+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -1105,16 +1114,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.15",
+ "version": "9.6.17",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1"
+ "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1",
- "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1a156980d78a6666721b7e8e8502fe210b587fcd",
+ "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd",
"shasum": ""
},
"require": {
@@ -1188,7 +1197,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.17"
},
"funding": [
{
@@ -1204,7 +1213,7 @@
"type": "tidelift"
}
],
- "time": "2023-12-01T16:55:19+00:00"
+ "time": "2024-02-23T13:14:51+00:00"
},
{
"name": "psr/cache",
@@ -1360,16 +1369,16 @@
},
{
"name": "sebastian/cli-parser",
- "version": "1.0.1",
+ "version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/cli-parser.git",
- "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
+ "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
- "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
+ "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
"shasum": ""
},
"require": {
@@ -1404,7 +1413,7 @@
"homepage": "https://github.com/sebastianbergmann/cli-parser",
"support": {
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
- "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
},
"funding": [
{
@@ -1412,7 +1421,7 @@
"type": "github"
}
],
- "time": "2020-09-28T06:08:49+00:00"
+ "time": "2024-03-02T06:27:43+00:00"
},
{
"name": "sebastian/code-unit",
@@ -1658,16 +1667,16 @@
},
{
"name": "sebastian/diff",
- "version": "4.0.5",
+ "version": "4.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
+ "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
- "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
+ "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
"shasum": ""
},
"require": {
@@ -1712,7 +1721,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
- "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
+ "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
},
"funding": [
{
@@ -1720,7 +1729,7 @@
"type": "github"
}
],
- "time": "2023-05-07T05:35:17+00:00"
+ "time": "2024-03-02T06:30:58+00:00"
},
{
"name": "sebastian/environment",
@@ -1787,16 +1796,16 @@
},
{
"name": "sebastian/exporter",
- "version": "4.0.5",
+ "version": "4.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d"
+ "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
- "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
+ "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
"shasum": ""
},
"require": {
@@ -1852,7 +1861,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
- "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5"
+ "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
},
"funding": [
{
@@ -1860,20 +1869,20 @@
"type": "github"
}
],
- "time": "2022-09-14T06:03:37+00:00"
+ "time": "2024-03-02T06:33:00+00:00"
},
{
"name": "sebastian/global-state",
- "version": "5.0.6",
+ "version": "5.0.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "bde739e7565280bda77be70044ac1047bc007e34"
+ "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
- "reference": "bde739e7565280bda77be70044ac1047bc007e34",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
+ "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
"shasum": ""
},
"require": {
@@ -1916,7 +1925,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
- "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
+ "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
},
"funding": [
{
@@ -1924,7 +1933,7 @@
"type": "github"
}
],
- "time": "2023-08-02T09:26:13+00:00"
+ "time": "2024-03-02T06:35:11+00:00"
},
{
"name": "sebastian/lines-of-code",
@@ -2324,16 +2333,16 @@
},
{
"name": "seld/jsonlint",
- "version": "1.10.1",
+ "version": "1.10.2",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/jsonlint.git",
- "reference": "76d449a358ece77d6f1d6331c68453e657172202"
+ "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/76d449a358ece77d6f1d6331c68453e657172202",
- "reference": "76d449a358ece77d6f1d6331c68453e657172202",
+ "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9bb7db07b5d66d90f6ebf542f09fc67d800e5259",
+ "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259",
"shasum": ""
},
"require": {
@@ -2372,7 +2381,7 @@
],
"support": {
"issues": "https://github.com/Seldaek/jsonlint/issues",
- "source": "https://github.com/Seldaek/jsonlint/tree/1.10.1"
+ "source": "https://github.com/Seldaek/jsonlint/tree/1.10.2"
},
"funding": [
{
@@ -2384,62 +2393,20 @@
"type": "tidelift"
}
],
- "time": "2023-12-18T13:03:25+00:00"
- },
- {
- "name": "swoole/ide-helper",
- "version": "4.8.3",
- "source": {
- "type": "git",
- "url": "https://github.com/swoole/ide-helper.git",
- "reference": "3ac4971814273889933b871e03b2a6b340e58f79"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/swoole/ide-helper/zipball/3ac4971814273889933b871e03b2a6b340e58f79",
- "reference": "3ac4971814273889933b871e03b2a6b340e58f79",
- "shasum": ""
- },
- "type": "library",
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "Apache-2.0"
- ],
- "authors": [
- {
- "name": "Team Swoole",
- "email": "team@swoole.com"
- }
- ],
- "description": "IDE help files for Swoole.",
- "support": {
- "issues": "https://github.com/swoole/ide-helper/issues",
- "source": "https://github.com/swoole/ide-helper/tree/4.8.3"
- },
- "funding": [
- {
- "url": "https://gitee.com/swoole/swoole?donate=true",
- "type": "custom"
- },
- {
- "url": "https://github.com/swoole",
- "type": "github"
- }
- ],
- "time": "2021-12-01T08:11:40+00:00"
+ "time": "2024-02-07T12:57:50+00:00"
},
{
"name": "symfony/console",
- "version": "v7.0.2",
+ "version": "v7.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "f8587c4cdc5acad67af71c37db34ef03af91e59c"
+ "reference": "6b099f3306f7c9c2d2786ed736d0026b2903205f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/f8587c4cdc5acad67af71c37db34ef03af91e59c",
- "reference": "f8587c4cdc5acad67af71c37db34ef03af91e59c",
+ "url": "https://api.github.com/repos/symfony/console/zipball/6b099f3306f7c9c2d2786ed736d0026b2903205f",
+ "reference": "6b099f3306f7c9c2d2786ed736d0026b2903205f",
"shasum": ""
},
"require": {
@@ -2503,7 +2470,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.0.2"
+ "source": "https://github.com/symfony/console/tree/v7.0.4"
},
"funding": [
{
@@ -2519,7 +2486,7 @@
"type": "tidelift"
}
],
- "time": "2023-12-10T16:54:46+00:00"
+ "time": "2024-02-22T20:27:20+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -2590,16 +2557,16 @@
},
{
"name": "symfony/filesystem",
- "version": "v7.0.0",
+ "version": "v7.0.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "7da8ea2362a283771478c5f7729cfcb43a76b8b7"
+ "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/7da8ea2362a283771478c5f7729cfcb43a76b8b7",
- "reference": "7da8ea2362a283771478c5f7729cfcb43a76b8b7",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/2890e3a825bc0c0558526c04499c13f83e1b6b12",
+ "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12",
"shasum": ""
},
"require": {
@@ -2633,7 +2600,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v7.0.0"
+ "source": "https://github.com/symfony/filesystem/tree/v7.0.3"
},
"funding": [
{
@@ -2649,7 +2616,7 @@
"type": "tidelift"
}
],
- "time": "2023-07-27T06:33:22+00:00"
+ "time": "2024-01-23T15:02:46+00:00"
},
{
"name": "symfony/finder",
@@ -2784,16 +2751,16 @@
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.28.0",
+ "version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
+ "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
- "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
+ "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
"shasum": ""
},
"require": {
@@ -2807,9 +2774,6 @@
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "1.28-dev"
- },
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
@@ -2846,7 +2810,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
},
"funding": [
{
@@ -2862,20 +2826,20 @@
"type": "tidelift"
}
],
- "time": "2023-01-26T09:26:14+00:00"
+ "time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.28.0",
+ "version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "875e90aeea2777b6f135677f618529449334a612"
+ "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
- "reference": "875e90aeea2777b6f135677f618529449334a612",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f",
+ "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f",
"shasum": ""
},
"require": {
@@ -2886,9 +2850,6 @@
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "1.28-dev"
- },
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
@@ -2927,7 +2888,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0"
},
"funding": [
{
@@ -2943,20 +2904,20 @@
"type": "tidelift"
}
],
- "time": "2023-01-26T09:26:14+00:00"
+ "time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.28.0",
+ "version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
+ "reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
- "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
+ "reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
"shasum": ""
},
"require": {
@@ -2967,9 +2928,6 @@
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "1.28-dev"
- },
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
@@ -3011,7 +2969,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
},
"funding": [
{
@@ -3027,20 +2985,20 @@
"type": "tidelift"
}
],
- "time": "2023-01-26T09:26:14+00:00"
+ "time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.28.0",
+ "version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "42292d99c55abe617799667f454222c54c60e229"
+ "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
- "reference": "42292d99c55abe617799667f454222c54c60e229",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
+ "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"shasum": ""
},
"require": {
@@ -3054,9 +3012,6 @@
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "1.28-dev"
- },
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
@@ -3094,7 +3049,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
},
"funding": [
{
@@ -3110,20 +3065,20 @@
"type": "tidelift"
}
],
- "time": "2023-07-28T09:04:16+00:00"
+ "time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/process",
- "version": "v7.0.2",
+ "version": "v7.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a"
+ "reference": "0e7727191c3b71ebec6d529fa0e50a01ca5679e9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a",
- "reference": "acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a",
+ "url": "https://api.github.com/repos/symfony/process/zipball/0e7727191c3b71ebec6d529fa0e50a01ca5679e9",
+ "reference": "0e7727191c3b71ebec6d529fa0e50a01ca5679e9",
"shasum": ""
},
"require": {
@@ -3155,7 +3110,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v7.0.2"
+ "source": "https://github.com/symfony/process/tree/v7.0.4"
},
"funding": [
{
@@ -3171,7 +3126,7 @@
"type": "tidelift"
}
],
- "time": "2023-12-24T09:15:37+00:00"
+ "time": "2024-02-22T20:27:20+00:00"
},
{
"name": "symfony/service-contracts",
@@ -3257,16 +3212,16 @@
},
{
"name": "symfony/string",
- "version": "v7.0.2",
+ "version": "v7.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5"
+ "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/cc78f14f91f5e53b42044d0620961c48028ff9f5",
- "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5",
+ "url": "https://api.github.com/repos/symfony/string/zipball/f5832521b998b0bec40bee688ad5de98d4cf111b",
+ "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b",
"shasum": ""
},
"require": {
@@ -3323,7 +3278,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v7.0.2"
+ "source": "https://github.com/symfony/string/tree/v7.0.4"
},
"funding": [
{
@@ -3339,20 +3294,20 @@
"type": "tidelift"
}
],
- "time": "2023-12-10T16:54:46+00:00"
+ "time": "2024-02-01T13:17:36+00:00"
},
{
"name": "theseer/tokenizer",
- "version": "1.2.2",
+ "version": "1.2.3",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
- "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
- "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
"shasum": ""
},
"require": {
@@ -3381,7 +3336,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
- "source": "https://github.com/theseer/tokenizer/tree/1.2.2"
+ "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
},
"funding": [
{
@@ -3389,7 +3344,7 @@
"type": "github"
}
],
- "time": "2023-11-20T00:12:19+00:00"
+ "time": "2024-03-03T12:36:25+00:00"
},
{
"name": "webmozart/glob",
@@ -3451,5 +3406,5 @@
"ext-swoole": "*"
},
"platform-dev": [],
- "plugin-api-version": "2.3.0"
+ "plugin-api-version": "2.6.0"
}
diff --git a/src/Http/Http.php b/src/Http/Http.php
index c203462f..37638edb 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -740,6 +740,9 @@ protected function getArguments(Hook $hook, string $context, array $values, arra
$paramExists = $existsInRequest || $existsInValues;
$arg = $existsInRequest ? $requestParams[$key] : $param['default'];
+ if (\is_callable($arg)) {
+ $arg = \call_user_func_array($arg, $this->getResources($param['injections']));
+ }
$value = $existsInValues ? $values[$key] : $arg;
if (!$param['skipValidation']) {
diff --git a/tests/HttpTest.php b/tests/HttpTest.php
index 64235e0f..57d34bd0 100755
--- a/tests/HttpTest.php
+++ b/tests/HttpTest.php
@@ -117,6 +117,49 @@ public function testCanGetResources(): void
$this->assertEquals('x-def-y-def-' . $resource, $result);
}
+ public function testCanGetDefaultValue(): void
+ {
+ App::setResource('first', fn ($second) => "first-{$second}", ['second']);
+ App::setResource('second', fn () => 'second');
+
+ $second = $this->app->getResource('second');
+ $first = $this->app->getResource('first');
+ $this->assertEquals('second', $second);
+ $this->assertEquals('first-second', $first);
+
+ // Default Params
+ $route = new Route('GET', '/path');
+
+ $route
+ ->param('x', 'x-def', new Text(200), 'x param', true)
+ ->action(function ($x) {
+ echo $x;
+ });
+
+ \ob_start();
+ $this->app->execute($route, new Request(), new Response());
+ $result = \ob_get_contents();
+ \ob_end_clean();
+
+ // Default Value using function
+ $route = new Route('GET', '/path');
+
+ $route
+ ->param('x', function ($first, $second) {
+ return $first . '-' . $second;
+ } , new Text(200), 'x param', true, ['first', 'second'])
+ ->action(function ($x) {
+ echo $x;
+ });
+
+ \ob_start();
+ $this->app->execute($route, new Request(), new Response());
+ $result = \ob_get_contents();
+ \ob_end_clean();
+
+ $this->assertEquals('first-second-second', $result);
+ }
+
public function testCanExecuteRoute(): void
{
Http::setResource('rand', fn () => rand());
From 7d7ca4aa0d8bc2236434d3dd6bf9c21684d25678 Mon Sep 17 00:00:00 2001
From: Christy Jacob
Date: Thu, 7 Mar 2024 16:54:34 +0000
Subject: [PATCH 095/119] chore: update test
---
tests/HttpTest.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/HttpTest.php b/tests/HttpTest.php
index 57d34bd0..fcee79f7 100755
--- a/tests/HttpTest.php
+++ b/tests/HttpTest.php
@@ -117,7 +117,7 @@ public function testCanGetResources(): void
$this->assertEquals('x-def-y-def-' . $resource, $result);
}
- public function testCanGetDefaultValue(): void
+ public function testCanGetDefaultValueWithFunction(): void
{
App::setResource('first', fn ($second) => "first-{$second}", ['second']);
App::setResource('second', fn () => 'second');
From 8baa1c79185e4d27e95661053405d2613fc32be5 Mon Sep 17 00:00:00 2001
From: Christy Jacob
Date: Thu, 7 Mar 2024 16:57:25 +0000
Subject: [PATCH 096/119] chore: linter
---
tests/HttpTest.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/HttpTest.php b/tests/HttpTest.php
index fcee79f7..da678821 100755
--- a/tests/HttpTest.php
+++ b/tests/HttpTest.php
@@ -127,7 +127,7 @@ public function testCanGetDefaultValueWithFunction(): void
$this->assertEquals('second', $second);
$this->assertEquals('first-second', $first);
- // Default Params
+ // Default Params
$route = new Route('GET', '/path');
$route
@@ -147,7 +147,7 @@ public function testCanGetDefaultValueWithFunction(): void
$route
->param('x', function ($first, $second) {
return $first . '-' . $second;
- } , new Text(200), 'x param', true, ['first', 'second'])
+ }, new Text(200), 'x param', true, ['first', 'second'])
->action(function ($x) {
echo $x;
});
From 96cec116613a94d667a694b15af2a22652361b4f Mon Sep 17 00:00:00 2001
From: Christy Jacob
Date: Thu, 7 Mar 2024 17:04:38 +0000
Subject: [PATCH 097/119] chore: fix tests
---
composer.lock | 42 ++++++++++++++++++++++++++++++++++++++++++
tests/HttpTest.php | 24 +++++-------------------
2 files changed, 47 insertions(+), 19 deletions(-)
diff --git a/composer.lock b/composer.lock
index bc775e43..cb7278bc 100644
--- a/composer.lock
+++ b/composer.lock
@@ -2395,6 +2395,48 @@
],
"time": "2024-02-07T12:57:50+00:00"
},
+ {
+ "name": "swoole/ide-helper",
+ "version": "4.8.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/swoole/ide-helper.git",
+ "reference": "3ac4971814273889933b871e03b2a6b340e58f79"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/swoole/ide-helper/zipball/3ac4971814273889933b871e03b2a6b340e58f79",
+ "reference": "3ac4971814273889933b871e03b2a6b340e58f79",
+ "shasum": ""
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Team Swoole",
+ "email": "team@swoole.com"
+ }
+ ],
+ "description": "IDE help files for Swoole.",
+ "support": {
+ "issues": "https://github.com/swoole/ide-helper/issues",
+ "source": "https://github.com/swoole/ide-helper/tree/4.8.3"
+ },
+ "funding": [
+ {
+ "url": "https://gitee.com/swoole/swoole?donate=true",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/swoole",
+ "type": "github"
+ }
+ ],
+ "time": "2021-12-01T08:11:40+00:00"
+ },
{
"name": "symfony/console",
"version": "v7.0.4",
diff --git a/tests/HttpTest.php b/tests/HttpTest.php
index da678821..0d314cd3 100755
--- a/tests/HttpTest.php
+++ b/tests/HttpTest.php
@@ -119,28 +119,14 @@ public function testCanGetResources(): void
public function testCanGetDefaultValueWithFunction(): void
{
- App::setResource('first', fn ($second) => "first-{$second}", ['second']);
- App::setResource('second', fn () => 'second');
+ Http::setResource('first', fn ($second) => "first-{$second}", ['second']);
+ Http::setResource('second', fn () => 'second');
- $second = $this->app->getResource('second');
- $first = $this->app->getResource('first');
+ $second = $this->http->getResource('second');
+ $first = $this->http->getResource('first');
$this->assertEquals('second', $second);
$this->assertEquals('first-second', $first);
- // Default Params
- $route = new Route('GET', '/path');
-
- $route
- ->param('x', 'x-def', new Text(200), 'x param', true)
- ->action(function ($x) {
- echo $x;
- });
-
- \ob_start();
- $this->app->execute($route, new Request(), new Response());
- $result = \ob_get_contents();
- \ob_end_clean();
-
// Default Value using function
$route = new Route('GET', '/path');
@@ -153,7 +139,7 @@ public function testCanGetDefaultValueWithFunction(): void
});
\ob_start();
- $this->app->execute($route, new Request(), new Response());
+ $this->http->execute($route, new Request(), '1');
$result = \ob_get_contents();
\ob_end_clean();
From c96d01129e55b6c126150497a44e08f42800b8bd Mon Sep 17 00:00:00 2001
From: Steven Nguyen
Date: Mon, 11 Mar 2024 14:22:53 +0100
Subject: [PATCH 098/119] refactor(validator): simplify return
---
src/Http/Validator/Host.php | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/src/Http/Validator/Host.php b/src/Http/Validator/Host.php
index 916e6193..a693cedb 100755
--- a/src/Http/Validator/Host.php
+++ b/src/Http/Validator/Host.php
@@ -53,11 +53,7 @@ public function isValid($value): bool
$hostnameValidator = new Hostname($this->whitelist);
- if (!$hostnameValidator->isValid(\parse_url($value, PHP_URL_HOST))) {
- return false;
- }
-
- return true;
+ return $hostnameValidator->isValid(\parse_url($value, PHP_URL_HOST));
}
/**
From 65d4fb863f215b89fdaa269ef6cc2951b52663af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 2 Jul 2024 06:28:28 +0000
Subject: [PATCH 099/119] Implement rules for multiple validator
---
composer.lock | 292 ++++++++++++++++---------------
src/Http/Validator/Multiple.php | 54 ++++--
tests/Validator/MultipleTest.php | 26 +++
3 files changed, 214 insertions(+), 158 deletions(-)
diff --git a/composer.lock b/composer.lock
index cb7278bc..67cde3f0 100644
--- a/composer.lock
+++ b/composer.lock
@@ -232,16 +232,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.14.0",
+ "version": "v1.16.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "6b127276e3f263f7bb17d5077e9e0269e61b2a0e"
+ "reference": "9266a47f1b9231b83e0cfd849009547329d871b1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/6b127276e3f263f7bb17d5077e9e0269e61b2a0e",
- "reference": "6b127276e3f263f7bb17d5077e9e0269e61b2a0e",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/9266a47f1b9231b83e0cfd849009547329d871b1",
+ "reference": "9266a47f1b9231b83e0cfd849009547329d871b1",
"shasum": ""
},
"require": {
@@ -252,13 +252,13 @@
"php": "^8.1.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.49.0",
- "illuminate/view": "^10.43.0",
- "larastan/larastan": "^2.8.1",
- "laravel-zero/framework": "^10.3.0",
- "mockery/mockery": "^1.6.7",
+ "friendsofphp/php-cs-fixer": "^3.59.3",
+ "illuminate/view": "^10.48.12",
+ "larastan/larastan": "^2.9.7",
+ "laravel-zero/framework": "^10.4.0",
+ "mockery/mockery": "^1.6.12",
"nunomaduro/termwind": "^1.15.1",
- "pestphp/pest": "^2.33.6"
+ "pestphp/pest": "^2.34.8"
},
"bin": [
"builds/pint"
@@ -294,20 +294,20 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2024-02-20T17:38:05+00:00"
+ "time": "2024-06-18T16:50:05+00:00"
},
{
"name": "myclabs/deep-copy",
- "version": "1.11.1",
+ "version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
+ "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
- "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
+ "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
"shasum": ""
},
"require": {
@@ -315,11 +315,12 @@
},
"conflict": {
"doctrine/collections": "<1.6.8",
- "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+ "doctrine/common": "<2.13.3 || >=3 <3.2.2"
},
"require-dev": {
"doctrine/collections": "^1.6.8",
"doctrine/common": "^2.13.3 || ^3.2.2",
+ "phpspec/prophecy": "^1.10",
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
},
"type": "library",
@@ -345,7 +346,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
},
"funding": [
{
@@ -353,20 +354,20 @@
"type": "tidelift"
}
],
- "time": "2023-03-08T13:26:56+00:00"
+ "time": "2024-06-12T14:39:25+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v5.0.2",
+ "version": "v5.1.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13"
+ "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13",
- "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1",
+ "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1",
"shasum": ""
},
"require": {
@@ -377,7 +378,7 @@
},
"require-dev": {
"ircmaxell/php-yacc": "^0.0.7",
- "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
+ "phpunit/phpunit": "^9.0"
},
"bin": [
"bin/php-parse"
@@ -409,9 +410,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0"
},
- "time": "2024-03-05T20:51:40+00:00"
+ "time": "2024-07-01T20:03:41+00:00"
},
{
"name": "phar-io/manifest",
@@ -635,16 +636,16 @@
},
{
"name": "phpbench/phpbench",
- "version": "1.2.15",
+ "version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/phpbench/phpbench.git",
- "reference": "f7000319695cfad04a57fc64bf7ef7abdf4c437c"
+ "reference": "a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpbench/phpbench/zipball/f7000319695cfad04a57fc64bf7ef7abdf4c437c",
- "reference": "f7000319695cfad04a57fc64bf7ef7abdf4c437c",
+ "url": "https://api.github.com/repos/phpbench/phpbench/zipball/a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0",
+ "reference": "a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0",
"shasum": ""
},
"require": {
@@ -656,29 +657,30 @@
"ext-spl": "*",
"ext-tokenizer": "*",
"php": "^8.1",
- "phpbench/container": "^2.1",
+ "phpbench/container": "^2.2",
"phpbench/dom": "~0.3.3",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"seld/jsonlint": "^1.1",
- "symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0",
- "symfony/filesystem": "^4.2 || ^5.0 || ^6.0 || ^7.0",
- "symfony/finder": "^4.2 || ^5.0 || ^6.0 || ^7.0",
- "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0",
- "symfony/process": "^4.2 || ^5.0 || ^6.0 || ^7.0",
+ "symfony/console": "^6.1 || ^7.0",
+ "symfony/filesystem": "^6.1 || ^7.0",
+ "symfony/finder": "^6.1 || ^7.0",
+ "symfony/options-resolver": "^6.1 || ^7.0",
+ "symfony/process": "^6.1 || ^7.0",
"webmozart/glob": "^4.6"
},
"require-dev": {
"dantleech/invoke": "^2.0",
+ "ergebnis/composer-normalize": "^2.39",
"friendsofphp/php-cs-fixer": "^3.0",
"jangregor/phpstan-prophecy": "^1.0",
"phpspec/prophecy": "dev-master",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
- "phpunit/phpunit": "^10.0",
- "rector/rector": "^0.18.10",
- "symfony/error-handler": "^5.2 || ^6.0 || ^7.0",
- "symfony/var-dumper": "^4.0 || ^5.0 || ^6.0 || ^7.0"
+ "phpunit/phpunit": "^10.4",
+ "rector/rector": "^0.18.11 || ^1.0.0",
+ "symfony/error-handler": "^6.1 || ^7.0",
+ "symfony/var-dumper": "^6.1 || ^7.0"
},
"suggest": {
"ext-xdebug": "For Xdebug profiling extension."
@@ -721,7 +723,7 @@
],
"support": {
"issues": "https://github.com/phpbench/phpbench/issues",
- "source": "https://github.com/phpbench/phpbench/tree/1.2.15"
+ "source": "https://github.com/phpbench/phpbench/tree/1.3.1"
},
"funding": [
{
@@ -729,20 +731,20 @@
"type": "github"
}
],
- "time": "2023-11-29T12:21:11+00:00"
+ "time": "2024-06-30T11:04:37+00:00"
},
{
"name": "phpstan/phpstan",
- "version": "1.10.60",
+ "version": "1.11.6",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "95dcea7d6c628a3f2f56d091d8a0219485a86bbe"
+ "reference": "6ac78f1165346c83b4a753f7e4186d969c6ad0ee"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/95dcea7d6c628a3f2f56d091d8a0219485a86bbe",
- "reference": "95dcea7d6c628a3f2f56d091d8a0219485a86bbe",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6ac78f1165346c83b4a753f7e4186d969c6ad0ee",
+ "reference": "6ac78f1165346c83b4a753f7e4186d969c6ad0ee",
"shasum": ""
},
"require": {
@@ -785,13 +787,9 @@
{
"url": "https://github.com/phpstan",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
- "type": "tidelift"
}
],
- "time": "2024-03-07T13:30:19+00:00"
+ "time": "2024-07-01T15:33:06+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -1114,16 +1112,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.17",
+ "version": "9.6.19",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd"
+ "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1a156980d78a6666721b7e8e8502fe210b587fcd",
- "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1a54a473501ef4cdeaae4e06891674114d79db8",
+ "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8",
"shasum": ""
},
"require": {
@@ -1197,7 +1195,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.17"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.19"
},
"funding": [
{
@@ -1213,7 +1211,7 @@
"type": "tidelift"
}
],
- "time": "2024-02-23T13:14:51+00:00"
+ "time": "2024-04-05T04:35:58+00:00"
},
{
"name": "psr/cache",
@@ -2169,16 +2167,16 @@
},
{
"name": "sebastian/resource-operations",
- "version": "3.0.3",
+ "version": "3.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/resource-operations.git",
- "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
+ "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
- "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
+ "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
"shasum": ""
},
"require": {
@@ -2190,7 +2188,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-main": "3.0-dev"
}
},
"autoload": {
@@ -2211,8 +2209,7 @@
"description": "Provides a list of PHP built-in functions that operate on resources",
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
"support": {
- "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
- "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
+ "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
},
"funding": [
{
@@ -2220,7 +2217,7 @@
"type": "github"
}
],
- "time": "2020-09-28T06:45:17+00:00"
+ "time": "2024-03-14T16:00:52+00:00"
},
{
"name": "sebastian/type",
@@ -2439,16 +2436,16 @@
},
{
"name": "symfony/console",
- "version": "v7.0.4",
+ "version": "v7.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "6b099f3306f7c9c2d2786ed736d0026b2903205f"
+ "reference": "0aa29ca177f432ab68533432db0de059f39c92ae"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/6b099f3306f7c9c2d2786ed736d0026b2903205f",
- "reference": "6b099f3306f7c9c2d2786ed736d0026b2903205f",
+ "url": "https://api.github.com/repos/symfony/console/zipball/0aa29ca177f432ab68533432db0de059f39c92ae",
+ "reference": "0aa29ca177f432ab68533432db0de059f39c92ae",
"shasum": ""
},
"require": {
@@ -2512,7 +2509,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.0.4"
+ "source": "https://github.com/symfony/console/tree/v7.1.2"
},
"funding": [
{
@@ -2528,20 +2525,20 @@
"type": "tidelift"
}
],
- "time": "2024-02-22T20:27:20+00:00"
+ "time": "2024-06-28T10:03:55+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.4.0",
+ "version": "v3.5.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
+ "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
- "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
+ "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
"shasum": ""
},
"require": {
@@ -2550,7 +2547,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "3.4-dev"
+ "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -2579,7 +2576,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
},
"funding": [
{
@@ -2595,20 +2592,20 @@
"type": "tidelift"
}
],
- "time": "2023-05-23T14:45:45+00:00"
+ "time": "2024-04-18T09:32:20+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v7.0.3",
+ "version": "v7.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12"
+ "reference": "92a91985250c251de9b947a14bb2c9390b1a562c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/2890e3a825bc0c0558526c04499c13f83e1b6b12",
- "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/92a91985250c251de9b947a14bb2c9390b1a562c",
+ "reference": "92a91985250c251de9b947a14bb2c9390b1a562c",
"shasum": ""
},
"require": {
@@ -2616,6 +2613,9 @@
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8"
},
+ "require-dev": {
+ "symfony/process": "^6.4|^7.0"
+ },
"type": "library",
"autoload": {
"psr-4": {
@@ -2642,7 +2642,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v7.0.3"
+ "source": "https://github.com/symfony/filesystem/tree/v7.1.2"
},
"funding": [
{
@@ -2658,20 +2658,20 @@
"type": "tidelift"
}
],
- "time": "2024-01-23T15:02:46+00:00"
+ "time": "2024-06-28T10:03:55+00:00"
},
{
"name": "symfony/finder",
- "version": "v7.0.0",
+ "version": "v7.1.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "6e5688d69f7cfc4ed4a511e96007e06c2d34ce56"
+ "reference": "fbb0ba67688b780efbc886c1a0a0948dcf7205d6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/6e5688d69f7cfc4ed4a511e96007e06c2d34ce56",
- "reference": "6e5688d69f7cfc4ed4a511e96007e06c2d34ce56",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/fbb0ba67688b780efbc886c1a0a0948dcf7205d6",
+ "reference": "fbb0ba67688b780efbc886c1a0a0948dcf7205d6",
"shasum": ""
},
"require": {
@@ -2706,7 +2706,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v7.0.0"
+ "source": "https://github.com/symfony/finder/tree/v7.1.1"
},
"funding": [
{
@@ -2722,20 +2722,20 @@
"type": "tidelift"
}
],
- "time": "2023-10-31T17:59:56+00:00"
+ "time": "2024-05-31T14:57:53+00:00"
},
{
"name": "symfony/options-resolver",
- "version": "v7.0.0",
+ "version": "v7.1.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
- "reference": "700ff4096e346f54cb628ea650767c8130f1001f"
+ "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/700ff4096e346f54cb628ea650767c8130f1001f",
- "reference": "700ff4096e346f54cb628ea650767c8130f1001f",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/47aa818121ed3950acd2b58d1d37d08a94f9bf55",
+ "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55",
"shasum": ""
},
"require": {
@@ -2773,7 +2773,7 @@
"options"
],
"support": {
- "source": "https://github.com/symfony/options-resolver/tree/v7.0.0"
+ "source": "https://github.com/symfony/options-resolver/tree/v7.1.1"
},
"funding": [
{
@@ -2789,20 +2789,20 @@
"type": "tidelift"
}
],
- "time": "2023-08-08T10:20:21+00:00"
+ "time": "2024-05-31T14:57:53+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.29.0",
+ "version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
+ "reference": "0424dff1c58f028c451efff2045f5d92410bd540"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
- "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540",
+ "reference": "0424dff1c58f028c451efff2045f5d92410bd540",
"shasum": ""
},
"require": {
@@ -2852,7 +2852,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
},
"funding": [
{
@@ -2868,20 +2868,20 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-05-31T15:07:36+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.29.0",
+ "version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f"
+ "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f",
- "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a",
+ "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a",
"shasum": ""
},
"require": {
@@ -2930,7 +2930,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0"
},
"funding": [
{
@@ -2946,20 +2946,20 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-05-31T15:07:36+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.29.0",
+ "version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
+ "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
- "reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb",
+ "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb",
"shasum": ""
},
"require": {
@@ -3011,7 +3011,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0"
},
"funding": [
{
@@ -3027,20 +3027,20 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-05-31T15:07:36+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.29.0",
+ "version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
+ "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
- "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c",
+ "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c",
"shasum": ""
},
"require": {
@@ -3091,7 +3091,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0"
},
"funding": [
{
@@ -3107,20 +3107,20 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-06-19T12:30:46+00:00"
},
{
"name": "symfony/process",
- "version": "v7.0.4",
+ "version": "v7.1.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "0e7727191c3b71ebec6d529fa0e50a01ca5679e9"
+ "reference": "febf90124323a093c7ee06fdb30e765ca3c20028"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/0e7727191c3b71ebec6d529fa0e50a01ca5679e9",
- "reference": "0e7727191c3b71ebec6d529fa0e50a01ca5679e9",
+ "url": "https://api.github.com/repos/symfony/process/zipball/febf90124323a093c7ee06fdb30e765ca3c20028",
+ "reference": "febf90124323a093c7ee06fdb30e765ca3c20028",
"shasum": ""
},
"require": {
@@ -3152,7 +3152,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v7.0.4"
+ "source": "https://github.com/symfony/process/tree/v7.1.1"
},
"funding": [
{
@@ -3168,25 +3168,26 @@
"type": "tidelift"
}
],
- "time": "2024-02-22T20:27:20+00:00"
+ "time": "2024-05-31T14:57:53+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v3.4.1",
+ "version": "v3.5.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0"
+ "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0",
- "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
+ "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
"shasum": ""
},
"require": {
"php": ">=8.1",
- "psr/container": "^1.1|^2.0"
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
@@ -3194,7 +3195,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "3.4-dev"
+ "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -3234,7 +3235,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.4.1"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.5.0"
},
"funding": [
{
@@ -3250,20 +3251,20 @@
"type": "tidelift"
}
],
- "time": "2023-12-26T14:02:43+00:00"
+ "time": "2024-04-18T09:32:20+00:00"
},
{
"name": "symfony/string",
- "version": "v7.0.4",
+ "version": "v7.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b"
+ "reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/f5832521b998b0bec40bee688ad5de98d4cf111b",
- "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b",
+ "url": "https://api.github.com/repos/symfony/string/zipball/14221089ac66cf82e3cf3d1c1da65de305587ff8",
+ "reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8",
"shasum": ""
},
"require": {
@@ -3277,6 +3278,7 @@
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
+ "symfony/emoji": "^7.1",
"symfony/error-handler": "^6.4|^7.0",
"symfony/http-client": "^6.4|^7.0",
"symfony/intl": "^6.4|^7.0",
@@ -3320,7 +3322,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v7.0.4"
+ "source": "https://github.com/symfony/string/tree/v7.1.2"
},
"funding": [
{
@@ -3336,7 +3338,7 @@
"type": "tidelift"
}
],
- "time": "2024-02-01T13:17:36+00:00"
+ "time": "2024-06-28T09:27:18+00:00"
},
{
"name": "theseer/tokenizer",
@@ -3390,16 +3392,16 @@
},
{
"name": "webmozart/glob",
- "version": "4.6.0",
+ "version": "4.7.0",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/glob.git",
- "reference": "3c17f7dec3d9d0e87b575026011f2e75a56ed655"
+ "reference": "8a2842112d6916e61e0e15e316465b611f3abc17"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webmozarts/glob/zipball/3c17f7dec3d9d0e87b575026011f2e75a56ed655",
- "reference": "3c17f7dec3d9d0e87b575026011f2e75a56ed655",
+ "url": "https://api.github.com/repos/webmozarts/glob/zipball/8a2842112d6916e61e0e15e316465b611f3abc17",
+ "reference": "8a2842112d6916e61e0e15e316465b611f3abc17",
"shasum": ""
},
"require": {
@@ -3433,9 +3435,9 @@
"description": "A PHP implementation of Ant's glob.",
"support": {
"issues": "https://github.com/webmozarts/glob/issues",
- "source": "https://github.com/webmozarts/glob/tree/4.6.0"
+ "source": "https://github.com/webmozarts/glob/tree/4.7.0"
},
- "time": "2022-05-24T19:45:58+00:00"
+ "time": "2024-03-07T20:33:40+00:00"
}
],
"aliases": [],
diff --git a/src/Http/Validator/Multiple.php b/src/Http/Validator/Multiple.php
index 4c919377..61b45d09 100644
--- a/src/Http/Validator/Multiple.php
+++ b/src/Http/Validator/Multiple.php
@@ -16,9 +16,14 @@ class Multiple extends Validator
/**
* @var Validator[]
*/
- protected $rules = [];
+ protected $validators = [];
protected $type = self::TYPE_MIXED;
+ protected $rule = self::RULE_ALL;
+
+ public const RULE_ALL = "ruleAll";
+ public const RULE_ANY = "ruleAny";
+ public const RULE_NONE = "ruleNone";
/**
* Constructor
@@ -29,26 +34,32 @@ class Multiple extends Validator
*
* $multiple = new Multiple([$validator1, $validator2]);
* $multiple = new Multiple([$validator1, $validator2, $validator3], self::TYPE_STRING);
+ *
+ * Rule is set to define criteria of validation:
+ * RULE_ANY: At least one validator must pass
+ * RULE_ALL: All validators must pass
+ * RULE_NONE: No validators must pass - all validators must fail
*/
- public function __construct(array $rules, ?string $type = self::TYPE_MIXED)
+ public function __construct(array $validators, ?string $type = self::TYPE_MIXED, ?string $rule = self::RULE_ALL)
{
- foreach ($rules as $rule) {
- $this->addRule($rule);
+ foreach ($validators as $validator) {
+ $this->addValidator($validator);
}
$this->type = $type;
+ $this->rule = $rule;
}
/**
- * Add rule
+ * Add validator
*
- * Add a new rule to the end of the rules containing array
+ * Add a new validator to check against during isVaid() call
*
- * @param Validator $rule
+ * @param Validator $validator
* @return $this
*/
- public function addRule(Validator $rule)
+ public function addValidator(Validator $validator)
{
- $this->rules[] = $rule;
+ $this->validators[] = $validator;
return $this;
}
@@ -63,7 +74,7 @@ public function addRule(Validator $rule)
public function getDescription(): string
{
$description = '';
- foreach ($this->rules as $key => $rule) {
+ foreach ($this->validators as $key => $rule) {
$description .= ++$key . '. ' . $rule->getDescription() . " \n";
}
@@ -80,12 +91,29 @@ public function getDescription(): string
*/
public function isValid(mixed $value): bool
{
- foreach ($this->rules as $rule) { /* @var $rule Validator */
- if (false === $rule->isValid($value)) {
- return false;
+ foreach ($this->validators as $rule) { /* @var $rule Validator */
+ $valid = $rule->isValid($value);
+
+ // Oprimization improvements
+ if($this->rule === self::RULE_ALL) {
+ if(!$valid) {
+ return false;
+ }
+ } if($this->rule === self::RULE_NONE) {
+ if($valid) {
+ return false;
+ }
+ } if($this->rule === self::RULE_ANY) {
+ if($valid) {
+ return true;
+ }
}
}
+ if($this->rule === self::RULE_ANY) {
+ return false;
+ }
+
return true;
}
diff --git a/tests/Validator/MultipleTest.php b/tests/Validator/MultipleTest.php
index 348c3244..9f1bf12d 100644
--- a/tests/Validator/MultipleTest.php
+++ b/tests/Validator/MultipleTest.php
@@ -32,4 +32,30 @@ public function testIsValid()
$this->assertFalse($this->validator->isValid('example.com/hello-world'));
$this->assertFalse($this->validator->isValid(''));
}
+
+ public function testRules()
+ {
+ $validTextValidUrl = 'http://example.com';
+ $validTextInvalidUrl = 'hello world';
+ $invalidTextValidUrl = 'http://example.com/very-long-url';
+ $invalidTextInvalidUrl = 'Some very long text that is also not an URL';
+
+ $vaidator = new Multiple([new Text(20), new URL()], Multiple::TYPE_STRING, Multiple::RULE_ALL);
+ $this->assertTrue($vaidator->isValid($validTextValidUrl));
+ $this->assertFalse($vaidator->isValid($validTextInvalidUrl));
+ $this->assertFalse($vaidator->isValid($invalidTextValidUrl));
+ $this->assertFalse($vaidator->isValid($invalidTextInvalidUrl));
+
+ $vaidator = new Multiple([new Text(20), new URL()], Multiple::TYPE_STRING, Multiple::RULE_ANY);
+ $this->assertTrue($vaidator->isValid($validTextValidUrl));
+ $this->assertTrue($vaidator->isValid($validTextInvalidUrl));
+ $this->assertTrue($vaidator->isValid($invalidTextValidUrl));
+ $this->assertFalse($vaidator->isValid($invalidTextInvalidUrl));
+
+ $vaidator = new Multiple([new Text(20), new URL()], Multiple::TYPE_STRING, Multiple::RULE_NONE);
+ $this->assertFalse($vaidator->isValid($validTextValidUrl));
+ $this->assertFalse($vaidator->isValid($validTextInvalidUrl));
+ $this->assertFalse($vaidator->isValid($invalidTextValidUrl));
+ $this->assertTrue($vaidator->isValid($invalidTextInvalidUrl));
+ }
}
From 102c44b46add9095ecaf8fd2945289bfbceffe75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 2 Jul 2024 08:21:17 +0000
Subject: [PATCH 100/119] Separate validators
---
src/Http/Validator/AllOf.php | 82 ++++++++++
src/Http/Validator/AnyOf.php | 82 ++++++++++
src/Http/Validator/Multiple.php | 143 ------------------
src/Http/Validator/NoneOf.php | 82 ++++++++++
.../{MultipleTest.php => MultipleOfTest.php} | 30 ++--
5 files changed, 261 insertions(+), 158 deletions(-)
create mode 100644 src/Http/Validator/AllOf.php
create mode 100644 src/Http/Validator/AnyOf.php
delete mode 100644 src/Http/Validator/Multiple.php
create mode 100644 src/Http/Validator/NoneOf.php
rename tests/Validator/{MultipleTest.php => MultipleOfTest.php} (60%)
diff --git a/src/Http/Validator/AllOf.php b/src/Http/Validator/AllOf.php
new file mode 100644
index 00000000..84cd8f9f
--- /dev/null
+++ b/src/Http/Validator/AllOf.php
@@ -0,0 +1,82 @@
+ $validators
+ */
+ public function __construct(protected array $validators, protected string $type = self::TYPE_MIXED)
+ {
+ }
+
+ /**
+ * Get Description
+ *
+ * Returns validator description
+ *
+ * @return string
+ */
+ public function getDescription(): string
+ {
+ $description = '';
+ foreach ($this->validators as $key => $rule) {
+ $description .= ++$key . '. ' . $rule->getDescription() . " \n";
+ }
+
+ return $description;
+ }
+
+ /**
+ * Is valid
+ *
+ * Validation will pass when all rules are valid if only one of the rules is invalid validation will fail.
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function isValid(mixed $value): bool
+ {
+ foreach ($this->validators as $rule) {
+ $valid = $rule->isValid($value);
+
+ if(!$valid) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get Type
+ *
+ * Returns validator type.
+ *
+ * @return string
+ */
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ /**
+ * Is array
+ *
+ * Function will return true if object is array.
+ *
+ * @return bool
+ */
+ public function isArray(): bool
+ {
+ return true;
+ }
+}
diff --git a/src/Http/Validator/AnyOf.php b/src/Http/Validator/AnyOf.php
new file mode 100644
index 00000000..253891dc
--- /dev/null
+++ b/src/Http/Validator/AnyOf.php
@@ -0,0 +1,82 @@
+ $validators
+ */
+ public function __construct(protected array $validators, protected string $type = self::TYPE_MIXED)
+ {
+ }
+
+ /**
+ * Get Description
+ *
+ * Returns validator description
+ *
+ * @return string
+ */
+ public function getDescription(): string
+ {
+ $description = '';
+ foreach ($this->validators as $key => $rule) {
+ $description .= ++$key . '. ' . $rule->getDescription() . " \n";
+ }
+
+ return $description;
+ }
+
+ /**
+ * Is valid
+ *
+ * Validation will pass when all rules are valid if only one of the rules is invalid validation will fail.
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function isValid(mixed $value): bool
+ {
+ foreach ($this->validators as $rule) {
+ $valid = $rule->isValid($value);
+
+ if($valid) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get Type
+ *
+ * Returns validator type.
+ *
+ * @return string
+ */
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ /**
+ * Is array
+ *
+ * Function will return true if object is array.
+ *
+ * @return bool
+ */
+ public function isArray(): bool
+ {
+ return true;
+ }
+}
diff --git a/src/Http/Validator/Multiple.php b/src/Http/Validator/Multiple.php
deleted file mode 100644
index 61b45d09..00000000
--- a/src/Http/Validator/Multiple.php
+++ /dev/null
@@ -1,143 +0,0 @@
-addValidator($validator);
- }
-
- $this->type = $type;
- $this->rule = $rule;
- }
- /**
- * Add validator
- *
- * Add a new validator to check against during isVaid() call
- *
- * @param Validator $validator
- * @return $this
- */
- public function addValidator(Validator $validator)
- {
- $this->validators[] = $validator;
-
- return $this;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- $description = '';
- foreach ($this->validators as $key => $rule) {
- $description .= ++$key . '. ' . $rule->getDescription() . " \n";
- }
-
- return $description;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when all rules are valid if only one of the rules is invalid validation will fail.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- foreach ($this->validators as $rule) { /* @var $rule Validator */
- $valid = $rule->isValid($value);
-
- // Oprimization improvements
- if($this->rule === self::RULE_ALL) {
- if(!$valid) {
- return false;
- }
- } if($this->rule === self::RULE_NONE) {
- if($valid) {
- return false;
- }
- } if($this->rule === self::RULE_ANY) {
- if($valid) {
- return true;
- }
- }
- }
-
- if($this->rule === self::RULE_ANY) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return $this->type;
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return true;
- }
-}
diff --git a/src/Http/Validator/NoneOf.php b/src/Http/Validator/NoneOf.php
new file mode 100644
index 00000000..97680811
--- /dev/null
+++ b/src/Http/Validator/NoneOf.php
@@ -0,0 +1,82 @@
+ $validators
+ */
+ public function __construct(protected array $validators, protected string $type = self::TYPE_MIXED)
+ {
+ }
+
+ /**
+ * Get Description
+ *
+ * Returns validator description
+ *
+ * @return string
+ */
+ public function getDescription(): string
+ {
+ $description = '';
+ foreach ($this->validators as $key => $rule) {
+ $description .= ++$key . '. ' . $rule->getDescription() . " \n";
+ }
+
+ return $description;
+ }
+
+ /**
+ * Is valid
+ *
+ * Validation will pass when all rules are valid if only one of the rules is invalid validation will fail.
+ *
+ * @param mixed $value
+ * @return bool
+ */
+ public function isValid(mixed $value): bool
+ {
+ foreach ($this->validators as $rule) {
+ $valid = $rule->isValid($value);
+
+ if($valid) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get Type
+ *
+ * Returns validator type.
+ *
+ * @return string
+ */
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ /**
+ * Is array
+ *
+ * Function will return true if object is array.
+ *
+ * @return bool
+ */
+ public function isArray(): bool
+ {
+ return true;
+ }
+}
diff --git a/tests/Validator/MultipleTest.php b/tests/Validator/MultipleOfTest.php
similarity index 60%
rename from tests/Validator/MultipleTest.php
rename to tests/Validator/MultipleOfTest.php
index 9f1bf12d..1162ae2d 100644
--- a/tests/Validator/MultipleTest.php
+++ b/tests/Validator/MultipleOfTest.php
@@ -3,34 +3,34 @@
namespace Utopia\Http\Validator;
use PHPUnit\Framework\TestCase;
+use Utopia\Http\Validator;
-class MultipleTest extends TestCase
+class MultipleOfTest extends TestCase
{
- protected Multiple $validator;
-
public function setUp(): void
{
- $this->validator = new Multiple([new Text(20), new URL()], Multiple::TYPE_STRING);
}
public function testIsValid()
{
- $this->assertEquals('string', $this->validator->getType());
- $this->assertEquals("1. Value must be a valid string and at least 1 chars and no longer than 20 chars \n2. Value must be a valid URL \n", $this->validator->getDescription());
+ $validator = new AllOf([new Text(20), new URL()], Validator::TYPE_STRING);
+
+ $this->assertEquals('string', $validator->getType());
+ $this->assertEquals("1. Value must be a valid string and at least 1 chars and no longer than 20 chars \n2. Value must be a valid URL \n", $validator->getDescription());
// Valid URL but invalid text length
- $this->assertFalse($this->validator->isValid('http://example.com/very-long-url'));
+ $this->assertFalse($validator->isValid('http://example.com/very-long-url'));
// Valid text within length, but invalid URL
- $this->assertFalse($this->validator->isValid('hello world'));
+ $this->assertFalse($validator->isValid('hello world'));
// Both conditions satisfied
- $this->assertTrue($this->validator->isValid('http://example.com'));
- $this->assertTrue($this->validator->isValid('https://google.com'));
+ $this->assertTrue($validator->isValid('http://example.com'));
+ $this->assertTrue($validator->isValid('https://google.com'));
// Neither condition satisfied
- $this->assertFalse($this->validator->isValid('example.com/hello-world'));
- $this->assertFalse($this->validator->isValid(''));
+ $this->assertFalse($validator->isValid('example.com/hello-world'));
+ $this->assertFalse($validator->isValid(''));
}
public function testRules()
@@ -40,19 +40,19 @@ public function testRules()
$invalidTextValidUrl = 'http://example.com/very-long-url';
$invalidTextInvalidUrl = 'Some very long text that is also not an URL';
- $vaidator = new Multiple([new Text(20), new URL()], Multiple::TYPE_STRING, Multiple::RULE_ALL);
+ $vaidator = new AllOf([new Text(20), new URL()], Validator::TYPE_STRING);
$this->assertTrue($vaidator->isValid($validTextValidUrl));
$this->assertFalse($vaidator->isValid($validTextInvalidUrl));
$this->assertFalse($vaidator->isValid($invalidTextValidUrl));
$this->assertFalse($vaidator->isValid($invalidTextInvalidUrl));
- $vaidator = new Multiple([new Text(20), new URL()], Multiple::TYPE_STRING, Multiple::RULE_ANY);
+ $vaidator = new AnyOf([new Text(20), new URL()], Validator::TYPE_STRING);
$this->assertTrue($vaidator->isValid($validTextValidUrl));
$this->assertTrue($vaidator->isValid($validTextInvalidUrl));
$this->assertTrue($vaidator->isValid($invalidTextValidUrl));
$this->assertFalse($vaidator->isValid($invalidTextInvalidUrl));
- $vaidator = new Multiple([new Text(20), new URL()], Multiple::TYPE_STRING, Multiple::RULE_NONE);
+ $vaidator = new NoneOf([new Text(20), new URL()], Validator::TYPE_STRING);
$this->assertFalse($vaidator->isValid($validTextValidUrl));
$this->assertFalse($vaidator->isValid($validTextInvalidUrl));
$this->assertFalse($vaidator->isValid($invalidTextValidUrl));
From f60479fc740fe41596924b313bb60c6423fcc144 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 2 Jul 2024 14:59:34 +0000
Subject: [PATCH 101/119] PR review changes
---
src/Http/Validator/AllOf.php | 8 ++++++--
src/Http/Validator/AnyOf.php | 9 +++++++--
src/Http/Validator/NoneOf.php | 8 ++++++--
3 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/src/Http/Validator/AllOf.php b/src/Http/Validator/AllOf.php
index 84cd8f9f..f73dd156 100644
--- a/src/Http/Validator/AllOf.php
+++ b/src/Http/Validator/AllOf.php
@@ -11,6 +11,8 @@
*/
class AllOf extends Validator
{
+ protected ?Validator $failedRule = null;
+
/**
* @param array $validators
*/
@@ -28,8 +30,9 @@ public function __construct(protected array $validators, protected string $type
public function getDescription(): string
{
$description = '';
- foreach ($this->validators as $key => $rule) {
- $description .= ++$key . '. ' . $rule->getDescription() . " \n";
+
+ if(!(\is_null($this->failedRule))) {
+ $description .= $this->failedRule->getDescription();
}
return $description;
@@ -49,6 +52,7 @@ public function isValid(mixed $value): bool
$valid = $rule->isValid($value);
if(!$valid) {
+ $this->failedRule = $rule;
return false;
}
}
diff --git a/src/Http/Validator/AnyOf.php b/src/Http/Validator/AnyOf.php
index 253891dc..780b9a59 100644
--- a/src/Http/Validator/AnyOf.php
+++ b/src/Http/Validator/AnyOf.php
@@ -11,6 +11,8 @@
*/
class AnyOf extends Validator
{
+ protected ?Validator $failedRule = null;
+
/**
* @param array $validators
*/
@@ -28,8 +30,9 @@ public function __construct(protected array $validators, protected string $type
public function getDescription(): string
{
$description = '';
- foreach ($this->validators as $key => $rule) {
- $description .= ++$key . '. ' . $rule->getDescription() . " \n";
+
+ if(!(\is_null($this->failedRule))) {
+ $description .= $this->failedRule->getDescription();
}
return $description;
@@ -48,6 +51,8 @@ public function isValid(mixed $value): bool
foreach ($this->validators as $rule) {
$valid = $rule->isValid($value);
+ $this->failedRule = $rule;
+
if($valid) {
return true;
}
diff --git a/src/Http/Validator/NoneOf.php b/src/Http/Validator/NoneOf.php
index 97680811..240d9271 100644
--- a/src/Http/Validator/NoneOf.php
+++ b/src/Http/Validator/NoneOf.php
@@ -11,6 +11,8 @@
*/
class NoneOf extends Validator
{
+ protected ?Validator $failedRule = null;
+
/**
* @param array $validators
*/
@@ -28,8 +30,9 @@ public function __construct(protected array $validators, protected string $type
public function getDescription(): string
{
$description = '';
- foreach ($this->validators as $key => $rule) {
- $description .= ++$key . '. ' . $rule->getDescription() . " \n";
+
+ if(!(\is_null($this->failedRule))) {
+ $description .= $this->failedRule->getDescription();
}
return $description;
@@ -49,6 +52,7 @@ public function isValid(mixed $value): bool
$valid = $rule->isValid($value);
if($valid) {
+ $this->failedRule = $rule;
return false;
}
}
From 6ae1f18bbb2f905101317f36bf85b271063429c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 2 Jul 2024 15:01:11 +0000
Subject: [PATCH 102/119] Fix tests
---
tests/Validator/MultipleOfTest.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/Validator/MultipleOfTest.php b/tests/Validator/MultipleOfTest.php
index 1162ae2d..f8e9bb37 100644
--- a/tests/Validator/MultipleOfTest.php
+++ b/tests/Validator/MultipleOfTest.php
@@ -16,7 +16,7 @@ public function testIsValid()
$validator = new AllOf([new Text(20), new URL()], Validator::TYPE_STRING);
$this->assertEquals('string', $validator->getType());
- $this->assertEquals("1. Value must be a valid string and at least 1 chars and no longer than 20 chars \n2. Value must be a valid URL \n", $validator->getDescription());
+ $this->assertEquals("1Value must be a valid string and at least 1 chars and no longer than 20 chars", $validator->getDescription());
// Valid URL but invalid text length
$this->assertFalse($validator->isValid('http://example.com/very-long-url'));
From ed89b1991f5882a4fdd9ba700effb8f5b98675eb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 2 Jul 2024 15:04:37 +0000
Subject: [PATCH 103/119] Fix CI/CD
---
src/Http/Validator/AllOf.php | 6 +++---
src/Http/Validator/AnyOf.php | 6 +++---
src/Http/Validator/NoneOf.php | 4 +++-
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/Http/Validator/AllOf.php b/src/Http/Validator/AllOf.php
index f73dd156..70b40751 100644
--- a/src/Http/Validator/AllOf.php
+++ b/src/Http/Validator/AllOf.php
@@ -29,10 +29,10 @@ public function __construct(protected array $validators, protected string $type
*/
public function getDescription(): string
{
- $description = '';
-
if(!(\is_null($this->failedRule))) {
- $description .= $this->failedRule->getDescription();
+ $description = $this->failedRule->getDescription();
+ } else {
+ $description = $this->validators[0]->getDescription();
}
return $description;
diff --git a/src/Http/Validator/AnyOf.php b/src/Http/Validator/AnyOf.php
index 780b9a59..ad2bd921 100644
--- a/src/Http/Validator/AnyOf.php
+++ b/src/Http/Validator/AnyOf.php
@@ -29,10 +29,10 @@ public function __construct(protected array $validators, protected string $type
*/
public function getDescription(): string
{
- $description = '';
-
if(!(\is_null($this->failedRule))) {
- $description .= $this->failedRule->getDescription();
+ $description = $this->failedRule->getDescription();
+ } else {
+ $description = $this->validators[0]->getDescription();
}
return $description;
diff --git a/src/Http/Validator/NoneOf.php b/src/Http/Validator/NoneOf.php
index 240d9271..20af51b7 100644
--- a/src/Http/Validator/NoneOf.php
+++ b/src/Http/Validator/NoneOf.php
@@ -32,7 +32,9 @@ public function getDescription(): string
$description = '';
if(!(\is_null($this->failedRule))) {
- $description .= $this->failedRule->getDescription();
+ $description = $this->failedRule->getDescription();
+ } else {
+ $description = $this->validators[0]->getDescription();
}
return $description;
From 726540d0bda3253f9ef628fd510dc13289938c2d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 2 Jul 2024 15:06:19 +0000
Subject: [PATCH 104/119] Typo
---
tests/Validator/MultipleOfTest.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/Validator/MultipleOfTest.php b/tests/Validator/MultipleOfTest.php
index f8e9bb37..06435aa8 100644
--- a/tests/Validator/MultipleOfTest.php
+++ b/tests/Validator/MultipleOfTest.php
@@ -16,7 +16,7 @@ public function testIsValid()
$validator = new AllOf([new Text(20), new URL()], Validator::TYPE_STRING);
$this->assertEquals('string', $validator->getType());
- $this->assertEquals("1Value must be a valid string and at least 1 chars and no longer than 20 chars", $validator->getDescription());
+ $this->assertEquals("Value must be a valid string and at least 1 chars and no longer than 20 chars", $validator->getDescription());
// Valid URL but invalid text length
$this->assertFalse($validator->isValid('http://example.com/very-long-url'));
From d3e12307739b7f7930d7a69b1cac332714c385dd Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Thu, 22 May 2025 17:14:56 +0100
Subject: [PATCH 105/119] fix: add missing status codes
---
src/Http/Response.php | 77 ++++++++++++++++++++++---------------------
1 file changed, 39 insertions(+), 38 deletions(-)
diff --git a/src/Http/Response.php b/src/Http/Response.php
index 8d085d63..8b319679 100755
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -42,92 +42,74 @@ abstract class Response
* HTTP response status codes
*/
public const STATUS_CODE_CONTINUE = 100;
-
public const STATUS_CODE_SWITCHING_PROTOCOLS = 101;
+ public const STATUS_CODE_PROCESSING = 102;
+ public const STATUS_CODE_EARLY_HINTS = 103;
public const STATUS_CODE_OK = 200;
-
public const STATUS_CODE_CREATED = 201;
-
public const STATUS_CODE_ACCEPTED = 202;
-
public const STATUS_CODE_NON_AUTHORITATIVE_INFORMATION = 203;
-
public const STATUS_CODE_NOCONTENT = 204;
-
public const STATUS_CODE_RESETCONTENT = 205;
-
public const STATUS_CODE_PARTIALCONTENT = 206;
+ public const STATUS_CODE_MULTI_STATUS = 207;
+ public const STATUS_CODE_ALREADY_REPORTED = 208;
+ public const STATUS_CODE_IM_USED = 226;
public const STATUS_CODE_MULTIPLE_CHOICES = 300;
-
public const STATUS_CODE_MOVED_PERMANENTLY = 301;
-
public const STATUS_CODE_FOUND = 302;
-
public const STATUS_CODE_SEE_OTHER = 303;
-
public const STATUS_CODE_NOT_MODIFIED = 304;
-
public const STATUS_CODE_USE_PROXY = 305;
-
public const STATUS_CODE_UNUSED = 306;
-
public const STATUS_CODE_TEMPORARY_REDIRECT = 307;
+ public const STATUS_CODE_PERMANENT_REDIRECT = 308;
public const STATUS_CODE_BAD_REQUEST = 400;
-
public const STATUS_CODE_UNAUTHORIZED = 401;
-
public const STATUS_CODE_PAYMENT_REQUIRED = 402;
-
public const STATUS_CODE_FORBIDDEN = 403;
-
public const STATUS_CODE_NOT_FOUND = 404;
-
public const STATUS_CODE_METHOD_NOT_ALLOWED = 405;
-
public const STATUS_CODE_NOT_ACCEPTABLE = 406;
-
public const STATUS_CODE_PROXY_AUTHENTICATION_REQUIRED = 407;
-
public const STATUS_CODE_REQUEST_TIMEOUT = 408;
-
public const STATUS_CODE_CONFLICT = 409;
-
public const STATUS_CODE_GONE = 410;
-
public const STATUS_CODE_LENGTH_REQUIRED = 411;
-
public const STATUS_CODE_PRECONDITION_FAILED = 412;
-
public const STATUS_CODE_REQUEST_ENTITY_TOO_LARGE = 413;
-
public const STATUS_CODE_REQUEST_URI_TOO_LONG = 414;
-
public const STATUS_CODE_UNSUPPORTED_MEDIA_TYPE = 415;
-
public const STATUS_CODE_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
-
public const STATUS_CODE_EXPECTATION_FAILED = 417;
-
+ public const STATUS_CODE_IM_A_TEAPOT = 418;
+ public const STATUS_CODE_MISDIRECTED_REQUEST = 421;
+ public const STATUS_CODE_UNPROCESSABLE_ENTITY = 422;
+ public const STATUS_CODE_LOCKED = 423;
+ public const STATUS_CODE_FAILED_DEPENDENCY = 424;
public const STATUS_CODE_TOO_EARLY = 425;
-
+ public const STATUS_CODE_UPGRADE_REQUIRED = 426;
+ public const STATUS_CODE_PRECONDITION_REQUIRED = 428;
public const STATUS_CODE_TOO_MANY_REQUESTS = 429;
+ public const STATUS_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
+ public const STATUS_CODE_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
public const STATUS_CODE_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
public const STATUS_CODE_INTERNAL_SERVER_ERROR = 500;
-
public const STATUS_CODE_NOT_IMPLEMENTED = 501;
-
public const STATUS_CODE_BAD_GATEWAY = 502;
-
public const STATUS_CODE_SERVICE_UNAVAILABLE = 503;
-
public const STATUS_CODE_GATEWAY_TIMEOUT = 504;
-
public const STATUS_CODE_HTTP_VERSION_NOT_SUPPORTED = 505;
+ public const STATUS_CODE_VARIANT_ALSO_NEGOTIATES = 506;
+ public const STATUS_CODE_INSUFFICIENT_STORAGE = 507;
+ public const STATUS_CODE_LOOP_DETECTED = 508;
+ public const STATUS_CODE_NOT_EXTENDED = 510;
+ public const STATUS_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511;
/**
* @var array
@@ -135,6 +117,8 @@ abstract class Response
protected $statusCodes = [
self::STATUS_CODE_CONTINUE => 'Continue',
self::STATUS_CODE_SWITCHING_PROTOCOLS => 'Switching Protocols',
+ self::STATUS_CODE_PROCESSING => 'Processing',
+ self::STATUS_CODE_EARLY_HINTS => 'Early Hints',
self::STATUS_CODE_OK => 'OK',
self::STATUS_CODE_CREATED => 'Created',
self::STATUS_CODE_ACCEPTED => 'Accepted',
@@ -142,6 +126,9 @@ abstract class Response
self::STATUS_CODE_NOCONTENT => 'No Content',
self::STATUS_CODE_RESETCONTENT => 'Reset Content',
self::STATUS_CODE_PARTIALCONTENT => 'Partial Content',
+ self::STATUS_CODE_MULTI_STATUS => 'Multi-Status',
+ self::STATUS_CODE_ALREADY_REPORTED => 'Already Reported',
+ self::STATUS_CODE_IM_USED => 'IM Used',
self::STATUS_CODE_MULTIPLE_CHOICES => 'Multiple Choices',
self::STATUS_CODE_MOVED_PERMANENTLY => 'Moved Permanently',
self::STATUS_CODE_FOUND => 'Found',
@@ -150,6 +137,7 @@ abstract class Response
self::STATUS_CODE_USE_PROXY => 'Use Proxy',
self::STATUS_CODE_UNUSED => '(Unused)',
self::STATUS_CODE_TEMPORARY_REDIRECT => 'Temporary Redirect',
+ self::STATUS_CODE_PERMANENT_REDIRECT => 'Permanent Redirect',
self::STATUS_CODE_BAD_REQUEST => 'Bad Request',
self::STATUS_CODE_UNAUTHORIZED => 'Unauthorized',
self::STATUS_CODE_PAYMENT_REQUIRED => 'Payment Required',
@@ -168,8 +156,16 @@ abstract class Response
self::STATUS_CODE_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type',
self::STATUS_CODE_REQUESTED_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable',
self::STATUS_CODE_EXPECTATION_FAILED => 'Expectation Failed',
+ self::STATUS_CODE_IM_A_TEAPOT => 'I\'m a teapot',
+ self::STATUS_CODE_MISDIRECTED_REQUEST => 'Misdirected Request',
+ self::STATUS_CODE_UNPROCESSABLE_ENTITY => 'Unprocessable Entity',
+ self::STATUS_CODE_LOCKED => 'Locked',
+ self::STATUS_CODE_FAILED_DEPENDENCY => 'Failed Dependency',
self::STATUS_CODE_TOO_EARLY => 'Too Early',
+ self::STATUS_CODE_UPGRADE_REQUIRED => 'Upgrade Required',
+ self::STATUS_CODE_PRECONDITION_REQUIRED => 'Precondition Required',
self::STATUS_CODE_TOO_MANY_REQUESTS => 'Too Many Requests',
+ self::STATUS_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large',
self::STATUS_CODE_UNAVAILABLE_FOR_LEGAL_REASONS => 'Unavailable For Legal Reasons',
self::STATUS_CODE_INTERNAL_SERVER_ERROR => 'Internal Server Error',
self::STATUS_CODE_NOT_IMPLEMENTED => 'Not Implemented',
@@ -177,6 +173,11 @@ abstract class Response
self::STATUS_CODE_SERVICE_UNAVAILABLE => 'Service Unavailable',
self::STATUS_CODE_GATEWAY_TIMEOUT => 'Gateway Timeout',
self::STATUS_CODE_HTTP_VERSION_NOT_SUPPORTED => 'HTTP Version Not Supported',
+ self::STATUS_CODE_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates',
+ self::STATUS_CODE_INSUFFICIENT_STORAGE => 'Insufficient Storage',
+ self::STATUS_CODE_LOOP_DETECTED => 'Loop Detected',
+ self::STATUS_CODE_NOT_EXTENDED => 'Not Extended',
+ self::STATUS_CODE_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required',
];
/**
From 3e8733e0b2f07ce1b8034ced3246b3b08ce9e1be Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Thu, 22 May 2025 17:17:24 +0100
Subject: [PATCH 106/119] ci: fix docker-compose
---
.github/workflows/test.yml | 4 ++--
CONTRIBUTING.md | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index e17e5507..2c707436 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -19,7 +19,7 @@ jobs:
run: composer validate --strict
- name: Setup Docker
- run: docker-compose up -d --build
+ run: docker compose up -d --build
- name: Wait for Server to be ready
run: sleep 10
@@ -28,4 +28,4 @@ jobs:
run: docker compose exec fpm vendor/bin/phpunit --configuration phpunit.xml
- name: Run Swoole Tests
- run: docker compose exec swoole vendor/bin/phpunit --configuration phpunit.xml
\ No newline at end of file
+ run: docker compose exec swoole vendor/bin/phpunit --configuration phpunit.xml
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3ab8893b..361c6a7b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -66,9 +66,9 @@ $ git push origin [name_of_your_new_branch]
### Testing
-- `docker-compose up -d`
-- `docker-compose exec web vendor/bin/phpunit --configuration phpunit.xml`
-- `docker-compose exec web vendor/bin/psalm --show-info=true`
+- `docker compose up -d`
+- `docker compose exec web vendor/bin/phpunit --configuration phpunit.xml`
+- `docker compose exec web vendor/bin/psalm --show-info=true`
## Introducing New Features
From 35839e91e9b147da2ddf66f31d02b980b833c3e4 Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Thu, 22 May 2025 19:12:17 +0100
Subject: [PATCH 107/119] fix: duplicate
---
src/Http/Response.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/Http/Response.php b/src/Http/Response.php
index 8b319679..e4545325 100755
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -97,8 +97,6 @@ abstract class Response
public const STATUS_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
public const STATUS_CODE_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
- public const STATUS_CODE_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
-
public const STATUS_CODE_INTERNAL_SERVER_ERROR = 500;
public const STATUS_CODE_NOT_IMPLEMENTED = 501;
public const STATUS_CODE_BAD_GATEWAY = 502;
From 2cad921b3f9256169a4ded84c9c9fa04b9c593d2 Mon Sep 17 00:00:00 2001
From: loks0n <22452787+loks0n@users.noreply.github.com>
Date: Mon, 30 Jun 2025 21:36:53 +0100
Subject: [PATCH 108/119] fix: prevent callable strings
---
composer.json | 5 ++
phpunit.xml | 23 ++++----
src/Http/Http.php | 2 +-
tests/HttpTest.php | 59 ++++++++++++++++++-
...questTest.php => UtopiaFPMRequestTest.php} | 0
5 files changed, 76 insertions(+), 13 deletions(-)
rename tests/{UtopiaRequestTest.php => UtopiaFPMRequestTest.php} (100%)
diff --git a/composer.json b/composer.json
index b5c168bc..06ff7c94 100644
--- a/composer.json
+++ b/composer.json
@@ -16,6 +16,11 @@
"Tests\\E2E\\": "tests/e2e"
}
},
+ "autoload-dev": {
+ "psr-4": {
+ "Utopia\\Http\\Tests\\": "tests/"
+ }
+ },
"scripts": {
"lint": "vendor/bin/pint --test",
"format": "vendor/bin/pint",
diff --git a/phpunit.xml b/phpunit.xml
index de6deb0b..e33b301e 100755
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,17 +1,18 @@
-
+
./tests/e2e/Client.php
./tests/
-
\ No newline at end of file
+
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 37638edb..f0ab42d8 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -740,7 +740,7 @@ protected function getArguments(Hook $hook, string $context, array $values, arra
$paramExists = $existsInRequest || $existsInValues;
$arg = $existsInRequest ? $requestParams[$key] : $param['default'];
- if (\is_callable($arg)) {
+ if (\is_callable($arg) && !\is_string($arg)) {
$arg = \call_user_func_array($arg, $this->getResources($param['injections']));
}
$value = $existsInValues ? $values[$key] : $arg;
diff --git a/tests/HttpTest.php b/tests/HttpTest.php
index 0d314cd3..ae6c5dd6 100755
--- a/tests/HttpTest.php
+++ b/tests/HttpTest.php
@@ -454,7 +454,7 @@ public function providerRouteMatching(): array
/**
* @dataProvider providerRouteMatching
*/
- public function testCanMatchRoute(string $method, string $path, string $url = null): void
+ public function testCanMatchRoute(string $method, string $path, ?string $url = null): void
{
$url ??= $path;
$expected = null;
@@ -616,4 +616,61 @@ public function testWildcardRoute(): void
$_SERVER['REQUEST_METHOD'] = $method;
$_SERVER['REQUEST_URI'] = $uri;
}
+
+ public function testCallableStringParametersNotExecuted(): void
+ {
+ // Test that callable strings (like function names) are not executed
+ $route = new Route('GET', '/test-callable-string');
+
+ $route
+ ->param('callback', 'phpinfo', new Text(200), 'callback param', true)
+ ->action(function ($callback) {
+ // If the string 'phpinfo' was executed as a function,
+ // it would output PHP info. Instead, it should just be the string.
+ echo 'callback-value: ' . $callback;
+ });
+
+ \ob_start();
+ $this->http->execute($route, new Request(), '1');
+ $result = \ob_get_contents();
+ \ob_end_clean();
+
+ $this->assertEquals('callback-value: phpinfo', $result);
+
+ // Test with request parameter that is a callable string
+ $route2 = new Route('GET', '/test-callable-string-param');
+
+ $route2
+ ->param('func', 'default', new Text(200), 'func param', false)
+ ->action(function ($func) {
+ echo 'func-value: ' . $func;
+ });
+
+ \ob_start();
+ $request = new UtopiaFPMRequestTest();
+ $request::_setParams(['func' => 'system']);
+ $this->http->execute($route2, $request, '1');
+ $result = \ob_get_contents();
+ \ob_end_clean();
+
+ $this->assertEquals('func-value: system', $result);
+
+ // Test callable closure still works
+ $route3 = new Route('GET', '/test-callable-closure');
+
+ $route3
+ ->param('generated', function () {
+ return 'generated-value';
+ }, new Text(200), 'generated param', true)
+ ->action(function ($generated) {
+ echo 'generated: ' . $generated;
+ });
+
+ \ob_start();
+ $this->http->execute($route3, new Request(), '1');
+ $result = \ob_get_contents();
+ \ob_end_clean();
+
+ $this->assertEquals('generated: generated-value', $result);
+ }
}
diff --git a/tests/UtopiaRequestTest.php b/tests/UtopiaFPMRequestTest.php
similarity index 100%
rename from tests/UtopiaRequestTest.php
rename to tests/UtopiaFPMRequestTest.php
From 569d423048e323bc7d2e211e6f4dd1fd89a218f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Thu, 21 Aug 2025 14:46:06 +0200
Subject: [PATCH 109/119] trigger ci/cd checks
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 137e384c..5eb2641d 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+.
+
From f23a6e7247208b0f0dfc66b78d3a7ce5cecb5a88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Thu, 21 Aug 2025 16:17:55 +0200
Subject: [PATCH 110/119] Make CI/CD checks pass
---
README.md | 2 -
composer.json | 4 +-
composer.lock | 569 ++++++++++++++-------------
src/Http/Adapter/FPM/Request.php | 2 +-
src/Http/Adapter/FPM/Response.php | 4 +-
src/Http/Adapter/Swoole/Request.php | 2 +-
src/Http/Adapter/Swoole/Response.php | 2 +-
src/Http/Adapter/Swoole/Server.php | 4 +-
src/Http/Files.php | 2 +-
src/Http/Http.php | 12 +-
src/Http/Request.php | 2 +-
src/Http/Response.php | 22 +-
src/Http/Validator/AllOf.php | 4 +-
src/Http/Validator/AnyOf.php | 4 +-
src/Http/Validator/ArrayList.php | 2 +-
src/Http/Validator/NoneOf.php | 4 +-
tests/ResponseTest.php | 2 +-
17 files changed, 337 insertions(+), 306 deletions(-)
diff --git a/README.md b/README.md
index 5eb2641d..137e384c 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,3 @@
-.
-
diff --git a/composer.json b/composer.json
index 06ff7c94..3b0d7f66 100644
--- a/composer.json
+++ b/composer.json
@@ -34,9 +34,9 @@
},
"require-dev": {
"phpunit/phpunit": "^9.5.25",
- "laravel/pint": "^1.2",
+ "laravel/pint": "1.*",
"swoole/ide-helper": "4.8.3",
- "phpstan/phpstan": "^1.10",
+ "phpstan/phpstan": "1.*",
"phpbench/phpbench": "^1.2"
}
}
diff --git a/composer.lock b/composer.lock
index 67cde3f0..abee3f7b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,21 +4,21 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "33b8cf270cfbd8f86cbd1338d81f5140",
+ "content-hash": "47587a7a55803f5b0fdf225267c03f03",
"packages": [],
"packages-dev": [
{
"name": "doctrine/annotations",
- "version": "2.0.1",
+ "version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
- "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f"
+ "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
- "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
+ "url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7",
+ "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7",
"shasum": ""
},
"require": {
@@ -30,10 +30,10 @@
"require-dev": {
"doctrine/cache": "^2.0",
"doctrine/coding-standard": "^10",
- "phpstan/phpstan": "^1.8.0",
+ "phpstan/phpstan": "^1.10.28",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
- "symfony/cache": "^5.4 || ^6",
- "vimeo/psalm": "^4.10"
+ "symfony/cache": "^5.4 || ^6.4 || ^7",
+ "vimeo/psalm": "^4.30 || ^5.14"
},
"suggest": {
"php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
@@ -79,9 +79,9 @@
],
"support": {
"issues": "https://github.com/doctrine/annotations/issues",
- "source": "https://github.com/doctrine/annotations/tree/2.0.1"
+ "source": "https://github.com/doctrine/annotations/tree/2.0.2"
},
- "time": "2023-02-02T22:02:53+00:00"
+ "time": "2024-09-05T10:17:24+00:00"
},
{
"name": "doctrine/instantiator",
@@ -232,16 +232,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.16.1",
+ "version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "9266a47f1b9231b83e0cfd849009547329d871b1"
+ "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/9266a47f1b9231b83e0cfd849009547329d871b1",
- "reference": "9266a47f1b9231b83e0cfd849009547329d871b1",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/0345f3b05f136801af8c339f9d16ef29e6b4df8a",
+ "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a",
"shasum": ""
},
"require": {
@@ -249,22 +249,25 @@
"ext-mbstring": "*",
"ext-tokenizer": "*",
"ext-xml": "*",
- "php": "^8.1.0"
+ "php": "^8.2.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.59.3",
- "illuminate/view": "^10.48.12",
- "larastan/larastan": "^2.9.7",
- "laravel-zero/framework": "^10.4.0",
+ "friendsofphp/php-cs-fixer": "^3.82.2",
+ "illuminate/view": "^11.45.1",
+ "larastan/larastan": "^3.5.0",
+ "laravel-zero/framework": "^11.45.0",
"mockery/mockery": "^1.6.12",
- "nunomaduro/termwind": "^1.15.1",
- "pestphp/pest": "^2.34.8"
+ "nunomaduro/termwind": "^2.3.1",
+ "pestphp/pest": "^2.36.0"
},
"bin": [
"builds/pint"
],
"type": "project",
"autoload": {
+ "files": [
+ "overrides/Runner/Parallel/ProcessFactory.php"
+ ],
"psr-4": {
"App\\": "app/",
"Database\\Seeders\\": "database/seeders/",
@@ -294,20 +297,20 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2024-06-18T16:50:05+00:00"
+ "time": "2025-07-10T18:09:32+00:00"
},
{
"name": "myclabs/deep-copy",
- "version": "1.12.0",
+ "version": "1.13.4",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
- "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
"shasum": ""
},
"require": {
@@ -346,7 +349,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
},
"funding": [
{
@@ -354,20 +357,20 @@
"type": "tidelift"
}
],
- "time": "2024-06-12T14:39:25+00:00"
+ "time": "2025-08-01T08:46:24+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v5.1.0",
+ "version": "v5.6.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1"
+ "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1",
- "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
+ "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"shasum": ""
},
"require": {
@@ -386,7 +389,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "5.x-dev"
}
},
"autoload": {
@@ -410,9 +413,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
},
- "time": "2024-07-01T20:03:41+00:00"
+ "time": "2025-08-13T20:13:15+00:00"
},
{
"name": "phar-io/manifest",
@@ -583,69 +586,18 @@
},
"time": "2023-10-30T13:38:26+00:00"
},
- {
- "name": "phpbench/dom",
- "version": "0.3.3",
- "source": {
- "type": "git",
- "url": "https://github.com/phpbench/dom.git",
- "reference": "786a96db538d0def931f5b19225233ec42ec7a72"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpbench/dom/zipball/786a96db538d0def931f5b19225233ec42ec7a72",
- "reference": "786a96db538d0def931f5b19225233ec42ec7a72",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "php": "^7.3||^8.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.14",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^8.0||^9.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "PhpBench\\Dom\\": "lib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Daniel Leech",
- "email": "daniel@dantleech.com"
- }
- ],
- "description": "DOM wrapper to simplify working with the PHP DOM implementation",
- "support": {
- "issues": "https://github.com/phpbench/dom/issues",
- "source": "https://github.com/phpbench/dom/tree/0.3.3"
- },
- "time": "2023-03-06T23:46:57+00:00"
- },
{
"name": "phpbench/phpbench",
- "version": "1.3.1",
+ "version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/phpbench/phpbench.git",
- "reference": "a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0"
+ "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpbench/phpbench/zipball/a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0",
- "reference": "a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0",
+ "url": "https://api.github.com/repos/phpbench/phpbench/zipball/78cd98a9aa34e0f8f80ca01972a8b88d2c30194b",
+ "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b",
"shasum": ""
},
"require": {
@@ -658,7 +610,6 @@
"ext-tokenizer": "*",
"php": "^8.1",
"phpbench/container": "^2.2",
- "phpbench/dom": "~0.3.3",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"seld/jsonlint": "^1.1",
"symfony/console": "^6.1 || ^7.0",
@@ -677,8 +628,8 @@
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
- "phpunit/phpunit": "^10.4",
- "rector/rector": "^0.18.11 || ^1.0.0",
+ "phpunit/phpunit": "^10.4 || ^11.0",
+ "rector/rector": "^1.2",
"symfony/error-handler": "^6.1 || ^7.0",
"symfony/var-dumper": "^6.1 || ^7.0"
},
@@ -723,7 +674,7 @@
],
"support": {
"issues": "https://github.com/phpbench/phpbench/issues",
- "source": "https://github.com/phpbench/phpbench/tree/1.3.1"
+ "source": "https://github.com/phpbench/phpbench/tree/1.4.1"
},
"funding": [
{
@@ -731,20 +682,20 @@
"type": "github"
}
],
- "time": "2024-06-30T11:04:37+00:00"
+ "time": "2025-03-12T08:01:40+00:00"
},
{
"name": "phpstan/phpstan",
- "version": "1.11.6",
+ "version": "1.12.28",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "6ac78f1165346c83b4a753f7e4186d969c6ad0ee"
+ "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6ac78f1165346c83b4a753f7e4186d969c6ad0ee",
- "reference": "6ac78f1165346c83b4a753f7e4186d969c6ad0ee",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9",
+ "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9",
"shasum": ""
},
"require": {
@@ -789,39 +740,39 @@
"type": "github"
}
],
- "time": "2024-07-01T15:33:06+00:00"
+ "time": "2025-07-17T17:15:39+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "9.2.31",
+ "version": "9.2.32",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965"
+ "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965",
- "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5",
+ "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
- "nikic/php-parser": "^4.18 || ^5.0",
+ "nikic/php-parser": "^4.19.1 || ^5.1.0",
"php": ">=7.3",
- "phpunit/php-file-iterator": "^3.0.3",
- "phpunit/php-text-template": "^2.0.2",
- "sebastian/code-unit-reverse-lookup": "^2.0.2",
- "sebastian/complexity": "^2.0",
- "sebastian/environment": "^5.1.2",
- "sebastian/lines-of-code": "^1.0.3",
- "sebastian/version": "^3.0.1",
- "theseer/tokenizer": "^1.2.0"
+ "phpunit/php-file-iterator": "^3.0.6",
+ "phpunit/php-text-template": "^2.0.4",
+ "sebastian/code-unit-reverse-lookup": "^2.0.3",
+ "sebastian/complexity": "^2.0.3",
+ "sebastian/environment": "^5.1.5",
+ "sebastian/lines-of-code": "^1.0.4",
+ "sebastian/version": "^3.0.2",
+ "theseer/tokenizer": "^1.2.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^9.6"
},
"suggest": {
"ext-pcov": "PHP extension that provides line coverage",
@@ -830,7 +781,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "9.2-dev"
+ "dev-main": "9.2.x-dev"
}
},
"autoload": {
@@ -859,7 +810,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32"
},
"funding": [
{
@@ -867,7 +818,7 @@
"type": "github"
}
],
- "time": "2024-03-02T06:37:42+00:00"
+ "time": "2024-08-22T04:23:01+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -1112,45 +1063,45 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.19",
+ "version": "9.6.25",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8"
+ "reference": "049c011e01be805202d8eebedef49f769a8ec7b7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1a54a473501ef4cdeaae4e06891674114d79db8",
- "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/049c011e01be805202d8eebedef49f769a8ec7b7",
+ "reference": "049c011e01be805202d8eebedef49f769a8ec7b7",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.3.1 || ^2",
+ "doctrine/instantiator": "^1.5.0 || ^2",
"ext-dom": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.10.1",
- "phar-io/manifest": "^2.0.3",
- "phar-io/version": "^3.0.2",
+ "myclabs/deep-copy": "^1.13.4",
+ "phar-io/manifest": "^2.0.4",
+ "phar-io/version": "^3.2.1",
"php": ">=7.3",
- "phpunit/php-code-coverage": "^9.2.28",
- "phpunit/php-file-iterator": "^3.0.5",
+ "phpunit/php-code-coverage": "^9.2.32",
+ "phpunit/php-file-iterator": "^3.0.6",
"phpunit/php-invoker": "^3.1.1",
- "phpunit/php-text-template": "^2.0.3",
- "phpunit/php-timer": "^5.0.2",
- "sebastian/cli-parser": "^1.0.1",
- "sebastian/code-unit": "^1.0.6",
- "sebastian/comparator": "^4.0.8",
- "sebastian/diff": "^4.0.3",
- "sebastian/environment": "^5.1.3",
- "sebastian/exporter": "^4.0.5",
- "sebastian/global-state": "^5.0.1",
- "sebastian/object-enumerator": "^4.0.3",
- "sebastian/resource-operations": "^3.0.3",
- "sebastian/type": "^3.2",
+ "phpunit/php-text-template": "^2.0.4",
+ "phpunit/php-timer": "^5.0.3",
+ "sebastian/cli-parser": "^1.0.2",
+ "sebastian/code-unit": "^1.0.8",
+ "sebastian/comparator": "^4.0.9",
+ "sebastian/diff": "^4.0.6",
+ "sebastian/environment": "^5.1.5",
+ "sebastian/exporter": "^4.0.6",
+ "sebastian/global-state": "^5.0.8",
+ "sebastian/object-enumerator": "^4.0.4",
+ "sebastian/resource-operations": "^3.0.4",
+ "sebastian/type": "^3.2.1",
"sebastian/version": "^3.0.2"
},
"suggest": {
@@ -1195,7 +1146,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.19"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.25"
},
"funding": [
{
@@ -1206,12 +1157,20 @@
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
"type": "tidelift"
}
],
- "time": "2024-04-05T04:35:58+00:00"
+ "time": "2025-08-20T14:38:31+00:00"
},
{
"name": "psr/cache",
@@ -1317,16 +1276,16 @@
},
{
"name": "psr/log",
- "version": "3.0.0",
+ "version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
- "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
- "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"shasum": ""
},
"require": {
@@ -1361,9 +1320,9 @@
"psr-3"
],
"support": {
- "source": "https://github.com/php-fig/log/tree/3.0.0"
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
},
- "time": "2021-07-14T16:46:02+00:00"
+ "time": "2024-09-11T13:17:53+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -1534,16 +1493,16 @@
},
{
"name": "sebastian/comparator",
- "version": "4.0.8",
+ "version": "4.0.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
+ "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
- "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5",
+ "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5",
"shasum": ""
},
"require": {
@@ -1596,15 +1555,27 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
- "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
+ "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
+ "type": "tidelift"
}
],
- "time": "2022-09-14T12:41:17+00:00"
+ "time": "2025-08-10T06:51:50+00:00"
},
{
"name": "sebastian/complexity",
@@ -1871,16 +1842,16 @@
},
{
"name": "sebastian/global-state",
- "version": "5.0.7",
+ "version": "5.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
+ "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
- "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6",
+ "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6",
"shasum": ""
},
"require": {
@@ -1923,15 +1894,27 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
- "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
+ "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state",
+ "type": "tidelift"
}
],
- "time": "2024-03-02T06:35:11+00:00"
+ "time": "2025-08-10T07:10:35+00:00"
},
{
"name": "sebastian/lines-of-code",
@@ -2104,16 +2087,16 @@
},
{
"name": "sebastian/recursion-context",
- "version": "4.0.5",
+ "version": "4.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
+ "reference": "539c6691e0623af6dc6f9c20384c120f963465a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
- "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0",
+ "reference": "539c6691e0623af6dc6f9c20384c120f963465a0",
"shasum": ""
},
"require": {
@@ -2155,15 +2138,27 @@
"homepage": "https://github.com/sebastianbergmann/recursion-context",
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
- "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
+ "type": "tidelift"
}
],
- "time": "2023-02-03T06:07:39+00:00"
+ "time": "2025-08-10T06:57:39+00:00"
},
{
"name": "sebastian/resource-operations",
@@ -2330,23 +2325,23 @@
},
{
"name": "seld/jsonlint",
- "version": "1.10.2",
+ "version": "1.11.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/jsonlint.git",
- "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259"
+ "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9bb7db07b5d66d90f6ebf542f09fc67d800e5259",
- "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259",
+ "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2",
+ "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2",
"shasum": ""
},
"require": {
"php": "^5.3 || ^7.0 || ^8.0"
},
"require-dev": {
- "phpstan/phpstan": "^1.5",
+ "phpstan/phpstan": "^1.11",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13"
},
"bin": [
@@ -2378,7 +2373,7 @@
],
"support": {
"issues": "https://github.com/Seldaek/jsonlint/issues",
- "source": "https://github.com/Seldaek/jsonlint/tree/1.10.2"
+ "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0"
},
"funding": [
{
@@ -2390,7 +2385,7 @@
"type": "tidelift"
}
],
- "time": "2024-02-07T12:57:50+00:00"
+ "time": "2024-07-11T14:55:45+00:00"
},
{
"name": "swoole/ide-helper",
@@ -2436,23 +2431,24 @@
},
{
"name": "symfony/console",
- "version": "v7.1.2",
+ "version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "0aa29ca177f432ab68533432db0de059f39c92ae"
+ "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/0aa29ca177f432ab68533432db0de059f39c92ae",
- "reference": "0aa29ca177f432ab68533432db0de059f39c92ae",
+ "url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1",
+ "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1",
"shasum": ""
},
"require": {
"php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^2.5|^3",
- "symfony/string": "^6.4|^7.0"
+ "symfony/string": "^7.2"
},
"conflict": {
"symfony/dependency-injection": "<6.4",
@@ -2509,7 +2505,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.1.2"
+ "source": "https://github.com/symfony/console/tree/v7.3.2"
},
"funding": [
{
@@ -2520,25 +2516,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-06-28T10:03:55+00:00"
+ "time": "2025-07-30T17:13:41+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.5.0",
+ "version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
@@ -2546,12 +2546,12 @@
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "3.5-dev"
- },
"thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
}
},
"autoload": {
@@ -2576,7 +2576,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
@@ -2592,20 +2592,20 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v7.1.2",
+ "version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "92a91985250c251de9b947a14bb2c9390b1a562c"
+ "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/92a91985250c251de9b947a14bb2c9390b1a562c",
- "reference": "92a91985250c251de9b947a14bb2c9390b1a562c",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd",
+ "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd",
"shasum": ""
},
"require": {
@@ -2642,7 +2642,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v7.1.2"
+ "source": "https://github.com/symfony/filesystem/tree/v7.3.2"
},
"funding": [
{
@@ -2653,25 +2653,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-06-28T10:03:55+00:00"
+ "time": "2025-07-07T08:17:47+00:00"
},
{
"name": "symfony/finder",
- "version": "v7.1.1",
+ "version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "fbb0ba67688b780efbc886c1a0a0948dcf7205d6"
+ "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/fbb0ba67688b780efbc886c1a0a0948dcf7205d6",
- "reference": "fbb0ba67688b780efbc886c1a0a0948dcf7205d6",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
+ "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
"shasum": ""
},
"require": {
@@ -2706,7 +2710,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v7.1.1"
+ "source": "https://github.com/symfony/finder/tree/v7.3.2"
},
"funding": [
{
@@ -2717,25 +2721,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-05-31T14:57:53+00:00"
+ "time": "2025-07-15T13:41:35+00:00"
},
{
"name": "symfony/options-resolver",
- "version": "v7.1.1",
+ "version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
- "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55"
+ "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/47aa818121ed3950acd2b58d1d37d08a94f9bf55",
- "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37",
+ "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37",
"shasum": ""
},
"require": {
@@ -2773,7 +2781,7 @@
"options"
],
"support": {
- "source": "https://github.com/symfony/options-resolver/tree/v7.1.1"
+ "source": "https://github.com/symfony/options-resolver/tree/v7.3.2"
},
"funding": [
{
@@ -2784,29 +2792,33 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-05-31T14:57:53+00:00"
+ "time": "2025-07-15T11:36:08+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.30.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "0424dff1c58f028c451efff2045f5d92410bd540"
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540",
- "reference": "0424dff1c58f028c451efff2045f5d92410bd540",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
@@ -2817,8 +2829,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -2852,7 +2864,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
},
"funding": [
{
@@ -2863,29 +2875,33 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-05-31T15:07:36+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.30.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a"
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a",
- "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
@@ -2893,8 +2909,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -2930,7 +2946,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
},
"funding": [
{
@@ -2941,29 +2957,33 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-05-31T15:07:36+00:00"
+ "time": "2025-06-27T09:58:17+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.30.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb"
+ "reference": "3833d7255cc303546435cb650316bff708a1c75c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb",
- "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
+ "reference": "3833d7255cc303546435cb650316bff708a1c75c",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
@@ -2971,8 +2991,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -3011,7 +3031,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
},
"funding": [
{
@@ -3022,29 +3042,34 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-05-31T15:07:36+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.30.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c"
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c",
- "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "ext-iconv": "*",
+ "php": ">=7.2"
},
"provide": {
"ext-mbstring": "*"
@@ -3055,8 +3080,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -3091,7 +3116,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
},
"funding": [
{
@@ -3102,25 +3127,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-06-19T12:30:46+00:00"
+ "time": "2024-12-23T08:48:59+00:00"
},
{
"name": "symfony/process",
- "version": "v7.1.1",
+ "version": "v7.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "febf90124323a093c7ee06fdb30e765ca3c20028"
+ "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/febf90124323a093c7ee06fdb30e765ca3c20028",
- "reference": "febf90124323a093c7ee06fdb30e765ca3c20028",
+ "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
+ "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
"shasum": ""
},
"require": {
@@ -3152,7 +3181,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v7.1.1"
+ "source": "https://github.com/symfony/process/tree/v7.3.0"
},
"funding": [
{
@@ -3168,20 +3197,20 @@
"type": "tidelift"
}
],
- "time": "2024-05-31T14:57:53+00:00"
+ "time": "2025-04-17T09:11:12+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v3.5.0",
+ "version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f"
+ "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
- "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
"shasum": ""
},
"require": {
@@ -3194,12 +3223,12 @@
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "3.5-dev"
- },
"thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
}
},
"autoload": {
@@ -3235,7 +3264,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
},
"funding": [
{
@@ -3251,20 +3280,20 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2025-04-25T09:37:31+00:00"
},
{
"name": "symfony/string",
- "version": "v7.1.2",
+ "version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8"
+ "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/14221089ac66cf82e3cf3d1c1da65de305587ff8",
- "reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8",
+ "url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca",
+ "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca",
"shasum": ""
},
"require": {
@@ -3322,7 +3351,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v7.1.2"
+ "source": "https://github.com/symfony/string/tree/v7.3.2"
},
"funding": [
{
@@ -3333,12 +3362,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-06-28T09:27:18+00:00"
+ "time": "2025-07-10T08:47:49+00:00"
},
{
"name": "theseer/tokenizer",
@@ -3450,5 +3483,5 @@
"ext-swoole": "*"
},
"platform-dev": [],
- "plugin-api-version": "2.6.0"
+ "plugin-api-version": "2.3.0"
}
diff --git a/src/Http/Adapter/FPM/Request.php b/src/Http/Adapter/FPM/Request.php
index ecabb457..41452440 100644
--- a/src/Http/Adapter/FPM/Request.php
+++ b/src/Http/Adapter/FPM/Request.php
@@ -36,7 +36,7 @@ public function getRawPayload(): string
* @param string|null $default
* @return string|null
*/
- public function getServer(string $key, string $default = null): ?string
+ public function getServer(string $key, ?string $default = null): ?string
{
return $_SERVER[$key] ?? $default;
}
diff --git a/src/Http/Adapter/FPM/Response.php b/src/Http/Adapter/FPM/Response.php
index e58cc3d4..6c877918 100644
--- a/src/Http/Adapter/FPM/Response.php
+++ b/src/Http/Adapter/FPM/Response.php
@@ -25,10 +25,10 @@ public function write(string $content): bool
*
* Send optional content and end
*
- * @param string $content
+ * @param string|null $content
* @return void
*/
- public function end(string $content = null): void
+ public function end(?string $content = null): void
{
if (!is_null($content)) {
echo $content;
diff --git a/src/Http/Adapter/Swoole/Request.php b/src/Http/Adapter/Swoole/Request.php
index 8a717730..164cf81c 100644
--- a/src/Http/Adapter/Swoole/Request.php
+++ b/src/Http/Adapter/Swoole/Request.php
@@ -43,7 +43,7 @@ public function getRawPayload(): string
* @param string|null $default
* @return string|null
*/
- public function getServer(string $key, string $default = null): ?string
+ public function getServer(string $key, ?string $default = null): ?string
{
return $this->swoole->server[$key] ?? $default;
}
diff --git a/src/Http/Adapter/Swoole/Response.php b/src/Http/Adapter/Swoole/Response.php
index 4bb03926..b0b99978 100644
--- a/src/Http/Adapter/Swoole/Response.php
+++ b/src/Http/Adapter/Swoole/Response.php
@@ -45,7 +45,7 @@ public function write(string $content): bool
* @param string|null $content
* @return void
*/
- public function end(string $content = null): void
+ public function end(?string $content = null): void
{
$this->swoole->end($content);
}
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index 9fe73e98..fff99f1e 100755
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -15,7 +15,7 @@ class Server extends Adapter
{
protected SwooleServer $server;
- public function __construct(string $host, string $port = null, array $settings = [])
+ public function __construct(string $host, ?string $port = null, array $settings = [])
{
$this->server = new SwooleServer($host, $port);
$this->server->set(\array_merge($settings, [
@@ -42,7 +42,7 @@ public function onStart(callable $callback)
public function start()
{
- if(Coroutine::getCid() === -1) {
+ if (Coroutine::getCid() === -1) {
run(fn () => $this->server->start());
} else {
$this->server->start();
diff --git a/src/Http/Files.php b/src/Http/Files.php
index 5ecd353f..b5fc5199 100644
--- a/src/Http/Files.php
+++ b/src/Http/Files.php
@@ -83,7 +83,7 @@ public function getCount(): int
*
* @throws \Exception
*/
- public function load(string $directory, string $root = null): void
+ public function load(string $directory, ?string $root = null): void
{
if (!is_readable($directory)) {
throw new Exception("Failed to load directory: {$directory}");
diff --git a/src/Http/Http.php b/src/Http/Http.php
index f0ab42d8..8fe02785 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -295,7 +295,7 @@ public static function error(): Hook
* @param string|null $default
* @return string|null
*/
- public static function getEnv(string $key, string $default = null): ?string
+ public static function getEnv(string $key, ?string $default = null): ?string
{
return $_SERVER[$key] ?? $default;
}
@@ -366,7 +366,7 @@ public function getResource(string $name, string $context = 'utopia', bool $fres
$this->resources[$context] ??= [];
$resourcesCallback = &self::$resourcesCallbacks[$context] ?? [];
- if(empty($resourcesCallback) || !\array_key_exists($name, $resourcesCallback)) {
+ if (empty($resourcesCallback) || !\array_key_exists($name, $resourcesCallback)) {
$resourcesCallback = &self::$resourcesCallbacks['utopia'];
}
@@ -514,7 +514,7 @@ public static function addRoute(string $method, string $url): Route
*
* @throws \Exception
*/
- public function loadFiles(string $directory, string $root = null): void
+ public function loadFiles(string $directory, ?string $root = null): void
{
$this->files->load($directory, $root);
}
@@ -576,7 +576,7 @@ public function start()
try {
$this->run($request, $response, $context);
} finally {
- if(isset(self::$resourcesCallbacks[$context])) {
+ if (isset(self::$resourcesCallbacks[$context])) {
unset(self::$resourcesCallbacks[$context]);
}
}
@@ -593,7 +593,7 @@ public function start()
$arguments = $this->getArguments($hook, 'utopia', [], []);
\call_user_func_array($hook->getAction(), $arguments);
}
- } catch(\Exception $e) {
+ } catch (\Exception $e) {
self::setResource('error', fn () => $e);
foreach (self::$errors as $error) { // Global error hooks
@@ -793,7 +793,7 @@ public function run(Request $request, Response $response, string $context): stat
$arguments = $this->getArguments($hook, $context, [], []);
\call_user_func_array($hook->getAction(), $arguments);
}
- } catch(\Exception $e) {
+ } catch (\Exception $e) {
self::setResource('error', fn () => $e, [], $context);
foreach (self::$errors as $error) { // Global error hooks
diff --git a/src/Http/Request.php b/src/Http/Request.php
index 65f67b28..8332d99d 100755
--- a/src/Http/Request.php
+++ b/src/Http/Request.php
@@ -124,7 +124,7 @@ abstract public function getRawPayload(): string;
* @param string|null $default
* @return string|null
*/
- abstract public function getServer(string $key, string $default = null): ?string;
+ abstract public function getServer(string $key, ?string $default = null): ?string;
/**
* Set server
diff --git a/src/Http/Response.php b/src/Http/Response.php
index e4545325..d0e6e793 100755
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -404,15 +404,15 @@ public function getHeaders(): array
* Add an HTTP cookie to response header
*
* @param string $name
- * @param string $value
- * @param int $expire
- * @param string $path
- * @param string $domain
- * @param bool $secure
- * @param bool $httponly
- * @param string $sameSite
- */
- public function addCookie(string $name, string $value = null, int $expire = null, string $path = null, string $domain = null, bool $secure = null, bool $httponly = null, string $sameSite = null): static
+ * @param string|null $value
+ * @param int|null $expire
+ * @param string|null $path
+ * @param string|null $domain
+ * @param bool|null $secure
+ * @param bool|null $httponly
+ * @param string|null $sameSite
+ */
+ public function addCookie(string $name, ?string $value = null, ?int $expire = null, ?string $path = null, ?string $domain = null, ?bool $secure = null, ?bool $httponly = null, ?string $sameSite = null): static
{
$name = strtolower($name);
@@ -519,10 +519,10 @@ abstract public function write(string $content): bool;
*
* Send optional content and end
*
- * @param string $content
+ * @param string|null $content
* @return void
*/
- abstract public function end(string $content = null): void;
+ abstract public function end(?string $content = null): void;
/**
* Output response
diff --git a/src/Http/Validator/AllOf.php b/src/Http/Validator/AllOf.php
index 70b40751..5e52f5ed 100644
--- a/src/Http/Validator/AllOf.php
+++ b/src/Http/Validator/AllOf.php
@@ -29,7 +29,7 @@ public function __construct(protected array $validators, protected string $type
*/
public function getDescription(): string
{
- if(!(\is_null($this->failedRule))) {
+ if (!(\is_null($this->failedRule))) {
$description = $this->failedRule->getDescription();
} else {
$description = $this->validators[0]->getDescription();
@@ -51,7 +51,7 @@ public function isValid(mixed $value): bool
foreach ($this->validators as $rule) {
$valid = $rule->isValid($value);
- if(!$valid) {
+ if (!$valid) {
$this->failedRule = $rule;
return false;
}
diff --git a/src/Http/Validator/AnyOf.php b/src/Http/Validator/AnyOf.php
index ad2bd921..ff96a54c 100644
--- a/src/Http/Validator/AnyOf.php
+++ b/src/Http/Validator/AnyOf.php
@@ -29,7 +29,7 @@ public function __construct(protected array $validators, protected string $type
*/
public function getDescription(): string
{
- if(!(\is_null($this->failedRule))) {
+ if (!(\is_null($this->failedRule))) {
$description = $this->failedRule->getDescription();
} else {
$description = $this->validators[0]->getDescription();
@@ -53,7 +53,7 @@ public function isValid(mixed $value): bool
$this->failedRule = $rule;
- if($valid) {
+ if ($valid) {
return true;
}
}
diff --git a/src/Http/Validator/ArrayList.php b/src/Http/Validator/ArrayList.php
index 79dc4696..c2c7e5ab 100644
--- a/src/Http/Validator/ArrayList.php
+++ b/src/Http/Validator/ArrayList.php
@@ -46,7 +46,7 @@ public function getDescription(): string
{
$msg = 'Value must a valid array';
- if($this->length > 0) {
+ if ($this->length > 0) {
$msg .= ' no longer than ' . $this->length . ' items';
}
diff --git a/src/Http/Validator/NoneOf.php b/src/Http/Validator/NoneOf.php
index 20af51b7..f74762fc 100644
--- a/src/Http/Validator/NoneOf.php
+++ b/src/Http/Validator/NoneOf.php
@@ -31,7 +31,7 @@ public function getDescription(): string
{
$description = '';
- if(!(\is_null($this->failedRule))) {
+ if (!(\is_null($this->failedRule))) {
$description = $this->failedRule->getDescription();
} else {
$description = $this->validators[0]->getDescription();
@@ -53,7 +53,7 @@ public function isValid(mixed $value): bool
foreach ($this->validators as $rule) {
$valid = $rule->isValid($value);
- if($valid) {
+ if ($valid) {
$this->failedRule = $rule;
return false;
}
diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php
index d9d0acc1..8dd8394a 100755
--- a/tests/ResponseTest.php
+++ b/tests/ResponseTest.php
@@ -36,7 +36,7 @@ public function testCanSetStatus()
try {
$this->response->setStatusCode(0); // Unknown status code
- } catch(\Exception $e) {
+ } catch (\Exception $e) {
$this->assertInstanceOf('\Exception', $e);
return;
From 9d62aad909b651fd45175644ec0c86c55550e29a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Thu, 21 Aug 2025 16:28:08 +0200
Subject: [PATCH 111/119] Add cookies header support for swoole
---
composer.json | 2 +-
src/Http/Adapter/Swoole/Request.php | 17 ++++++++++++++++-
tests/e2e/BaseTest.php | 10 ++++++++++
tests/e2e/init.php | 9 +++++++++
4 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/composer.json b/composer.json
index 3b0d7f66..377787e6 100644
--- a/composer.json
+++ b/composer.json
@@ -24,7 +24,7 @@
"scripts": {
"lint": "vendor/bin/pint --test",
"format": "vendor/bin/pint",
- "check": "vendor/bin/phpstan analyse -c phpstan.neon",
+ "check": "vendor/bin/phpstan analyse -c phpstan.neon --memory-limit 512M",
"test": "vendor/bin/phpunit --configuration phpunit.xml",
"bench": "vendor/bin/phpbench run --report=benchmark"
},
diff --git a/src/Http/Adapter/Swoole/Request.php b/src/Http/Adapter/Swoole/Request.php
index 164cf81c..0ec31263 100644
--- a/src/Http/Adapter/Swoole/Request.php
+++ b/src/Http/Adapter/Swoole/Request.php
@@ -359,6 +359,21 @@ protected function generateInput(): array
*/
protected function generateHeaders(): array
{
- return $this->swoole->header;
+ $headers = $this->swoole->header;
+
+ if (empty($this->swoole->cookie)) {
+ return $headers;
+ }
+
+ $cookieHeaders = [];
+ foreach ($this->swoole->cookie as $key => $value) {
+ $cookieHeaders[] = "{$key}={$value}";
+ }
+
+ if (!empty($cookieHeaders)) {
+ $headers['cookie'] = \implode('; ', $cookieHeaders);
+ }
+
+ return $headers;
}
}
diff --git a/tests/e2e/BaseTest.php b/tests/e2e/BaseTest.php
index 3fbdef51..57d04aa6 100644
--- a/tests/e2e/BaseTest.php
+++ b/tests/e2e/BaseTest.php
@@ -35,4 +35,14 @@ public function testFile()
$response = $this->client->call(Client::METHOD_GET, '/humans.txt');
$this->assertEquals(204, $response['headers']['status-code']);
}
+
+ public function testCookie()
+ {
+ $response = $this->client->call(Client::METHOD_GET, '/cookies', [
+ 'Cookie: cookie1=value1; cookie2=value2'
+ ]);
+
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals('cookie1=value1; cookie2=value2', $response['body']);
+ }
}
diff --git a/tests/e2e/init.php b/tests/e2e/init.php
index 64bb3cfa..2c85bd13 100644
--- a/tests/e2e/init.php
+++ b/tests/e2e/init.php
@@ -3,6 +3,7 @@
require_once __DIR__.'/../../vendor/autoload.php';
use Utopia\Http\Http;
+use Utopia\Http\Request;
use Utopia\Http\Response;
use Utopia\Http\Validator\Text;
@@ -25,6 +26,14 @@
$response->send($value);
});
+
+Http::get('/cookies')
+ ->inject('request')
+ ->inject('response')
+ ->action(function (Request $request, Response $response) {
+ $response->send($request->getHeaders()['cookie'] ?? '');
+ });
+
Http::get('/chunked')
->inject('response')
->action(function (Response $response) {
From 4700d389a63eabb1e2accfceaacaf89c73c66079 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 2 Sep 2025 12:19:35 +0200
Subject: [PATCH 112/119] Improve cookie handling
---
src/Http/Adapter/Swoole/Request.php | 29 ++++++++++++++++-------------
src/Http/Adapter/Swoole/Server.php | 3 ++-
tests/e2e/BaseTest.php | 19 +++++++++++++++++--
3 files changed, 35 insertions(+), 16 deletions(-)
diff --git a/src/Http/Adapter/Swoole/Request.php b/src/Http/Adapter/Swoole/Request.php
index 0ec31263..f0dd1d66 100644
--- a/src/Http/Adapter/Swoole/Request.php
+++ b/src/Http/Adapter/Swoole/Request.php
@@ -253,9 +253,21 @@ public function getFiles($key): array
*/
public function getCookie(string $key, string $default = ''): string
{
- $key = strtolower($key);
+ $key = \strtolower($key);
+
+ $cookies = \explode(';', $this->getHeader('cookie', ''));
+ foreach ($cookies as $cookie) {
+ $cookie = \trim($cookie);
+ [$cookieKey, $cookieValue] = \explode('=', $cookie, 2);
+ $cookieKey = \trim($cookieKey);
+ $cookieKey = \strtolower($cookieKey);
+ $cookieValue = \trim($cookieValue);
+ if ($cookieValue === $key) {
+ return $cookieValue;
+ }
+ }
- return $this->swoole->cookie[$key] ?? $default;
+ return $default;
}
/**
@@ -361,17 +373,8 @@ protected function generateHeaders(): array
{
$headers = $this->swoole->header;
- if (empty($this->swoole->cookie)) {
- return $headers;
- }
-
- $cookieHeaders = [];
- foreach ($this->swoole->cookie as $key => $value) {
- $cookieHeaders[] = "{$key}={$value}";
- }
-
- if (!empty($cookieHeaders)) {
- $headers['cookie'] = \implode('; ', $cookieHeaders);
+ foreach ($headers as $key => $value) {
+ $headers[strtolower($key)] = $value;
}
return $headers;
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index fff99f1e..bb3b87d8 100755
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -19,7 +19,8 @@ public function __construct(string $host, ?string $port = null, array $settings
{
$this->server = new SwooleServer($host, $port);
$this->server->set(\array_merge($settings, [
- 'enable_coroutine' => true
+ 'enable_coroutine' => true,
+ 'http_parse_cookie' => false,
]));
}
diff --git a/tests/e2e/BaseTest.php b/tests/e2e/BaseTest.php
index 57d04aa6..f95e96cd 100644
--- a/tests/e2e/BaseTest.php
+++ b/tests/e2e/BaseTest.php
@@ -38,11 +38,26 @@ public function testFile()
public function testCookie()
{
+ $cookie = 'cookie1=value1';
$response = $this->client->call(Client::METHOD_GET, '/cookies', [
- 'Cookie: cookie1=value1; cookie2=value2'
+ 'Cookie: ' . $cookie
]);
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals($cookie, $response['body']);
+
+ $cookie = 'cookie1=value1; cookie2=value2';
+ $response = $this->client->call(Client::METHOD_GET, '/cookies', [
+ 'Cookie: ' . $cookie
+ ]);
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals($cookie, $response['body']);
+
+ $cookie = 'cookie1=value1;cookie2=value2';
+ $response = $this->client->call(Client::METHOD_GET, '/cookies', [
+ 'Cookie: ' . $cookie
+ ]);
$this->assertEquals(200, $response['headers']['status-code']);
- $this->assertEquals('cookie1=value1; cookie2=value2', $response['body']);
+ $this->assertEquals($cookie, $response['body']);
}
}
From abe33048a19edde616c444d3d6f0d425c7eb0555 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Tue, 2 Sep 2025 13:16:19 +0200
Subject: [PATCH 113/119] Logical fixes & new tests
---
src/Http/Adapter/Swoole/Request.php | 3 +--
tests/e2e/BaseTest.php | 28 ++++++++++++++++++----------
2 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/src/Http/Adapter/Swoole/Request.php b/src/Http/Adapter/Swoole/Request.php
index f0dd1d66..b07a5fdb 100644
--- a/src/Http/Adapter/Swoole/Request.php
+++ b/src/Http/Adapter/Swoole/Request.php
@@ -260,9 +260,8 @@ public function getCookie(string $key, string $default = ''): string
$cookie = \trim($cookie);
[$cookieKey, $cookieValue] = \explode('=', $cookie, 2);
$cookieKey = \trim($cookieKey);
- $cookieKey = \strtolower($cookieKey);
$cookieValue = \trim($cookieValue);
- if ($cookieValue === $key) {
+ if ($cookieKey === $key) {
return $cookieValue;
}
}
diff --git a/tests/e2e/BaseTest.php b/tests/e2e/BaseTest.php
index f95e96cd..7279ee41 100644
--- a/tests/e2e/BaseTest.php
+++ b/tests/e2e/BaseTest.php
@@ -38,25 +38,33 @@ public function testFile()
public function testCookie()
{
+ // One cookie
$cookie = 'cookie1=value1';
- $response = $this->client->call(Client::METHOD_GET, '/cookies', [
- 'Cookie: ' . $cookie
- ]);
+ $response = $this->client->call(Client::METHOD_GET, '/cookies', [ 'Cookie: ' . $cookie ]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($cookie, $response['body']);
+ // Two cookiees
$cookie = 'cookie1=value1; cookie2=value2';
- $response = $this->client->call(Client::METHOD_GET, '/cookies', [
- 'Cookie: ' . $cookie
- ]);
+ $response = $this->client->call(Client::METHOD_GET, '/cookies', [ 'Cookie: ' . $cookie ]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($cookie, $response['body']);
-
+ // Two cookies without optional space
$cookie = 'cookie1=value1;cookie2=value2';
- $response = $this->client->call(Client::METHOD_GET, '/cookies', [
- 'Cookie: ' . $cookie
- ]);
+ $response = $this->client->call(Client::METHOD_GET, '/cookies', [ 'Cookie: ' . $cookie ]);
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals($cookie, $response['body']);
+
+ // Cookie with "=" in value
+ $cookie = 'cookie1=value1=value2';
+ $response = $this->client->call(Client::METHOD_GET, '/cookies', [ 'Cookie: ' . $cookie ]);
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals($cookie, $response['body']);
+
+ // Case sensitivity for cookie names
+ $cookie = 'cookie1=v1; Cookie1=v2';
+ $response = $this->client->call(Client::METHOD_GET, '/cookies', [ 'Cookie: ' . $cookie ]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($cookie, $response['body']);
}
From d19da136fc560eaf7c2137c4448809b5c7eeebf3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Ba=C4=8Do?=
Date: Wed, 3 Sep 2025 19:05:57 +0200
Subject: [PATCH 114/119] Allow array for headers
---
src/Http/Adapter/FPM/Response.php | 12 ++++++++---
src/Http/Adapter/Swoole/Response.php | 4 ++--
src/Http/Response.php | 32 ++++++++++++++++++++++------
tests/e2e/BaseTest.php | 8 +++++++
tests/e2e/Client.php | 27 ++++++++++++++++++++++-
tests/e2e/init.php | 9 ++++++++
6 files changed, 80 insertions(+), 12 deletions(-)
diff --git a/src/Http/Adapter/FPM/Response.php b/src/Http/Adapter/FPM/Response.php
index 6c877918..6a5d4dd4 100644
--- a/src/Http/Adapter/FPM/Response.php
+++ b/src/Http/Adapter/FPM/Response.php
@@ -53,12 +53,18 @@ protected function sendStatus(int $statusCode): void
* Output Header
*
* @param string $key
- * @param string $value
+ * @param string|array $value
* @return void
*/
- public function sendHeader(string $key, string $value): void
+ public function sendHeader(string $key, mixed $value): void
{
- \header($key.': '.$value);
+ if (\is_array($value)) {
+ foreach ($value as $v) {
+ \header($key.': '.$v, false);
+ }
+ } else {
+ \header($key.': '.$value);
+ }
}
/**
diff --git a/src/Http/Adapter/Swoole/Response.php b/src/Http/Adapter/Swoole/Response.php
index b0b99978..be48a027 100644
--- a/src/Http/Adapter/Swoole/Response.php
+++ b/src/Http/Adapter/Swoole/Response.php
@@ -65,10 +65,10 @@ protected function sendStatus(int $statusCode): void
* Send Header
*
* @param string $key
- * @param string $value
+ * @param string|array $value
* @return void
*/
- public function sendHeader(string $key, string $value): void
+ public function sendHeader(string $key, mixed $value): void
{
$this->swoole->header($key, $value);
}
diff --git a/src/Http/Response.php b/src/Http/Response.php
index d0e6e793..2bc4a5f4 100755
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -225,7 +225,7 @@ abstract class Response
protected bool $sent = false;
/**
- * @var array
+ * @var array>
*/
protected array $headers = [];
@@ -365,7 +365,15 @@ public function enablePayload(): static
*/
public function addHeader(string $key, string $value): static
{
- $this->headers[$key] = $value;
+ if (\array_key_exists($key, $this->headers)) {
+ if (\is_array($this->headers[$key])) {
+ $this->headers[$key][] = $value;
+ } else {
+ $this->headers[$key] = [$this->headers[$key], $value];
+ }
+ } else {
+ $this->headers[$key] = $value;
+ }
return $this;
}
@@ -391,7 +399,7 @@ public function removeHeader(string $key): static
*
* Return array of all response headers
*
- * @return array
+ * @return array>
*/
public function getHeaders(): array
{
@@ -483,7 +491,19 @@ public function send(string $body = ''): void
if (!$this->disablePayload) {
$length = strlen($body);
- $this->size = $this->size + strlen(implode("\n", $this->headers)) + $length;
+ $headersSize = 0;
+ foreach ($this->headers as $name => $values) {
+ if (\is_array($values)) {
+ foreach ($values as $value) {
+ $headersSize += \strlen($name . ': ' . $value);
+ }
+ $headersSize += (\count($values) - 1) * 2; // linebreaks
+ } else {
+ $headersSize += \strlen($name . ': ' . $values);
+ }
+ }
+ $headersSize += (\count($this->headers) - 1) * 2; // linebreaks
+ $this->size = $this->size + $headersSize + $length;
if (array_key_exists(
$this->contentType,
@@ -599,10 +619,10 @@ abstract protected function sendStatus(int $statusCode): void;
* Output Header
*
* @param string $key
- * @param string $value
+ * @param string|array $value
* @return void
*/
- abstract public function sendHeader(string $key, string $value): void;
+ abstract public function sendHeader(string $key, mixed $value): void;
/**
* Send Cookie
diff --git a/tests/e2e/BaseTest.php b/tests/e2e/BaseTest.php
index 7279ee41..04b4249d 100644
--- a/tests/e2e/BaseTest.php
+++ b/tests/e2e/BaseTest.php
@@ -68,4 +68,12 @@ public function testCookie()
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($cookie, $response['body']);
}
+
+ public function testSetCookie()
+ {
+ $response = $this->client->call(Client::METHOD_GET, '/set-cookie');
+ $this->assertEquals(200, $response['headers']['status-code']);
+ $this->assertEquals('value1', $response['cookies']['key1']);
+ $this->assertEquals('value2', $response['cookies']['key2']);
+ }
}
diff --git a/tests/e2e/Client.php b/tests/e2e/Client.php
index 5bf15b2e..42fdd5a8 100644
--- a/tests/e2e/Client.php
+++ b/tests/e2e/Client.php
@@ -61,6 +61,8 @@ public function call(string $method, string $path = '', array $headers = [], arr
$responseType = '';
$responseBody = '';
+ $cookies = [];
+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
@@ -68,7 +70,7 @@ public function call(string $method, string $path = '', array $headers = [], arr
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
- curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders) {
+ curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders, &$cookies) {
$len = strlen($header);
$header = explode(':', $header, 2);
@@ -76,6 +78,12 @@ public function call(string $method, string $path = '', array $headers = [], arr
return $len;
}
+ if (strtolower(trim($header[0])) == 'set-cookie') {
+ $parsed = $this->parseCookie((string)trim($header[1]));
+ $name = array_key_first($parsed);
+ $cookies[$name] = $parsed[$name];
+ }
+
$responseHeaders[strtolower(trim($header[0]))] = trim($header[1]);
return $len;
@@ -99,6 +107,23 @@ public function call(string $method, string $path = '', array $headers = [], arr
return [
'headers' => $responseHeaders,
'body' => $responseBody,
+ 'cookies' => $cookies,
];
}
+
+ /**
+ * Parse Cookie String
+ *
+ * @param string $cookie
+ * @return array
+ */
+ public function parseCookie(string $cookie): array
+ {
+ $cookies = [];
+
+ parse_str(strtr($cookie, ['&' => '%26', '+' => '%2B', ';' => '&']), $cookies);
+
+ return $cookies;
+ }
+
}
diff --git a/tests/e2e/init.php b/tests/e2e/init.php
index 2c85bd13..54638fd9 100644
--- a/tests/e2e/init.php
+++ b/tests/e2e/init.php
@@ -34,6 +34,15 @@
$response->send($request->getHeaders()['cookie'] ?? '');
});
+Http::get('/set-cookie')
+ ->inject('request')
+ ->inject('response')
+ ->action(function (Request $request, Response $response) {
+ $response->addHeader('Set-Cookie', 'key1=value1');
+ $response->addHeader('Set-Cookie', 'key2=value2');
+ $response->send('OK');
+ });
+
Http::get('/chunked')
->inject('response')
->action(function (Response $response) {
From 2b500d0798806e0fad62cd9a27dda42fa183f2b7 Mon Sep 17 00:00:00 2001
From: Chirag Aggarwal
Date: Thu, 11 Dec 2025 18:30:55 +0530
Subject: [PATCH 115/119] Fix array to string conversion warning in
Request::getSize()
Headers can now be arrays (after recent changes allowing array headers).
The getSize() method was attempting to directly implode headers, causing
a warning when a header value was an array.
This fix properly handles both string and array header values by joining
array values with commas (standard HTTP header format) before calculating
the request size.
Added test case to verify the fix works correctly with array headers.
---
src/Http/Request.php | 11 ++++++++++-
tests/RequestTest.php | 19 +++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/src/Http/Request.php b/src/Http/Request.php
index 8332d99d..c9762123 100755
--- a/src/Http/Request.php
+++ b/src/Http/Request.php
@@ -332,7 +332,16 @@ abstract public function removeHeader(string $key): static;
*/
public function getSize(): int
{
- return \mb_strlen(\implode("\n", $this->generateHeaders()), '8bit') + \mb_strlen(\file_get_contents('php://input'), '8bit');
+ $headers = $this->generateHeaders();
+ $headerStrings = [];
+ foreach ($headers as $key => $value) {
+ if (\is_array($value)) {
+ $headerStrings[] = $key . ': ' . \implode(', ', $value);
+ } else {
+ $headerStrings[] = $key . ': ' . $value;
+ }
+ }
+ return \mb_strlen(\implode("\n", $headerStrings), '8bit') + \mb_strlen(\file_get_contents('php://input'), '8bit');
}
/**
diff --git a/tests/RequestTest.php b/tests/RequestTest.php
index 55d49ee9..02d8930a 100755
--- a/tests/RequestTest.php
+++ b/tests/RequestTest.php
@@ -313,4 +313,23 @@ public function testCanGetRange()
$this->assertEquals(null, $this->request->getRangeStart());
$this->assertEquals(null, $this->request->getRangeEnd());
}
+
+ public function testCanGetSizeWithArrayHeaders()
+ {
+ $this->request->addHeader('content-type', 'application/json');
+
+ $reflection = new \ReflectionClass($this->request);
+ $headersProperty = $reflection->getProperty('headers');
+ $headersProperty->setAccessible(true);
+
+ $headers = $headersProperty->getValue($this->request) ?? [];
+ $headers['accept'] = ['application/json', 'text/html'];
+ $headers['x-custom'] = ['value1', 'value2', 'value3'];
+ $headersProperty->setValue($this->request, $headers);
+
+ $size = $this->request->getSize();
+
+ $this->assertIsInt($size);
+ $this->assertGreaterThan(0, $size);
+ }
}
From b73e9e8500fada78ff4104e9b625be2dbf38c1ca Mon Sep 17 00:00:00 2001
From: Chirag Aggarwal
Date: Thu, 18 Dec 2025 13:39:22 +0530
Subject: [PATCH 116/119] feat: remove validators and use utopia validators lib
---
composer.json | 3 +-
composer.lock | 361 ++++++++++++++-----------
docs/Getting-Starting-Guide.md | 2 +-
example/src/server.php | 2 +-
src/Http/Hook.php | 2 +
src/Http/Http.php | 2 +
src/Http/Validator.php | 57 ----
src/Http/Validator/AllOf.php | 86 ------
src/Http/Validator/AnyOf.php | 87 ------
src/Http/Validator/ArrayList.php | 116 --------
src/Http/Validator/Assoc.php | 88 ------
src/Http/Validator/Boolean.php | 94 -------
src/Http/Validator/Domain.php | 78 ------
src/Http/Validator/FloatValidator.php | 88 ------
src/Http/Validator/HexColor.php | 53 ----
src/Http/Validator/Host.php | 82 ------
src/Http/Validator/Hostname.php | 114 --------
src/Http/Validator/IP.php | 113 --------
src/Http/Validator/Integer.php | 88 ------
src/Http/Validator/JSON.php | 59 ----
src/Http/Validator/NoneOf.php | 88 ------
src/Http/Validator/Nullable.php | 73 -----
src/Http/Validator/Numeric.php | 66 -----
src/Http/Validator/Range.php | 149 ----------
src/Http/Validator/Text.php | 138 ----------
src/Http/Validator/URL.php | 86 ------
src/Http/Validator/WhiteList.php | 119 --------
src/Http/Validator/Wildcard.php | 62 -----
tests/HookTest.php | 4 +-
tests/HttpTest.php | 2 +-
tests/RouteTest.php | 2 +-
tests/Validator/ArrayListTest.php | 52 ----
tests/Validator/AssocTest.php | 43 ---
tests/Validator/BooleanTest.php | 46 ----
tests/Validator/DomainTest.php | 37 ---
tests/Validator/FloatValidatorTest.php | 39 ---
tests/Validator/HexColorTest.php | 26 --
tests/Validator/HostTest.php | 30 --
tests/Validator/HostnameTest.php | 106 --------
tests/Validator/IPTest.php | 67 -----
tests/Validator/IntegerTest.php | 36 ---
tests/Validator/JSONTest.php | 28 --
tests/Validator/MultipleOfTest.php | 61 -----
tests/Validator/NullableTest.php | 22 --
tests/Validator/NumericTest.php | 24 --
tests/Validator/RangeTest.php | 60 ----
tests/Validator/TextTest.php | 88 ------
tests/Validator/URLTest.php | 43 ---
tests/Validator/WhiteListTest.php | 58 ----
tests/Validator/WildcardTest.php | 21 --
tests/e2e/init.php | 2 +-
51 files changed, 219 insertions(+), 3034 deletions(-)
delete mode 100755 src/Http/Validator.php
delete mode 100644 src/Http/Validator/AllOf.php
delete mode 100644 src/Http/Validator/AnyOf.php
delete mode 100644 src/Http/Validator/ArrayList.php
delete mode 100644 src/Http/Validator/Assoc.php
delete mode 100644 src/Http/Validator/Boolean.php
delete mode 100644 src/Http/Validator/Domain.php
delete mode 100755 src/Http/Validator/FloatValidator.php
delete mode 100644 src/Http/Validator/HexColor.php
delete mode 100755 src/Http/Validator/Host.php
delete mode 100644 src/Http/Validator/Hostname.php
delete mode 100644 src/Http/Validator/IP.php
delete mode 100755 src/Http/Validator/Integer.php
delete mode 100644 src/Http/Validator/JSON.php
delete mode 100644 src/Http/Validator/NoneOf.php
delete mode 100644 src/Http/Validator/Nullable.php
delete mode 100755 src/Http/Validator/Numeric.php
delete mode 100755 src/Http/Validator/Range.php
delete mode 100644 src/Http/Validator/Text.php
delete mode 100644 src/Http/Validator/URL.php
delete mode 100755 src/Http/Validator/WhiteList.php
delete mode 100644 src/Http/Validator/Wildcard.php
delete mode 100755 tests/Validator/ArrayListTest.php
delete mode 100755 tests/Validator/AssocTest.php
delete mode 100755 tests/Validator/BooleanTest.php
delete mode 100644 tests/Validator/DomainTest.php
delete mode 100755 tests/Validator/FloatValidatorTest.php
delete mode 100755 tests/Validator/HexColorTest.php
delete mode 100644 tests/Validator/HostTest.php
delete mode 100755 tests/Validator/HostnameTest.php
delete mode 100644 tests/Validator/IPTest.php
delete mode 100755 tests/Validator/IntegerTest.php
delete mode 100755 tests/Validator/JSONTest.php
delete mode 100644 tests/Validator/MultipleOfTest.php
delete mode 100755 tests/Validator/NullableTest.php
delete mode 100755 tests/Validator/NumericTest.php
delete mode 100755 tests/Validator/RangeTest.php
delete mode 100755 tests/Validator/TextTest.php
delete mode 100644 tests/Validator/URLTest.php
delete mode 100755 tests/Validator/WhiteListTest.php
delete mode 100644 tests/Validator/WildcardTest.php
diff --git a/composer.json b/composer.json
index 377787e6..e5953bc4 100644
--- a/composer.json
+++ b/composer.json
@@ -30,7 +30,8 @@
},
"require": {
"php": ">=8.0",
- "ext-swoole": "*"
+ "ext-swoole": "*",
+ "utopia-php/validators": "0.1.*"
},
"require-dev": {
"phpunit/phpunit": "^9.5.25",
diff --git a/composer.lock b/composer.lock
index abee3f7b..b68b4ff5 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,54 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "47587a7a55803f5b0fdf225267c03f03",
- "packages": [],
+ "content-hash": "3851bd0696173988209c33d95ad3fd35",
+ "packages": [
+ {
+ "name": "utopia-php/validators",
+ "version": "0.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/validators.git",
+ "reference": "5c57d5b6cf964f8981807c1d3ea8df620c869080"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/validators/zipball/5c57d5b6cf964f8981807c1d3ea8df620c869080",
+ "reference": "5c57d5b6cf964f8981807c1d3ea8df620c869080",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0"
+ },
+ "require-dev": {
+ "laravel/pint": "1.*",
+ "phpstan/phpstan": "1.*",
+ "phpunit/phpunit": "11.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A lightweight collection of reusable validators for Utopia projects",
+ "keywords": [
+ "php",
+ "utopia",
+ "validation",
+ "validator"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/validators/issues",
+ "source": "https://github.com/utopia-php/validators/tree/0.1.0"
+ },
+ "time": "2025-11-18T11:05:46+00:00"
+ }
+ ],
"packages-dev": [
{
"name": "doctrine/annotations",
@@ -81,6 +127,7 @@
"issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/2.0.2"
},
+ "abandoned": true,
"time": "2024-09-05T10:17:24+00:00"
},
{
@@ -232,16 +279,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.24.0",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a"
+ "reference": "69dcca060ecb15e4b564af63d1f642c81a241d6f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/0345f3b05f136801af8c339f9d16ef29e6b4df8a",
- "reference": "0345f3b05f136801af8c339f9d16ef29e6b4df8a",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/69dcca060ecb15e4b564af63d1f642c81a241d6f",
+ "reference": "69dcca060ecb15e4b564af63d1f642c81a241d6f",
"shasum": ""
},
"require": {
@@ -252,22 +299,19 @@
"php": "^8.2.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.82.2",
- "illuminate/view": "^11.45.1",
- "larastan/larastan": "^3.5.0",
- "laravel-zero/framework": "^11.45.0",
+ "friendsofphp/php-cs-fixer": "^3.90.0",
+ "illuminate/view": "^12.40.1",
+ "larastan/larastan": "^3.8.0",
+ "laravel-zero/framework": "^12.0.4",
"mockery/mockery": "^1.6.12",
- "nunomaduro/termwind": "^2.3.1",
- "pestphp/pest": "^2.36.0"
+ "nunomaduro/termwind": "^2.3.3",
+ "pestphp/pest": "^3.8.4"
},
"bin": [
"builds/pint"
],
"type": "project",
"autoload": {
- "files": [
- "overrides/Runner/Parallel/ProcessFactory.php"
- ],
"psr-4": {
"App\\": "app/",
"Database\\Seeders\\": "database/seeders/",
@@ -287,6 +331,7 @@
"description": "An opinionated code formatter for PHP.",
"homepage": "https://laravel.com",
"keywords": [
+ "dev",
"format",
"formatter",
"lint",
@@ -297,7 +342,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2025-07-10T18:09:32+00:00"
+ "time": "2025-11-25T21:15:52+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -361,16 +406,16 @@
},
{
"name": "nikic/php-parser",
- "version": "v5.6.1",
+ "version": "v5.7.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
- "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
"shasum": ""
},
"require": {
@@ -413,9 +458,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
},
- "time": "2025-08-13T20:13:15+00:00"
+ "time": "2025-12-06T11:56:16+00:00"
},
{
"name": "phar-io/manifest",
@@ -537,24 +582,24 @@
},
{
"name": "phpbench/container",
- "version": "2.2.2",
+ "version": "2.2.3",
"source": {
"type": "git",
"url": "https://github.com/phpbench/container.git",
- "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33"
+ "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpbench/container/zipball/a59b929e00b87b532ca6d0edd8eca0967655af33",
- "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33",
+ "url": "https://api.github.com/repos/phpbench/container/zipball/0c7b2d36c1ea53fe27302fb8873ded7172047196",
+ "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196",
"shasum": ""
},
"require": {
"psr/container": "^1.0|^2.0",
- "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0"
+ "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^2.16",
+ "php-cs-fixer/shim": "^3.89",
"phpstan/phpstan": "^0.12.52",
"phpunit/phpunit": "^8"
},
@@ -582,22 +627,22 @@
"description": "Simple, configurable, service container.",
"support": {
"issues": "https://github.com/phpbench/container/issues",
- "source": "https://github.com/phpbench/container/tree/2.2.2"
+ "source": "https://github.com/phpbench/container/tree/2.2.3"
},
- "time": "2023-10-30T13:38:26+00:00"
+ "time": "2025-11-06T09:05:13+00:00"
},
{
"name": "phpbench/phpbench",
- "version": "1.4.1",
+ "version": "1.4.3",
"source": {
"type": "git",
"url": "https://github.com/phpbench/phpbench.git",
- "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b"
+ "reference": "b641dde59d969ea42eed70a39f9b51950bc96878"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpbench/phpbench/zipball/78cd98a9aa34e0f8f80ca01972a8b88d2c30194b",
- "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b",
+ "url": "https://api.github.com/repos/phpbench/phpbench/zipball/b641dde59d969ea42eed70a39f9b51950bc96878",
+ "reference": "b641dde59d969ea42eed70a39f9b51950bc96878",
"shasum": ""
},
"require": {
@@ -612,26 +657,26 @@
"phpbench/container": "^2.2",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"seld/jsonlint": "^1.1",
- "symfony/console": "^6.1 || ^7.0",
- "symfony/filesystem": "^6.1 || ^7.0",
- "symfony/finder": "^6.1 || ^7.0",
- "symfony/options-resolver": "^6.1 || ^7.0",
- "symfony/process": "^6.1 || ^7.0",
+ "symfony/console": "^6.1 || ^7.0 || ^8.0",
+ "symfony/filesystem": "^6.1 || ^7.0 || ^8.0",
+ "symfony/finder": "^6.1 || ^7.0 || ^8.0",
+ "symfony/options-resolver": "^6.1 || ^7.0 || ^8.0",
+ "symfony/process": "^6.1 || ^7.0 || ^8.0",
"webmozart/glob": "^4.6"
},
"require-dev": {
"dantleech/invoke": "^2.0",
"ergebnis/composer-normalize": "^2.39",
- "friendsofphp/php-cs-fixer": "^3.0",
"jangregor/phpstan-prophecy": "^1.0",
- "phpspec/prophecy": "dev-master",
+ "php-cs-fixer/shim": "^3.9",
+ "phpspec/prophecy": "^1.22",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^10.4 || ^11.0",
"rector/rector": "^1.2",
- "symfony/error-handler": "^6.1 || ^7.0",
- "symfony/var-dumper": "^6.1 || ^7.0"
+ "symfony/error-handler": "^6.1 || ^7.0 || ^8.0",
+ "symfony/var-dumper": "^6.1 || ^7.0 || ^8.0"
},
"suggest": {
"ext-xdebug": "For Xdebug profiling extension."
@@ -674,7 +719,7 @@
],
"support": {
"issues": "https://github.com/phpbench/phpbench/issues",
- "source": "https://github.com/phpbench/phpbench/tree/1.4.1"
+ "source": "https://github.com/phpbench/phpbench/tree/1.4.3"
},
"funding": [
{
@@ -682,20 +727,15 @@
"type": "github"
}
],
- "time": "2025-03-12T08:01:40+00:00"
+ "time": "2025-11-06T19:07:31+00:00"
},
{
"name": "phpstan/phpstan",
- "version": "1.12.28",
- "source": {
- "type": "git",
- "url": "https://github.com/phpstan/phpstan.git",
- "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9"
- },
+ "version": "1.12.32",
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9",
- "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8",
+ "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8",
"shasum": ""
},
"require": {
@@ -740,7 +780,7 @@
"type": "github"
}
],
- "time": "2025-07-17T17:15:39+00:00"
+ "time": "2025-09-30T10:16:31+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -1063,16 +1103,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.25",
+ "version": "9.6.31",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "049c011e01be805202d8eebedef49f769a8ec7b7"
+ "reference": "945d0b7f346a084ce5549e95289962972c4272e5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/049c011e01be805202d8eebedef49f769a8ec7b7",
- "reference": "049c011e01be805202d8eebedef49f769a8ec7b7",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/945d0b7f346a084ce5549e95289962972c4272e5",
+ "reference": "945d0b7f346a084ce5549e95289962972c4272e5",
"shasum": ""
},
"require": {
@@ -1097,7 +1137,7 @@
"sebastian/comparator": "^4.0.9",
"sebastian/diff": "^4.0.6",
"sebastian/environment": "^5.1.5",
- "sebastian/exporter": "^4.0.6",
+ "sebastian/exporter": "^4.0.8",
"sebastian/global-state": "^5.0.8",
"sebastian/object-enumerator": "^4.0.4",
"sebastian/resource-operations": "^3.0.4",
@@ -1146,7 +1186,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.25"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.31"
},
"funding": [
{
@@ -1170,7 +1210,7 @@
"type": "tidelift"
}
],
- "time": "2025-08-20T14:38:31+00:00"
+ "time": "2025-12-06T07:45:52+00:00"
},
{
"name": "psr/cache",
@@ -1765,16 +1805,16 @@
},
{
"name": "sebastian/exporter",
- "version": "4.0.6",
+ "version": "4.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
+ "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
- "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c",
+ "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c",
"shasum": ""
},
"require": {
@@ -1830,15 +1870,27 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
- "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
+ "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.8"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
+ "type": "tidelift"
}
],
- "time": "2024-03-02T06:33:00+00:00"
+ "time": "2025-09-24T06:03:27+00:00"
},
{
"name": "sebastian/global-state",
@@ -2431,47 +2483,39 @@
},
{
"name": "symfony/console",
- "version": "v7.3.2",
+ "version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1"
+ "reference": "fcb73f69d655b48fcb894a262f074218df08bd58"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1",
- "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1",
+ "url": "https://api.github.com/repos/symfony/console/zipball/fcb73f69d655b48fcb894a262f074218df08bd58",
+ "reference": "fcb73f69d655b48fcb894a262f074218df08bd58",
"shasum": ""
},
"require": {
- "php": ">=8.2",
- "symfony/deprecation-contracts": "^2.5|^3",
- "symfony/polyfill-mbstring": "~1.0",
+ "php": ">=8.4",
+ "symfony/polyfill-mbstring": "^1.0",
"symfony/service-contracts": "^2.5|^3",
- "symfony/string": "^7.2"
- },
- "conflict": {
- "symfony/dependency-injection": "<6.4",
- "symfony/dotenv": "<6.4",
- "symfony/event-dispatcher": "<6.4",
- "symfony/lock": "<6.4",
- "symfony/process": "<6.4"
+ "symfony/string": "^7.4|^8.0"
},
"provide": {
"psr/log-implementation": "1.0|2.0|3.0"
},
"require-dev": {
"psr/log": "^1|^2|^3",
- "symfony/config": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/event-dispatcher": "^6.4|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/lock": "^6.4|^7.0",
- "symfony/messenger": "^6.4|^7.0",
- "symfony/process": "^6.4|^7.0",
- "symfony/stopwatch": "^6.4|^7.0",
- "symfony/var-dumper": "^6.4|^7.0"
+ "symfony/config": "^7.4|^8.0",
+ "symfony/dependency-injection": "^7.4|^8.0",
+ "symfony/event-dispatcher": "^7.4|^8.0",
+ "symfony/http-foundation": "^7.4|^8.0",
+ "symfony/http-kernel": "^7.4|^8.0",
+ "symfony/lock": "^7.4|^8.0",
+ "symfony/messenger": "^7.4|^8.0",
+ "symfony/process": "^7.4|^8.0",
+ "symfony/stopwatch": "^7.4|^8.0",
+ "symfony/var-dumper": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -2505,7 +2549,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.3.2"
+ "source": "https://github.com/symfony/console/tree/v8.0.1"
},
"funding": [
{
@@ -2525,7 +2569,7 @@
"type": "tidelift"
}
],
- "time": "2025-07-30T17:13:41+00:00"
+ "time": "2025-12-05T15:25:33+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -2596,25 +2640,25 @@
},
{
"name": "symfony/filesystem",
- "version": "v7.3.2",
+ "version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd"
+ "reference": "d937d400b980523dc9ee946bb69972b5e619058d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd",
- "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d",
+ "reference": "d937d400b980523dc9ee946bb69972b5e619058d",
"shasum": ""
},
"require": {
- "php": ">=8.2",
+ "php": ">=8.4",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8"
},
"require-dev": {
- "symfony/process": "^6.4|^7.0"
+ "symfony/process": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -2642,7 +2686,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v7.3.2"
+ "source": "https://github.com/symfony/filesystem/tree/v8.0.1"
},
"funding": [
{
@@ -2662,27 +2706,27 @@
"type": "tidelift"
}
],
- "time": "2025-07-07T08:17:47+00:00"
+ "time": "2025-12-01T09:13:36+00:00"
},
{
"name": "symfony/finder",
- "version": "v7.3.2",
+ "version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
+ "reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
- "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/7598dd5770580fa3517ec83e8da0c9b9e01f4291",
+ "reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291",
"shasum": ""
},
"require": {
- "php": ">=8.2"
+ "php": ">=8.4"
},
"require-dev": {
- "symfony/filesystem": "^6.4|^7.0"
+ "symfony/filesystem": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -2710,7 +2754,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v7.3.2"
+ "source": "https://github.com/symfony/finder/tree/v8.0.0"
},
"funding": [
{
@@ -2730,24 +2774,24 @@
"type": "tidelift"
}
],
- "time": "2025-07-15T13:41:35+00:00"
+ "time": "2025-11-05T14:36:47+00:00"
},
{
"name": "symfony/options-resolver",
- "version": "v7.3.2",
+ "version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
- "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37"
+ "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37",
- "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d2b592535ffa6600c265a3893a7f7fd2bad82dd7",
+ "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7",
"shasum": ""
},
"require": {
- "php": ">=8.2",
+ "php": ">=8.4",
"symfony/deprecation-contracts": "^2.5|^3"
},
"type": "library",
@@ -2781,7 +2825,7 @@
"options"
],
"support": {
- "source": "https://github.com/symfony/options-resolver/tree/v7.3.2"
+ "source": "https://github.com/symfony/options-resolver/tree/v8.0.0"
},
"funding": [
{
@@ -2801,7 +2845,7 @@
"type": "tidelift"
}
],
- "time": "2025-07-15T11:36:08+00:00"
+ "time": "2025-11-12T15:55:31+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -3140,20 +3184,20 @@
},
{
"name": "symfony/process",
- "version": "v7.3.0",
+ "version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af"
+ "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
- "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
+ "url": "https://api.github.com/repos/symfony/process/zipball/a0a750500c4ce900d69ba4e9faf16f82c10ee149",
+ "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149",
"shasum": ""
},
"require": {
- "php": ">=8.2"
+ "php": ">=8.4"
},
"type": "library",
"autoload": {
@@ -3181,7 +3225,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v7.3.0"
+ "source": "https://github.com/symfony/process/tree/v8.0.0"
},
"funding": [
{
@@ -3192,25 +3236,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-17T09:11:12+00:00"
+ "time": "2025-10-16T16:25:44+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v3.6.0",
+ "version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
- "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
"shasum": ""
},
"require": {
@@ -3264,7 +3312,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
},
"funding": [
{
@@ -3275,44 +3323,47 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-25T09:37:31+00:00"
+ "time": "2025-07-15T11:30:57+00:00"
},
{
"name": "symfony/string",
- "version": "v7.3.2",
+ "version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca"
+ "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca",
- "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca",
+ "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc",
+ "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc",
"shasum": ""
},
"require": {
- "php": ">=8.2",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-intl-grapheme": "~1.0",
- "symfony/polyfill-intl-normalizer": "~1.0",
- "symfony/polyfill-mbstring": "~1.0"
+ "php": ">=8.4",
+ "symfony/polyfill-ctype": "^1.8",
+ "symfony/polyfill-intl-grapheme": "^1.33",
+ "symfony/polyfill-intl-normalizer": "^1.0",
+ "symfony/polyfill-mbstring": "^1.0"
},
"conflict": {
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/emoji": "^7.1",
- "symfony/error-handler": "^6.4|^7.0",
- "symfony/http-client": "^6.4|^7.0",
- "symfony/intl": "^6.4|^7.0",
+ "symfony/emoji": "^7.4|^8.0",
+ "symfony/http-client": "^7.4|^8.0",
+ "symfony/intl": "^7.4|^8.0",
"symfony/translation-contracts": "^2.5|^3.0",
- "symfony/var-exporter": "^6.4|^7.0"
+ "symfony/var-exporter": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -3351,7 +3402,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v7.3.2"
+ "source": "https://github.com/symfony/string/tree/v8.0.1"
},
"funding": [
{
@@ -3371,20 +3422,20 @@
"type": "tidelift"
}
],
- "time": "2025-07-10T08:47:49+00:00"
+ "time": "2025-12-01T09:13:36+00:00"
},
{
"name": "theseer/tokenizer",
- "version": "1.2.3",
+ "version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c",
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c",
"shasum": ""
},
"require": {
@@ -3413,7 +3464,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
- "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
+ "source": "https://github.com/theseer/tokenizer/tree/1.3.1"
},
"funding": [
{
@@ -3421,7 +3472,7 @@
"type": "github"
}
],
- "time": "2024-03-03T12:36:25+00:00"
+ "time": "2025-11-17T20:03:58+00:00"
},
{
"name": "webmozart/glob",
@@ -3475,13 +3526,13 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=8.0",
"ext-swoole": "*"
},
- "platform-dev": [],
- "plugin-api-version": "2.3.0"
+ "platform-dev": {},
+ "plugin-api-version": "2.6.0"
}
diff --git a/docs/Getting-Starting-Guide.md b/docs/Getting-Starting-Guide.md
index b0f46a4b..831d0687 100644
--- a/docs/Getting-Starting-Guide.md
+++ b/docs/Getting-Starting-Guide.md
@@ -144,7 +144,7 @@ use Utopia\Http\Swoole\Response;
use Swoole\Http\Server;
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
-use Utopia\Http\Validator\Wildcard;
+use Utopia\Validator\Wildcard;
$http = new Server("0.0.0.0", 8080);
diff --git a/example/src/server.php b/example/src/server.php
index 4eb07f71..d05f80f2 100644
--- a/example/src/server.php
+++ b/example/src/server.php
@@ -5,7 +5,7 @@
use Utopia\Http\Http;
use Utopia\Http\Response;
use Utopia\Http\Adapter\Swoole\Server;
-use Utopia\Http\Validator\Text;
+use Utopia\Validator\Text;
Http::get('/')
->param('name', 'World', new Text(256), 'Name to greet. Optional, max length 256.', true)
diff --git a/src/Http/Hook.php b/src/Http/Hook.php
index 2266da26..0f177dc3 100644
--- a/src/Http/Hook.php
+++ b/src/Http/Hook.php
@@ -2,6 +2,8 @@
namespace Utopia\Http;
+use Utopia\Validator;
+
class Hook
{
/**
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 8fe02785..61434842 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -2,6 +2,8 @@
namespace Utopia\Http;
+use Utopia\Validator;
+
class Http
{
/**
diff --git a/src/Http/Validator.php b/src/Http/Validator.php
deleted file mode 100755
index 6a8304ea..00000000
--- a/src/Http/Validator.php
+++ /dev/null
@@ -1,57 +0,0 @@
- $validators
- */
- public function __construct(protected array $validators, protected string $type = self::TYPE_MIXED)
- {
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- if (!(\is_null($this->failedRule))) {
- $description = $this->failedRule->getDescription();
- } else {
- $description = $this->validators[0]->getDescription();
- }
-
- return $description;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when all rules are valid if only one of the rules is invalid validation will fail.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- foreach ($this->validators as $rule) {
- $valid = $rule->isValid($value);
-
- if (!$valid) {
- $this->failedRule = $rule;
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return $this->type;
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return true;
- }
-}
diff --git a/src/Http/Validator/AnyOf.php b/src/Http/Validator/AnyOf.php
deleted file mode 100644
index ff96a54c..00000000
--- a/src/Http/Validator/AnyOf.php
+++ /dev/null
@@ -1,87 +0,0 @@
- $validators
- */
- public function __construct(protected array $validators, protected string $type = self::TYPE_MIXED)
- {
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- if (!(\is_null($this->failedRule))) {
- $description = $this->failedRule->getDescription();
- } else {
- $description = $this->validators[0]->getDescription();
- }
-
- return $description;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when all rules are valid if only one of the rules is invalid validation will fail.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- foreach ($this->validators as $rule) {
- $valid = $rule->isValid($value);
-
- $this->failedRule = $rule;
-
- if ($valid) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return $this->type;
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return true;
- }
-}
diff --git a/src/Http/Validator/ArrayList.php b/src/Http/Validator/ArrayList.php
deleted file mode 100644
index c2c7e5ab..00000000
--- a/src/Http/Validator/ArrayList.php
+++ /dev/null
@@ -1,116 +0,0 @@
-validator = $validator;
- $this->length = $length;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- $msg = 'Value must a valid array';
-
- if ($this->length > 0) {
- $msg .= ' no longer than ' . $this->length . ' items';
- }
-
- return $msg . ' and ' . $this->validator->getDescription();
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return true;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return $this->validator->getType();
- }
-
- /**
- * Get Nested Validator
- *
- * @return Validator
- */
- public function getValidator(): Validator
- {
- return $this->validator;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value is valid array and validator is valid.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- if (!\is_array($value)) {
- return false;
- }
-
- if ($this->length && \count($value) > $this->length) {
- return false;
- }
-
- foreach ($value as $element) {
- if (!$this->validator->isValid($element)) {
- return false;
- }
- }
-
- return true;
- }
-}
diff --git a/src/Http/Validator/Assoc.php b/src/Http/Validator/Assoc.php
deleted file mode 100644
index 9b7697e4..00000000
--- a/src/Http/Validator/Assoc.php
+++ /dev/null
@@ -1,88 +0,0 @@
-length = $length;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- return 'Value must be a valid object.';
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return true;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return self::TYPE_ARRAY;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value is valid assoc array.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid($value): bool
- {
- if (!\is_array($value)) {
- return false;
- }
-
- $jsonString = \json_encode($value);
- $jsonStringSize = \strlen($jsonString);
-
- if ($jsonStringSize > $this->length) {
- return false;
- }
-
- return \array_keys($value) !== \range(0, \count($value) - 1);
- }
-}
diff --git a/src/Http/Validator/Boolean.php b/src/Http/Validator/Boolean.php
deleted file mode 100644
index 38b498ec..00000000
--- a/src/Http/Validator/Boolean.php
+++ /dev/null
@@ -1,94 +0,0 @@
-loose = $loose;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- return 'Value must be a valid boolean';
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return self::TYPE_BOOLEAN;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value has a boolean value.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid($value): bool
- {
- if ($this->loose && ($value === 'true' || $value === 'false')) { // Accept strings
- return true;
- }
-
- if ($this->loose && ($value === '1' || $value === '0')) { // Accept numeric strings
- return true;
- }
-
- if ($this->loose && ($value === 1 || $value === 0)) { // Accept integers
- return true;
- }
-
- if (\is_bool($value)) {
- return true;
- }
-
- return false;
- }
-}
diff --git a/src/Http/Validator/Domain.php b/src/Http/Validator/Domain.php
deleted file mode 100644
index dd213191..00000000
--- a/src/Http/Validator/Domain.php
+++ /dev/null
@@ -1,78 +0,0 @@
-loose = $loose;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- return 'Value must be a valid float';
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return self::TYPE_FLOAT;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value is float.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- if ($this->loose) {
- if (!\is_numeric($value)) {
- return false;
- }
- $value = $value + 0;
- }
- if (!\is_float($value) && !\is_int($value)) {
- return false;
- }
-
- return true;
- }
-}
diff --git a/src/Http/Validator/HexColor.php b/src/Http/Validator/HexColor.php
deleted file mode 100644
index fe9d5926..00000000
--- a/src/Http/Validator/HexColor.php
+++ /dev/null
@@ -1,53 +0,0 @@
-whitelist = $whitelist;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- return 'URL host must be one of: ' . \implode(', ', $this->whitelist);
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value starts with one of the given hosts
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid($value): bool
- {
- $urlValidator = new URL();
-
- if (!$urlValidator->isValid($value)) {
- return false;
- }
-
- $hostnameValidator = new Hostname($this->whitelist);
-
- return $hostnameValidator->isValid(\parse_url($value, PHP_URL_HOST));
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return self::TYPE_STRING;
- }
-}
diff --git a/src/Http/Validator/Hostname.php b/src/Http/Validator/Hostname.php
deleted file mode 100644
index d3231f10..00000000
--- a/src/Http/Validator/Hostname.php
+++ /dev/null
@@ -1,114 +0,0 @@
-allowList = $allowList;
- }
-
- /**
- * @return string
- */
- public function getDescription(): string
- {
- return 'Value must be a valid hostname without path, port and protocol.';
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return self::TYPE_STRING;
- }
-
- /**
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- // Validate proper format
- if (!\is_string($value) || empty($value)) {
- return false;
- }
-
- // Max length 253 chars: https://en.wikipedia.org/wiki/Hostname#:~:text=The%20entire%20hostname%2C%20including%20the,maximum%20of%20253%20ASCII%20characters
- if (\mb_strlen($value) > 253) {
- return false;
- }
-
- // This tests: 'http://', 'https://', and 'myapp.com/route'
- if (\str_contains($value, '/')) {
- return false;
- }
-
- // This tests for: 'myapp.com:3000'
- if (\str_contains($value, ':')) {
- return false;
- }
-
- // Logic #1: Empty allowList means everything is allowed
- if (empty($this->allowList)) {
- return true;
- }
-
- // Logic #2: Allow List not empty, there are rules to check
- // Loop through all allowed hostnames until match is found
- foreach ($this->allowList as $allowedHostname) {
- // If exact match; allow
- // If *, allow everything
- if ($value === $allowedHostname || $allowedHostname === '*') {
- return true;
- }
-
- // If wildcard symbol used
- if (\str_starts_with($allowedHostname, '*')) {
- // Remove starting * symbol before comparing
- $allowedHostname = substr($allowedHostname, 1);
-
- // If rest of hostname match; allow
- // Notice allowedHostname still includes starting dot. Root domain is NOT allowed by wildcard.
- if (\str_ends_with($value, $allowedHostname)) {
- return true;
- }
- }
- }
-
- // If finished loop above without result, match is not found
- return false;
- }
-}
diff --git a/src/Http/Validator/IP.php b/src/Http/Validator/IP.php
deleted file mode 100644
index e0ffef49..00000000
--- a/src/Http/Validator/IP.php
+++ /dev/null
@@ -1,113 +0,0 @@
-type = $type;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- return 'Value must be a valid IP address';
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value is valid IP address.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid($value): bool
- {
- switch ($this->type) {
- case self::ALL:
- if (\filter_var($value, FILTER_VALIDATE_IP)) {
- return true;
- }
- break;
-
- case self::V4:
- if (\filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
- return true;
- }
- break;
-
- case self::V6:
- if (\filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
- return true;
- }
- break;
-
- default:
- return false;
- }
-
- return false;
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return self::TYPE_STRING;
- }
-}
diff --git a/src/Http/Validator/Integer.php b/src/Http/Validator/Integer.php
deleted file mode 100755
index 76af2aa4..00000000
--- a/src/Http/Validator/Integer.php
+++ /dev/null
@@ -1,88 +0,0 @@
-loose = $loose;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- return 'Value must be a valid integer';
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return self::TYPE_INTEGER;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value is integer.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- if ($this->loose) {
- if (!\is_numeric($value)) {
- return false;
- }
- $value = $value + 0;
- }
- if (!\is_int($value)) {
- return false;
- }
-
- return true;
- }
-}
diff --git a/src/Http/Validator/JSON.php b/src/Http/Validator/JSON.php
deleted file mode 100644
index 5bb734f6..00000000
--- a/src/Http/Validator/JSON.php
+++ /dev/null
@@ -1,59 +0,0 @@
- $validators
- */
- public function __construct(protected array $validators, protected string $type = self::TYPE_MIXED)
- {
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- $description = '';
-
- if (!(\is_null($this->failedRule))) {
- $description = $this->failedRule->getDescription();
- } else {
- $description = $this->validators[0]->getDescription();
- }
-
- return $description;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when all rules are valid if only one of the rules is invalid validation will fail.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- foreach ($this->validators as $rule) {
- $valid = $rule->isValid($value);
-
- if ($valid) {
- $this->failedRule = $rule;
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return $this->type;
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return true;
- }
-}
diff --git a/src/Http/Validator/Nullable.php b/src/Http/Validator/Nullable.php
deleted file mode 100644
index b6c0007b..00000000
--- a/src/Http/Validator/Nullable.php
+++ /dev/null
@@ -1,73 +0,0 @@
-validator->getDescription() . ' or null';
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return $this->validator->getType();
- }
-
- /**
- * @return Validator
- */
- public function getValidator(): Validator
- {
- return $this->validator;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value is text with valid length.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- if (\is_null($value)) {
- return true;
- }
-
- return $this->validator->isValid($value);
- }
-}
diff --git a/src/Http/Validator/Numeric.php b/src/Http/Validator/Numeric.php
deleted file mode 100755
index 13c88610..00000000
--- a/src/Http/Validator/Numeric.php
+++ /dev/null
@@ -1,66 +0,0 @@
-min = $min;
- $this->max = $max;
- $this->format = $format;
- }
-
- /**
- * Get Range Minimum Value
- *
- * @return int|float
- */
- public function getMin(): int|float
- {
- return $this->min;
- }
-
- /**
- * Get Range Maximum Value
- *
- * @return int|float
- */
- public function getMax(): int|float
- {
- return $this->max;
- }
-
- /**
- * Get Range Format
- *
- * @return string
- */
- public function getFormat(): string
- {
- return $this->format;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- return 'Value must be a valid range between '.\number_format($this->min).' and '.\number_format($this->max);
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return $this->format;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value number is bigger or equal than $min number and lower or equal than $max.
- * Not strict, considers any valid integer to be a valid float
- * Considers infinity to be a valid integer
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- if (!parent::isValid($value)) {
- return false;
- }
-
- switch ($this->format) {
- case self::TYPE_INTEGER:
- // Accept infinity as an integer
- // Since gettype(INF) === TYPE_FLOAT
- if ($value === INF || $value === -INF) {
- break; // move to check if value is within range
- }
- $value = $value + 0;
- if (!is_int($value)) {
- return false;
- }
- break;
- case self::TYPE_FLOAT:
- if (!is_numeric($value)) {
- return false;
- }
- $value = $value + 0.0;
- break;
- default:
- return false;
- }
-
- if ($this->min <= $value && $this->max >= $value) {
- return true;
- }
-
- return false;
- }
-}
diff --git a/src/Http/Validator/Text.php b/src/Http/Validator/Text.php
deleted file mode 100644
index 4df5d7e4..00000000
--- a/src/Http/Validator/Text.php
+++ /dev/null
@@ -1,138 +0,0 @@
-length = $length;
- $this->min = $min;
- $this->allowList = $allowList;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- $message = 'Value must be a valid string';
-
- if ($this->min === $this->length) {
- $message .= ' and exactly '.$this->length.' chars';
- } else {
- if ($this->min) {
- $message .= ' and at least '.$this->min.' chars';
- }
-
- if ($this->length) {
- $message .= ' and no longer than '.$this->length.' chars';
- }
- }
-
- if ($this->allowList) {
- $message .= ' and only consist of \''.\implode(', ', $this->allowList).'\' chars';
- }
-
- return $message;
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return self::TYPE_STRING;
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value is text with valid length.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- if (!\is_string($value)) {
- return false;
- }
-
- if (\mb_strlen($value) < $this->min) {
- return false;
- }
-
- if (\mb_strlen($value) > $this->length && $this->length !== 0) {
- return false;
- }
-
- if (\count($this->allowList) > 0) {
- foreach (\str_split($value) as $char) {
- if (!\in_array($char, $this->allowList)) {
- return false;
- }
- }
- }
-
- return true;
- }
-}
diff --git a/src/Http/Validator/URL.php b/src/Http/Validator/URL.php
deleted file mode 100644
index f6434e98..00000000
--- a/src/Http/Validator/URL.php
+++ /dev/null
@@ -1,86 +0,0 @@
-allowedSchemes = $allowedSchemes;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- if (!empty($this->allowedSchemes)) {
- return 'Value must be a valid URL with following schemes (' . \implode(', ', $this->allowedSchemes) . ')';
- }
-
- return 'Value must be a valid URL';
- }
-
- /**
- * Is valid
- *
- * Validation will pass when $value is valid URL.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid($value): bool
- {
- if (\filter_var($value, FILTER_VALIDATE_URL) === false) {
- return false;
- }
-
- if (!empty($this->allowedSchemes) && !\in_array(\parse_url($value, PHP_URL_SCHEME), $this->allowedSchemes)) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return self::TYPE_STRING;
- }
-}
diff --git a/src/Http/Validator/WhiteList.php b/src/Http/Validator/WhiteList.php
deleted file mode 100755
index 53a6bb16..00000000
--- a/src/Http/Validator/WhiteList.php
+++ /dev/null
@@ -1,119 +0,0 @@
-list = $list;
- $this->strict = $strict;
- $this->type = $type;
-
- if (!$this->strict) {
- foreach ($this->list as $key => &$value) {
- $this->list[$key] = \strtolower($value);
- }
- }
- }
-
- /**
- * Get List of All Allowed Values
- *
- * @return array
- */
- public function getList(): array
- {
- return $this->list;
- }
-
- /**
- * Get Description
- *
- * Returns validator description
- *
- * @return string
- */
- public function getDescription(): string
- {
- return 'Value must be one of ('.\implode(', ', $this->list).')';
- }
-
- /**
- * Is array
- *
- * Function will return true if object is array.
- *
- * @return bool
- */
- public function isArray(): bool
- {
- return false;
- }
-
- /**
- * Get Type
- *
- * Returns validator type.
- *
- * @return string
- */
- public function getType(): string
- {
- return $this->type;
- }
-
- /**
- * Is valid
- *
- * Validation will pass if $value is in the white list array.
- *
- * @param mixed $value
- * @return bool
- */
- public function isValid(mixed $value): bool
- {
- if (\is_array($value)) {
- return false;
- }
-
- $value = ($this->strict) ? $value : \strtolower($value);
-
- if (!\in_array($value, $this->list, $this->strict)) {
- return false;
- }
-
- return true;
- }
-}
diff --git a/src/Http/Validator/Wildcard.php b/src/Http/Validator/Wildcard.php
deleted file mode 100644
index 1e7314a8..00000000
--- a/src/Http/Validator/Wildcard.php
+++ /dev/null
@@ -1,62 +0,0 @@
-assertFalse($arrayList->isValid(['text']));
- $this->assertEquals('Value must a valid array and Value must be a valid integer', $arrayList->getDescription());
-
- $arrayList = new ArrayList(new Integer(), 3);
- $this->assertFalse($arrayList->isValid(['a', 'b', 'c', 'd']));
- $this->assertEquals('Value must a valid array no longer than 3 items and Value must be a valid integer', $arrayList->getDescription());
- }
-
- public function testCanValidateTextValues(): void
- {
- $arrayList = new ArrayList(new Text(100));
- $this->assertTrue($arrayList->isArray(), 'true');
- $this->assertTrue($arrayList->isValid([0 => 'string', 1 => 'string']));
- $this->assertTrue($arrayList->isValid(['string', 'string']));
- $this->assertFalse($arrayList->isValid(['string', 'string', 3]));
- $this->assertFalse($arrayList->isValid('string'));
- $this->assertFalse($arrayList->isValid('string'));
- $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $arrayList->getType());
- $this->assertInstanceOf(Text::class, $arrayList->getValidator());
- }
-
- public function testCanValidateNumericValues(): void
- {
- $arrayList = new ArrayList(new Numeric());
- $this->assertTrue($arrayList->isValid([1, 2, 3]));
- $this->assertFalse($arrayList->isValid(1));
- $this->assertFalse($arrayList->isValid('string'));
- $this->assertEquals(\Utopia\Http\Validator::TYPE_MIXED, $arrayList->getType());
- $this->assertInstanceOf(Numeric::class, $arrayList->getValidator());
- }
-
- public function testCanValidateNumericValuesWithBoundaries(): void
- {
- $arrayList = new ArrayList(new Numeric(), 2);
- $this->assertTrue($arrayList->isValid([1]));
- $this->assertTrue($arrayList->isValid([1, 2]));
- $this->assertFalse($arrayList->isValid([1, 2, 3]));
- $this->assertEquals($arrayList->getType(), \Utopia\Http\Validator::TYPE_MIXED);
- $this->assertInstanceOf(Numeric::class, $arrayList->getValidator());
- }
-}
diff --git a/tests/Validator/AssocTest.php b/tests/Validator/AssocTest.php
deleted file mode 100755
index 2036998b..00000000
--- a/tests/Validator/AssocTest.php
+++ /dev/null
@@ -1,43 +0,0 @@
-assoc = new Assoc();
- }
-
- public function tearDown(): void
- {
- $this->assoc = null;
- }
-
- public function testCanValidateAssocArray(): void
- {
- $this->assertTrue($this->assoc->isValid(['1' => 'a', '0' => 'b', '2' => 'c']));
- $this->assertTrue($this->assoc->isValid(['a' => 'a', 'b' => 'b', 'c' => 'c']));
- $this->assertTrue($this->assoc->isValid([]));
- $this->assertTrue($this->assoc->isValid(['value' => str_repeat('-', 62000)]));
- $this->assertTrue($this->assoc->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_ARRAY, $this->assoc->getType());
- }
-
- public function testCantValidateSequentialArray(): void
- {
- $this->assertFalse($this->assoc->isValid([0 => 'string', 1 => 'string']));
- $this->assertFalse($this->assoc->isValid(['a']));
- $this->assertFalse($this->assoc->isValid(['a', 'b', 'c']));
- $this->assertFalse($this->assoc->isValid(['0' => 'a', '1' => 'b', '2' => 'c']));
- }
-
- public function testCantValidateAssocArrayWithOver65kCharacters(): void
- {
- $this->assertFalse($this->assoc->isValid(['value' => str_repeat('-', 66000)]));
- }
-}
diff --git a/tests/Validator/BooleanTest.php b/tests/Validator/BooleanTest.php
deleted file mode 100755
index bda71580..00000000
--- a/tests/Validator/BooleanTest.php
+++ /dev/null
@@ -1,46 +0,0 @@
-assertTrue($boolean->isValid(true));
- $this->assertTrue($boolean->isValid(false));
- $this->assertFalse($boolean->isValid('false'));
- $this->assertFalse($boolean->isValid('true'));
- $this->assertFalse($boolean->isValid('0'));
- $this->assertFalse($boolean->isValid('1'));
- $this->assertFalse($boolean->isValid(0));
- $this->assertFalse($boolean->isValid(1));
- $this->assertFalse($boolean->isValid(['string', 'string']));
- $this->assertFalse($boolean->isValid('string'));
- $this->assertFalse($boolean->isValid(1.2));
- $this->assertFalse($boolean->isArray());
- $this->assertEquals($boolean->getType(), \Utopia\Http\Validator::TYPE_BOOLEAN);
- }
-
- public function testCanValidateLoosely()
- {
- $boolean = new Boolean(true);
-
- $this->assertTrue($boolean->isValid(true));
- $this->assertTrue($boolean->isValid(false));
- $this->assertTrue($boolean->isValid('false'));
- $this->assertTrue($boolean->isValid('true'));
- $this->assertTrue($boolean->isValid('0'));
- $this->assertTrue($boolean->isValid('1'));
- $this->assertTrue($boolean->isValid(0));
- $this->assertTrue($boolean->isValid(1));
- $this->assertFalse($boolean->isValid(['string', 'string']));
- $this->assertFalse($boolean->isValid('string'));
- $this->assertFalse($boolean->isValid(1.2));
- $this->assertFalse($boolean->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_BOOLEAN, $boolean->getType());
- }
-}
diff --git a/tests/Validator/DomainTest.php b/tests/Validator/DomainTest.php
deleted file mode 100644
index 85a346e1..00000000
--- a/tests/Validator/DomainTest.php
+++ /dev/null
@@ -1,37 +0,0 @@
-domain = new Domain();
- }
-
- public function testIsValid()
- {
- // Assertions
- $this->assertEquals(true, $this->domain->isValid('example.com'));
- $this->assertEquals(true, $this->domain->isValid('subdomain.example.com'));
- $this->assertEquals(true, $this->domain->isValid('subdomain.example-app.com'));
- $this->assertEquals(true, $this->domain->isValid('subdomain.example_app.com'));
- $this->assertEquals(true, $this->domain->isValid('subdomain-new.example.com'));
- $this->assertEquals(true, $this->domain->isValid('subdomain_new.example.com'));
- $this->assertEquals(true, $this->domain->isValid('localhost'));
- $this->assertEquals(true, $this->domain->isValid('example.io'));
- $this->assertEquals(true, $this->domain->isValid('example.org'));
- $this->assertEquals(true, $this->domain->isValid('example.org'));
- $this->assertEquals(false, $this->domain->isValid(false));
- $this->assertEquals(false, $this->domain->isValid('.'));
- $this->assertEquals(false, $this->domain->isValid('..'));
- $this->assertEquals(false, $this->domain->isValid(''));
- $this->assertEquals(false, $this->domain->isValid(['string', 'string']));
- $this->assertEquals(false, $this->domain->isValid(1));
- $this->assertEquals(false, $this->domain->isValid(1.2));
- }
-}
diff --git a/tests/Validator/FloatValidatorTest.php b/tests/Validator/FloatValidatorTest.php
deleted file mode 100755
index be905b68..00000000
--- a/tests/Validator/FloatValidatorTest.php
+++ /dev/null
@@ -1,39 +0,0 @@
-assertTrue($validator->isValid(27.25));
- $this->assertTrue($validator->isValid(23));
- $this->assertTrue($validator->isValid(23.5));
- $this->assertTrue($validator->isValid(1e7));
- $this->assertFalse($validator->isValid('abc'));
- $this->assertFalse($validator->isValid(true));
- $this->assertFalse($validator->isValid('23.5'));
- $this->assertFalse($validator->isValid('23'));
- $this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_FLOAT, $validator->getType());
- }
-
- public function testCanValidateLoosely(): void
- {
- $validator = new FloatValidator(true);
-
- $this->assertTrue($validator->isValid(27.25));
- $this->assertTrue($validator->isValid(23));
- $this->assertTrue($validator->isValid(23.5));
- $this->assertTrue($validator->isValid(1e7));
- $this->assertTrue($validator->isValid('23.5'));
- $this->assertTrue($validator->isValid('23'));
- $this->assertFalse($validator->isValid('abc'));
- $this->assertFalse($validator->isValid(true));
- $this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_FLOAT, $validator->getType());
- }
-}
diff --git a/tests/Validator/HexColorTest.php b/tests/Validator/HexColorTest.php
deleted file mode 100755
index f90d92fe..00000000
--- a/tests/Validator/HexColorTest.php
+++ /dev/null
@@ -1,26 +0,0 @@
-assertTrue($hexColor->isValid('000'));
- $this->assertTrue($hexColor->isValid('ffffff'));
- $this->assertTrue($hexColor->isValid('fff'));
- $this->assertTrue($hexColor->isValid('000000'));
-
- $this->assertFalse($hexColor->isValid('AB10BC99'));
- $this->assertFalse($hexColor->isValid('AR1012'));
- $this->assertFalse($hexColor->isValid('ab12bc99'));
- $this->assertFalse($hexColor->isValid('00'));
- $this->assertFalse($hexColor->isValid('ffff'));
- $this->assertFalse($hexColor->isArray());
-
- $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $hexColor->getType());
- }
-}
diff --git a/tests/Validator/HostTest.php b/tests/Validator/HostTest.php
deleted file mode 100644
index 4162a5b3..00000000
--- a/tests/Validator/HostTest.php
+++ /dev/null
@@ -1,30 +0,0 @@
-host = new Host(['example.io', 'subdomain.example.test', 'localhost', '*.appwrite.io']);
- }
-
- public function testIsValid()
- {
- // Assertions
- $this->assertEquals($this->host->isValid('https://example.io/link'), true);
- $this->assertEquals($this->host->isValid('https://localhost'), true);
- $this->assertEquals($this->host->isValid('localhost'), false);
- $this->assertEquals($this->host->isValid('http://subdomain.example.test/path'), true);
- $this->assertEquals($this->host->isValid('http://test.subdomain.example.test/path'), false);
- $this->assertEquals($this->host->isValid('http://appwrite.io/path'), false);
- $this->assertEquals($this->host->isValid('http://me.appwrite.io/path'), true);
- $this->assertEquals($this->host->isValid('http://you.appwrite.io/path'), true);
- $this->assertEquals($this->host->isValid('http://us.together.appwrite.io/path'), true);
- $this->assertEquals($this->host->getType(), 'string');
- }
-}
diff --git a/tests/Validator/HostnameTest.php b/tests/Validator/HostnameTest.php
deleted file mode 100755
index 2760648d..00000000
--- a/tests/Validator/HostnameTest.php
+++ /dev/null
@@ -1,106 +0,0 @@
-assertEquals(\Utopia\Http\Validator::TYPE_STRING, $validator->getType());
- $this->assertFalse($validator->isArray());
-
- $this->assertTrue($validator->isValid('myweb.com'));
- $this->assertTrue($validator->isValid('httpmyweb.com'));
- $this->assertTrue($validator->isValid('httpsmyweb.com'));
- $this->assertTrue($validator->isValid('wsmyweb.com'));
- $this->assertTrue($validator->isValid('wssmyweb.com'));
- $this->assertTrue($validator->isValid('vercel.app'));
- $this->assertTrue($validator->isValid('web.vercel.app'));
- $this->assertTrue($validator->isValid('my-web.vercel.app'));
- $this->assertTrue($validator->isValid('my-project.my-web.vercel.app'));
- $this->assertTrue($validator->isValid('my-commit.my-project.my-web.vercel.app'));
- $this->assertTrue($validator->isValid('myapp.co.uk'));
- $this->assertTrue($validator->isValid('*.myapp.com'));
- $this->assertTrue($validator->isValid('myapp.*'));
-
- $this->assertFalse($validator->isValid('https://myweb.com'));
- $this->assertFalse($validator->isValid('ws://myweb.com'));
- $this->assertFalse($validator->isValid('wss://myweb.com'));
- $this->assertFalse($validator->isValid('http://myweb.com'));
- $this->assertFalse($validator->isValid('http://myweb.com:3000'));
- $this->assertFalse($validator->isValid('http://myweb.com/blog'));
- $this->assertFalse($validator->isValid('myweb.com:80'));
- $this->assertFalse($validator->isValid('myweb.com:3000'));
- $this->assertFalse($validator->isValid('myweb.com/blog'));
- $this->assertFalse($validator->isValid('myweb.com/blog/article1'));
-
- // Max length test
- $domain = \str_repeat('bestdomain', 25); // 250 chars total
-
- $domain .= '.sk'; // Exactly at the limit
- $this->assertTrue($validator->isValid($domain));
-
- $domain .= 'a'; // Exactly over the limit
- $this->assertFalse($validator->isValid($domain));
- }
-
- public function testCanValidateHostnamesWithAllowList(): void
- {
- // allowList tests
- $validator = new Hostname([
- 'myweb.vercel.app',
- 'myweb.com',
- '*.myapp.com',
- ]);
-
- $this->assertTrue($validator->isValid('myweb.vercel.app'));
- $this->assertFalse($validator->isValid('myweb.vercel.com'));
- $this->assertFalse($validator->isValid('myweb2.vercel.app'));
- $this->assertFalse($validator->isValid('vercel.app'));
- $this->assertFalse($validator->isValid('mycommit.myweb.vercel.app'));
-
- $this->assertTrue($validator->isValid('myweb.com'));
- $this->assertFalse($validator->isValid('myweb.eu'));
- $this->assertFalse($validator->isValid('project.myweb.eu'));
- $this->assertFalse($validator->isValid('commit.project.myweb.eu'));
-
- $this->assertTrue($validator->isValid('project1.myapp.com'));
- $this->assertTrue($validator->isValid('project2.myapp.com'));
- $this->assertTrue($validator->isValid('project-with-dash.myapp.com'));
- $this->assertTrue($validator->isValid('anything.myapp.com'));
- $this->assertTrue($validator->isValid('commit.anything.myapp.com'));
- $this->assertFalse($validator->isValid('anything.myapp.eu'));
- $this->assertFalse($validator->isValid('myapp.com'));
-
- $validator = new Hostname(['localhost']);
- $this->assertTrue($validator->isValid('localhost'));
- }
-
- public function testCanValidateHostnamesWithWildcard(): void
- {
- $validator = new Hostname();
- $this->assertTrue($validator->isValid('*'));
-
- $validator = new Hostname(['netlify.*']);
- $this->assertFalse($validator->isValid('netlify.com'));
- $this->assertFalse($validator->isValid('netlify.eu'));
- $this->assertFalse($validator->isValid('netlify.app'));
-
- $validator = new Hostname(['*.*.app.io']);
- $this->assertFalse($validator->isValid('app.io'));
- $this->assertFalse($validator->isValid('project.app.io'));
- $this->assertFalse($validator->isValid('commit.project.app.io'));
- $this->assertFalse($validator->isValid('api.commit.project.app.io'));
-
- $validator = new Hostname(['*']);
- $this->assertTrue($validator->isValid('*'));
- $this->assertTrue($validator->isValid('localhost'));
- $this->assertTrue($validator->isValid('anything')); // Like localhost
- $this->assertTrue($validator->isValid('anything.com'));
- $this->assertTrue($validator->isValid('anything.with.subdomains.eu'));
- }
-}
diff --git a/tests/Validator/IPTest.php b/tests/Validator/IPTest.php
deleted file mode 100644
index 074a8f68..00000000
--- a/tests/Validator/IPTest.php
+++ /dev/null
@@ -1,67 +0,0 @@
-assertEquals($validator->isValid('2001:0db8:85a3:08d3:1319:8a2e:0370:7334'), true);
- $this->assertEquals($validator->isValid('109.67.204.101'), true);
- $this->assertEquals($validator->isValid(23.5), false);
- $this->assertEquals($validator->isValid('23.5'), false);
- $this->assertEquals($validator->isValid(null), false);
- $this->assertEquals($validator->isValid(true), false);
- $this->assertEquals($validator->isValid(false), false);
- $this->assertEquals($validator->getType(), 'string');
- }
-
- public function testIsValidIPALL()
- {
- $validator = new IP(IP::ALL);
-
- // Assertions
- $this->assertEquals($validator->isValid('2001:0db8:85a3:08d3:1319:8a2e:0370:7334'), true);
- $this->assertEquals($validator->isValid('109.67.204.101'), true);
- $this->assertEquals($validator->isValid(23.5), false);
- $this->assertEquals($validator->isValid('23.5'), false);
- $this->assertEquals($validator->isValid(null), false);
- $this->assertEquals($validator->isValid(true), false);
- $this->assertEquals($validator->isValid(false), false);
- }
-
- public function testIsValidIPV4()
- {
- $validator = new IP(IP::V4);
-
- // Assertions
- $this->assertEquals($validator->isValid('2001:0db8:85a3:08d3:1319:8a2e:0370:7334'), false);
- $this->assertEquals($validator->isValid('109.67.204.101'), true);
- $this->assertEquals($validator->isValid(23.5), false);
- $this->assertEquals($validator->isValid('23.5'), false);
- $this->assertEquals($validator->isValid(null), false);
- $this->assertEquals($validator->isValid(true), false);
- $this->assertEquals($validator->isValid(false), false);
- }
-
- public function testIsValidIPV6()
- {
- $validator = new IP(IP::V6);
-
- // Assertions
- $this->assertEquals($validator->isValid('2001:0db8:85a3:08d3:1319:8a2e:0370:7334'), true);
- $this->assertEquals($validator->isValid('109.67.204.101'), false);
- $this->assertEquals($validator->isValid(23.5), false);
- $this->assertEquals($validator->isValid('23.5'), false);
- $this->assertEquals($validator->isValid(null), false);
- $this->assertEquals($validator->isValid(true), false);
- $this->assertEquals($validator->isValid(false), false);
- }
-}
diff --git a/tests/Validator/IntegerTest.php b/tests/Validator/IntegerTest.php
deleted file mode 100755
index faddca2c..00000000
--- a/tests/Validator/IntegerTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-assertTrue($validator->isValid(23));
- $this->assertFalse($validator->isValid('23'));
- $this->assertFalse($validator->isValid(23.5));
- $this->assertFalse($validator->isValid('23.5'));
- $this->assertFalse($validator->isValid(null));
- $this->assertFalse($validator->isValid(true));
- $this->assertFalse($validator->isValid(false));
- $this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_INTEGER, $validator->getType());
- }
-
- public function testCanValidateLoosely()
- {
- $validator = new Integer(true);
- $this->assertTrue($validator->isValid(23));
- $this->assertTrue($validator->isValid('23'));
- $this->assertFalse($validator->isValid(23.5));
- $this->assertFalse($validator->isValid('23.5'));
- $this->assertFalse($validator->isValid(null));
- $this->assertFalse($validator->isValid(true));
- $this->assertFalse($validator->isValid(false));
- $this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_INTEGER, $validator->getType());
- }
-}
diff --git a/tests/Validator/JSONTest.php b/tests/Validator/JSONTest.php
deleted file mode 100755
index d4a4e358..00000000
--- a/tests/Validator/JSONTest.php
+++ /dev/null
@@ -1,28 +0,0 @@
-assertTrue($json->isValid('{}'));
- $this->assertTrue($json->isValid([]));
- $this->assertTrue($json->isValid(['test']));
- $this->assertTrue($json->isValid(['test' => 'demo']));
- $this->assertTrue($json->isValid('{"test": "demo"}'));
-
- $this->assertFalse($json->isValid(''));
- $this->assertFalse($json->isValid(false));
- $this->assertFalse($json->isValid(null));
- $this->assertFalse($json->isValid('string'));
- $this->assertFalse($json->isValid(1));
- $this->assertFalse($json->isValid(1.2));
- $this->assertFalse($json->isValid("{'test': 'demo'}"));
- $this->assertFalse($json->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_OBJECT, $json->getType());
- }
-}
diff --git a/tests/Validator/MultipleOfTest.php b/tests/Validator/MultipleOfTest.php
deleted file mode 100644
index 06435aa8..00000000
--- a/tests/Validator/MultipleOfTest.php
+++ /dev/null
@@ -1,61 +0,0 @@
-assertEquals('string', $validator->getType());
- $this->assertEquals("Value must be a valid string and at least 1 chars and no longer than 20 chars", $validator->getDescription());
-
- // Valid URL but invalid text length
- $this->assertFalse($validator->isValid('http://example.com/very-long-url'));
-
- // Valid text within length, but invalid URL
- $this->assertFalse($validator->isValid('hello world'));
-
- // Both conditions satisfied
- $this->assertTrue($validator->isValid('http://example.com'));
- $this->assertTrue($validator->isValid('https://google.com'));
-
- // Neither condition satisfied
- $this->assertFalse($validator->isValid('example.com/hello-world'));
- $this->assertFalse($validator->isValid(''));
- }
-
- public function testRules()
- {
- $validTextValidUrl = 'http://example.com';
- $validTextInvalidUrl = 'hello world';
- $invalidTextValidUrl = 'http://example.com/very-long-url';
- $invalidTextInvalidUrl = 'Some very long text that is also not an URL';
-
- $vaidator = new AllOf([new Text(20), new URL()], Validator::TYPE_STRING);
- $this->assertTrue($vaidator->isValid($validTextValidUrl));
- $this->assertFalse($vaidator->isValid($validTextInvalidUrl));
- $this->assertFalse($vaidator->isValid($invalidTextValidUrl));
- $this->assertFalse($vaidator->isValid($invalidTextInvalidUrl));
-
- $vaidator = new AnyOf([new Text(20), new URL()], Validator::TYPE_STRING);
- $this->assertTrue($vaidator->isValid($validTextValidUrl));
- $this->assertTrue($vaidator->isValid($validTextInvalidUrl));
- $this->assertTrue($vaidator->isValid($invalidTextValidUrl));
- $this->assertFalse($vaidator->isValid($invalidTextInvalidUrl));
-
- $vaidator = new NoneOf([new Text(20), new URL()], Validator::TYPE_STRING);
- $this->assertFalse($vaidator->isValid($validTextValidUrl));
- $this->assertFalse($vaidator->isValid($validTextInvalidUrl));
- $this->assertFalse($vaidator->isValid($invalidTextValidUrl));
- $this->assertTrue($vaidator->isValid($invalidTextInvalidUrl));
- }
-}
diff --git a/tests/Validator/NullableTest.php b/tests/Validator/NullableTest.php
deleted file mode 100755
index ebd24834..00000000
--- a/tests/Validator/NullableTest.php
+++ /dev/null
@@ -1,22 +0,0 @@
-assertTrue($validator->isValid('text'));
- $this->assertTrue($validator->isValid(null));
- $this->assertFalse($validator->isValid(123));
- }
-
- public function testCanReturnValidator(): void
- {
- $validator = new Nullable(new Text(0));
- $this->assertTrue($validator->getValidator() instanceof Text);
- }
-}
diff --git a/tests/Validator/NumericTest.php b/tests/Validator/NumericTest.php
deleted file mode 100755
index 88ea5030..00000000
--- a/tests/Validator/NumericTest.php
+++ /dev/null
@@ -1,24 +0,0 @@
-assertTrue($numeric->isValid('42'));
- $this->assertTrue($numeric->isValid(1337));
- $this->assertTrue($numeric->isValid(0x539));
- $this->assertTrue($numeric->isValid(02471));
- $this->assertTrue($numeric->isValid(1337e0));
- $this->assertTrue($numeric->isValid(9.1));
- $this->assertFalse($numeric->isValid('not numeric'));
- $this->assertFalse($numeric->isValid([]));
- $this->assertFalse($numeric->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_MIXED, $numeric->getType());
- }
-}
diff --git a/tests/Validator/RangeTest.php b/tests/Validator/RangeTest.php
deleted file mode 100755
index aafbab4a..00000000
--- a/tests/Validator/RangeTest.php
+++ /dev/null
@@ -1,60 +0,0 @@
-assertTrue($range->isValid(0));
- $this->assertTrue($range->isValid(1));
- $this->assertTrue($range->isValid(4));
- $this->assertTrue($range->isValid(5));
- $this->assertTrue($range->isValid('5'));
- $this->assertFalse($range->isValid('1.5'));
- $this->assertFalse($range->isValid(6));
- $this->assertFalse($range->isValid(-1));
- $this->assertEquals(0, $range->getMin());
- $this->assertEquals(5, $range->getMax());
- $this->assertFalse($range->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_INTEGER, $range->getFormat());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_INTEGER, $range->getType());
- }
-
- public function testCanValidateFloatRange()
- {
- $range = new Range(0, 1, \Utopia\Http\Validator::TYPE_FLOAT);
-
- $this->assertTrue($range->isValid(0.0));
- $this->assertTrue($range->isValid(1.0));
- $this->assertTrue($range->isValid(0.5));
- $this->assertTrue($range->isValid('0.5'));
- $this->assertTrue($range->isValid('0.6'));
- $this->assertFalse($range->isValid(4));
- $this->assertFalse($range->isValid(1.5));
- $this->assertFalse($range->isValid(-1));
- $this->assertEquals(0, $range->getMin());
- $this->assertEquals(1, $range->getMax());
- $this->assertFalse($range->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_FLOAT, $range->getFormat());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_FLOAT, $range->getType(), \Utopia\Http\Validator::TYPE_FLOAT);
- }
-
- public function canValidateInfinityRange()
- {
- $integer = new Range(5, INF, \Utopia\Http\Validator::TYPE_INTEGER);
- $float = new Range(-INF, 45.6, \Utopia\Http\Validator::TYPE_FLOAT);
-
- $this->assertTrue($integer->isValid(25));
- $this->assertFalse($integer->isValid(3));
- $this->assertTrue($integer->isValid(INF));
- $this->assertTrue($float->isValid(32.1));
- $this->assertFalse($float->isValid(97.6));
- $this->assertTrue($float->isValid(-INF));
- }
-}
diff --git a/tests/Validator/TextTest.php b/tests/Validator/TextTest.php
deleted file mode 100755
index 476cfd8a..00000000
--- a/tests/Validator/TextTest.php
+++ /dev/null
@@ -1,88 +0,0 @@
-assertTrue($validator->isValid('text'));
- $this->assertTrue($validator->isValid('7'));
- $this->assertTrue($validator->isValid('7.9'));
- $this->assertTrue($validator->isValid('["seven"]'));
- $this->assertFalse($validator->isValid(['seven']));
- $this->assertFalse($validator->isValid(['seven', 8, 9.0]));
- $this->assertFalse($validator->isValid(false));
- $this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $validator->getType());
- }
-
- public function testCanValidateBoundaries(): void
- {
- $validator = new Text(5);
- $this->assertTrue($validator->isValid('hell'));
- $this->assertTrue($validator->isValid('hello'));
- $this->assertFalse($validator->isValid('hellow'));
- $this->assertFalse($validator->isValid(''));
-
- $validator = new Text(5, 3);
- $this->assertTrue($validator->isValid('hel'));
- $this->assertTrue($validator->isValid('hell'));
- $this->assertTrue($validator->isValid('hello'));
- $this->assertFalse($validator->isValid('hellow'));
- $this->assertFalse($validator->isValid('he'));
- $this->assertFalse($validator->isValid('h'));
- }
-
- public function testCanValidateTextWithAllowList(): void
- {
- // Test lowercase alphabet
- $validator = new Text(100, allowList: Text::ALPHABET_LOWER);
- $this->assertFalse($validator->isArray());
- $this->assertTrue($validator->isValid('qwertzuiopasdfghjklyxcvbnm'));
- $this->assertTrue($validator->isValid('hello'));
- $this->assertTrue($validator->isValid('world'));
- $this->assertFalse($validator->isValid('hello world'));
- $this->assertFalse($validator->isValid('Hello'));
- $this->assertFalse($validator->isValid('worlD'));
- $this->assertFalse($validator->isValid('hello123'));
-
- // Test uppercase alphabet
- $validator = new Text(100, allowList: Text::ALPHABET_UPPER);
- $this->assertFalse($validator->isArray());
- $this->assertTrue($validator->isValid('QWERTZUIOPASDFGHJKLYXCVBNM'));
- $this->assertTrue($validator->isValid('HELLO'));
- $this->assertTrue($validator->isValid('WORLD'));
- $this->assertFalse($validator->isValid('HELLO WORLD'));
- $this->assertFalse($validator->isValid('hELLO'));
- $this->assertFalse($validator->isValid('WORLd'));
- $this->assertFalse($validator->isValid('HELLO123'));
-
- // Test numbers
- $validator = new Text(100, allowList: Text::NUMBERS);
- $this->assertFalse($validator->isArray());
- $this->assertTrue($validator->isValid('1234567890'));
- $this->assertTrue($validator->isValid('123'));
- $this->assertFalse($validator->isValid('123 456'));
- $this->assertFalse($validator->isValid('hello123'));
-
- // Test combination of allowLists
- $validator = new Text(100, allowList: [
- ...Text::ALPHABET_LOWER,
- ...Text::ALPHABET_UPPER,
- ...Text::NUMBERS,
- ]);
-
- $this->assertFalse($validator->isArray());
- $this->assertTrue($validator->isValid('1234567890'));
- $this->assertTrue($validator->isValid('qwertzuiopasdfghjklyxcvbnm'));
- $this->assertTrue($validator->isValid('QWERTZUIOPASDFGHJKLYXCVBNM'));
- $this->assertTrue($validator->isValid('QWERTZUIOPASDFGHJKLYXCVBNMqwertzuiopasdfghjklyxcvbnm1234567890'));
- $this->assertFalse($validator->isValid('hello-world'));
- $this->assertFalse($validator->isValid('hello_world'));
- $this->assertFalse($validator->isValid('hello/world'));
- }
-}
diff --git a/tests/Validator/URLTest.php b/tests/Validator/URLTest.php
deleted file mode 100644
index de530cd1..00000000
--- a/tests/Validator/URLTest.php
+++ /dev/null
@@ -1,43 +0,0 @@
-url = new URL();
- }
-
- public function tearDown(): void
- {
- $this->url = null;
- }
-
- public function testIsValid(): void
- {
- $this->assertEquals('Value must be a valid URL', $this->url->getDescription());
- $this->assertEquals(true, $this->url->isValid('http://example.com'));
- $this->assertEquals(true, $this->url->isValid('https://example.com'));
- $this->assertEquals(true, $this->url->isValid('htts://example.com')); // does not validate protocol
- $this->assertEquals(false, $this->url->isValid('example.com')); // though, requires some kind of protocol
- $this->assertEquals(false, $this->url->isValid('http:/example.com'));
- $this->assertEquals(true, $this->url->isValid('http://exa-mple.com'));
- $this->assertEquals(false, $this->url->isValid('htt@s://example.com'));
- $this->assertEquals(true, $this->url->isValid('http://www.example.com/foo%2\u00c2\u00a9zbar'));
- $this->assertEquals(true, $this->url->isValid('http://www.example.com/?q=%3Casdf%3E'));
- }
-
- public function testIsValidAllowedSchemes(): void
- {
- $this->url = new URL(['http', 'https']);
- $this->assertEquals('Value must be a valid URL with following schemes (http, https)', $this->url->getDescription());
- $this->assertEquals(true, $this->url->isValid('http://example.com'));
- $this->assertEquals(true, $this->url->isValid('https://example.com'));
- $this->assertEquals(false, $this->url->isValid('gopher://www.example.com'));
- }
-}
diff --git a/tests/Validator/WhiteListTest.php b/tests/Validator/WhiteListTest.php
deleted file mode 100755
index f024908c..00000000
--- a/tests/Validator/WhiteListTest.php
+++ /dev/null
@@ -1,58 +0,0 @@
-assertTrue($whiteList->isValid(3));
- $this->assertTrue($whiteList->isValid(4));
- $this->assertTrue($whiteList->isValid('string1'));
- $this->assertTrue($whiteList->isValid('string2'));
-
- $this->assertFalse($whiteList->isValid('string3'));
- $this->assertFalse($whiteList->isValid('STRING1'));
- $this->assertFalse($whiteList->isValid('strIng1'));
- $this->assertFalse($whiteList->isValid('3'));
- $this->assertFalse($whiteList->isValid(5));
- $this->assertFalse($whiteList->isArray());
- $this->assertEquals($whiteList->getList(), ['string1', 'string2', 3, 4]);
- $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $whiteList->getType());
- }
-
- public function testCanValidateLoosely(): void
- {
- $whiteList = new WhiteList(['string1', 'string2', 3, 4]);
-
- $this->assertTrue($whiteList->isValid(3));
- $this->assertTrue($whiteList->isValid(4));
- $this->assertTrue($whiteList->isValid('string1'));
- $this->assertTrue($whiteList->isValid('string2'));
- $this->assertTrue($whiteList->isValid('STRING1'));
- $this->assertTrue($whiteList->isValid('strIng1'));
- $this->assertTrue($whiteList->isValid('3'));
- $this->assertTrue($whiteList->isValid('4'));
- $this->assertFalse($whiteList->isValid('string3'));
- $this->assertFalse($whiteList->isValid(5));
- $this->assertEquals($whiteList->getList(), ['string1', 'string2', 3, 4]);
-
- $whiteList = new WhiteList(['STRING1', 'STRING2', 3, 4]);
-
- $this->assertTrue($whiteList->isValid(3));
- $this->assertTrue($whiteList->isValid(4));
- $this->assertTrue($whiteList->isValid('string1'));
- $this->assertTrue($whiteList->isValid('string2'));
- $this->assertTrue($whiteList->isValid('STRING1'));
- $this->assertTrue($whiteList->isValid('strIng1'));
- $this->assertTrue($whiteList->isValid('3'));
- $this->assertTrue($whiteList->isValid('4'));
- $this->assertFalse($whiteList->isValid('string3'));
- $this->assertFalse($whiteList->isValid(5));
- $this->assertEquals($whiteList->getList(), ['string1', 'string2', 3, 4]);
- }
-}
diff --git a/tests/Validator/WildcardTest.php b/tests/Validator/WildcardTest.php
deleted file mode 100644
index 4de71475..00000000
--- a/tests/Validator/WildcardTest.php
+++ /dev/null
@@ -1,21 +0,0 @@
-assertTrue($validator->isValid([0 => 'string', 1 => 'string']));
- $this->assertTrue($validator->isValid(''));
- $this->assertTrue($validator->isValid([]));
- $this->assertTrue($validator->isValid(1));
- $this->assertTrue($validator->isValid(true));
- $this->assertTrue($validator->isValid(false));
- $this->assertFalse($validator->isArray());
- $this->assertEquals(\Utopia\Http\Validator::TYPE_STRING, $validator->getType());
- }
-}
diff --git a/tests/e2e/init.php b/tests/e2e/init.php
index 54638fd9..fb0d9d59 100644
--- a/tests/e2e/init.php
+++ b/tests/e2e/init.php
@@ -5,7 +5,7 @@
use Utopia\Http\Http;
use Utopia\Http\Request;
use Utopia\Http\Response;
-use Utopia\Http\Validator\Text;
+use Utopia\Validator\Text;
ini_set('memory_limit', '1024M');
ini_set('display_errors', '1');
From 396a8e3872a42f67c645994e512f132419a8ca8e Mon Sep 17 00:00:00 2001
From: Hemachandar <132386067+hmacr@users.noreply.github.com>
Date: Thu, 19 Feb 2026 18:30:14 +0530
Subject: [PATCH 117/119] Convert hostname to lowercase (#214)
---
src/Http/Adapter/FPM/Request.php | 3 ++-
src/Http/Adapter/Swoole/Request.php | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/Http/Adapter/FPM/Request.php b/src/Http/Adapter/FPM/Request.php
index 41452440..d095445f 100644
--- a/src/Http/Adapter/FPM/Request.php
+++ b/src/Http/Adapter/FPM/Request.php
@@ -108,7 +108,8 @@ public function getPort(): string
*/
public function getHostname(): string
{
- return (string) \parse_url($this->getProtocol().'://'.$this->getServer('HTTP_HOST', ''), PHP_URL_HOST);
+ $hostname = \parse_url($this->getProtocol().'://'.$this->getServer('HTTP_HOST', ''), PHP_URL_HOST);
+ return strtolower((string) ($hostname));
}
/**
diff --git a/src/Http/Adapter/Swoole/Request.php b/src/Http/Adapter/Swoole/Request.php
index b07a5fdb..d5bd799c 100644
--- a/src/Http/Adapter/Swoole/Request.php
+++ b/src/Http/Adapter/Swoole/Request.php
@@ -122,7 +122,8 @@ public function getPort(): string
*/
public function getHostname(): string
{
- return strval(\parse_url($this->getProtocol().'://'.$this->getHeader('x-forwarded-host', $this->getHeader('host')), PHP_URL_HOST));
+ $hostname = \parse_url($this->getProtocol().'://'.$this->getHeader('x-forwarded-host', $this->getHeader('host')), PHP_URL_HOST);
+ return strtolower(strval($hostname));
}
/**
From d60c9ce7eea3e4f89599d995e0058e3729a1ef7c Mon Sep 17 00:00:00 2001
From: Chirag Aggarwal
Date: Wed, 25 Feb 2026 23:01:12 +0530
Subject: [PATCH 118/119] chore: bump validators lib (#218)
---
composer.json | 2 +-
composer.lock | 133 +++++++++++++++++++++++++-------------------------
2 files changed, 67 insertions(+), 68 deletions(-)
diff --git a/composer.json b/composer.json
index e5953bc4..2c5bf2c6 100644
--- a/composer.json
+++ b/composer.json
@@ -31,7 +31,7 @@
"require": {
"php": ">=8.0",
"ext-swoole": "*",
- "utopia-php/validators": "0.1.*"
+ "utopia-php/validators": "0.2.*"
},
"require-dev": {
"phpunit/phpunit": "^9.5.25",
diff --git a/composer.lock b/composer.lock
index b68b4ff5..3d5b401a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "3851bd0696173988209c33d95ad3fd35",
+ "content-hash": "e7104035855b324e167057fd44e2a875",
"packages": [
{
"name": "utopia-php/validators",
- "version": "0.1.0",
+ "version": "0.2.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/validators.git",
- "reference": "5c57d5b6cf964f8981807c1d3ea8df620c869080"
+ "reference": "30b6030a5b100fc1dff34506e5053759594b2a20"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/utopia-php/validators/zipball/5c57d5b6cf964f8981807c1d3ea8df620c869080",
- "reference": "5c57d5b6cf964f8981807c1d3ea8df620c869080",
+ "url": "https://api.github.com/repos/utopia-php/validators/zipball/30b6030a5b100fc1dff34506e5053759594b2a20",
+ "reference": "30b6030a5b100fc1dff34506e5053759594b2a20",
"shasum": ""
},
"require": {
@@ -25,7 +25,7 @@
},
"require-dev": {
"laravel/pint": "1.*",
- "phpstan/phpstan": "1.*",
+ "phpstan/phpstan": "2.*",
"phpunit/phpunit": "11.*"
},
"type": "library",
@@ -47,9 +47,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/validators/issues",
- "source": "https://github.com/utopia-php/validators/tree/0.1.0"
+ "source": "https://github.com/utopia-php/validators/tree/0.2.0"
},
- "time": "2025-11-18T11:05:46+00:00"
+ "time": "2026-01-13T09:16:51+00:00"
}
],
"packages-dev": [
@@ -132,30 +132,29 @@
},
{
"name": "doctrine/instantiator",
- "version": "2.0.0",
+ "version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
- "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
+ "reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
- "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/23da848e1a2308728fe5fdddabf4be17ff9720c7",
+ "reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7",
"shasum": ""
},
"require": {
- "php": "^8.1"
+ "php": "^8.4"
},
"require-dev": {
- "doctrine/coding-standard": "^11",
+ "doctrine/coding-standard": "^14",
"ext-pdo": "*",
"ext-phar": "*",
"phpbench/phpbench": "^1.2",
- "phpstan/phpstan": "^1.9.4",
- "phpstan/phpstan-phpunit": "^1.3",
- "phpunit/phpunit": "^9.5.27",
- "vimeo/psalm": "^5.4"
+ "phpstan/phpstan": "^2.1",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpunit/phpunit": "^10.5.58"
},
"type": "library",
"autoload": {
@@ -182,7 +181,7 @@
],
"support": {
"issues": "https://github.com/doctrine/instantiator/issues",
- "source": "https://github.com/doctrine/instantiator/tree/2.0.0"
+ "source": "https://github.com/doctrine/instantiator/tree/2.1.0"
},
"funding": [
{
@@ -198,7 +197,7 @@
"type": "tidelift"
}
],
- "time": "2022-12-30T00:23:10+00:00"
+ "time": "2026-01-05T06:47:08+00:00"
},
{
"name": "doctrine/lexer",
@@ -279,16 +278,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.26.0",
+ "version": "v1.27.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "69dcca060ecb15e4b564af63d1f642c81a241d6f"
+ "reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/69dcca060ecb15e4b564af63d1f642c81a241d6f",
- "reference": "69dcca060ecb15e4b564af63d1f642c81a241d6f",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/54cca2de13790570c7b6f0f94f37896bee4abcb5",
+ "reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5",
"shasum": ""
},
"require": {
@@ -299,13 +298,13 @@
"php": "^8.2.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.90.0",
- "illuminate/view": "^12.40.1",
- "larastan/larastan": "^3.8.0",
- "laravel-zero/framework": "^12.0.4",
+ "friendsofphp/php-cs-fixer": "^3.93.1",
+ "illuminate/view": "^12.51.0",
+ "larastan/larastan": "^3.9.2",
+ "laravel-zero/framework": "^12.0.5",
"mockery/mockery": "^1.6.12",
"nunomaduro/termwind": "^2.3.3",
- "pestphp/pest": "^3.8.4"
+ "pestphp/pest": "^3.8.5"
},
"bin": [
"builds/pint"
@@ -342,7 +341,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2025-11-25T21:15:52+00:00"
+ "time": "2026-02-10T20:00:20+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -1103,16 +1102,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.31",
+ "version": "9.6.34",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "945d0b7f346a084ce5549e95289962972c4272e5"
+ "reference": "b36f02317466907a230d3aa1d34467041271ef4a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/945d0b7f346a084ce5549e95289962972c4272e5",
- "reference": "945d0b7f346a084ce5549e95289962972c4272e5",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b36f02317466907a230d3aa1d34467041271ef4a",
+ "reference": "b36f02317466907a230d3aa1d34467041271ef4a",
"shasum": ""
},
"require": {
@@ -1134,7 +1133,7 @@
"phpunit/php-timer": "^5.0.3",
"sebastian/cli-parser": "^1.0.2",
"sebastian/code-unit": "^1.0.8",
- "sebastian/comparator": "^4.0.9",
+ "sebastian/comparator": "^4.0.10",
"sebastian/diff": "^4.0.6",
"sebastian/environment": "^5.1.5",
"sebastian/exporter": "^4.0.8",
@@ -1186,7 +1185,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.31"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.34"
},
"funding": [
{
@@ -1210,7 +1209,7 @@
"type": "tidelift"
}
],
- "time": "2025-12-06T07:45:52+00:00"
+ "time": "2026-01-27T05:45:00+00:00"
},
{
"name": "psr/cache",
@@ -1533,16 +1532,16 @@
},
{
"name": "sebastian/comparator",
- "version": "4.0.9",
+ "version": "4.0.10",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5"
+ "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5",
- "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e4df00b9b3571187db2831ae9aada2c6efbd715d",
+ "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d",
"shasum": ""
},
"require": {
@@ -1595,7 +1594,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
- "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9"
+ "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.10"
},
"funding": [
{
@@ -1615,7 +1614,7 @@
"type": "tidelift"
}
],
- "time": "2025-08-10T06:51:50+00:00"
+ "time": "2026-01-24T09:22:56+00:00"
},
{
"name": "sebastian/complexity",
@@ -2483,16 +2482,16 @@
},
{
"name": "symfony/console",
- "version": "v8.0.1",
+ "version": "v8.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "fcb73f69d655b48fcb894a262f074218df08bd58"
+ "reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/fcb73f69d655b48fcb894a262f074218df08bd58",
- "reference": "fcb73f69d655b48fcb894a262f074218df08bd58",
+ "url": "https://api.github.com/repos/symfony/console/zipball/ace03c4cf9805080ff40cbeec69fca180c339a3b",
+ "reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b",
"shasum": ""
},
"require": {
@@ -2549,7 +2548,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v8.0.1"
+ "source": "https://github.com/symfony/console/tree/v8.0.4"
},
"funding": [
{
@@ -2569,7 +2568,7 @@
"type": "tidelift"
}
],
- "time": "2025-12-05T15:25:33+00:00"
+ "time": "2026-01-13T13:06:50+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -2710,16 +2709,16 @@
},
{
"name": "symfony/finder",
- "version": "v8.0.0",
+ "version": "v8.0.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291"
+ "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/7598dd5770580fa3517ec83e8da0c9b9e01f4291",
- "reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/8bd576e97c67d45941365bf824e18dc8538e6eb0",
+ "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0",
"shasum": ""
},
"require": {
@@ -2754,7 +2753,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v8.0.0"
+ "source": "https://github.com/symfony/finder/tree/v8.0.5"
},
"funding": [
{
@@ -2774,7 +2773,7 @@
"type": "tidelift"
}
],
- "time": "2025-11-05T14:36:47+00:00"
+ "time": "2026-01-26T15:08:38+00:00"
},
{
"name": "symfony/options-resolver",
@@ -3184,16 +3183,16 @@
},
{
"name": "symfony/process",
- "version": "v8.0.0",
+ "version": "v8.0.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149"
+ "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/a0a750500c4ce900d69ba4e9faf16f82c10ee149",
- "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149",
+ "url": "https://api.github.com/repos/symfony/process/zipball/b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674",
+ "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674",
"shasum": ""
},
"require": {
@@ -3225,7 +3224,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v8.0.0"
+ "source": "https://github.com/symfony/process/tree/v8.0.5"
},
"funding": [
{
@@ -3245,7 +3244,7 @@
"type": "tidelift"
}
],
- "time": "2025-10-16T16:25:44+00:00"
+ "time": "2026-01-26T15:08:38+00:00"
},
{
"name": "symfony/service-contracts",
@@ -3336,16 +3335,16 @@
},
{
"name": "symfony/string",
- "version": "v8.0.1",
+ "version": "v8.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc"
+ "reference": "758b372d6882506821ed666032e43020c4f57194"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc",
- "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc",
+ "url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194",
+ "reference": "758b372d6882506821ed666032e43020c4f57194",
"shasum": ""
},
"require": {
@@ -3402,7 +3401,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v8.0.1"
+ "source": "https://github.com/symfony/string/tree/v8.0.4"
},
"funding": [
{
@@ -3422,7 +3421,7 @@
"type": "tidelift"
}
],
- "time": "2025-12-01T09:13:36+00:00"
+ "time": "2026-01-12T12:37:40+00:00"
},
{
"name": "theseer/tokenizer",
From 15d1195fc26cd542b1a5a7e5eb00a042bc7cf350 Mon Sep 17 00:00:00 2001
From: Chirag Aggarwal
Date: Fri, 13 Mar 2026 16:58:26 +0530
Subject: [PATCH 119/119] Move resource ownership into utopia-php/di (#220)
* Use utopia-php/di for resource injection
* Move resource ownership into utopia-php/di
* Update DI branch dependency
* update getting started
* update
* update
* update appwrite base version
* update to use php 8.2
* fix: restore php 8.2 test runtime
* chore: use container scopes
* remove utopia keyword
* remove optional container in run
* remove optional container in run
* renaming
* remove public getContainer
* fix getcontainer
* fix getcontainer
* update
* remove tests
* make public
* remove tests
* add scoped request containers
* cleanup
* feat: request scopes
* fixes
---------
Co-authored-by: loks0n <22452787+loks0n@users.noreply.github.com>
---
.github/workflows/test.yml | 2 +-
Dockerfile.fpm | 8 +-
Dockerfile.swoole | 2 +-
README.md | 41 +++--
composer.json | 20 ++-
composer.lock | 280 +++++++++++++++++------------
docker-compose.yml | 2 -
docs/Getting-Starting-Guide.md | 27 +--
example/Dockerfile | 2 +-
src/Http/Adapter.php | 3 +
src/Http/Adapter/FPM/Server.php | 17 +-
src/Http/Adapter/Swoole/Server.php | 27 ++-
src/Http/Http.php | 220 +++++++++--------------
src/Http/Response.php | 14 +-
tests/HttpTest.php | 117 +++---------
tests/docker/start | 8 +-
tests/docker/supervisord.conf | 4 +-
tests/e2e/server-fpm.php | 3 +-
18 files changed, 388 insertions(+), 409 deletions(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 2c707436..087875d5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -13,7 +13,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
- php-version: '8.1'
+ php-version: '8.2'
- name: Validate composer.json and composer.lock
run: composer validate --strict
diff --git a/Dockerfile.fpm b/Dockerfile.fpm
index 54c948a6..4b17ec96 100644
--- a/Dockerfile.fpm
+++ b/Dockerfile.fpm
@@ -13,15 +13,15 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist \
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
-FROM php:8.0-cli-alpine as final
+FROM php:8.2-fpm-alpine AS final
LABEL maintainer="team@appwrite.io"
ENV DEBIAN_FRONTEND=noninteractive \
- PHP_VERSION=8
+ PHP_FPM_POOL_CONF=/usr/local/etc/php-fpm.d/www.conf
RUN \
apk add --no-cache --virtual .deps \
- supervisor php$PHP_VERSION php$PHP_VERSION-fpm php$PHP_VERSION-mbstring nginx bash
+ supervisor nginx bash
# Nginx Configuration (with self-signed ssl certificates)
@@ -29,7 +29,7 @@ COPY ./tests/docker/nginx.conf /etc/nginx/nginx.conf
# PHP Configuration
RUN mkdir -p /var/run/php
-COPY ./tests/docker/www.conf /etc/php/$PHP_VERSION/fpm/pool.d/www.conf
+COPY ./tests/docker/www.conf /usr/local/etc/php-fpm.d/www.conf
# Script
COPY ./tests/docker/start /usr/local/bin/start
diff --git a/Dockerfile.swoole b/Dockerfile.swoole
index 6e0fdba1..ff80ec9f 100644
--- a/Dockerfile.swoole
+++ b/Dockerfile.swoole
@@ -13,7 +13,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist \
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
-FROM appwrite/base:0.4.3 as final
+FROM appwrite/base:0.5.0 AS final
LABEL maintainer="team@appwrite.io"
WORKDIR /usr/src/code
diff --git a/README.md b/README.md
index 137e384c..f55045f4 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
Utopia HTTP is a PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. This library is maintained by the [Appwrite team](https://appwrite.io).
-Utopia HTTP is dependency-free. Any extra features, such as authentication or caching are available as standalone models in order to keep the framework core clean, light, and easy to learn.
+Utopia HTTP keeps routing and request lifecycle concerns separate from resource wiring by relying on the standalone Utopia DI package for dependency injection.
## Getting Started
@@ -23,11 +23,14 @@ Init your first application in `src/server.php`:
```php
require_once __DIR__.'/../vendor/autoload.php';
+use Utopia\DI\Container;
use Utopia\Http\Http;
use Utopia\Http\Request;
use Utopia\Http\Response;
use Utopia\Http\Adapter\FPM\Server;
+$container = new Container();
+
Http::get('/hello-world') // Define Route
->inject('request')
->inject('response')
@@ -43,7 +46,7 @@ Http::get('/hello-world') // Define Route
Http::setMode(Http::MODE_TYPE_PRODUCTION);
-$http = new Http(new Server(), 'America/New_York');
+$http = new Http(new Server(), 'America/New_York', $container);
$http->start();
```
@@ -66,10 +69,13 @@ The library supports server adapters to be able to run on any PHP setup. You cou
#### Use PHP FPM server
```php
+use Utopia\DI\Container;
use Utopia\Http\Http;
use Utopia\Http\Response;
use Utopia\Http\Adapter\FPM\Server;
+$container = new Container();
+
Http::get('/')
->inject('response')
->action(
@@ -78,7 +84,7 @@ Http::get('/')
}
);
-$http = new Http(new Server(), 'America/New_York');
+$http = new Http(new Server(), 'America/New_York', $container);
$http->start();
```
@@ -87,11 +93,14 @@ $http->start();
#### Using Swoole server
```php
+use Utopia\DI\Container;
use Utopia\Http\Http;
use Utopia\Http\Request;
use Utopia\Http\Response;
use Utopia\Http\Adapter\Swoole\Server;
+$container = new Container();
+
Http::get('/')
->inject('request')
->inject('response')
@@ -101,7 +110,7 @@ Http::get('/')
}
);
-$http = new Http(new Server('0.0.0.0', '80'), 'America/New_York');
+$http = new Http(new Server('0.0.0.0', '80'), 'America/New_York', $container);
$http->start();
```
@@ -208,12 +217,12 @@ Groups are designed to be actions that run during the lifecycle of requests to e
### Resources
-Resources allow you to prepare dependencies for requests such as database connection or the user who sent the request. A new instance of a resource is created for every request.
+Resources allow you to prepare dependencies for requests such as database connections or shared services. Register application dependencies on the DI container with `set()`. Runtime values such as `request`, `response`, `route`, `error`, and `context` are scoped by `Http` for each request.
-Define a resource:
+Define a dependency on the DI container:
```php
-Http::setResource('timing', function() {
+$container->set('bootTime', function () {
return \microtime(true);
});
```
@@ -221,11 +230,13 @@ Http::setResource('timing', function() {
Inject resource into endpoint action:
```php
+$http = new Http(new Server(), 'America/New_York', $container);
+
Http::get('/')
- ->inject('timing')
+ ->inject('bootTime')
->inject('response')
- ->action(function(float $timing, Response $response) {
- $response->send('Request Unix timestamp: ' . \strval($timing));
+ ->action(function(float $bootTime, Response $response) {
+ $response->send('Process started at: ' . \strval($bootTime));
});
```
@@ -233,10 +244,10 @@ Inject resource into a hook:
```php
Http::shutdown()
- ->inject('timing')
- ->action(function(float $timing) {
- $difference = \microtime(true) - $timing;
- \var_dump("Request took: " . $difference . " seconds");
+ ->inject('bootTime')
+ ->action(function(float $bootTime) {
+ $uptime = \microtime(true) - $bootTime;
+ \var_dump("Process uptime: " . $uptime . " seconds");
});
```
@@ -248,7 +259,7 @@ To learn more about architecture and features for this library, check out more i
## System Requirements
-Utopia HTTP requires PHP 8.1 or later. We recommend using the latest PHP version whenever possible.
+Utopia HTTP requires PHP 8.2 or later. We recommend using the latest PHP version whenever possible.
## More from Utopia
diff --git a/composer.json b/composer.json
index 2c5bf2c6..40e0392d 100644
--- a/composer.json
+++ b/composer.json
@@ -29,15 +29,23 @@
"bench": "vendor/bin/phpbench run --report=benchmark"
},
"require": {
- "php": ">=8.0",
- "ext-swoole": "*",
- "utopia-php/validators": "0.2.*"
+ "php": ">=8.2",
+ "utopia-php/di": "0.3.*",
+ "utopia-php/validators": "0.2.*",
+ "ext-swoole": "*"
+ },
+ "config": {
+ "allow-plugins": {
+ "php-http/discovery": true,
+ "tbachert/spi": true
+ }
},
"require-dev": {
- "phpunit/phpunit": "^9.5.25",
+ "doctrine/instantiator": "^1.5",
"laravel/pint": "1.*",
- "swoole/ide-helper": "4.8.3",
+ "phpbench/phpbench": "^1.2",
"phpstan/phpstan": "1.*",
- "phpbench/phpbench": "^1.2"
+ "phpunit/phpunit": "^9.5.25",
+ "swoole/ide-helper": "4.8.3"
}
}
diff --git a/composer.lock b/composer.lock
index 3d5b401a..c854c2ab 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,112 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "e7104035855b324e167057fd44e2a875",
+ "content-hash": "5afd948989df91d546b1694354e2f9d2",
"packages": [
+ {
+ "name": "psr/container",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
+ },
+ {
+ "name": "utopia-php/di",
+ "version": "0.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/di.git",
+ "reference": "68873b7267842315d01d82a83b988bae525eab31"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/di/zipball/68873b7267842315d01d82a83b988bae525eab31",
+ "reference": "68873b7267842315d01d82a83b988bae525eab31",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/container": "^2.0"
+ },
+ "require-dev": {
+ "laravel/pint": "^1.27",
+ "phpbench/phpbench": "^1.2",
+ "phpstan/phpstan": "^2.1",
+ "phpunit/phpunit": "^9.5.25",
+ "swoole/ide-helper": "4.8.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\": "src/",
+ "Tests\\E2E\\": "tests/e2e"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A simple and lite library for managing dependency injections",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "dependency-injection",
+ "di",
+ "php",
+ "utopia"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/di/issues",
+ "source": "https://github.com/utopia-php/di/tree/0.3.1"
+ },
+ "time": "2026-03-13T05:47:23+00:00"
+ },
{
"name": "utopia-php/validators",
"version": "0.2.0",
@@ -132,29 +236,30 @@
},
{
"name": "doctrine/instantiator",
- "version": "2.1.0",
+ "version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
- "reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7"
+ "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/23da848e1a2308728fe5fdddabf4be17ff9720c7",
- "reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b",
+ "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b",
"shasum": ""
},
"require": {
- "php": "^8.4"
+ "php": "^7.1 || ^8.0"
},
"require-dev": {
- "doctrine/coding-standard": "^14",
+ "doctrine/coding-standard": "^9 || ^11",
"ext-pdo": "*",
"ext-phar": "*",
- "phpbench/phpbench": "^1.2",
- "phpstan/phpstan": "^2.1",
- "phpstan/phpstan-phpunit": "^2.0",
- "phpunit/phpunit": "^10.5.58"
+ "phpbench/phpbench": "^0.16 || ^1",
+ "phpstan/phpstan": "^1.4",
+ "phpstan/phpstan-phpunit": "^1",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+ "vimeo/psalm": "^4.30 || ^5.4"
},
"type": "library",
"autoload": {
@@ -181,7 +286,7 @@
],
"support": {
"issues": "https://github.com/doctrine/instantiator/issues",
- "source": "https://github.com/doctrine/instantiator/tree/2.1.0"
+ "source": "https://github.com/doctrine/instantiator/tree/1.5.0"
},
"funding": [
{
@@ -197,7 +302,7 @@
"type": "tidelift"
}
],
- "time": "2026-01-05T06:47:08+00:00"
+ "time": "2022-12-30T00:15:36+00:00"
},
{
"name": "doctrine/lexer",
@@ -278,16 +383,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.27.1",
+ "version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5"
+ "reference": "bdec963f53172c5e36330f3a400604c69bf02d39"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/54cca2de13790570c7b6f0f94f37896bee4abcb5",
- "reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/bdec963f53172c5e36330f3a400604c69bf02d39",
+ "reference": "bdec963f53172c5e36330f3a400604c69bf02d39",
"shasum": ""
},
"require": {
@@ -298,13 +403,14 @@
"php": "^8.2.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.93.1",
- "illuminate/view": "^12.51.0",
- "larastan/larastan": "^3.9.2",
+ "friendsofphp/php-cs-fixer": "^3.94.2",
+ "illuminate/view": "^12.54.1",
+ "larastan/larastan": "^3.9.3",
"laravel-zero/framework": "^12.0.5",
"mockery/mockery": "^1.6.12",
- "nunomaduro/termwind": "^2.3.3",
- "pestphp/pest": "^3.8.5"
+ "nunomaduro/termwind": "^2.4.0",
+ "pestphp/pest": "^3.8.6",
+ "shipfastlabs/agent-detector": "^1.1.0"
},
"bin": [
"builds/pint"
@@ -341,7 +447,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2026-02-10T20:00:20+00:00"
+ "time": "2026-03-12T15:51:39+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -632,16 +738,16 @@
},
{
"name": "phpbench/phpbench",
- "version": "1.4.3",
+ "version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/phpbench/phpbench.git",
- "reference": "b641dde59d969ea42eed70a39f9b51950bc96878"
+ "reference": "9a28fd0833f11171b949843c6fd663eb69b6d14c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpbench/phpbench/zipball/b641dde59d969ea42eed70a39f9b51950bc96878",
- "reference": "b641dde59d969ea42eed70a39f9b51950bc96878",
+ "url": "https://api.github.com/repos/phpbench/phpbench/zipball/9a28fd0833f11171b949843c6fd663eb69b6d14c",
+ "reference": "9a28fd0833f11171b949843c6fd663eb69b6d14c",
"shasum": ""
},
"require": {
@@ -652,7 +758,7 @@
"ext-reflection": "*",
"ext-spl": "*",
"ext-tokenizer": "*",
- "php": "^8.1",
+ "php": "^8.2",
"phpbench/container": "^2.2",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"seld/jsonlint": "^1.1",
@@ -672,8 +778,9 @@
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
- "phpunit/phpunit": "^10.4 || ^11.0",
+ "phpunit/phpunit": "^11.5",
"rector/rector": "^1.2",
+ "sebastian/exporter": "^6.3.2",
"symfony/error-handler": "^6.1 || ^7.0 || ^8.0",
"symfony/var-dumper": "^6.1 || ^7.0 || ^8.0"
},
@@ -718,7 +825,7 @@
],
"support": {
"issues": "https://github.com/phpbench/phpbench/issues",
- "source": "https://github.com/phpbench/phpbench/tree/1.4.3"
+ "source": "https://github.com/phpbench/phpbench/tree/1.5.1"
},
"funding": [
{
@@ -726,15 +833,15 @@
"type": "github"
}
],
- "time": "2025-11-06T19:07:31+00:00"
+ "time": "2026-03-05T08:18:58+00:00"
},
{
"name": "phpstan/phpstan",
- "version": "1.12.32",
+ "version": "1.12.33",
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8",
- "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/37982d6fc7cbb746dda7773530cda557cdf119e1",
+ "reference": "37982d6fc7cbb746dda7773530cda557cdf119e1",
"shasum": ""
},
"require": {
@@ -779,7 +886,7 @@
"type": "github"
}
],
- "time": "2025-09-30T10:16:31+00:00"
+ "time": "2026-02-28T20:30:03+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -1260,59 +1367,6 @@
},
"time": "2021-02-03T23:26:27+00:00"
},
- {
- "name": "psr/container",
- "version": "2.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/container.git",
- "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
- "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
- "shasum": ""
- },
- "require": {
- "php": ">=7.4.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Container\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common Container Interface (PHP FIG PSR-11)",
- "homepage": "https://github.com/php-fig/container",
- "keywords": [
- "PSR-11",
- "container",
- "container-interface",
- "container-interop",
- "psr"
- ],
- "support": {
- "issues": "https://github.com/php-fig/container/issues",
- "source": "https://github.com/php-fig/container/tree/2.0.2"
- },
- "time": "2021-11-05T16:47:00+00:00"
- },
{
"name": "psr/log",
"version": "3.0.2",
@@ -2482,16 +2536,16 @@
},
{
"name": "symfony/console",
- "version": "v8.0.4",
+ "version": "v8.0.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b"
+ "reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/ace03c4cf9805080ff40cbeec69fca180c339a3b",
- "reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b",
+ "url": "https://api.github.com/repos/symfony/console/zipball/15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a",
+ "reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a",
"shasum": ""
},
"require": {
@@ -2548,7 +2602,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v8.0.4"
+ "source": "https://github.com/symfony/console/tree/v8.0.7"
},
"funding": [
{
@@ -2568,7 +2622,7 @@
"type": "tidelift"
}
],
- "time": "2026-01-13T13:06:50+00:00"
+ "time": "2026-03-06T14:06:22+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -2639,16 +2693,16 @@
},
{
"name": "symfony/filesystem",
- "version": "v8.0.1",
+ "version": "v8.0.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "d937d400b980523dc9ee946bb69972b5e619058d"
+ "reference": "7bf9162d7a0dff98d079b72948508fa48018a770"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d",
- "reference": "d937d400b980523dc9ee946bb69972b5e619058d",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/7bf9162d7a0dff98d079b72948508fa48018a770",
+ "reference": "7bf9162d7a0dff98d079b72948508fa48018a770",
"shasum": ""
},
"require": {
@@ -2685,7 +2739,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v8.0.1"
+ "source": "https://github.com/symfony/filesystem/tree/v8.0.6"
},
"funding": [
{
@@ -2705,20 +2759,20 @@
"type": "tidelift"
}
],
- "time": "2025-12-01T09:13:36+00:00"
+ "time": "2026-02-25T16:59:43+00:00"
},
{
"name": "symfony/finder",
- "version": "v8.0.5",
+ "version": "v8.0.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0"
+ "reference": "441404f09a54de6d1bd6ad219e088cdf4c91f97c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/8bd576e97c67d45941365bf824e18dc8538e6eb0",
- "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/441404f09a54de6d1bd6ad219e088cdf4c91f97c",
+ "reference": "441404f09a54de6d1bd6ad219e088cdf4c91f97c",
"shasum": ""
},
"require": {
@@ -2753,7 +2807,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v8.0.5"
+ "source": "https://github.com/symfony/finder/tree/v8.0.6"
},
"funding": [
{
@@ -2773,7 +2827,7 @@
"type": "tidelift"
}
],
- "time": "2026-01-26T15:08:38+00:00"
+ "time": "2026-01-29T09:41:02+00:00"
},
{
"name": "symfony/options-resolver",
@@ -3335,16 +3389,16 @@
},
{
"name": "symfony/string",
- "version": "v8.0.4",
+ "version": "v8.0.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "758b372d6882506821ed666032e43020c4f57194"
+ "reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194",
- "reference": "758b372d6882506821ed666032e43020c4f57194",
+ "url": "https://api.github.com/repos/symfony/string/zipball/6c9e1108041b5dce21a9a4984b531c4923aa9ec4",
+ "reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4",
"shasum": ""
},
"require": {
@@ -3401,7 +3455,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v8.0.4"
+ "source": "https://github.com/symfony/string/tree/v8.0.6"
},
"funding": [
{
@@ -3421,7 +3475,7 @@
"type": "tidelift"
}
],
- "time": "2026-01-12T12:37:40+00:00"
+ "time": "2026-02-09T10:14:57+00:00"
},
{
"name": "theseer/tokenizer",
@@ -3529,7 +3583,7 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": ">=8.0",
+ "php": ">=8.2",
"ext-swoole": "*"
},
"platform-dev": {},
diff --git a/docker-compose.yml b/docker-compose.yml
index 0c4e0011..322de5ba 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,5 +1,3 @@
-version: '3'
-
services:
fpm:
build:
diff --git a/docs/Getting-Starting-Guide.md b/docs/Getting-Starting-Guide.md
index 831d0687..86455959 100644
--- a/docs/Getting-Starting-Guide.md
+++ b/docs/Getting-Starting-Guide.md
@@ -10,33 +10,21 @@ If you’re new to Utopia, let’s get started by looking at an example of a bas
```php
use Utopia\Http\Http;
-use Utopia\Http\Swoole\Request;
-use Utopia\Http\Swoole\Response;
-use Swoole\Http\Server;
-use Swoole\Http\Request as SwooleRequest;
-use Swoole\Http\Response as SwooleResponse;
-
-$http = new Server("0.0.0.0", 8080);
+use Utopia\Http\Request;
+use Utopia\Http\Response;
+use Utopia\Http\Adapter\Swoole\Server;
Http::get('/')
->inject('request')
->inject('response')
->action(
- function($request, $response) {
+ function(Request $request, Response $response) {
// Return raw HTML
$response->send(" Hello World!
");
}
-/*
- Configure your HTTP server to respond with the Utopia http.
-*/
-
-$http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) {
- $request = new Request($swooleRequest);
- $response = new Response($swooleResponse);
- $http = new Http('America/Toronto');
- $http->run($request, $response);
-});
+ );
+$http = new Http(new Server("0.0.0.0", "8080"), 'America/Toronto');
$http->start();
```
@@ -281,7 +269,6 @@ Http::shutdown(function($request) {
# Running Locally
If you have PHP and Composer installed on your device, you can run Utopia apps locally by downloading the `utopia-php/http` dependency using `composer require utopia-php/http` command.
-> Utopia HTTP requires PHP 8.1 or later. We recommend using the latest PHP version whenever possible.
+> Utopia HTTP requires PHP 8.2 or later. We recommend using the latest PHP version whenever possible.
Wonderful! 😄 You’re all set to create a basic demo app using the Utopia HTTP. If you have any issues or questions feel free to reach out to us on our [Discord Server](https://appwrite.io/discord).
-
diff --git a/example/Dockerfile b/example/Dockerfile
index 3abcbeed..2153e4e8 100644
--- a/example/Dockerfile
+++ b/example/Dockerfile
@@ -3,7 +3,7 @@ WORKDIR /usr/local/src/
COPY composer.* /usr/local/src/
RUN composer install --ignore-platform-reqs --optimize-autoloader --no-plugins --no-scripts --prefer-dist
-FROM appwrite/base:0.4.3 as final
+FROM appwrite/base:0.5.0 AS final
WORKDIR /usr/src/code
COPY ./src /usr/src/code/src
COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor
diff --git a/src/Http/Adapter.php b/src/Http/Adapter.php
index 082ca6ab..f72d6bfb 100755
--- a/src/Http/Adapter.php
+++ b/src/Http/Adapter.php
@@ -2,9 +2,12 @@
namespace Utopia\Http;
+use Utopia\DI\Container;
+
abstract class Adapter
{
abstract public function onStart(callable $callback);
abstract public function onRequest(callable $callback);
abstract public function start();
+ abstract public function getContainer(): Container;
}
diff --git a/src/Http/Adapter/FPM/Server.php b/src/Http/Adapter/FPM/Server.php
index e90f0cd7..d48d6fec 100755
--- a/src/Http/Adapter/FPM/Server.php
+++ b/src/Http/Adapter/FPM/Server.php
@@ -2,12 +2,12 @@
namespace Utopia\Http\Adapter\FPM;
+use Utopia\DI\Container;
use Utopia\Http\Adapter;
-use Utopia\Http\Http;
class Server extends Adapter
{
- public function __construct()
+ public function __construct(private Container $container)
{
}
@@ -16,15 +16,20 @@ public function onRequest(callable $callback)
$request = new Request();
$response = new Response();
- Http::setResource('fpmRequest', fn () => $request);
- Http::setResource('fpmResponse', fn () => $response);
+ $this->container->set('fpmRequest', fn () => $request);
+ $this->container->set('fpmResponse', fn () => $response);
- call_user_func($callback, $request, $response, 'fpm');
+ \call_user_func($callback, $request, $response);
}
public function onStart(callable $callback)
{
- call_user_func($callback, $this);
+ \call_user_func($callback, $this);
+ }
+
+ public function getContainer(): Container
+ {
+ return $this->container;
}
public function start()
diff --git a/src/Http/Adapter/Swoole/Server.php b/src/Http/Adapter/Swoole/Server.php
index bb3b87d8..57b4f5fb 100755
--- a/src/Http/Adapter/Swoole/Server.php
+++ b/src/Http/Adapter/Swoole/Server.php
@@ -4,41 +4,54 @@
use Swoole\Coroutine;
use Utopia\Http\Adapter;
+use Utopia\DI\Container;
use Swoole\Coroutine\Http\Server as SwooleServer;
use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
-use Utopia\Http\Http;
use function Swoole\Coroutine\run;
class Server extends Adapter
{
protected SwooleServer $server;
+ protected const REQUEST_CONTAINER_CONTEXT_KEY = '__utopia_http_request_container';
+ protected Container $container;
- public function __construct(string $host, ?string $port = null, array $settings = [])
+ public function __construct(string $host, ?string $port = null, array $settings = [], ?Container $container = null)
{
$this->server = new SwooleServer($host, $port);
$this->server->set(\array_merge($settings, [
'enable_coroutine' => true,
'http_parse_cookie' => false,
]));
+ $this->container = $container ?? new Container();
}
public function onRequest(callable $callback)
{
$this->server->handle('/', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
- $context = \strval(Coroutine::getCid());
+ $requestContainer = new Container($this->container);
+ $requestContainer->set('swooleRequest', fn () => $request);
+ $requestContainer->set('swooleResponse', fn () => $response);
- Http::setResource('swooleRequest', fn () => $request, [], $context);
- Http::setResource('swooleResponse', fn () => $response, [], $context);
+ Coroutine::getContext()[self::REQUEST_CONTAINER_CONTEXT_KEY] = $requestContainer;
- call_user_func($callback, new Request($request), new Response($response), $context);
+ $utopiaRequest = new Request($request);
+ $utopiaResponse = new Response($response);
+
+ \call_user_func($callback, $utopiaRequest, $utopiaResponse);
});
}
+ public function getContainer(): Container
+ {
+ return Coroutine::getContext()[self::REQUEST_CONTAINER_CONTEXT_KEY] ?? $this->container;
+ }
+
public function onStart(callable $callback)
{
- call_user_func($callback, $this);
+
+ \call_user_func($callback, $this);
}
public function start()
diff --git a/src/Http/Http.php b/src/Http/Http.php
index 61434842..d3556a38 100755
--- a/src/Http/Http.php
+++ b/src/Http/Http.php
@@ -2,6 +2,7 @@
namespace Utopia\Http;
+use Utopia\DI\Container;
use Utopia\Validator;
class Http
@@ -32,22 +33,14 @@ class Http
public const MODE_TYPE_PRODUCTION = 'production';
- /**
- * @var array
- */
- protected array $resources = [
- 'error' => null,
- ];
-
/**
* @var Files
*/
protected Files $files;
- /**
- * @var array
- */
- protected static array $resourcesCallbacks = [];
+ protected Container $container;
+
+ protected ?Container $requestContainer = null;
/**
* Current running mode
@@ -351,78 +344,53 @@ public static function setAllowOverride(bool $value): void
}
/**
- * If a resource has been created return it, otherwise create it and then return it
- *
- * @param string $name
- * @param bool $fresh
- * @return mixed
+ * Get a single resource from the given scope.
*
* @throws Exception
*/
- public function getResource(string $name, string $context = 'utopia', bool $fresh = false): mixed
+ public function getResource(string $name): mixed
{
- if ($name === 'utopia') {
- return $this;
- }
-
- $this->resources[$context] ??= [];
-
- $resourcesCallback = &self::$resourcesCallbacks[$context] ?? [];
- if (empty($resourcesCallback) || !\array_key_exists($name, $resourcesCallback)) {
- $resourcesCallback = &self::$resourcesCallbacks['utopia'];
- }
+ try {
+ return $this->server->getContainer()->get($name);
+ } catch (\Throwable $e) {
+ // Normalize DI container errors to the Http layer's "resource" terminology.
+ $message = \str_replace('dependency', 'resource', $e->getMessage());
- if (!\array_key_exists($name, $this->resources[$context]) || $fresh || ($resourcesCallback[$name]['reset'][$context] ?? true)) {
- if (!\array_key_exists($name, $resourcesCallback)) {
- throw new Exception('Failed to find resource: "' . $name . '"');
+ if ($message === $e->getMessage() && !\str_contains($message, 'resource')) {
+ $message = 'Failed to find resource: "' . $name . '"';
}
- $this->resources[$context][$name] = \call_user_func_array(
- $resourcesCallback[$name]['callback'],
- $this->getResources($resourcesCallback[$name]['injections'], $context)
- );
+ throw new Exception($message, 500, $e);
}
-
- $resourcesCallback[$name]['reset'][$context] = false;
- return $this->resources[$context][$name];
}
/**
- * Get Resources By List
+ * Get multiple resources from the given scope.
*
- * @param array $list
- * @return array
+ * @param string[] $list
+ * @return array
+ *
+ * @throws Exception
*/
- public function getResources(array $list, string $context = 'utopia'): array
+ public function getResources(array $list): array
{
$resources = [];
foreach ($list as $name) {
- $resources[$name] = $this->getResource($name, $context);
+ $resources[$name] = $this->getResource($name);
}
return $resources;
}
/**
- * Set a new resource callback
- *
- * @param string $name
- * @param callable $callback
- * @param array $injections
- * @return void
+ * Set a resource on the given scope.
*
- * @throws Exception
+ * @param string[] $injections
*/
- public static function setResource(string $name, callable $callback, array $injections = [], string $context = 'utopia'): void
+ public function setResource(string $name, callable $callback, array $injections = []): void
{
- if ($name === 'utopia') {
- throw new Exception("'utopia' is a reserved keyword.", 500);
- }
-
- self::$resourcesCallbacks[$context] ??= [];
-
- self::$resourcesCallbacks[$context][$name] = ['callback' => $callback, 'injections' => $injections, 'resets' => []];
+ $this->server->getContainer()->set($name, $callback, $injections);
}
/**
@@ -574,34 +542,28 @@ public static function onRequest(): Hook
public function start()
{
- $this->server->onRequest(function ($request, $response, $context) {
- try {
- $this->run($request, $response, $context);
- } finally {
- if (isset(self::$resourcesCallbacks[$context])) {
- unset(self::$resourcesCallbacks[$context]);
- }
- }
- });
+
+ $this->server->onRequest(
+ fn (Request $request, Response $response) => $this->run($request, $response)
+ );
+
$this->server->onStart(function ($server) {
- $this->resources['utopia'] ??= [];
- $this->resources['utopia']['server'] = $server;
- self::setResource('server', function () use ($server) {
+ $this->setResource('server', function () use ($server) {
return $server;
});
try {
foreach (self::$startHooks as $hook) {
- $arguments = $this->getArguments($hook, 'utopia', [], []);
+ $arguments = $this->getArguments($hook, [], []);
\call_user_func_array($hook->getAction(), $arguments);
}
} catch (\Exception $e) {
- self::setResource('error', fn () => $e);
+ $this->setResource('error', fn () => $e);
foreach (self::$errors as $error) { // Global error hooks
if (in_array('*', $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, 'utopia', [], []);
+ $arguments = $this->getArguments($error, [], []);
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
@@ -644,7 +606,7 @@ public function match(Request $request, bool $fresh = true): ?Route
* @param Route $route
* @param Request $request
*/
- public function execute(Route $route, Request $request, string $context): static
+ public function execute(Route $route, Request $request): static
{
$arguments = [];
$groups = $route->getGroups();
@@ -654,7 +616,7 @@ public function execute(Route $route, Request $request, string $context): static
if ($route->getHook()) {
foreach (self::$init as $hook) { // Global init hooks
if (in_array('*', $hook->getGroups())) {
- $arguments = $this->getArguments($hook, $context, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($hook, $pathValues, $request->getParams());
\call_user_func_array($hook->getAction(), $arguments);
}
}
@@ -662,20 +624,20 @@ public function execute(Route $route, Request $request, string $context): static
foreach ($groups as $group) {
foreach (self::$init as $hook) { // Group init hooks
- if (in_array($group, $hook->getGroups())) {
- $arguments = $this->getArguments($hook, $context, $pathValues, $request->getParams());
+ if (\in_array($group, $hook->getGroups())) {
+ $arguments = $this->getArguments($hook, $pathValues, $request->getParams());
\call_user_func_array($hook->getAction(), $arguments);
}
}
}
- $arguments = $this->getArguments($route, $context, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($route, $pathValues, $request->getParams());
\call_user_func_array($route->getAction(), $arguments);
foreach ($groups as $group) {
foreach (self::$shutdown as $hook) { // Group shutdown hooks
- if (in_array($group, $hook->getGroups())) {
- $arguments = $this->getArguments($hook, $context, $pathValues, $request->getParams());
+ if (\in_array($group, $hook->getGroups())) {
+ $arguments = $this->getArguments($hook, $pathValues, $request->getParams());
\call_user_func_array($hook->getAction(), $arguments);
}
}
@@ -683,20 +645,20 @@ public function execute(Route $route, Request $request, string $context): static
if ($route->getHook()) {
foreach (self::$shutdown as $hook) { // Group shutdown hooks
- if (in_array('*', $hook->getGroups())) {
- $arguments = $this->getArguments($hook, $context, $pathValues, $request->getParams());
+ if (\in_array('*', $hook->getGroups())) {
+ $arguments = $this->getArguments($hook, $pathValues, $request->getParams());
\call_user_func_array($hook->getAction(), $arguments);
}
}
}
} catch (\Throwable $e) {
- self::setResource('error', fn () => $e, [], $context);
+ $this->setResource('error', fn () => $e, []);
foreach ($groups as $group) {
foreach (self::$errors as $error) { // Group error hooks
- if (in_array($group, $error->getGroups())) {
+ if (\in_array($group, $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, $context, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($error, $pathValues, $request->getParams());
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
@@ -706,9 +668,9 @@ public function execute(Route $route, Request $request, string $context): static
}
foreach (self::$errors as $error) { // Global error hooks
- if (in_array('*', $error->getGroups())) {
+ if (\in_array('*', $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, $context, $pathValues, $request->getParams());
+ $arguments = $this->getArguments($error, $pathValues, $request->getParams());
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
@@ -717,9 +679,6 @@ public function execute(Route $route, Request $request, string $context): static
}
}
- // Reset resources for the context
- $this->resources[$context] = [];
-
return $this;
}
@@ -733,7 +692,7 @@ public function execute(Route $route, Request $request, string $context): static
*
* @throws Exception
*/
- protected function getArguments(Hook $hook, string $context, array $values, array $requestParams): array
+ protected function getArguments(Hook $hook, array $values, array $requestParams): array
{
$arguments = [];
foreach ($hook->getParams() as $key => $param) { // Get value from route or request object
@@ -753,7 +712,7 @@ protected function getArguments(Hook $hook, string $context, array $values, arra
}
if ($paramExists) {
- $this->validate($key, $param, $value, $context);
+ $this->validate($key, $param, $value);
}
}
@@ -762,7 +721,7 @@ protected function getArguments(Hook $hook, string $context, array $values, arra
}
foreach ($hook->getInjections() as $key => $injection) {
- $arguments[$injection['order']] = $this->getResource($injection['name'], $context);
+ $arguments[$injection['order']] = $this->getResource($injection['name']);
}
return $arguments;
@@ -777,31 +736,23 @@ protected function getArguments(Hook $hook, string $context, array $values, arra
* @param Request $request
* @param Response $response;
*/
- public function run(Request $request, Response $response, string $context): static
+ public function run(Request $request, Response $response): static
{
- $this->resources[$context] = [];
- $this->resources[$context]['request'] = $request;
- $this->resources[$context]['response'] = $response;
-
- self::setResource('context', fn () => $context, [], $context);
-
- self::setResource('request', fn () => $request, [], $context);
-
- self::setResource('response', fn () => $response, [], $context);
+ $this->setResource('request', fn () => $request);
+ $this->setResource('response', fn () => $response);
try {
-
foreach (self::$requestHooks as $hook) {
- $arguments = $this->getArguments($hook, $context, [], []);
+ $arguments = $this->getArguments($hook, [], []);
\call_user_func_array($hook->getAction(), $arguments);
}
} catch (\Exception $e) {
- self::setResource('error', fn () => $e, [], $context);
+ $this->setResource('error', fn () => $e, []);
foreach (self::$errors as $error) { // Global error hooks
- if (in_array('*', $error->getGroups())) {
+ if (\in_array('*', $error->getGroups())) {
try {
- $arguments = $this->getArguments($error, $context, [], []);
+ $arguments = $this->getArguments($error, [], []);
\call_user_func_array($error->getAction(), $arguments);
} catch (\Throwable $e) {
throw new Exception('Error handler had an error: ' . $e->getMessage(), 500, $e);
@@ -821,11 +772,12 @@ public function run(Request $request, Response $response, string $context): stat
return $this;
}
+
$method = $request->getMethod();
$route = $this->match($request);
$groups = ($route instanceof Route) ? $route->getGroups() : [];
- self::setResource('route', fn () => $route, [], $context);
+ $this->setResource('route', fn () => $route, []);
if (self::REQUEST_METHOD_HEAD == $method) {
$method = self::REQUEST_METHOD_GET;
@@ -837,26 +789,26 @@ public function run(Request $request, Response $response, string $context): stat
foreach ($groups as $group) {
foreach (self::$options as $option) { // Group options hooks
/** @var Hook $option */
- if (in_array($group, $option->getGroups())) {
- \call_user_func_array($option->getAction(), $this->getArguments($option, $context, [], $request->getParams()));
+ if (\in_array($group, $option->getGroups())) {
+ \call_user_func_array($option->getAction(), $this->getArguments($option, [], $request->getParams()));
}
}
}
foreach (self::$options as $option) { // Global options hooks
/** @var Hook $option */
- if (in_array('*', $option->getGroups())) {
- \call_user_func_array($option->getAction(), $this->getArguments($option, $context, [], $request->getParams()));
+ if (\in_array('*', $option->getGroups())) {
+ \call_user_func_array($option->getAction(), $this->getArguments($option, [], $request->getParams()));
}
}
} catch (\Throwable $e) {
foreach (self::$errors as $error) { // Global error hooks
/** @var Hook $error */
- if (in_array('*', $error->getGroups())) {
- self::setResource('error', function () use ($e) {
+ if (\in_array('*', $error->getGroups())) {
+ $this->setResource('error', function () use ($e) {
return $e;
- }, [], $context);
- \call_user_func_array($error->getAction(), $this->getArguments($error, $context, [], $request->getParams()));
+ }, []);
+ \call_user_func_array($error->getAction(), $this->getArguments($error, [], $request->getParams()));
}
}
}
@@ -870,43 +822,41 @@ public function run(Request $request, Response $response, string $context): stat
$path = \parse_url($request->getURI(), PHP_URL_PATH);
$route->path($path);
- self::setResource('route', fn () => $route, [], $context);
+ $this->setResource('route', fn () => $route, []);
}
if (null !== $route) {
- return $this->execute($route, $request, $context);
+ return $this->execute($route, $request);
} elseif (self::REQUEST_METHOD_OPTIONS == $method) {
try {
foreach ($groups as $group) {
foreach (self::$options as $option) { // Group options hooks
- if (in_array($group, $option->getGroups())) {
- \call_user_func_array($option->getAction(), $this->getArguments($option, $context, [], $request->getParams()));
+ if (\in_array($group, $option->getGroups())) {
+ \call_user_func_array($option->getAction(), $this->getArguments($option, [], $request->getParams()));
}
}
}
foreach (self::$options as $option) { // Global options hooks
- if (in_array('*', $option->getGroups())) {
- \call_user_func_array($option->getAction(), $this->getArguments($option, $context, [], $request->getParams()));
+ if (\in_array('*', $option->getGroups())) {
+ \call_user_func_array($option->getAction(), $this->getArguments($option, [], $request->getParams()));
}
}
} catch (\Throwable $e) {
foreach (self::$errors as $error) { // Global error hooks
- if (in_array('*', $error->getGroups())) {
- self::setResource('error', function () use ($e) {
+ if (\in_array('*', $error->getGroups())) {
+ $this->setResource('error', function () use ($e) {
return $e;
- }, [], $context);
- \call_user_func_array($error->getAction(), $this->getArguments($error, $context, [], $request->getParams()));
+ }, []);
+ \call_user_func_array($error->getAction(), $this->getArguments($error, [], $request->getParams()));
}
}
}
} else {
foreach (self::$errors as $error) { // Global error hooks
- if (in_array('*', $error->getGroups())) {
- self::setResource('error', function () {
- return new Exception('Not Found', 404);
- }, [], $context);
- \call_user_func_array($error->getAction(), $this->getArguments($error, $context, [], $request->getParams()));
+ if (\in_array('*', $error->getGroups())) {
+ $this->setResource('error', fn () => new Exception('Not Found', 404), []);
+ \call_user_func_array($error->getAction(), $this->getArguments($error, [], $request->getParams()));
}
}
}
@@ -914,6 +864,7 @@ public function run(Request $request, Response $response, string $context): stat
return $this;
}
+
/**
* Validate Param
*
@@ -926,7 +877,7 @@ public function run(Request $request, Response $response, string $context): stat
*
* @throws Exception
*/
- protected function validate(string $key, array $param, mixed $value, $context): void
+ protected function validate(string $key, array $param, mixed $value): void
{
if ($param['optional'] && \is_null($value)) {
return;
@@ -935,7 +886,7 @@ protected function validate(string $key, array $param, mixed $value, $context):
$validator = $param['validator']; // checking whether the class exists
if (\is_callable($validator)) {
- $validator = \call_user_func_array($validator, $this->getResources($param['injections'], $context));
+ $validator = \call_user_func_array($validator, $this->getResources($param['injections']));
}
if (!$validator instanceof Validator) { // is the validator object an instance of the Validator class
@@ -955,12 +906,13 @@ protected function validate(string $key, array $param, mixed $value, $context):
public static function reset(): void
{
Router::reset();
- self::$resourcesCallbacks = [];
self::$mode = '';
self::$errors = [];
self::$init = [];
self::$shutdown = [];
self::$options = [];
self::$startHooks = [];
+ self::$requestHooks = [];
+ self::$wildcardRoute = null;
}
}
diff --git a/src/Http/Response.php b/src/Http/Response.php
index 2bc4a5f4..444bc4f8 100755
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -224,6 +224,8 @@ abstract class Response
*/
protected bool $sent = false;
+ protected bool $headersSent = false;
+
/**
* @var array>
*/
@@ -488,6 +490,8 @@ public function send(string $body = ''): void
->appendCookies()
->appendHeaders();
+ $this->headersSent = true;
+
if (!$this->disablePayload) {
$length = strlen($body);
@@ -566,9 +570,13 @@ public function chunk(string $body = '', bool $end = false): void
$this->addHeader('X-Debug-Speed', (string) (microtime(true) - $this->startTime));
- $this
- ->appendCookies()
- ->appendHeaders();
+ if (!$this->headersSent) {
+ $this
+ ->appendCookies()
+ ->appendHeaders();
+
+ $this->headersSent = true;
+ }
if (!$this->disablePayload) {
$this->write($body);
diff --git a/tests/HttpTest.php b/tests/HttpTest.php
index a735a41f..a6ce883e 100755
--- a/tests/HttpTest.php
+++ b/tests/HttpTest.php
@@ -3,6 +3,7 @@
namespace Utopia\Http;
use PHPUnit\Framework\TestCase;
+use Utopia\DI\Container;
use Utopia\Http\Tests\UtopiaFPMRequestTest;
use Utopia\Validator\Text;
use Utopia\Http\Adapter\FPM\Request;
@@ -13,6 +14,8 @@ class HttpTest extends TestCase
{
protected ?Http $http;
+ protected ?Container $container;
+
protected ?string $method;
protected ?string $uri;
@@ -20,13 +23,15 @@ class HttpTest extends TestCase
public function setUp(): void
{
Http::reset();
- $this->http = new Http(new Server(), 'Asia/Tel_Aviv');
+ $this->container = new Container();
+ $this->http = new Http(new Server($this->container), 'Asia/Tel_Aviv');
$this->saveRequest();
}
public function tearDown(): void
{
$this->http = null;
+ $this->container = null;
$this->restoreRequest();
}
@@ -80,76 +85,10 @@ public function testCanGetEnvironmentVariable(): void
$this->assertEquals(Http::getEnv('unknown', 'test'), 'test');
}
- public function testCanGetResources(): void
- {
- Http::setResource('rand', fn () => rand());
- Http::setResource('first', fn ($second) => "first-{$second}", ['second']);
- Http::setResource('second', fn () => 'second');
-
- $second = $this->http->getResource('second', '1');
- $first = $this->http->getResource('first', '1');
- $this->assertEquals('second', $second);
- $this->assertEquals('first-second', $first);
-
- $resource = $this->http->getResource('rand', '1');
-
- $this->assertNotEmpty($resource);
- $this->assertEquals($resource, $this->http->getResource('rand', '1'));
- $this->assertEquals($resource, $this->http->getResource('rand', '1'));
- $this->assertEquals($resource, $this->http->getResource('rand', '1'));
-
- // Default Params
- $route = new Route('GET', '/path');
-
- $route
- ->inject('rand')
- ->param('x', 'x-def', new Text(200), 'x param', true)
- ->param('y', 'y-def', new Text(200), 'y param', true)
- ->action(function ($x, $y, $rand) {
- echo $x . '-' . $y . '-' . $rand;
- });
-
- \ob_start();
- $this->http->execute($route, new Request(), '1');
- $result = \ob_get_contents();
- \ob_end_clean();
-
- $this->assertEquals('x-def-y-def-' . $resource, $result);
- }
-
- public function testCanGetDefaultValueWithFunction(): void
- {
- Http::setResource('first', fn ($second) => "first-{$second}", ['second']);
- Http::setResource('second', fn () => 'second');
-
- $second = $this->http->getResource('second');
- $first = $this->http->getResource('first');
- $this->assertEquals('second', $second);
- $this->assertEquals('first-second', $first);
-
- // Default Value using function
- $route = new Route('GET', '/path');
-
- $route
- ->param('x', function ($first, $second) {
- return $first . '-' . $second;
- }, new Text(200), 'x param', true, ['first', 'second'])
- ->action(function ($x) {
- echo $x;
- });
-
- \ob_start();
- $this->http->execute($route, new Request(), '1');
- $result = \ob_get_contents();
- \ob_end_clean();
-
- $this->assertEquals('first-second-second', $result);
- }
-
public function testCanExecuteRoute(): void
{
- Http::setResource('rand', fn () => rand());
- $resource = $this->http->getResource('rand', '1');
+ $this->container->set('rand', fn () => rand());
+ $resource = $this->container->get('rand');
$this->http
->error()
@@ -169,12 +108,12 @@ public function testCanExecuteRoute(): void
});
\ob_start();
- $this->http->execute($route, new Request(), '1');
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
// With Params
- $resource = $this->http->getResource('rand', '1');
+ $resource = $this->container->get('rand');
$route = new Route('GET', '/path');
$route
@@ -193,14 +132,14 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y', 'z' => 'param-z']);
- $this->http->execute($route, $request, '1');
+ $this->http->execute($route, $request);
$result = \ob_get_contents();
\ob_end_clean();
$this->assertEquals($resource . '-param-x-param-y', $result);
// With Error
- $resource = $this->http->getResource('rand', '1');
+ $resource = $this->container->get('rand');
$route = new Route('GET', '/path');
$route
@@ -213,14 +152,14 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->http->execute($route, $request, '1');
+ $this->http->execute($route, $request);
$result = \ob_get_contents();
\ob_end_clean();
$this->assertEquals('error: Invalid `x` param: Value must be a valid string and no longer than 1 chars', $result);
// With Hooks
- $resource = $this->http->getResource('rand', '1');
+ $resource = $this->container->get('rand');
$this->http
->init()
->inject('rand')
@@ -285,17 +224,17 @@ public function testCanExecuteRoute(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->http->execute($route, $request, '1');
+ $this->http->execute($route, $request);
$result = \ob_get_contents();
\ob_end_clean();
$this->assertEquals('init-' . $resource . '-(init-api)-param-x-param-y-(shutdown-api)-shutdown', $result);
- $resource = $this->http->getResource('rand', '1');
+ $resource = $this->container->get('rand');
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['x' => 'param-x', 'y' => 'param-y']);
- $this->http->execute($homepage, $request, '1');
+ $this->http->execute($homepage, $request);
$result = \ob_get_contents();
\ob_end_clean();
@@ -325,7 +264,7 @@ public function testCanAddAndExecuteHooks()
});
\ob_start();
- $this->http->execute($route, new Request(), '1');
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -341,7 +280,7 @@ public function testCanAddAndExecuteHooks()
});
\ob_start();
- $this->http->execute($route, new Request(), '1');
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -409,7 +348,7 @@ public function testCanHookThrowExceptions()
});
\ob_start();
- $this->http->execute($route, new Request(), '1');
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -417,7 +356,7 @@ public function testCanHookThrowExceptions()
\ob_start();
$_GET['y'] = 'y-def';
- $this->http->execute($route, new Request(), '1');
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -561,7 +500,7 @@ public function testCanRunRequest(): void
});
\ob_start();
- $this->http->run(new Request(), new Response(), '1');
+ $this->http->run(new Request(), new Response());
$result = \ob_get_contents();
\ob_end_clean();
@@ -582,7 +521,7 @@ public function testWildcardRoute(): void
Http::init()
->action(function () {
$route = $this->http->getRoute();
- Http::setResource('myRoute', fn () => $route);
+ $this->container->set('myRoute', fn () => $route);
});
@@ -598,7 +537,7 @@ public function testWildcardRoute(): void
});
\ob_start();
- @$this->http->run(new Request(), new Response(), '1');
+ @$this->http->run(new Request(), new Response());
$result = \ob_get_contents();
\ob_end_clean();
@@ -607,7 +546,7 @@ public function testWildcardRoute(): void
\ob_start();
$req = new Request();
$req = $req->setMethod('OPTIONS');
- @$this->http->run($req, new Response(), '1');
+ @$this->http->run($req, new Response());
$result = \ob_get_contents();
\ob_end_clean();
@@ -631,7 +570,7 @@ public function testCallableStringParametersNotExecuted(): void
});
\ob_start();
- $this->http->execute($route, new Request(), '1');
+ $this->http->execute($route, new Request());
$result = \ob_get_contents();
\ob_end_clean();
@@ -649,7 +588,7 @@ public function testCallableStringParametersNotExecuted(): void
\ob_start();
$request = new UtopiaFPMRequestTest();
$request::_setParams(['func' => 'system']);
- $this->http->execute($route2, $request, '1');
+ $this->http->execute($route2, $request);
$result = \ob_get_contents();
\ob_end_clean();
@@ -667,7 +606,7 @@ public function testCallableStringParametersNotExecuted(): void
});
\ob_start();
- $this->http->execute($route3, new Request(), '1');
+ $this->http->execute($route3, new Request());
$result = \ob_get_contents();
\ob_end_clean();
diff --git a/tests/docker/start b/tests/docker/start
index f6df2a64..66526ef0 100755
--- a/tests/docker/start
+++ b/tests/docker/start
@@ -1,6 +1,6 @@
#!/bin/bash
-export PHP_VERSION=$PHP_VERSION
+POOL_CONF="${PHP_FPM_POOL_CONF:-/usr/local/etc/php-fpm.d/www.conf}"
chown -Rf www-data.www-data /usr/share/nginx/html/
@@ -12,13 +12,13 @@ function setEnvironmentVariable() {
fi
# Check whether variable already exists
- if ! grep -q "\[$1\]" /etc/php/$PHP_VERSION/fpm/pool.d/www.conf; then
+ if ! grep -q "\[$1\]" "$POOL_CONF"; then
# Add variable
- echo "env[$1] = $2" >> /etc/php/$PHP_VERSION/fpm/pool.d/www.conf
+ echo "env[$1] = $2" >> "$POOL_CONF"
fi
# Reset variable
- # sed -i "s/^env\[$1.*/env[$1] = $2/g" /etc/php/$PHP_VERSION/fpm/pool.d/www.conf
+ # sed -i "s/^env\[$1.*/env[$1] = $2/g" "$POOL_CONF"
}
# Start supervisord and services
diff --git a/tests/docker/supervisord.conf b/tests/docker/supervisord.conf
index 41f5c4d3..00c651f3 100644
--- a/tests/docker/supervisord.conf
+++ b/tests/docker/supervisord.conf
@@ -22,8 +22,8 @@ supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
-[program:php8-fpm]
-command=php-fpm%(ENV_PHP_VERSION)s -F
+[program:php-fpm]
+command=php-fpm -F
autostart=true
autorestart=true
priority=5
diff --git a/tests/e2e/server-fpm.php b/tests/e2e/server-fpm.php
index b886c118..eb15c7e2 100644
--- a/tests/e2e/server-fpm.php
+++ b/tests/e2e/server-fpm.php
@@ -2,9 +2,10 @@
require_once __DIR__.'/init.php';
+use Utopia\DI\Container;
use Utopia\Http\Adapter\FPM\Server;
use Utopia\Http\Http;
-$server = new Server();
+$server = new Server(new Container());
$http = new Http($server, 'UTC');
$http->start();