From e817592556f31445b2edf46fe1550376a47b61c9 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 6 Jul 2023 06:24:21 +0000 Subject: [PATCH 01/81] 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 02/81] 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 03/81] 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 04/81] 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 05/81] 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 06/81] 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 07/81] 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 08/81] 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 09/81] 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 10/81] 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 11/81] 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 12/81] 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 13/81] 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 14/81] 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 15/81] 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 16/81] 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 17/81] 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 18/81] 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 19/81] 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 20/81] 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 21/81] 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 22/81] 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 23/81] 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 24/81] 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 25/81] 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 26/81] 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: ![untitled@2x](https://user-images.githubusercontent.com/43381712/146966398-0f4af03b-213e-47d7-9002-01983053c5aa.png) @@ -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 27/81] 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 28/81] 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 29/81] 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 30/81] 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 31/81] 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 32/81] 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 33/81] 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 34/81] 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 35/81] 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 36/81] 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 37/81] 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 38/81] 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 39/81] 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 40/81] 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 41/81] 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 42/81] 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 43/81] 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 44/81] 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 45/81] 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 46/81] 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 47/81] 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 48/81] 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 49/81] 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 50/81] 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 51/81] 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 52/81] 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 53/81] 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 54/81] 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 55/81] 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 56/81] 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 57/81] 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 58/81] 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 59/81] 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 60/81] 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 61/81] 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 62/81] 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 63/81] 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 64/81] 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 65/81] 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 66/81] 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 67/81] 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 68/81] 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 69/81] 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 70/81] 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 71/81] 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 72/81] 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 73/81] 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 74/81] 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 75/81] 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 76/81] 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 77/81] 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 78/81] 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 79/81] 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 80/81] 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 81/81] 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 = []; } }