From 3fe4b68491eeea5a5396f30d8c3e3b37aa7206c0 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 3 Jan 2025 12:01:13 -0500 Subject: [PATCH 001/133] feat: integrate sessions --- composer.json | 2 +- composer.lock | 451 +++++++++++++++++++++++++++++++++----------- config/database.php | 19 +- config/session.php | 58 ++++++ 4 files changed, 412 insertions(+), 118 deletions(-) create mode 100644 config/session.php diff --git a/composer.json b/composer.json index 1d9d037..68c5d7c 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "^0.5.1" + "phenixphp/framework": "^0.5.2" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index 04f0f85..fa1276d 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": "12678b8ca569b08e5a39bea562a402ad", + "content-hash": "fa526c576a1c4753394c6ac3820d4f9c", "packages": [ { "name": "adbario/php-dot-notation", @@ -690,16 +690,16 @@ }, { "name": "amphp/http-server", - "version": "v3.4.1", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/amphp/http-server.git", - "reference": "027bd022ee76927bf1b9f0c188744af461ea9f0d" + "reference": "c60cde9a1e331f539b7ef5a7705f42092e646f90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-server/zipball/027bd022ee76927bf1b9f0c188744af461ea9f0d", - "reference": "027bd022ee76927bf1b9f0c188744af461ea9f0d", + "url": "https://api.github.com/repos/amphp/http-server/zipball/c60cde9a1e331f539b7ef5a7705f42092e646f90", + "reference": "c60cde9a1e331f539b7ef5a7705f42092e646f90", "shasum": "" }, "require": { @@ -775,7 +775,7 @@ ], "support": { "issues": "https://github.com/amphp/http-server/issues", - "source": "https://github.com/amphp/http-server/tree/v3.4.1" + "source": "https://github.com/amphp/http-server/tree/v3.4.2" }, "funding": [ { @@ -783,7 +783,7 @@ "type": "github" } ], - "time": "2024-12-16T01:30:20+00:00" + "time": "2024-12-31T16:35:28+00:00" }, { "name": "amphp/http-server-form-parser", @@ -947,6 +947,82 @@ ], "time": "2023-08-05T19:16:57+00:00" }, + { + "name": "amphp/http-server-session", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/http-server-session.git", + "reference": "88ee2106cd79a21f225bb631f8686d509002c11b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http-server-session/zipball/88ee2106cd79a21f225bb631f8686d509002c11b", + "reference": "88ee2106cd79a21f225bb631f8686d509002c11b", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/cache": "^2", + "amphp/http": "^2", + "amphp/http-server": "^3", + "amphp/serialization": "^1", + "amphp/sync": "^2", + "paragonie/constant_time_encoding": "^2.2", + "php": ">=8.1" + }, + "conflict": { + "amphp/redis": "<2 || >=3" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "amphp/redis": "^2", + "league/uri": "^6", + "phpunit/phpunit": "^9", + "psalm/phar": "^5" + }, + "suggest": { + "amphp/redis": "Allows storing session data in Redis" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Http\\Server\\Session\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": " An HTTP server plugin that simplifies session management for your applications. Effortlessly handle user sessions, securely managing data across requests.", + "homepage": "https://amphp.org/http-server-session", + "support": { + "issues": "https://github.com/amphp/http-server-session/issues", + "source": "https://github.com/amphp/http-server-session/tree/v3.0.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2023-08-20T17:32:14+00:00" + }, { "name": "amphp/log", "version": "v2.0.0", @@ -1444,6 +1520,87 @@ ], "time": "2024-04-19T03:13:44+00:00" }, + { + "name": "amphp/redis", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/redis.git", + "reference": "679350556def8f8b412a15a4b82651c4a5caa597" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/redis/zipball/679350556def8f8b412a15a4b82651c4a5caa597", + "reference": "679350556def8f8b412a15a4b82651c4a5caa597", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/cache": "^2", + "amphp/parser": "^1", + "amphp/pipeline": "^1", + "amphp/serialization": "^1", + "amphp/socket": "^2", + "amphp/sync": "^2", + "league/uri": "^6.5|^7", + "php": ">=8.1", + "psr/log": "^1|^2|^3", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "amphp/process": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "5.22" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\Redis\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Efficient asynchronous communication with Redis servers, enabling scalable and responsive data storage and retrieval.", + "homepage": "https://amphp.org/redis", + "keywords": [ + "amp", + "amphp", + "async", + "client", + "redis", + "revolt" + ], + "support": { + "issues": "https://github.com/amphp/redis/issues", + "source": "https://github.com/amphp/redis/tree/v2.0.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-08-03T18:48:06+00:00" + }, { "name": "amphp/serialization", "version": "v1.0.0", @@ -2267,16 +2424,16 @@ }, { "name": "egulias/email-validator", - "version": "4.0.2", + "version": "4.0.3", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" + "reference": "b115554301161fa21467629f1e1391c1936de517" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", - "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517", + "reference": "b115554301161fa21467629f1e1391c1936de517", "shasum": "" }, "require": { @@ -2322,7 +2479,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.3" }, "funding": [ { @@ -2330,7 +2487,7 @@ "type": "github" } ], - "time": "2023-10-06T06:47:41+00:00" + "time": "2024-12-27T00:36:43+00:00" }, { "name": "fakerphp/faker", @@ -2958,16 +3115,16 @@ }, { "name": "nesbot/carbon", - "version": "3.8.3", + "version": "3.8.4", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "f01cfa96468f4c38325f507ab81a4f1d2cd93cfe" + "reference": "129700ed449b1f02d70272d2ac802357c8c30c58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/f01cfa96468f4c38325f507ab81a4f1d2cd93cfe", - "reference": "f01cfa96468f4c38325f507ab81a4f1d2cd93cfe", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", + "reference": "129700ed449b1f02d70272d2ac802357c8c30c58", "shasum": "" }, "require": { @@ -3060,7 +3217,7 @@ "type": "tidelift" } ], - "time": "2024-12-21T18:03:19+00:00" + "time": "2024-12-27T09:25:35+00:00" }, { "name": "nikic/fast-route", @@ -3112,30 +3269,100 @@ }, "time": "2018-02-13T20:26:39+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.7.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105", + "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2024-05-08T12:18:48+00:00" + }, { "name": "phenixphp/framework", - "version": "0.5.1", + "version": "0.5.2", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "68548860670d9e2b78277b1cfd0d570b9cdf2454" + "reference": "066d5bd27e309a09c78c2b0f7db0b747ea3c184a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/68548860670d9e2b78277b1cfd0d570b9cdf2454", - "reference": "68548860670d9e2b78277b1cfd0d570b9cdf2454", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/066d5bd27e309a09c78c2b0f7db0b747ea3c184a", + "reference": "066d5bd27e309a09c78c2b0f7db0b747ea3c184a", "shasum": "" }, "require": { "adbario/php-dot-notation": "^3.1", + "amphp/cache": "^2.0", "amphp/file": "^v3.0.0", "amphp/http-client": "^v5.0.1", "amphp/http-server": "^v3.2.0", "amphp/http-server-form-parser": "^2.0", "amphp/http-server-router": "^v2.0.0", + "amphp/http-server-session": "^3.0", "amphp/log": "^v2.0.0", "amphp/mysql": "^v3.0.0", "amphp/postgres": "v2.0.0", + "amphp/redis": "^2.0", "amphp/socket": "^2.1.0", "egulias/email-validator": "^4.0", "ext-pcntl": "*", @@ -3191,9 +3418,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/0.5.1" + "source": "https://github.com/phenixphp/framework/tree/0.5.2" }, - "time": "2024-12-24T17:45:32+00:00" + "time": "2025-01-03T16:51:53+00:00" }, { "name": "phenixphp/http-cors", @@ -4016,16 +4243,16 @@ }, { "name": "symfony/console", - "version": "v6.4.15", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "f1fc6f47283e27336e7cebb9e8946c8de7bff9bd" + "reference": "799445db3f15768ecc382ac5699e6da0520a0a04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/f1fc6f47283e27336e7cebb9e8946c8de7bff9bd", - "reference": "f1fc6f47283e27336e7cebb9e8946c8de7bff9bd", + "url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", + "reference": "799445db3f15768ecc382ac5699e6da0520a0a04", "shasum": "" }, "require": { @@ -4090,7 +4317,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.15" + "source": "https://github.com/symfony/console/tree/v6.4.17" }, "funding": [ { @@ -4106,7 +4333,7 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:19:14+00:00" + "time": "2024-12-07T12:07:30+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4127,12 +4354,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -4901,12 +5128,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -5049,16 +5276,16 @@ }, { "name": "symfony/translation", - "version": "v7.2.0", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "dc89e16b44048ceecc879054e5b7f38326ab6cc5" + "reference": "e2674a30132b7cc4d74540d6c2573aa363f05923" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/dc89e16b44048ceecc879054e5b7f38326ab6cc5", - "reference": "dc89e16b44048ceecc879054e5b7f38326ab6cc5", + "url": "https://api.github.com/repos/symfony/translation/zipball/e2674a30132b7cc4d74540d6c2573aa363f05923", + "reference": "e2674a30132b7cc4d74540d6c2573aa363f05923", "shasum": "" }, "require": { @@ -5124,7 +5351,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.2.0" + "source": "https://github.com/symfony/translation/tree/v7.2.2" }, "funding": [ { @@ -5140,7 +5367,7 @@ "type": "tidelift" } ], - "time": "2024-11-12T20:47:56+00:00" + "time": "2024-12-07T08:18:10+00:00" }, { "name": "symfony/translation-contracts", @@ -5161,12 +5388,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -6296,16 +6523,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.65.0", + "version": "v3.66.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f" + "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/79d4f3e77b250a7d8043d76c6af8f0695e8a469f", - "reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/5f5f2a142ff36b93c41885bca29cc5f861c013e6", + "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6", "shasum": "" }, "require": { @@ -6331,7 +6558,7 @@ "symfony/polyfill-mbstring": "^1.28", "symfony/polyfill-php80": "^1.28", "symfony/polyfill-php81": "^1.28", - "symfony/process": "^5.4 || ^6.0 || ^7.0", + "symfony/process": "^5.4 || ^6.0 || ^7.0 <7.2", "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { @@ -6387,7 +6614,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.65.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.66.0" }, "funding": [ { @@ -6395,7 +6622,7 @@ "type": "github" } ], - "time": "2024-11-25T00:39:24+00:00" + "time": "2024-12-29T13:46:23+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -6717,16 +6944,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.3.1", + "version": "v5.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", "shasum": "" }, "require": { @@ -6769,9 +6996,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" }, - "time": "2024-10-08T18:51:32+00:00" + "time": "2024-12-30T11:07:19+00:00" }, { "name": "nunomaduro/collision", @@ -7649,16 +7876,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.13", + "version": "1.12.14", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "9b469068840cfa031e1deaf2fa1886d00e20680f" + "reference": "e73868f809e68fff33be961ad4946e2e43ec9e38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9b469068840cfa031e1deaf2fa1886d00e20680f", - "reference": "9b469068840cfa031e1deaf2fa1886d00e20680f", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e73868f809e68fff33be961ad4946e2e43ec9e38", + "reference": "e73868f809e68fff33be961ad4946e2e43ec9e38", "shasum": "" }, "require": { @@ -7703,7 +7930,7 @@ "type": "github" } ], - "time": "2024-12-17T17:00:20+00:00" + "time": "2024-12-31T07:26:13+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -8399,33 +8626,33 @@ }, { "name": "react/child-process", - "version": "v0.6.5", + "version": "v0.6.6", "source": { "type": "git", "url": "https://github.com/reactphp/child-process.git", - "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43" + "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/child-process/zipball/e71eb1aa55f057c7a4a0d08d06b0b0a484bead43", - "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159", + "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159", "shasum": "" }, "require": { "evenement/evenement": "^3.0 || ^2.0 || ^1.0", "php": ">=5.3.0", "react/event-loop": "^1.2", - "react/stream": "^1.2" + "react/stream": "^1.4" }, "require-dev": { - "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35", - "react/socket": "^1.8", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/socket": "^1.16", "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" }, "type": "library", "autoload": { "psr-4": { - "React\\ChildProcess\\": "src" + "React\\ChildProcess\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -8462,19 +8689,15 @@ ], "support": { "issues": "https://github.com/reactphp/child-process/issues", - "source": "https://github.com/reactphp/child-process/tree/v0.6.5" + "source": "https://github.com/reactphp/child-process/tree/v0.6.6" }, "funding": [ { - "url": "https://github.com/WyriHaximus", - "type": "github" - }, - { - "url": "https://github.com/clue", - "type": "github" + "url": "https://opencollective.com/reactphp", + "type": "open_collective" } ], - "time": "2022-09-16T13:41:56+00:00" + "time": "2025-01-01T16:37:48+00:00" }, { "name": "react/dns", @@ -10141,12 +10364,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -10297,12 +10520,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -10355,16 +10578,16 @@ }, { "name": "symfony/finder", - "version": "v7.2.0", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49" + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/6de263e5868b9a137602dd1e33e4d48bfae99c49", - "reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", "shasum": "" }, "require": { @@ -10399,7 +10622,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.2.0" + "source": "https://github.com/symfony/finder/tree/v7.2.2" }, "funding": [ { @@ -10415,20 +10638,20 @@ "type": "tidelift" } ], - "time": "2024-10-23T06:56:12+00:00" + "time": "2024-12-30T19:00:17+00:00" }, { "name": "symfony/http-client", - "version": "v7.2.1", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "ff4df2b68d1c67abb9fef146e6540ea16b58d99e" + "reference": "339ba21476eb184290361542f732ad12c97591ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/ff4df2b68d1c67abb9fef146e6540ea16b58d99e", - "reference": "ff4df2b68d1c67abb9fef146e6540ea16b58d99e", + "url": "https://api.github.com/repos/symfony/http-client/zipball/339ba21476eb184290361542f732ad12c97591ec", + "reference": "339ba21476eb184290361542f732ad12c97591ec", "shasum": "" }, "require": { @@ -10494,7 +10717,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.2.1" + "source": "https://github.com/symfony/http-client/tree/v7.2.2" }, "funding": [ { @@ -10510,7 +10733,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:50:44+00:00" + "time": "2024-12-30T18:35:15+00:00" }, { "name": "symfony/http-client-contracts", @@ -10735,16 +10958,16 @@ }, { "name": "symfony/process", - "version": "v7.2.0", + "version": "v7.1.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" + "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", - "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", + "url": "https://api.github.com/repos/symfony/process/zipball/42783370fda6e538771f7c7a36e9fa2ee3a84892", + "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892", "shasum": "" }, "require": { @@ -10776,7 +10999,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.0" + "source": "https://github.com/symfony/process/tree/v7.1.8" }, "funding": [ { @@ -10792,20 +11015,20 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:24:19+00:00" + "time": "2024-11-06T14:23:19+00:00" }, { "name": "symfony/stopwatch", - "version": "v7.2.0", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "696f418b0d722a4225e1c3d95489d262971ca924" + "reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/696f418b0d722a4225e1c3d95489d262971ca924", - "reference": "696f418b0d722a4225e1c3d95489d262971ca924", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/e46690d5b9d7164a6d061cab1e8d46141b9f49df", + "reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df", "shasum": "" }, "require": { @@ -10838,7 +11061,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.2.0" + "source": "https://github.com/symfony/stopwatch/tree/v7.2.2" }, "funding": [ { @@ -10854,7 +11077,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2024-12-18T14:28:33+00:00" }, { "name": "symfony/var-exporter", diff --git a/config/database.php b/config/database.php index 24d3376..68a7ea1 100644 --- a/config/database.php +++ b/config/database.php @@ -2,14 +2,14 @@ declare(strict_types=1); -use Phenix\Database\Constants\Drivers; +use Phenix\Database\Constants\Driver; return [ 'default' => env('DB_CONNECTION', fn () => 'mysql'), 'connections' => [ 'mysql' => [ - 'driver' => Drivers::MYSQL, + 'driver' => Driver::MYSQL, 'host' => env('DB_HOST', fn () => '127.0.0.1'), 'port' => env('DB_PORT', fn () => '3306'), 'database' => env('DB_DATABASE'), @@ -21,7 +21,7 @@ 'prefix' => '', ], 'postgresql' => [ - 'driver' => Drivers::POSTGRESQL, + 'driver' => Driver::POSTGRESQL, 'host' => env('DB_HOST', fn () => '127.0.0.1'), 'port' => env('DB_PORT', fn () => '3306'), 'database' => env('DB_DATABASE'), @@ -30,6 +30,19 @@ ], ], + 'redis' => [ + 'connections' => [ + 'default' => [ + 'scheme' => env('REDIS_SCHEME', fn () => 'redis'), + 'host' => env('REDIS_HOST', fn () => '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', fn () => '6379'), + 'database' => env('REDIS_DB', fn () => 0), + ], + ], + ], + 'paths' => [ 'migrations' => base_path('database' . DIRECTORY_SEPARATOR . 'migrations'), 'seeds' => base_path('database' . DIRECTORY_SEPARATOR . 'seeds'), diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..1230e84 --- /dev/null +++ b/config/session.php @@ -0,0 +1,58 @@ + env('SESSION_DRIVER', fn (): string => 'redis'), + + 'lifetime' => env('SESSION_LIFETIME', fn () => 120), + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | For "redis" session drivers, you may specify a specific connection that + | should be used to manage the sessions. This should correspond to a + | connection in your database configuration options. + */ + + 'connection' => env('SESSION_CONNECTION', fn () => 'default'), + + 'cookie_name' => env( + 'SESSION_COOKIE_NAME', + fn () => Str::slug(env('APP_NAME', fn () => 'phenix'), '_') . '_session' + ), + + 'path' => '/', + + 'domain' => env('SESSION_DOMAIN'), + + 'secure' => env('SESSION_SECURE_COOKIE'), + + 'http_only' => true, + + /* + |-------------------------------------------------------------------------- + | Same-Site Cookies + |-------------------------------------------------------------------------- + | + | Supported: "Lax", "Strict", "None" + | + */ + + 'same_site' => 'Lax', + +]; From 12c0f827bbdd346447d2da64b3ec5ebcdff8be91 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 3 Jan 2025 12:01:39 -0500 Subject: [PATCH 002/133] style: phpcs --- app/Http/Middleware/HandleCors.php | 1 - config/cors.php | 2 +- tests/Pest.php | 6 ++---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app/Http/Middleware/HandleCors.php b/app/Http/Middleware/HandleCors.php index c9f5564..1664677 100644 --- a/app/Http/Middleware/HandleCors.php +++ b/app/Http/Middleware/HandleCors.php @@ -8,5 +8,4 @@ class HandleCors extends HandleCorsBase { - } diff --git a/config/cors.php b/config/cors.php index 0fc17e5..afc624b 100644 --- a/config/cors.php +++ b/config/cors.php @@ -6,5 +6,5 @@ 'max_age' => 8600, 'allowed_headers' => ['X-Request-Headers', 'Content-Type', 'Authorization', 'X-Requested-With'], 'exposable_headers' => [], - 'allow_credentials' => false + 'allow_credentials' => false, ]; diff --git a/tests/Pest.php b/tests/Pest.php index 5033acc..18a31ea 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -11,13 +11,11 @@ | */ -use Phenix\Util\URL; +use Amp\Http\Client\HttpClientBuilder; use Amp\Http\Client\Request; use Phenix\Constants\HttpMethod; use Phenix\Testing\TestResponse; -use Amp\Http\Client\HttpClientBuilder; - - +use Phenix\Util\URL; uses(Tests\TestCase::class)->in('Unit'); uses(Tests\TestCase::class)->in('Feature'); From 92c435af9b7ee874957781c20a5a0fc3bf799ce4 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 3 Jan 2025 12:03:10 -0500 Subject: [PATCH 003/133] ci: add check coding format step --- .github/workflows/run-tests.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 9bf527e..7ca6918 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -32,6 +32,10 @@ jobs: run: | composer install --no-interaction --prefer-dist --no-progress --no-suggest + - name: Check code formatting with PHP CS Fixer + run: | + vendor/bin/php-cs-fixer fix --dry-run --diff --ansi + - name: Check quality code with PHPInsights run: | vendor/bin/phpinsights -n --ansi --format=github-action From 420ed9b7989b8254882c201da3151c00996ad945 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 3 Jan 2025 12:12:46 -0500 Subject: [PATCH 004/133] style: phpcs --- app/Http/Controllers/WelcomeController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/WelcomeController.php b/app/Http/Controllers/WelcomeController.php index 18a8fdd..a23f23d 100644 --- a/app/Http/Controllers/WelcomeController.php +++ b/app/Http/Controllers/WelcomeController.php @@ -4,8 +4,8 @@ namespace App\Http\Controllers; -use Phenix\Http\Response; use Phenix\Http\Controller; +use Phenix\Http\Response; class WelcomeController extends Controller { From f92e89396d74b013bc3645f998d4b05f93560050 Mon Sep 17 00:00:00 2001 From: FSHLL Date: Mon, 3 Mar 2025 12:00:22 -0500 Subject: [PATCH 005/133] feat: initial config for docker --- .env.example | 7 +++++-- docker-compose.yml | 30 ++++++++++++++++++++++++++++++ docker/Dockerfile | 22 ++++++++++++++++++++++ docker/entrypoint.sh | 7 +++++++ 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 docker-compose.yml create mode 100644 docker/Dockerfile create mode 100755 docker/entrypoint.sh diff --git a/.env.example b/.env.example index 53e9973..73b7c36 100644 --- a/.env.example +++ b/.env.example @@ -5,7 +5,10 @@ APP_PORT=1337 DB_CONNECTION=mysql DB_DATABASE=phenix -DB_USERNAME=root -DB_PASSWORD= +DB_USERNAME=phenix +DB_PASSWORD=secret LOG_CHANNEL=stream + +USER_UID=1000 +USER_GID=1000 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..dffd3bd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,30 @@ +services: + app: + build: + context: ./docker + args: + - USER_UID=${USER_UID} + - USER_GID=${USER_GID} + volumes: + - .:/usr/src/phenix:rw + working_dir: /usr/src/phenix + extra_hosts: + - 'host.docker.internal:host-gateway' + environment: + - APP_PORT=${APP_PORT} + - APP_ENV=${APP_ENV} + ports: + - '${APP_PORT}:${APP_PORT}' + mysql: + image: mysql:8.0 + ports: + - "${MYSQL_PORT:-3307}:3306" + environment: + MYSQL_ROOT_HOST: "%" + MYSQL_DATABASE: '${DB_DATABASE}' + MYSQL_USER: '${DB_USERNAME}' + MYSQL_PASSWORD: '${DB_PASSWORD}' + MYSQL_ALLOW_EMPTY_PASSWORD: 1 +networks: + phenix: + driver: bridge \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..ebf570d --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,22 @@ +FROM php:8.2-cli +WORKDIR /usr/src/phenix + +ARG USER_UID +ARG USER_GID + +RUN groupadd -g ${USER_GID} phenix_group && useradd -ms /bin/bash -u ${USER_UID} -g ${USER_GID} phenix_user + +RUN docker-php-ext-install pcntl pdo pdo_mysql + +RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \ + apt-get install -y nodejs + +USER phenix_user + +COPY . /usr/src/phenix + +ENV APP_PORT=${APP_PORT} + +EXPOSE ${APP_PORT} + +ENTRYPOINT ["docker/entrypoint.sh"] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 0000000..29a2f45 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ "$APP_ENV" = "production" ]; then + php public/index.php --host=0.0.0.0 --port=${APP_PORT} +else + php ./server --host=0.0.0.0 --port=${APP_PORT} +fi \ No newline at end of file From ec57e2525c8786bc237dbd236fc3babeea323dd8 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 6 Aug 2025 18:12:22 -0500 Subject: [PATCH 006/133] fix: improve server start output format --- server | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server b/server index 1f8834f..dbd009e 100644 --- a/server +++ b/server @@ -107,7 +107,8 @@ class Watcher extends Watch $this->pid = $this->serverProcess->getPid(); - echo "Server started on {$this->host}:{$this->port}" . PHP_EOL . PHP_EOL; + echo "Server started on {$this->host}:{$this->port}" . PHP_EOL; + echo "PID: {$this->pid}" . PHP_EOL . PHP_EOL; } protected function killExistingProcess() From 7b00029a86da01e048543a0c6453d8c201840afb Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 6 Aug 2025 18:12:39 -0500 Subject: [PATCH 007/133] chore: update .env.example with QUEUE_DRIVER and CORS_ORIGIN variables --- .env.example | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.env.example b/.env.example index 53e9973..934db5b 100644 --- a/.env.example +++ b/.env.example @@ -9,3 +9,7 @@ DB_USERNAME=root DB_PASSWORD= LOG_CHANNEL=stream + +QUEUE_DRIVER=parallel + +CORS_ORIGIN= From 1e406b62d4bcf7d0c7918e420f1355a7d917b503 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 6 Aug 2025 18:12:49 -0500 Subject: [PATCH 008/133] Implement code changes to enhance functionality and improve performance --- composer.json | 2 +- composer.lock | 3256 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 2132 insertions(+), 1126 deletions(-) diff --git a/composer.json b/composer.json index 68c5d7c..74de825 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "^0.5.2" + "phenixphp/framework": "dev-feature/queue-system" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index fa1276d..509ab67 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": "fa526c576a1c4753394c6ac3820d4f9c", + "content-hash": "2ed9708a8850061a7a9063d9d58890cf", "packages": [ { "name": "adbario/php-dot-notation", @@ -62,16 +62,16 @@ }, { "name": "amphp/amp", - "version": "v3.0.2", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "138801fb68cfc9c329da8a7b39d01ce7291ee4b0" + "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/138801fb68cfc9c329da8a7b39d01ce7291ee4b0", - "reference": "138801fb68cfc9c329da8a7b39d01ce7291ee4b0", + "url": "https://api.github.com/repos/amphp/amp/zipball/7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9", + "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9", "shasum": "" }, "require": { @@ -131,7 +131,7 @@ ], "support": { "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v3.0.2" + "source": "https://github.com/amphp/amp/tree/v3.1.0" }, "funding": [ { @@ -139,20 +139,20 @@ "type": "github" } ], - "time": "2024-05-10T21:37:46+00:00" + "time": "2025-01-26T16:07:39+00:00" }, { "name": "amphp/byte-stream", - "version": "v2.1.1", + "version": "v2.1.2", "source": { "type": "git", "url": "https://github.com/amphp/byte-stream.git", - "reference": "daa00f2efdbd71565bf64ffefa89e37542addf93" + "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/daa00f2efdbd71565bf64ffefa89e37542addf93", - "reference": "daa00f2efdbd71565bf64ffefa89e37542addf93", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/55a6bd071aec26fa2a3e002618c20c35e3df1b46", + "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46", "shasum": "" }, "require": { @@ -206,7 +206,7 @@ ], "support": { "issues": "https://github.com/amphp/byte-stream/issues", - "source": "https://github.com/amphp/byte-stream/tree/v2.1.1" + "source": "https://github.com/amphp/byte-stream/tree/v2.1.2" }, "funding": [ { @@ -214,7 +214,7 @@ "type": "github" } ], - "time": "2024-02-17T04:49:38+00:00" + "time": "2025-03-16T17:10:27+00:00" }, { "name": "amphp/cache", @@ -283,16 +283,16 @@ }, { "name": "amphp/dns", - "version": "v2.3.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/amphp/dns.git", - "reference": "166c43737cef1b77782c648a9d9ed11ee0c9859f" + "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/dns/zipball/166c43737cef1b77782c648a9d9ed11ee0c9859f", - "reference": "166c43737cef1b77782c648a9d9ed11ee0c9859f", + "url": "https://api.github.com/repos/amphp/dns/zipball/78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", + "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", "shasum": "" }, "require": { @@ -360,7 +360,7 @@ ], "support": { "issues": "https://github.com/amphp/dns/issues", - "source": "https://github.com/amphp/dns/tree/v2.3.0" + "source": "https://github.com/amphp/dns/tree/v2.4.0" }, "funding": [ { @@ -368,7 +368,7 @@ "type": "github" } ], - "time": "2024-12-21T01:15:34+00:00" + "time": "2025-01-19T15:43:40+00:00" }, { "name": "amphp/file", @@ -595,16 +595,16 @@ }, { "name": "amphp/http-client", - "version": "v5.2.1", + "version": "v5.3.3", "source": { "type": "git", "url": "https://github.com/amphp/http-client.git", - "reference": "2117f7e7cd1ecf35d4d0daea1ba5dc6fd318b114" + "reference": "09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-client/zipball/2117f7e7cd1ecf35d4d0daea1ba5dc6fd318b114", - "reference": "2117f7e7cd1ecf35d4d0daea1ba5dc6fd318b114", + "url": "https://api.github.com/repos/amphp/http-client/zipball/09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc", + "reference": "09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc", "shasum": "" }, "require": { @@ -622,8 +622,11 @@ "psr/http-message": "^1 | ^2", "revolt/event-loop": "^1" }, + "conflict": { + "amphp/file": "<3 | >=5" + }, "require-dev": { - "amphp/file": "^3", + "amphp/file": "^3 | ^4", "amphp/http-server": "^3", "amphp/php-cs-fixer-config": "^2", "amphp/phpunit-util": "^3", @@ -678,7 +681,7 @@ ], "support": { "issues": "https://github.com/amphp/http-client/issues", - "source": "https://github.com/amphp/http-client/tree/v5.2.1" + "source": "https://github.com/amphp/http-client/tree/v5.3.3" }, "funding": [ { @@ -686,20 +689,20 @@ "type": "github" } ], - "time": "2024-12-13T16:16:08+00:00" + "time": "2025-05-21T03:24:20+00:00" }, { "name": "amphp/http-server", - "version": "v3.4.2", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/amphp/http-server.git", - "reference": "c60cde9a1e331f539b7ef5a7705f42092e646f90" + "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-server/zipball/c60cde9a1e331f539b7ef5a7705f42092e646f90", - "reference": "c60cde9a1e331f539b7ef5a7705f42092e646f90", + "url": "https://api.github.com/repos/amphp/http-server/zipball/7aa962b0569f664af3ba23bc819f2a69884329cd", + "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd", "shasum": "" }, "require": { @@ -775,7 +778,7 @@ ], "support": { "issues": "https://github.com/amphp/http-server/issues", - "source": "https://github.com/amphp/http-server/tree/v3.4.2" + "source": "https://github.com/amphp/http-server/tree/v3.4.3" }, "funding": [ { @@ -783,7 +786,7 @@ "type": "github" } ], - "time": "2024-12-31T16:35:28+00:00" + "time": "2025-05-18T15:43:42+00:00" }, { "name": "amphp/http-server-form-parser", @@ -1315,16 +1318,16 @@ }, { "name": "amphp/pipeline", - "version": "v1.2.1", + "version": "v1.2.3", "source": { "type": "git", "url": "https://github.com/amphp/pipeline.git", - "reference": "66c095673aa5b6e689e63b52d19e577459129ab3" + "reference": "7b52598c2e9105ebcddf247fc523161581930367" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/pipeline/zipball/66c095673aa5b6e689e63b52d19e577459129ab3", - "reference": "66c095673aa5b6e689e63b52d19e577459129ab3", + "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367", + "reference": "7b52598c2e9105ebcddf247fc523161581930367", "shasum": "" }, "require": { @@ -1370,7 +1373,7 @@ ], "support": { "issues": "https://github.com/amphp/pipeline/issues", - "source": "https://github.com/amphp/pipeline/tree/v1.2.1" + "source": "https://github.com/amphp/pipeline/tree/v1.2.3" }, "funding": [ { @@ -1378,7 +1381,7 @@ "type": "github" } ], - "time": "2024-07-04T00:56:47+00:00" + "time": "2025-03-16T16:33:53+00:00" }, { "name": "amphp/postgres", @@ -1522,16 +1525,16 @@ }, { "name": "amphp/redis", - "version": "v2.0.1", + "version": "v2.0.3", "source": { "type": "git", "url": "https://github.com/amphp/redis.git", - "reference": "679350556def8f8b412a15a4b82651c4a5caa597" + "reference": "1572c2fec2849d272570919e998f9a3c1a5b1703" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/redis/zipball/679350556def8f8b412a15a4b82651c4a5caa597", - "reference": "679350556def8f8b412a15a4b82651c4a5caa597", + "url": "https://api.github.com/repos/amphp/redis/zipball/1572c2fec2849d272570919e998f9a3c1a5b1703", + "reference": "1572c2fec2849d272570919e998f9a3c1a5b1703", "shasum": "" }, "require": { @@ -1543,7 +1546,7 @@ "amphp/serialization": "^1", "amphp/socket": "^2", "amphp/sync": "^2", - "league/uri": "^6.5|^7", + "league/uri": "^7", "php": ">=8.1", "psr/log": "^1|^2|^3", "revolt/event-loop": "^1" @@ -1591,7 +1594,7 @@ ], "support": { "issues": "https://github.com/amphp/redis/issues", - "source": "https://github.com/amphp/redis/tree/v2.0.1" + "source": "https://github.com/amphp/redis/tree/v2.0.3" }, "funding": [ { @@ -1599,7 +1602,7 @@ "type": "github" } ], - "time": "2024-08-03T18:48:06+00:00" + "time": "2025-01-15T04:14:11+00:00" }, { "name": "amphp/serialization", @@ -1799,16 +1802,16 @@ }, { "name": "amphp/sql-common", - "version": "v2.0.2", + "version": "v2.0.3", "source": { "type": "git", "url": "https://github.com/amphp/sql-common.git", - "reference": "069183d57f17f85c60842ea3a8ce5ff52dba5399" + "reference": "0c926e0348c238c61bead25af5c2fa0d5afaed8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/sql-common/zipball/069183d57f17f85c60842ea3a8ce5ff52dba5399", - "reference": "069183d57f17f85c60842ea3a8ce5ff52dba5399", + "url": "https://api.github.com/repos/amphp/sql-common/zipball/0c926e0348c238c61bead25af5c2fa0d5afaed8d", + "reference": "0c926e0348c238c61bead25af5c2fa0d5afaed8d", "shasum": "" }, "require": { @@ -1843,7 +1846,7 @@ ], "support": { "issues": "https://github.com/amphp/sql-common/issues", - "source": "https://github.com/amphp/sql-common/tree/v2.0.2" + "source": "https://github.com/amphp/sql-common/tree/v2.0.3" }, "funding": [ { @@ -1851,7 +1854,7 @@ "type": "github" } ], - "time": "2024-10-27T16:04:14+00:00" + "time": "2025-06-07T15:35:29+00:00" }, { "name": "amphp/sync", @@ -1928,18 +1931,143 @@ ], "time": "2024-08-03T19:31:26+00:00" }, + { + "name": "async-aws/core", + "version": "1.26.0", + "source": { + "type": "git", + "url": "https://github.com/async-aws/core.git", + "reference": "58ab79116d990e7053b2e31162f47df4223148c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/async-aws/core/zipball/58ab79116d990e7053b2e31162f47df4223148c5", + "reference": "58ab79116d990e7053b2e31162f47df4223148c5", + "shasum": "" + }, + "require": { + "ext-hash": "*", + "ext-json": "*", + "ext-simplexml": "*", + "php": "^7.2.5 || ^8.0", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/http-client": "^4.4.16 || ^5.1.7 || ^6.0 || ^7.0", + "symfony/http-client-contracts": "^1.1.8 || ^2.0 || ^3.0", + "symfony/service-contracts": "^1.0 || ^2.0 || ^3.0" + }, + "conflict": { + "async-aws/s3": "<1.1", + "symfony/http-client": "5.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.26-dev" + } + }, + "autoload": { + "psr-4": { + "AsyncAws\\Core\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Core package to integrate with AWS. This is a lightweight AWS SDK provider by AsyncAws.", + "keywords": [ + "amazon", + "async-aws", + "aws", + "sdk", + "sts" + ], + "support": { + "source": "https://github.com/async-aws/core/tree/1.26.0" + }, + "funding": [ + { + "url": "https://github.com/jderusse", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2025-05-12T09:35:01+00:00" + }, + { + "name": "async-aws/ses", + "version": "1.12.0", + "source": { + "type": "git", + "url": "https://github.com/async-aws/ses.git", + "reference": "904ee7b5c07d865c20db4c06c3c0b97e7035673d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/async-aws/ses/zipball/904ee7b5c07d865c20db4c06c3c0b97e7035673d", + "reference": "904ee7b5c07d865c20db4c06c3c0b97e7035673d", + "shasum": "" + }, + "require": { + "async-aws/core": "^1.9", + "ext-json": "*", + "php": "^7.2.5 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "AsyncAws\\Ses\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "SES client, part of the AWS SDK provided by AsyncAws.", + "keywords": [ + "amazon", + "async-aws", + "aws", + "sdk", + "ses" + ], + "support": { + "source": "https://github.com/async-aws/ses/tree/1.12.0" + }, + "funding": [ + { + "url": "https://github.com/jderusse", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2025-05-12T09:35:01+00:00" + }, { "name": "cakephp/chronos", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/cakephp/chronos.git", - "reference": "786d69e1ee4b735765cbdb5521b9603e9b98d650" + "reference": "6c820947bc1372a250288ab164ec1b3bb7afab39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/chronos/zipball/786d69e1ee4b735765cbdb5521b9603e9b98d650", - "reference": "786d69e1ee4b735765cbdb5521b9603e9b98d650", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/6c820947bc1372a250288ab164ec1b3bb7afab39", + "reference": "6c820947bc1372a250288ab164ec1b3bb7afab39", "shasum": "" }, "require": { @@ -1985,24 +2113,24 @@ "issues": "https://github.com/cakephp/chronos/issues", "source": "https://github.com/cakephp/chronos" }, - "time": "2024-07-18T03:18:04+00:00" + "time": "2025-06-28T11:35:59+00:00" }, { "name": "cakephp/core", - "version": "5.1.4", + "version": "5.2.6", "source": { "type": "git", "url": "https://github.com/cakephp/core.git", - "reference": "fdd2ab323284cc8475decaeaad4a3398aa90ff91" + "reference": "93f395b6d741775320c4b782ddb47b5c2906e7ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/core/zipball/fdd2ab323284cc8475decaeaad4a3398aa90ff91", - "reference": "fdd2ab323284cc8475decaeaad4a3398aa90ff91", + "url": "https://api.github.com/repos/cakephp/core/zipball/93f395b6d741775320c4b782ddb47b5c2906e7ad", + "reference": "93f395b6d741775320c4b782ddb47b5c2906e7ad", "shasum": "" }, "require": { - "cakephp/utility": "^5.1", + "cakephp/utility": "5.2.*@dev", "league/container": "^4.2", "php": ">=8.1", "psr/container": "^1.1 || ^2.0" @@ -2016,6 +2144,11 @@ "league/container": "To use Container and ServiceProvider classes" }, "type": "library", + "extra": { + "branch-alias": { + "dev-5.x": "5.2.x-dev" + } + }, "autoload": { "files": [ "functions.php" @@ -2047,38 +2180,43 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/core" }, - "time": "2024-11-30T18:47:29+00:00" + "time": "2025-07-20T02:02:49+00:00" }, { "name": "cakephp/database", - "version": "5.1.4", + "version": "5.2.6", "source": { "type": "git", "url": "https://github.com/cakephp/database.git", - "reference": "3a872d4ef14424679d30d2045eaca2643c967d64" + "reference": "1a2b357ed2deae8797c4ccb7a8062b1bdb5e27a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/database/zipball/3a872d4ef14424679d30d2045eaca2643c967d64", - "reference": "3a872d4ef14424679d30d2045eaca2643c967d64", + "url": "https://api.github.com/repos/cakephp/database/zipball/1a2b357ed2deae8797c4ccb7a8062b1bdb5e27a2", + "reference": "1a2b357ed2deae8797c4ccb7a8062b1bdb5e27a2", "shasum": "" }, "require": { "cakephp/chronos": "^3.1", - "cakephp/core": "^5.1", - "cakephp/datasource": "^5.1", + "cakephp/core": "5.2.*@dev", + "cakephp/datasource": "5.2.*@dev", "php": ">=8.1", "psr/log": "^3.0" }, "require-dev": { - "cakephp/i18n": "^5.1", - "cakephp/log": "^5.1" + "cakephp/i18n": "5.2.*@dev", + "cakephp/log": "5.2.*@dev" }, "suggest": { "cakephp/i18n": "If you are using locale-aware datetime formats.", "cakephp/log": "If you want to use query logging without providing a logger yourself." }, "type": "library", + "extra": { + "branch-alias": { + "dev-5.x": "5.2.x-dev" + } + }, "autoload": { "psr-4": { "Cake\\Database\\": "." @@ -2109,31 +2247,31 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/database" }, - "time": "2024-12-12T13:08:46+00:00" + "time": "2025-07-20T02:02:49+00:00" }, { "name": "cakephp/datasource", - "version": "5.1.4", + "version": "5.2.6", "source": { "type": "git", "url": "https://github.com/cakephp/datasource.git", - "reference": "34b9617febd47649011e8914a4dbb21194a78504" + "reference": "4d40b398897ada47569e82b351cabf00e37b2ba1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/datasource/zipball/34b9617febd47649011e8914a4dbb21194a78504", - "reference": "34b9617febd47649011e8914a4dbb21194a78504", + "url": "https://api.github.com/repos/cakephp/datasource/zipball/4d40b398897ada47569e82b351cabf00e37b2ba1", + "reference": "4d40b398897ada47569e82b351cabf00e37b2ba1", "shasum": "" }, "require": { - "cakephp/core": "^5.1", + "cakephp/core": "5.2.*@dev", "php": ">=8.1", "psr/simple-cache": "^2.0 || ^3.0" }, "require-dev": { - "cakephp/cache": "^5.1", - "cakephp/collection": "^5.1", - "cakephp/utility": "^5.1" + "cakephp/cache": "5.2.*@dev", + "cakephp/collection": "5.2.*@dev", + "cakephp/utility": "5.2.*@dev" }, "suggest": { "cakephp/cache": "If you decide to use Query caching.", @@ -2141,6 +2279,11 @@ "cakephp/utility": "If you decide to use EntityTrait." }, "type": "library", + "extra": { + "branch-alias": { + "dev-5.x": "5.2.x-dev" + } + }, "autoload": { "psr-4": { "Cake\\Datasource\\": "." @@ -2171,24 +2314,24 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/datasource" }, - "time": "2024-12-12T02:27:02+00:00" + "time": "2025-07-20T02:02:49+00:00" }, { "name": "cakephp/utility", - "version": "5.1.4", + "version": "5.2.6", "source": { "type": "git", "url": "https://github.com/cakephp/utility.git", - "reference": "943342ca3c0fc3cccb9f789340ff7eb5eceb1839" + "reference": "3188be6abdbe27f85a44c2d317477dc7b43582eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/utility/zipball/943342ca3c0fc3cccb9f789340ff7eb5eceb1839", - "reference": "943342ca3c0fc3cccb9f789340ff7eb5eceb1839", + "url": "https://api.github.com/repos/cakephp/utility/zipball/3188be6abdbe27f85a44c2d317477dc7b43582eb", + "reference": "3188be6abdbe27f85a44c2d317477dc7b43582eb", "shasum": "" }, "require": { - "cakephp/core": "^5.1", + "cakephp/core": "5.2.*@dev", "php": ">=8.1" }, "suggest": { @@ -2196,6 +2339,11 @@ "lib-ICU": "To use Text::transliterate() or Text::slug()" }, "type": "library", + "extra": { + "branch-alias": { + "dev-5.x": "5.2.x-dev" + } + }, "autoload": { "files": [ "bootstrap.php" @@ -2230,7 +2378,7 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/utility" }, - "time": "2024-11-30T18:47:29+00:00" + "time": "2025-07-20T02:02:49+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -2424,16 +2572,16 @@ }, { "name": "egulias/email-validator", - "version": "4.0.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "b115554301161fa21467629f1e1391c1936de517" + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517", - "reference": "b115554301161fa21467629f1e1391c1936de517", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", "shasum": "" }, "require": { @@ -2479,7 +2627,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.3" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" }, "funding": [ { @@ -2487,7 +2635,7 @@ "type": "github" } ], - "time": "2024-12-27T00:36:43+00:00" + "time": "2025-03-06T22:45:56+00:00" }, { "name": "fakerphp/faker", @@ -2615,36 +2763,56 @@ "time": "2024-07-20T21:45:45+00:00" }, { - "name": "kelunik/certificate", - "version": "v1.1.3", + "name": "guzzlehttp/guzzle", + "version": "7.9.3", "source": { "type": "git", - "url": "https://github.com/kelunik/certificate.git", - "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e" + "url": "https://github.com/guzzle/guzzle.git", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e", - "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", "shasum": "" }, "require": { - "ext-openssl": "*", - "php": ">=7.0" + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "phpunit/phpunit": "^6 | 7 | ^8 | ^9" + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.x-dev" + "bamarni-bin": { + "bin-links": true, + "forward-command": false } }, "autoload": { + "files": [ + "src/functions_include.php" + ], "psr-4": { - "Kelunik\\Certificate\\": "src" + "GuzzleHttp\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2653,71 +2821,104 @@ ], "authors": [ { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], - "description": "Access certificate details and transform between different formats.", + "description": "Guzzle is a PHP HTTP client library", "keywords": [ - "DER", - "certificate", - "certificates", - "openssl", - "pem", - "x509" + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" ], "support": { - "issues": "https://github.com/kelunik/certificate/issues", - "source": "https://github.com/kelunik/certificate/tree/v1.1.3" + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.3" }, - "time": "2023-02-03T21:26:53+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2025-03-27T13:37:11+00:00" }, { - "name": "league/container", - "version": "4.2.4", + "name": "guzzlehttp/promises", + "version": "2.2.0", "source": { "type": "git", - "url": "https://github.com/thephpleague/container.git", - "reference": "7ea728b013b9a156c409c6f0fc3624071b742dec" + "url": "https://github.com/guzzle/promises.git", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/container/zipball/7ea728b013b9a156c409c6f0fc3624071b742dec", - "reference": "7ea728b013b9a156c409c6f0fc3624071b742dec", + "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "psr/container": "^1.1 || ^2.0" - }, - "provide": { - "psr/container-implementation": "^1.0" - }, - "replace": { - "orno/di": "~2.0" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "nette/php-generator": "^3.4", - "nikic/php-parser": "^4.10", - "phpstan/phpstan": "^0.12.47", - "phpunit/phpunit": "^8.5.17", - "roave/security-advisories": "dev-latest", - "scrutinizer/ocular": "^1.8", - "squizlabs/php_codesniffer": "^3.6" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "type": "library", "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev", - "dev-2.x": "2.x-dev", - "dev-3.x": "3.x-dev", - "dev-4.x": "4.x-dev", - "dev-master": "4.x-dev" + "bamarni-bin": { + "bin-links": true, + "forward-command": false } }, "autoload": { "psr-4": { - "League\\Container\\": "src" + "GuzzleHttp\\Promise\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2726,57 +2927,329 @@ ], "authors": [ { - "name": "Phil Bennett", - "email": "mail@philbennett.co.uk", - "role": "Developer" + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], - "description": "A fast and intuitive dependency injection container.", - "homepage": "https://github.com/thephpleague/container", + "description": "Guzzle promises library", "keywords": [ - "container", - "dependency", - "di", - "injection", - "league", - "provider", - "service" + "promise" ], "support": { - "issues": "https://github.com/thephpleague/container/issues", - "source": "https://github.com/thephpleague/container/tree/4.2.4" + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.2.0" }, "funding": [ { - "url": "https://github.com/philipobenito", + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" } ], - "time": "2024-11-10T12:42:13+00:00" + "time": "2025-03-27T13:27:01+00:00" }, { - "name": "league/uri", - "version": "7.5.1", + "name": "guzzlehttp/psr7", + "version": "2.7.1", "source": { "type": "git", - "url": "https://github.com/thephpleague/uri.git", - "reference": "81fb5145d2644324614cc532b28efd0215bda430" + "url": "https://github.com/guzzle/psr7.git", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", - "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.5", - "php": "^8.1" + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" }, - "conflict": { - "league/uri-schemes": "^1.0" + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "suggest": { - "ext-bcmath": "to improve IPV4 host parsing", + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-03-27T12:30:47+00:00" + }, + { + "name": "kelunik/certificate", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/kelunik/certificate.git", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=7.0" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^6 | 7 | ^8 | ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Kelunik\\Certificate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Access certificate details and transform between different formats.", + "keywords": [ + "DER", + "certificate", + "certificates", + "openssl", + "pem", + "x509" + ], + "support": { + "issues": "https://github.com/kelunik/certificate/issues", + "source": "https://github.com/kelunik/certificate/tree/v1.1.3" + }, + "time": "2023-02-03T21:26:53+00:00" + }, + { + "name": "league/container", + "version": "4.2.5", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/container.git", + "reference": "d3cebb0ff4685ff61c749e54b27db49319e2ec00" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/container/zipball/d3cebb0ff4685ff61c749e54b27db49319e2ec00", + "reference": "d3cebb0ff4685ff61c749e54b27db49319e2ec00", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "psr/container": "^1.1 || ^2.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "replace": { + "orno/di": "~2.0" + }, + "require-dev": { + "nette/php-generator": "^3.4", + "nikic/php-parser": "^4.10", + "phpstan/phpstan": "^0.12.47", + "phpunit/phpunit": "^8.5.17", + "roave/security-advisories": "dev-latest", + "scrutinizer/ocular": "^1.8", + "squizlabs/php_codesniffer": "^3.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev", + "dev-2.x": "2.x-dev", + "dev-3.x": "3.x-dev", + "dev-4.x": "4.x-dev", + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Container\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Phil Bennett", + "email": "mail@philbennett.co.uk", + "role": "Developer" + } + ], + "description": "A fast and intuitive dependency injection container.", + "homepage": "https://github.com/thephpleague/container", + "keywords": [ + "container", + "dependency", + "di", + "injection", + "league", + "provider", + "service" + ], + "support": { + "issues": "https://github.com/thephpleague/container/issues", + "source": "https://github.com/thephpleague/container/tree/4.2.5" + }, + "funding": [ + { + "url": "https://github.com/philipobenito", + "type": "github" + } + ], + "time": "2025-05-20T12:55:37+00:00" + }, + { + "name": "league/uri", + "version": "7.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "81fb5145d2644324614cc532b28efd0215bda430" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", + "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.5", + "php": "^8.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", "ext-fileinfo": "to create Data URI from file contennts", "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", @@ -3012,16 +3485,16 @@ }, { "name": "monolog/monolog", - "version": "3.8.1", + "version": "3.9.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4" + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/aef6ee73a77a66e404dd6540934a9ef1b3c855b4", - "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", "shasum": "" }, "require": { @@ -3099,7 +3572,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.8.1" + "source": "https://github.com/Seldaek/monolog/tree/3.9.0" }, "funding": [ { @@ -3111,20 +3584,20 @@ "type": "tidelift" } ], - "time": "2024-12-05T17:15:07+00:00" + "time": "2025-03-24T10:02:05+00:00" }, { "name": "nesbot/carbon", - "version": "3.8.4", + "version": "3.10.2", "source": { "type": "git", - "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "129700ed449b1f02d70272d2ac802357c8c30c58" + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", - "reference": "129700ed449b1f02d70272d2ac802357c8c30c58", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", "shasum": "" }, "require": { @@ -3132,9 +3605,9 @@ "ext-json": "*", "php": "^8.1", "psr/clock": "^1.0", - "symfony/clock": "^6.3 || ^7.0", + "symfony/clock": "^6.3.12 || ^7.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" }, "provide": { "psr/clock-implementation": "1.0" @@ -3142,14 +3615,13 @@ "require-dev": { "doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/orm": "^2.15.2 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.57.2", + "friendsofphp/php-cs-fixer": "^3.75.0", "kylekatarnls/multi-tester": "^2.5.3", - "ondrejmirtes/better-reflection": "^6.25.0.4", "phpmd/phpmd": "^2.15.0", - "phpstan/extension-installer": "^1.3.1", - "phpstan/phpstan": "^1.11.2", - "phpunit/phpunit": "^10.5.20", - "squizlabs/php_codesniffer": "^3.9.0" + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.17", + "phpunit/phpunit": "^10.5.46", + "squizlabs/php_codesniffer": "^3.13.0" }, "bin": [ "bin/carbon" @@ -3200,8 +3672,8 @@ ], "support": { "docs": "https://carbon.nesbot.com/docs", - "issues": "https://github.com/briannesbitt/Carbon/issues", - "source": "https://github.com/briannesbitt/Carbon" + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" }, "funding": [ { @@ -3217,7 +3689,7 @@ "type": "tidelift" } ], - "time": "2024-12-27T09:25:35+00:00" + "time": "2025-08-02T09:36:06+00:00" }, { "name": "nikic/fast-route", @@ -3338,16 +3810,16 @@ }, { "name": "phenixphp/framework", - "version": "0.5.2", + "version": "dev-feature/queue-system", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "066d5bd27e309a09c78c2b0f7db0b747ea3c184a" + "reference": "5b6914812632e8349dd94e5b5ff2e5540155a713" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/066d5bd27e309a09c78c2b0f7db0b747ea3c184a", - "reference": "066d5bd27e309a09c78c2b0f7db0b747ea3c184a", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/5b6914812632e8349dd94e5b5ff2e5540155a713", + "reference": "5b6914812632e8349dd94e5b5ff2e5540155a713", "shasum": "" }, "require": { @@ -3361,6 +3833,7 @@ "amphp/http-server-session": "^3.0", "amphp/log": "^v2.0.0", "amphp/mysql": "^v3.0.0", + "amphp/parallel": "^2.3", "amphp/postgres": "v2.0.0", "amphp/redis": "^2.0", "amphp/socket": "^2.1.0", @@ -3372,10 +3845,14 @@ "phenixphp/http-cors": "^0.1.0", "php": "^8.2", "ramsey/collection": "^2.0", + "resend/resend-php": "^0.16.0", "robmorgan/phinx": "^0.15.2", + "symfony/amazon-mailer": "^7.2", "symfony/console": "^6.1", + "symfony/mailer": "^7.2", + "symfony/resend-mailer": "^7.2", "symfony/uid": "^7.1", - "symfony/var-dumper": "^7.0", + "symfony/var-dumper": "^7.2.0", "vlucas/phpdotenv": "^5.4" }, "require-dev": { @@ -3383,7 +3860,6 @@ "friendsofphp/php-cs-fixer": "^3.11", "mockery/mockery": "^1.6", "nunomaduro/collision": "^6.3", - "nunomaduro/phpinsights": "^2.6", "pestphp/pest": "^1.22", "pestphp/pest-plugin-faker": "^1.0", "pestphp/pest-plugin-global-assertions": "^1.0", @@ -3418,9 +3894,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/0.5.2" + "source": "https://github.com/phenixphp/framework/tree/feature/queue-system" }, - "time": "2025-01-03T16:51:53+00:00" + "time": "2025-08-06T22:41:55+00:00" }, { "name": "phenixphp/http-cors", @@ -3536,26 +4012,31 @@ "time": "2024-07-20T21:41:07+00:00" }, { - "name": "psr/clock", - "version": "1.0.0", + "name": "psr/cache", + "version": "3.0.0", "source": { "type": "git", - "url": "https://github.com/php-fig/clock.git", - "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", - "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", "shasum": "" }, "require": { - "php": "^7.0 || ^8.0" + "php": ">=8.0.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "Psr\\Clock\\": "src/" + "Psr\\Cache\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3568,27 +4049,71 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interface for reading the clock.", - "homepage": "https://github.com/php-fig/clock", + "description": "Common interface for caching libraries", "keywords": [ - "clock", - "now", + "cache", "psr", - "psr-20", - "time" + "psr-6" ], "support": { - "issues": "https://github.com/php-fig/clock/issues", - "source": "https://github.com/php-fig/clock/tree/1.0.0" + "source": "https://github.com/php-fig/cache/tree/3.0.0" }, - "time": "2022-11-25T14:36:26+00:00" + "time": "2021-02-03T23:26:27+00:00" }, { - "name": "psr/container", - "version": "2.0.2", + "name": "psr/clock", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/php-fig/container.git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { @@ -3636,6 +4161,108 @@ }, "time": "2021-11-05T16:47:00+00:00" }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, { "name": "psr/http-factory", "version": "1.1.0", @@ -3845,18 +4472,62 @@ }, "time": "2021-10-29T13:26:27+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "ramsey/collection", - "version": "2.0.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5" + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", - "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", + "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2", "shasum": "" }, "require": { @@ -3864,25 +4535,22 @@ }, "require-dev": { "captainhook/plugin-composer": "^5.3", - "ergebnis/composer-normalize": "^2.28.3", - "fakerphp/faker": "^1.21", + "ergebnis/composer-normalize": "^2.45", + "fakerphp/faker": "^1.24", "hamcrest/hamcrest-php": "^2.0", - "jangregor/phpstan-prophecy": "^1.0", - "mockery/mockery": "^1.5", + "jangregor/phpstan-prophecy": "^2.1", + "mockery/mockery": "^1.6", "php-parallel-lint/php-console-highlighter": "^1.0", - "php-parallel-lint/php-parallel-lint": "^1.3", - "phpcsstandards/phpcsutils": "^1.0.0-rc1", - "phpspec/prophecy-phpunit": "^2.0", - "phpstan/extension-installer": "^1.2", - "phpstan/phpstan": "^1.9", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5", - "psalm/plugin-mockery": "^1.1", - "psalm/plugin-phpunit": "^0.18.4", - "ramsey/coding-standard": "^2.0.3", - "ramsey/conventional-commits": "^1.3", - "vimeo/psalm": "^5.4" + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpspec/prophecy-phpunit": "^2.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5", + "ramsey/coding-standard": "^2.3", + "ramsey/conventional-commits": "^1.6", + "roave/security-advisories": "dev-latest" }, "type": "library", "extra": { @@ -3920,32 +4588,79 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/2.0.0" + "source": "https://github.com/ramsey/collection/tree/2.1.1" }, - "funding": [ - { - "url": "https://github.com/ramsey", - "type": "github" - }, + "time": "2025-03-22T05:38:12+00:00" + }, + { + "name": "resend/resend-php", + "version": "v0.16.0", + "source": { + "type": "git", + "url": "https://github.com/resend/resend-php.git", + "reference": "6e9be898c9e0035a5da3c2904e86d0b12999c2fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/resend/resend-php/zipball/6e9be898c9e0035a5da3c2904e86d0b12999c2fc", + "reference": "6e9be898c9e0035a5da3c2904e86d0b12999c2fc", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^7.5", + "php": "^8.1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.13", + "mockery/mockery": "^1.6", + "pestphp/pest": "^2.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Resend.php" + ], + "psr-4": { + "Resend\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", - "type": "tidelift" + "name": "Resend and contributors", + "homepage": "https://github.com/resend/resend-php/contributors" } ], - "time": "2022-12-31T21:50:55+00:00" + "description": "Resend PHP library.", + "homepage": "https://resend.com/", + "keywords": [ + "api", + "client", + "php", + "resend", + "sdk" + ], + "support": { + "issues": "https://github.com/resend/resend-php/issues", + "source": "https://github.com/resend/resend-php/tree/v0.16.0" + }, + "time": "2025-03-24T22:12:48+00:00" }, { "name": "revolt/event-loop", - "version": "v1.0.6", + "version": "v1.0.7", "source": { "type": "git", "url": "https://github.com/revoltphp/event-loop.git", - "reference": "25de49af7223ba039f64da4ae9a28ec2d10d0254" + "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/25de49af7223ba039f64da4ae9a28ec2d10d0254", - "reference": "25de49af7223ba039f64da4ae9a28ec2d10d0254", + "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3", + "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3", "shasum": "" }, "require": { @@ -4002,9 +4717,9 @@ ], "support": { "issues": "https://github.com/revoltphp/event-loop/issues", - "source": "https://github.com/revoltphp/event-loop/tree/v1.0.6" + "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7" }, - "time": "2023-11-30T05:34:44+00:00" + "time": "2025-01-25T19:27:39+00:00" }, { "name": "robmorgan/phinx", @@ -4093,34 +4808,31 @@ "time": "2023-12-05T13:24:00+00:00" }, { - "name": "symfony/clock", - "version": "v7.2.0", + "name": "symfony/amazon-mailer", + "version": "v7.3.0", "source": { "type": "git", - "url": "https://github.com/symfony/clock.git", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + "url": "https://github.com/symfony/amazon-mailer.git", + "reference": "7266d4285147c890f4f7f42dc875fe5a6df8006c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/7266d4285147c890f4f7f42dc875fe5a6df8006c", + "reference": "7266d4285147c890f4f7f42dc875fe5a6df8006c", "shasum": "" }, "require": { + "async-aws/ses": "^1.8", "php": ">=8.2", - "psr/clock": "^1.0", - "symfony/polyfill-php83": "^1.28" + "symfony/mailer": "^7.2" }, - "provide": { - "psr/clock-implementation": "1.0" + "require-dev": { + "symfony/http-client": "^6.4|^7.0" }, - "type": "library", + "type": "symfony-mailer-bridge", "autoload": { - "files": [ - "Resources/now.php" - ], "psr-4": { - "Symfony\\Component\\Clock\\": "" + "Symfony\\Component\\Mailer\\Bridge\\Amazon\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4132,23 +4844,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Decouples applications from the system clock", + "description": "Symfony Amazon Mailer Bridge", "homepage": "https://symfony.com", - "keywords": [ - "clock", - "psr20", - "time" - ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.2.0" + "source": "https://github.com/symfony/amazon-mailer/tree/v7.3.0" }, "funding": [ { @@ -4164,35 +4871,109 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-02-26T16:10:57+00:00" }, { - "name": "symfony/config", - "version": "v7.2.0", + "name": "symfony/clock", + "version": "v7.3.0", "source": { "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "bcd3c4adf0144dee5011bb35454728c38adec055" + "url": "https://github.com/symfony/clock.git", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/bcd3c4adf0144dee5011bb35454728c38adec055", - "reference": "bcd3c4adf0144dee5011bb35454728c38adec055", + "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^7.1", - "symfony/polyfill-ctype": "~1.8" + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" }, - "conflict": { - "symfony/finder": "<6.4", - "symfony/service-contracts": "<2.5" + "provide": { + "psr/clock-implementation": "1.0" }, - "require-dev": { - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/config", + "version": "v7.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "faef36e271bbeb74a9d733be4b56419b157762e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/faef36e271bbeb74a9d733be4b56419b157762e2", + "reference": "faef36e271bbeb74a9d733be4b56419b157762e2", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^7.1", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "require-dev": { + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", "symfony/messenger": "^6.4|^7.0", "symfony/service-contracts": "^2.5|^3", "symfony/yaml": "^6.4|^7.0" @@ -4223,7 +5004,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.2.0" + "source": "https://github.com/symfony/config/tree/v7.3.2" }, "funding": [ { @@ -4234,25 +5015,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-04T11:36:24+00:00" + "time": "2025-07-26T13:55:06+00:00" }, { "name": "symfony/console", - "version": "v6.4.17", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04" + "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04", + "url": "https://api.github.com/repos/symfony/console/zipball/59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", + "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", "shasum": "" }, "require": { @@ -4317,7 +5102,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.17" + "source": "https://github.com/symfony/console/tree/v6.4.24" }, "funding": [ { @@ -4328,25 +5113,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-07T12:07:30+00:00" + "time": "2025-07-30T10:38:54+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -4359,7 +5148,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -4384,7 +5173,163 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-22T09:11:45+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" }, "funding": [ { @@ -4400,20 +5345,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/filesystem", - "version": "v7.2.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" + "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", - "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", "shasum": "" }, "require": { @@ -4422,12 +5367,357 @@ "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^6.4|^7.0" + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-07T08:17:47+00:00" + }, + { + "name": "symfony/http-client", + "version": "v7.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "1c064a0c67749923483216b081066642751cc2c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/1c064a0c67749923483216b081066642751cc2c7", + "reference": "1c064a0c67749923483216b081066642751cc2c7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "amphp/amp": "<2.5", + "amphp/socket": "<1.1", + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^2.0", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/amphp-http-client-meta": "^1.0|^2.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "keywords": [ + "http" + ], + "support": { + "source": "https://github.com/symfony/http-client/tree/v7.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-15T11:36:08+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "75d7043853a42837e68111812f4d964b01e5101c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", + "reference": "75d7043853a42837e68111812f4d964b01e5101c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-29T11:18:49+00:00" + }, + { + "name": "symfony/mailer", + "version": "v7.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/d43e84d9522345f96ad6283d5dfccc8c1cfc299b", + "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.2", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/mime": "^7.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/twig-bridge": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/twig-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v7.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-15T11:36:08+00:00" + }, + { + "name": "symfony/mime", + "version": "v7.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/e0a0f859148daf1edf6c60b398eb40bfc96697d1", + "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Filesystem\\": "" + "Symfony\\Component\\Mime\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4447,10 +5737,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Provides basic utilities for the filesystem", + "description": "Allows manipulating MIME messages", "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.2.0" + "source": "https://github.com/symfony/mime/tree/v7.3.2" }, "funding": [ { @@ -4461,16 +5755,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-10-25T15:15:23+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -4529,7 +5827,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" }, "funding": [ { @@ -4549,7 +5847,7 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", @@ -4607,7 +5905,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" }, "funding": [ { @@ -4627,16 +5925,16 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", "shasum": "" }, "require": { @@ -4690,7 +5988,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" }, "funding": [ { @@ -4706,11 +6004,11 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-09-10T14:38:51+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -4771,7 +6069,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" }, "funding": [ { @@ -4791,19 +6089,20 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { + "ext-iconv": "*", "php": ">=7.2" }, "provide": { @@ -4851,7 +6150,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" }, "funding": [ { @@ -4867,20 +6166,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { @@ -4931,7 +6230,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" }, "funding": [ { @@ -4947,11 +6246,11 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-01-02T08:10:11+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", @@ -5007,7 +6306,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" }, "funding": [ { @@ -5027,7 +6326,7 @@ }, { "name": "symfony/polyfill-uuid", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", @@ -5086,7 +6385,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" }, "funding": [ { @@ -5104,18 +6403,88 @@ ], "time": "2024-09-09T11:45:10+00:00" }, + { + "name": "symfony/resend-mailer", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/resend-mailer.git", + "reference": "591d06a6603845933e921c10cedb2afb97376c50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/resend-mailer/zipball/591d06a6603845933e921c10cedb2afb97376c50", + "reference": "591d06a6603845933e921c10cedb2afb97376c50", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/mailer": "^7.2" + }, + "conflict": { + "symfony/http-foundation": "<7.1" + }, + "require-dev": { + "symfony/http-client": "^6.4|^7.0", + "symfony/http-foundation": "^7.1", + "symfony/webhook": "^6.4|^7.0" + }, + "type": "symfony-mailer-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\Bridge\\Resend\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mathieu Santostefano", + "homepage": "https://github.com/welcoMattic" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Resend Mailer Bridge", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/resend-mailer/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-28T08:24:38+00:00" + }, { "name": "symfony/service-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { @@ -5133,7 +6502,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -5169,7 +6538,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -5185,20 +6554,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { "name": "symfony/string", - "version": "v7.2.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" + "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", - "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", + "url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca", + "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca", "shasum": "" }, "require": { @@ -5256,7 +6625,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.2.0" + "source": "https://github.com/symfony/string/tree/v7.3.2" }, "funding": [ { @@ -5267,25 +6636,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-13T13:31:26+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { "name": "symfony/translation", - "version": "v7.2.2", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "e2674a30132b7cc4d74540d6c2573aa363f05923" + "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e2674a30132b7cc4d74540d6c2573aa363f05923", - "reference": "e2674a30132b7cc4d74540d6c2573aa363f05923", + "url": "https://api.github.com/repos/symfony/translation/zipball/81b48f4daa96272efcce9c7a6c4b58e629df3c90", + "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90", "shasum": "" }, "require": { @@ -5295,6 +6668,7 @@ "symfony/translation-contracts": "^2.5|^3.0" }, "conflict": { + "nikic/php-parser": "<5.0", "symfony/config": "<6.4", "symfony/console": "<6.4", "symfony/dependency-injection": "<6.4", @@ -5308,7 +6682,7 @@ "symfony/translation-implementation": "2.3|3.0" }, "require-dev": { - "nikic/php-parser": "^4.18|^5.0", + "nikic/php-parser": "^5.0", "psr/log": "^1|^2|^3", "symfony/config": "^6.4|^7.0", "symfony/console": "^6.4|^7.0", @@ -5351,7 +6725,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.2.2" + "source": "https://github.com/symfony/translation/tree/v7.3.2" }, "funding": [ { @@ -5362,25 +6736,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-07T08:18:10+00:00" + "time": "2025-07-30T17:31:46+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", "shasum": "" }, "require": { @@ -5393,7 +6771,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -5429,7 +6807,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" }, "funding": [ { @@ -5445,20 +6823,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-27T08:32:26+00:00" }, { "name": "symfony/uid", - "version": "v7.2.0", + "version": "v7.3.1", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "2d294d0c48df244c71c105a169d0190bfb080426" + "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/2d294d0c48df244c71c105a169d0190bfb080426", - "reference": "2d294d0c48df244c71c105a169d0190bfb080426", + "url": "https://api.github.com/repos/symfony/uid/zipball/a69f69f3159b852651a6bf45a9fdd149520525bb", + "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb", "shasum": "" }, "require": { @@ -5503,7 +6881,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.2.0" + "source": "https://github.com/symfony/uid/tree/v7.3.1" }, "funding": [ { @@ -5519,31 +6897,31 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-06-27T19:55:54+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.2.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "c6a22929407dec8765d6e2b6ff85b800b245879c" + "reference": "53205bea27450dc5c65377518b3275e126d45e75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c6a22929407dec8765d6e2b6ff85b800b245879c", - "reference": "c6a22929407dec8765d6e2b6ff85b800b245879c", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/53205bea27450dc5c65377518b3275e126d45e75", + "reference": "53205bea27450dc5c65377518b3275e126d45e75", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { "symfony/console": "<6.4" }, "require-dev": { - "ext-iconv": "*", "symfony/console": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", "symfony/process": "^6.4|^7.0", @@ -5586,7 +6964,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.2.0" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.2" }, "funding": [ { @@ -5597,25 +6975,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-08T15:48:14+00:00" + "time": "2025-07-29T20:02:46+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.6.1", + "version": "v5.6.2", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" + "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", - "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af", "shasum": "" }, "require": { @@ -5674,7 +7056,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2" }, "funding": [ { @@ -5686,7 +7068,7 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:52:34+00:00" + "time": "2025-04-30T23:37:27+00:00" } ], "packages-dev": [ @@ -5905,24 +7287,24 @@ }, { "name": "cmgmyr/phploc", - "version": "8.0.4", + "version": "8.0.6", "source": { "type": "git", "url": "https://github.com/cmgmyr/phploc.git", - "reference": "b0c4ec71f40ef84c9893e1a7212a72e1098b90f7" + "reference": "5d785f8fc8b891483cdbee3fb25f2b348c50c03f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cmgmyr/phploc/zipball/b0c4ec71f40ef84c9893e1a7212a72e1098b90f7", - "reference": "b0c4ec71f40ef84c9893e1a7212a72e1098b90f7", + "url": "https://api.github.com/repos/cmgmyr/phploc/zipball/5d785f8fc8b891483cdbee3fb25f2b348c50c03f", + "reference": "5d785f8fc8b891483cdbee3fb25f2b348c50c03f", "shasum": "" }, "require": { "ext-dom": "*", "ext-json": "*", "php": "^7.4 || ^8.0", - "phpunit/php-file-iterator": "^3.0|^4.0|^5.0", - "sebastian/cli-parser": "^1.0|^2.0|^3.0" + "phpunit/php-file-iterator": "^3.0|^4.0|^5.0|^6.0", + "sebastian/cli-parser": "^1.0|^2.0|^3.0|^4.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.2", @@ -5958,7 +7340,7 @@ "homepage": "https://github.com/cmgmyr/phploc", "support": { "issues": "https://github.com/cmgmyr/phploc/issues", - "source": "https://github.com/cmgmyr/phploc/tree/8.0.4" + "source": "https://github.com/cmgmyr/phploc/tree/8.0.6" }, "funding": [ { @@ -5966,7 +7348,7 @@ "type": "github" } ], - "time": "2024-10-31T19:26:53+00:00" + "time": "2025-03-29T16:41:46+00:00" }, { "name": "composer/pcre", @@ -6196,28 +7578,28 @@ }, { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.0.0", + "version": "v1.1.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "4be43904336affa5c2f70744a348312336afd0da" + "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", - "reference": "4be43904336affa5c2f70744a348312336afd0da", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", + "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0 || ^2.0", + "composer-plugin-api": "^2.2", "php": ">=5.4", "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, "require-dev": { - "composer/composer": "*", + "composer/composer": "^2.2", "ext-json": "*", "ext-zip": "*", - "php-parallel-lint/php-parallel-lint": "^1.3.1", + "php-parallel-lint/php-parallel-lint": "^1.4.0", "phpcompatibility/php-compatibility": "^9.0", "yoast/phpunit-polyfills": "^1.0" }, @@ -6237,9 +7619,9 @@ "authors": [ { "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" + "email": "opensource@frenck.dev", + "homepage": "https://frenck.dev", + "role": "Open source developer" }, { "name": "Contributors", @@ -6247,7 +7629,6 @@ } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", "keywords": [ "PHPCodeSniffer", "PHP_CodeSniffer", @@ -6268,9 +7649,28 @@ ], "support": { "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", "source": "https://github.com/PHPCSStandards/composer-installer" }, - "time": "2023-01-05T11:28:13+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-07-17T20:45:56+00:00" }, { "name": "doctrine/instantiator", @@ -6452,16 +7852,16 @@ }, { "name": "filp/whoops", - "version": "2.16.0", + "version": "2.18.3", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "befcdc0e5dce67252aa6322d82424be928214fa2" + "reference": "59a123a3d459c5a23055802237cb317f609867e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/befcdc0e5dce67252aa6322d82424be928214fa2", - "reference": "befcdc0e5dce67252aa6322d82424be928214fa2", + "url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5", + "reference": "59a123a3d459c5a23055802237cb317f609867e5", "shasum": "" }, "require": { @@ -6511,7 +7911,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.16.0" + "source": "https://github.com/filp/whoops/tree/2.18.3" }, "funding": [ { @@ -6519,61 +7919,63 @@ "type": "github" } ], - "time": "2024-09-25T12:00:00+00:00" + "time": "2025-06-16T00:02:10+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.66.0", + "version": "v3.85.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6" + "reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/5f5f2a142ff36b93c41885bca29cc5f861c013e6", - "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2fb6d7f6c3398dca5786a1635b27405d73a417ba", + "reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba", "shasum": "" }, "require": { - "clue/ndjson-react": "^1.0", + "clue/ndjson-react": "^1.3", "composer/semver": "^3.4", - "composer/xdebug-handler": "^3.0.3", + "composer/xdebug-handler": "^3.0.5", "ext-filter": "*", + "ext-hash": "*", "ext-json": "*", "ext-tokenizer": "*", "fidry/cpu-core-counter": "^1.2", "php": "^7.4 || ^8.0", - "react/child-process": "^0.6.5", - "react/event-loop": "^1.0", - "react/promise": "^2.0 || ^3.0", - "react/socket": "^1.0", - "react/stream": "^1.0", - "sebastian/diff": "^4.0 || ^5.0 || ^6.0", - "symfony/console": "^5.4 || ^6.0 || ^7.0", - "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0", - "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", - "symfony/finder": "^5.4 || ^6.0 || ^7.0", - "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0", - "symfony/polyfill-mbstring": "^1.28", - "symfony/polyfill-php80": "^1.28", - "symfony/polyfill-php81": "^1.28", - "symfony/process": "^5.4 || ^6.0 || ^7.0 <7.2", - "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" - }, - "require-dev": { - "facile-it/paraunit": "^1.3.1 || ^2.4", - "infection/infection": "^0.29.8", - "justinrainbow/json-schema": "^5.3 || ^6.0", - "keradus/cli-executor": "^2.1", + "react/child-process": "^0.6.6", + "react/event-loop": "^1.5", + "react/promise": "^3.2", + "react/socket": "^1.16", + "react/stream": "^1.4", + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", + "symfony/console": "^5.4.47 || ^6.4.13 || ^7.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", + "symfony/polyfill-mbstring": "^1.32", + "symfony/polyfill-php80": "^1.32", + "symfony/polyfill-php81": "^1.32", + "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", + "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" + }, + "require-dev": { + "facile-it/paraunit": "^1.3.1 || ^2.6", + "infection/infection": "^0.29.14", + "justinrainbow/json-schema": "^5.3 || ^6.4", + "keradus/cli-executor": "^2.2", "mikey179/vfsstream": "^1.6.12", - "php-coveralls/php-coveralls": "^2.7", + "php-coveralls/php-coveralls": "^2.8", "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5", - "phpunit/phpunit": "^9.6.21 || ^10.5.38 || ^11.4.3", - "symfony/var-dumper": "^5.4.47 || ^6.4.15 || ^7.1.8", - "symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.1.6" + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", + "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", + "symfony/polyfill-php84": "^1.32", + "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", + "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -6614,7 +8016,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.66.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.85.1" }, "funding": [ { @@ -6622,24 +8024,24 @@ "type": "github" } ], - "time": "2024-12-29T13:46:23+00:00" + "time": "2025-07-29T22:22:50+00:00" }, { "name": "hamcrest/hamcrest-php", - "version": "v2.0.1", + "version": "v2.1.1", "source": { "type": "git", "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3" + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", - "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", "shasum": "" }, "require": { - "php": "^5.3|^7.0|^8.0" + "php": "^7.4|^8.0" }, "replace": { "cordoval/hamcrest-php": "*", @@ -6647,8 +8049,8 @@ "kodova/hamcrest-php": "*" }, "require-dev": { - "phpunit/php-file-iterator": "^1.4 || ^2.0", - "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0" + "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0" }, "type": "library", "extra": { @@ -6671,22 +8073,22 @@ ], "support": { "issues": "https://github.com/hamcrest/hamcrest-php/issues", - "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1" + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.1.1" }, - "time": "2020-07-09T08:09:16+00:00" + "time": "2025-04-30T06:54:44+00:00" }, { "name": "jean85/pretty-package-versions", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10" + "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", - "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a", + "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a", "shasum": "" }, "require": { @@ -6696,8 +8098,9 @@ "require-dev": { "friendsofphp/php-cs-fixer": "^3.2", "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^1.4", + "phpstan/phpstan": "^2.0", "phpunit/phpunit": "^7.5|^8.5|^9.6", + "rector/rector": "^2.0", "vimeo/psalm": "^4.3 || ^5.0" }, "type": "library", @@ -6730,9 +8133,9 @@ ], "support": { "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0" + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1" }, - "time": "2024-11-18T16:19:46+00:00" + "time": "2025-03-19T14:43:43+00:00" }, { "name": "justinrainbow/json-schema", @@ -6884,16 +8287,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.12.1", + "version": "1.13.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", - "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { @@ -6932,7 +8335,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, "funding": [ { @@ -6940,20 +8343,20 @@ "type": "tidelift" } ], - "time": "2024-11-08T17:47:46+00:00" + "time": "2025-08-01T08:46:24+00:00" }, { "name": "nikic/php-parser", - "version": "v5.4.0", + "version": "v5.6.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56", + "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56", "shasum": "" }, "require": { @@ -6996,9 +8399,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0" }, - "time": "2024-12-30T11:07:19+00:00" + "time": "2025-07-27T20:03:57+00:00" }, { "name": "nunomaduro/collision", @@ -7829,30 +9232,30 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.33.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", - "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { "doctrine/annotations": "^2.0", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^5.3.0", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", "symfony/process": "^5.2" }, "type": "library", @@ -7870,22 +9273,22 @@ "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.33.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.2.0" }, - "time": "2024-10-13T11:25:22+00:00" + "time": "2025-07-13T07:04:09+00:00" }, { "name": "phpstan/phpstan", - "version": "1.12.14", + "version": "1.12.28", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e73868f809e68fff33be961ad4946e2e43ec9e38" + "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e73868f809e68fff33be961ad4946e2e43ec9e38", - "reference": "e73868f809e68fff33be961ad4946e2e43ec9e38", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", + "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", "shasum": "" }, "require": { @@ -7930,7 +9333,7 @@ "type": "github" } ], - "time": "2024-12-31T07:26:13+00:00" + "time": "2025-07-17T17:15:39+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -8350,207 +9753,116 @@ ], "time": "2020-10-26T13:16:10+00:00" }, - { - "name": "phpunit/phpunit", - "version": "9.6.22", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c", - "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.5.0 || ^2", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.1", - "phar-io/manifest": "^2.0.4", - "phar-io/version": "^3.2.1", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.32", - "phpunit/php-file-iterator": "^3.0.6", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.4", - "phpunit/php-timer": "^5.0.3", - "sebastian/cli-parser": "^1.0.2", - "sebastian/code-unit": "^1.0.8", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.6", - "sebastian/environment": "^5.1.5", - "sebastian/exporter": "^4.0.6", - "sebastian/global-state": "^5.0.7", - "sebastian/object-enumerator": "^4.0.4", - "sebastian/resource-operations": "^3.0.4", - "sebastian/type": "^3.2.1", - "sebastian/version": "^3.0.2" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.6-dev" - } - }, - "autoload": { - "files": [ - "src/Framework/Assert/Functions.php" - ], - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "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.22" - }, - "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" - } - ], - "time": "2024-12-05T13:48:26+00:00" - }, - { - "name": "psr/cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for caching libraries", - "keywords": [ - "cache", - "psr", - "psr-6" - ], - "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" - }, - "time": "2021-02-03T23:26:27+00:00" - }, - { - "name": "psr/event-dispatcher", - "version": "1.0.0", + { + "name": "phpunit/phpunit", + "version": "9.6.23", "source": { "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", "shasum": "" }, "require": { - "php": ">=7.2.0" + "doctrine/instantiator": "^1.5.0 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.32", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, + "bin": [ + "phpunit" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "9.6-dev" } }, "autoload": { - "psr-4": { - "Psr\\EventDispatcher\\": "src/" - } + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Standard interfaces for event handling.", + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", "keywords": [ - "events", - "psr", - "psr-14" + "phpunit", + "testing", + "xunit" ], "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.23" }, - "time": "2019-01-08T18:20:26+00:00" + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-05-02T06:40:34+00:00" }, { "name": "react/cache", @@ -10043,32 +11355,32 @@ }, { "name": "slevomat/coding-standard", - "version": "8.15.0", + "version": "8.20.0", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "7d1d957421618a3803b593ec31ace470177d7817" + "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817", - "reference": "7d1d957421618a3803b593ec31ace470177d7817", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b4f9f02edd4e6a586777f0cabe8d05574323f3eb", + "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", - "php": "^7.2 || ^8.0", - "phpstan/phpdoc-parser": "^1.23.1", - "squizlabs/php_codesniffer": "^3.9.0" + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2", + "php": "^7.4 || ^8.0", + "phpstan/phpdoc-parser": "^2.2.0", + "squizlabs/php_codesniffer": "^3.13.2" }, "require-dev": { - "phing/phing": "2.17.4", - "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "1.10.60", - "phpstan/phpstan-deprecation-rules": "1.1.4", - "phpstan/phpstan-phpunit": "1.3.16", - "phpstan/phpstan-strict-rules": "1.5.2", - "phpunit/phpunit": "8.5.21|9.6.8|10.5.11" + "phing/phing": "3.0.1|3.1.0", + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpstan/phpstan": "2.1.19", + "phpstan/phpstan-deprecation-rules": "2.0.3", + "phpstan/phpstan-phpunit": "2.0.7", + "phpstan/phpstan-strict-rules": "2.0.6", + "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.27|12.2.7" }, "type": "phpcodesniffer-standard", "extra": { @@ -10092,7 +11404,7 @@ ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.15.0" + "source": "https://github.com/slevomat/coding-standard/tree/8.20.0" }, "funding": [ { @@ -10104,7 +11416,7 @@ "type": "tidelift" } ], - "time": "2024-03-09T15:20:58+00:00" + "time": "2025-07-26T15:35:10+00:00" }, { "name": "spatie/file-system-watcher", @@ -10168,16 +11480,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.11.2", + "version": "3.13.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079" + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1368f4a58c3c52114b86b1abe8f4098869cb0079", - "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", "shasum": "" }, "require": { @@ -10217,250 +11529,94 @@ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - } - ], - "time": "2024-12-11T16:04:26+00:00" - }, - { - "name": "symfony/cache", - "version": "v7.2.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache.git", - "reference": "e7e983596b744c4539f31e79b0350a6cf5878a20" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/e7e983596b744c4539f31e79b0350a6cf5878a20", - "reference": "e7e983596b744c4539f31e79b0350a6cf5878a20", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "psr/cache": "^2.0|^3.0", - "psr/log": "^1.1|^2|^3", - "symfony/cache-contracts": "^2.5|^3", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.4|^7.0" - }, - "conflict": { - "doctrine/dbal": "<3.6", - "symfony/dependency-injection": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/var-dumper": "<6.4" - }, - "provide": { - "psr/cache-implementation": "2.0|3.0", - "psr/simple-cache-implementation": "1.0|2.0|3.0", - "symfony/cache-implementation": "1.1|2.0|3.0" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/dbal": "^3.6|^4", - "predis/predis": "^1.1|^2.0", - "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/filesystem": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Cache\\": "" - }, - "classmap": [ - "Traits/ValueWrapper.php" - ], - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", - "homepage": "https://symfony.com", - "keywords": [ - "caching", - "psr6" - ], - "support": { - "source": "https://github.com/symfony/cache/tree/v7.2.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-12-07T08:08:50+00:00" - }, - { - "name": "symfony/cache-contracts", - "version": "v3.5.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache-contracts.git", - "reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b", - "reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/cache": "^3.0" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.5-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Cache\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to caching", - "homepage": "https://symfony.com", + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "phpcs", + "standards", + "static analysis" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.5.1" + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" + "url": "https://github.com/PHPCSStandards", + "type": "github" }, { - "url": "https://github.com/fabpot", + "url": "https://github.com/jrfnl", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-06-17T22:17:01+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v7.2.0", + "name": "symfony/cache", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" + "url": "https://github.com/symfony/cache.git", + "reference": "6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", - "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", + "url": "https://api.github.com/repos/symfony/cache/zipball/6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6", + "reference": "6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/event-dispatcher-contracts": "^2.5|^3" + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^3.6", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.4|^7.0" }, "conflict": { + "doctrine/dbal": "<3.6", "symfony/dependency-injection": "<6.4", - "symfony/service-contracts": "<2.5" + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" }, "provide": { - "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0|3.0" + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2|^3", + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/clock": "^6.4|^7.0", "symfony/config": "^6.4|^7.0", "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/filesystem": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" + "Symfony\\Component\\Cache\\": "" }, + "classmap": [ + "Traits/ValueWrapper.php" + ], "exclude-from-classmap": [ "/Tests/" ] @@ -10471,18 +11627,22 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.2.0" + "source": "https://github.com/symfony/cache/tree/v7.3.2" }, "funding": [ { @@ -10493,30 +11653,34 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-07-30T17:13:41+00:00" }, { - "name": "symfony/event-dispatcher-contracts", - "version": "v3.5.1", + "name": "symfony/cache-contracts", + "version": "v3.6.0", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", "shasum": "" }, "require": { "php": ">=8.1", - "psr/event-dispatcher": "^1" + "psr/cache": "^3.0" }, "type": "library", "extra": { @@ -10525,12 +11689,12 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" + "Symfony\\Contracts\\Cache\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -10547,7 +11711,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to dispatching event", + "description": "Generic abstractions related to caching", "homepage": "https://symfony.com", "keywords": [ "abstractions", @@ -10558,7 +11722,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0" }, "funding": [ { @@ -10574,20 +11738,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-03-13T15:25:07+00:00" }, { "name": "symfony/finder", - "version": "v7.2.2", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", - "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", "shasum": "" }, "require": { @@ -10622,102 +11786,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.2.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-12-30T19:00:17+00:00" - }, - { - "name": "symfony/http-client", - "version": "v7.2.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-client.git", - "reference": "339ba21476eb184290361542f732ad12c97591ec" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/339ba21476eb184290361542f732ad12c97591ec", - "reference": "339ba21476eb184290361542f732ad12c97591ec", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "~3.4.4|^3.5.2", - "symfony/service-contracts": "^2.5|^3" - }, - "conflict": { - "amphp/amp": "<2.5", - "php-http/discovery": "<1.15", - "symfony/http-foundation": "<6.4" - }, - "provide": { - "php-http/async-client-implementation": "*", - "php-http/client-implementation": "*", - "psr/http-client-implementation": "1.0", - "symfony/http-client-implementation": "3.0" - }, - "require-dev": { - "amphp/http-client": "^4.2.1|^5.0", - "amphp/http-tunnel": "^1.0|^2.0", - "amphp/socket": "^1.1", - "guzzlehttp/promises": "^1.4|^2.0", - "nyholm/psr7": "^1.0", - "php-http/httplug": "^1.0|^2.0", - "psr/http-client": "^1.0", - "symfony/amphp-http-client-meta": "^1.0|^2.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpClient\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", - "homepage": "https://symfony.com", - "keywords": [ - "http" - ], - "support": { - "source": "https://github.com/symfony/http-client/tree/v7.2.2" + "source": "https://github.com/symfony/finder/tree/v7.3.2" }, "funding": [ { @@ -10729,81 +11798,7 @@ "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-12-30T18:35:15+00:00" - }, - { - "name": "symfony/http-client-contracts", - "version": "v3.5.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645", - "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.5-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\HttpClient\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to HTTP clients", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/nicolas-grekas", "type": "github" }, { @@ -10811,20 +11806,20 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:49:48+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.2.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" + "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37", + "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37", "shasum": "" }, "require": { @@ -10862,7 +11857,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" + "source": "https://github.com/symfony/options-resolver/tree/v7.3.2" }, "funding": [ { @@ -10873,16 +11868,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-20T11:17:29+00:00" + "time": "2025-07-15T11:36:08+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -10938,7 +11937,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0" }, "funding": [ { @@ -10958,16 +11957,16 @@ }, { "name": "symfony/process", - "version": "v7.1.8", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892" + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/42783370fda6e538771f7c7a36e9fa2ee3a84892", - "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892", + "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "shasum": "" }, "require": { @@ -10999,7 +11998,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.8" + "source": "https://github.com/symfony/process/tree/v7.3.0" }, "funding": [ { @@ -11015,20 +12014,20 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:23:19+00:00" + "time": "2025-04-17T09:11:12+00:00" }, { "name": "symfony/stopwatch", - "version": "v7.2.2", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df" + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/e46690d5b9d7164a6d061cab1e8d46141b9f49df", - "reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", "shasum": "" }, "require": { @@ -11061,7 +12060,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.2.2" + "source": "https://github.com/symfony/stopwatch/tree/v7.3.0" }, "funding": [ { @@ -11077,24 +12076,25 @@ "type": "tidelift" } ], - "time": "2024-12-18T14:28:33+00:00" + "time": "2025-02-24T10:49:57+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.2.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "1a6a89f95a46af0f142874c9d650a6358d13070d" + "reference": "05b3e90654c097817325d6abd284f7938b05f467" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/1a6a89f95a46af0f142874c9d650a6358d13070d", - "reference": "1a6a89f95a46af0f142874c9d650a6358d13070d", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/05b3e90654c097817325d6abd284f7938b05f467", + "reference": "05b3e90654c097817325d6abd284f7938b05f467", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { "symfony/property-access": "^6.4|^7.0", @@ -11137,7 +12137,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.2.0" + "source": "https://github.com/symfony/var-exporter/tree/v7.3.2" }, "funding": [ { @@ -11148,12 +12148,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-10-18T07:58:17+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { "name": "theseer/tokenizer", @@ -11208,7 +12212,9 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": {}, + "stability-flags": { + "phenixphp/framework": 20 + }, "prefer-stable": true, "prefer-lowest": false, "platform": { From 82d42881622ef9995a37ae3b9712e7dd149c80ca Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 6 Aug 2025 18:14:09 -0500 Subject: [PATCH 009/133] feature: update config file --- config/app.php | 27 ++++++++++++++++++--------- config/database.php | 28 ++++++++++++++-------------- config/mail.php | 30 ++++++++++++++++++++++++++++++ config/queue.php | 23 +++++++++++++++++++++++ config/services.php | 13 +++++++++++++ config/view.php | 7 +++++++ 6 files changed, 105 insertions(+), 23 deletions(-) create mode 100644 config/mail.php create mode 100644 config/queue.php create mode 100644 config/services.php create mode 100644 config/view.php diff --git a/config/app.php b/config/app.php index 2b501f2..6393975 100644 --- a/config/app.php +++ b/config/app.php @@ -3,20 +3,29 @@ declare(strict_types=1); return [ - 'name' => env('APP_NAME', fn () => 'Phenix'), - 'env' => env('APP_ENV', fn () => 'local'), - 'url' => env('APP_URL', fn () => '0.0.0.0'), - 'port' => env('APP_PORT', fn () => 1337), + 'name' => env('APP_NAME', static fn (): string => 'Phenix'), + 'env' => env('APP_ENV', static fn (): string => 'local'), + 'url' => env('APP_URL', static fn (): string => 'http://127.0.0.1'), + 'port' => env('APP_PORT', static fn (): int => 1337), + 'key' => env('APP_KEY'), + 'previous_key' => env('APP_PREVIOUS_KEY'), + 'debug' => env('APP_DEBUG', static fn (): bool => true), 'middlewares' => [ 'global' => [ - \App\Http\Middleware\HandleCors::class, + \Phenix\Http\Middlewares\HandleCors::class, ], 'router' => [], ], 'providers' => [ - Phenix\Providers\CommandsServiceProvider::class, - Phenix\Providers\RouteServiceProvider::class, - Phenix\Providers\DatabaseServiceProvider::class, - Phenix\Providers\FilesystemServiceProvider::class, + \Phenix\Console\CommandsServiceProvider::class, + \Phenix\Routing\RouteServiceProvider::class, + \Phenix\Database\DatabaseServiceProvider::class, + \Phenix\Redis\RedisServiceProvider::class, + \Phenix\Filesystem\FilesystemServiceProvider::class, + \Phenix\Tasks\TaskServiceProvider::class, + \Phenix\Views\ViewServiceProvider::class, + \Phenix\Mail\MailServiceProvider::class, + \Phenix\Crypto\CryptoServiceProvider::class, + \Phenix\Queue\QueueServiceProvider::class, ], ]; diff --git a/config/database.php b/config/database.php index 68a7ea1..922b002 100644 --- a/config/database.php +++ b/config/database.php @@ -5,13 +5,13 @@ use Phenix\Database\Constants\Driver; return [ - 'default' => env('DB_CONNECTION', fn () => 'mysql'), + 'default' => env('DB_CONNECTION', static fn () => 'mysql'), 'connections' => [ 'mysql' => [ 'driver' => Driver::MYSQL, - 'host' => env('DB_HOST', fn () => '127.0.0.1'), - 'port' => env('DB_PORT', fn () => '3306'), + 'host' => env('DB_HOST', static fn () => '127.0.0.1'), + 'port' => env('DB_PORT', static fn () => '3306'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), @@ -22,29 +22,29 @@ ], 'postgresql' => [ 'driver' => Driver::POSTGRESQL, - 'host' => env('DB_HOST', fn () => '127.0.0.1'), - 'port' => env('DB_PORT', fn () => '3306'), + 'host' => env('DB_HOST', static fn () => '127.0.0.1'), + 'port' => env('DB_PORT', static fn () => '3306'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), ], ], + 'paths' => [ + 'migrations' => base_path('database' . DIRECTORY_SEPARATOR . 'migrations'), + 'seeds' => base_path('database' . DIRECTORY_SEPARATOR . 'seeds'), + ], + 'redis' => [ 'connections' => [ 'default' => [ - 'scheme' => env('REDIS_SCHEME', fn () => 'redis'), - 'host' => env('REDIS_HOST', fn () => '127.0.0.1'), + 'scheme' => env('REDIS_SCHEME', static fn () => 'redis'), + 'host' => env('REDIS_HOST', static fn () => '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), - 'port' => env('REDIS_PORT', fn () => '6379'), - 'database' => env('REDIS_DB', fn () => 0), + 'port' => env('REDIS_PORT', static fn () => '6379'), + 'database' => env('REDIS_DB', static fn () => 0), ], ], ], - - 'paths' => [ - 'migrations' => base_path('database' . DIRECTORY_SEPARATOR . 'migrations'), - 'seeds' => base_path('database' . DIRECTORY_SEPARATOR . 'seeds'), - ], ]; diff --git a/config/mail.php b/config/mail.php new file mode 100644 index 0000000..bdef847 --- /dev/null +++ b/config/mail.php @@ -0,0 +1,30 @@ + env('MAIL_MAILER', static fn (): string => 'smtp'), + + 'mailers' => [ + 'smtp' => [ + 'transport' => 'smtp', + 'host' => env('MAIL_HOST', static fn (): string => 'smtp.mailgun.org'), + 'port' => env('MAIL_PORT', static fn (): int => 587), + 'encryption' => env('MAIL_ENCRYPTION', static fn (): string => 'tls'), + 'username' => env('MAIL_USERNAME'), + 'password' => env('MAIL_PASSWORD'), + 'timeout' => null, + ], + + 'ses' => [ + 'transport' => 'ses', + ], + + 'resend' => [ + 'transport' => 'resend', + ], + ], + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', static fn (): string => 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', static fn (): string => 'Example'), + ], +]; diff --git a/config/queue.php b/config/queue.php new file mode 100644 index 0000000..fce5f9e --- /dev/null +++ b/config/queue.php @@ -0,0 +1,23 @@ + env('QUEUE_DRIVER', fn (): string => 'database'), + + 'drivers' => [ + 'parallel' => [ + 'timeout' => env('PARALLEL_QUEUE_TIMEOUT', fn (): int => 2), + 'chunk_size' => env('PARALLEL_QUEUE_CHUNK_SIZE', fn (): int => 10), + ], + + 'database' => [ + 'connection' => env('DB_QUEUE_CONNECTION'), + 'table' => env('DB_QUEUE_TABLE', fn (): string => 'tasks'), + 'queue' => env('DB_QUEUE', fn (): string => 'default'), + ], + + 'redis' => [ + 'connection' => env('REDIS_QUEUE_CONNECTION', fn (): string => 'default'), + 'queue' => env('REDIS_QUEUE', fn (): string => 'default'), + ], + ], +]; diff --git a/config/services.php b/config/services.php new file mode 100644 index 0000000..f382b6a --- /dev/null +++ b/config/services.php @@ -0,0 +1,13 @@ + [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', static fn (): string => 'us-east-1'), + ], + + 'resend' => [ + 'key' => env('RESEND_API_KEY'), + ], +]; diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000..a8de9c3 --- /dev/null +++ b/config/view.php @@ -0,0 +1,7 @@ + env('VIEW_PATH', static fn () => base_path('resources/views')), + + 'compiled_path' => env('VIEW_COMPILED_PATH', static fn () => base_path('storage/framework/views')), +]; From b04777a17c24b6292c9b188e33211a48fbcfa31b Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 18 Aug 2025 11:27:22 -0500 Subject: [PATCH 010/133] fix: update database driver configuration to use string literals --- config/database.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/config/database.php b/config/database.php index 922b002..2bb5ceb 100644 --- a/config/database.php +++ b/config/database.php @@ -2,14 +2,12 @@ declare(strict_types=1); -use Phenix\Database\Constants\Driver; - return [ 'default' => env('DB_CONNECTION', static fn () => 'mysql'), 'connections' => [ 'mysql' => [ - 'driver' => Driver::MYSQL, + 'driver' => 'mysql', 'host' => env('DB_HOST', static fn () => '127.0.0.1'), 'port' => env('DB_PORT', static fn () => '3306'), 'database' => env('DB_DATABASE'), @@ -21,9 +19,9 @@ 'prefix' => '', ], 'postgresql' => [ - 'driver' => Driver::POSTGRESQL, + 'driver' => 'postgresql', 'host' => env('DB_HOST', static fn () => '127.0.0.1'), - 'port' => env('DB_PORT', static fn () => '3306'), + 'port' => env('DB_PORT', static fn () => '5432'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), From faf1b64abded62c4bdbc6755704fe3daa51bc653 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 18 Aug 2025 11:27:29 -0500 Subject: [PATCH 011/133] fix: add missing queue driver configuration options for parallel processing --- config/queue.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/queue.php b/config/queue.php index fce5f9e..7a46d4d 100644 --- a/config/queue.php +++ b/config/queue.php @@ -6,7 +6,11 @@ 'drivers' => [ 'parallel' => [ 'timeout' => env('PARALLEL_QUEUE_TIMEOUT', fn (): int => 2), + 'chunk_processing' => env('PARALLEL_QUEUE_CHUNK_PROCESSING', fn (): bool => true), 'chunk_size' => env('PARALLEL_QUEUE_CHUNK_SIZE', fn (): int => 10), + 'max_retries' => env('PARALLEL_QUEUE_MAX_RETRIES', fn (): int => 3), + 'retry_delay' => env('PARALLEL_QUEUE_RETRY_DELAY', fn (): int => 2), + 'interval' => env('PARALLEL_QUEUE_INTERVAL', fn (): float => 2.0), ], 'database' => [ From bffd303eddf2fc687b64088b5d5f2d34d1c072e5 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 20 Aug 2025 14:04:53 -0500 Subject: [PATCH 012/133] chore: update .env.example with Redis configuration options --- .env.example | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.env.example b/.env.example index 934db5b..fff5e03 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,12 @@ APP_NAME=Phenix +APP_KEY= APP_DEBUG=true APP_URL=http://127.0.0.1 APP_PORT=1337 DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 DB_DATABASE=phenix DB_USERNAME=root DB_PASSWORD= @@ -13,3 +16,8 @@ LOG_CHANNEL=stream QUEUE_DRIVER=parallel CORS_ORIGIN= + +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +REDIS_PASSWORD=null +REDIS_USERNAME=null From d6d00ccb3425f3c99e8ae3440eabf01bef0911c8 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 20 Aug 2025 14:12:33 -0500 Subject: [PATCH 013/133] refactor: update closure syntax to include return types in configuration files --- config/cors.php | 2 +- config/database.php | 18 +++++++++--------- config/filesystem.php | 2 +- config/logging.php | 2 +- config/queue.php | 24 ++++++++++++------------ config/session.php | 4 ++-- config/view.php | 4 ++-- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/config/cors.php b/config/cors.php index afc624b..d191010 100644 --- a/config/cors.php +++ b/config/cors.php @@ -1,7 +1,7 @@ env('CORS_ORIGIN', fn () => ['http://localhost', 'http://127.0.0.1']), + 'origins' => env('CORS_ORIGIN', fn (): array => ['http://localhost', 'http://127.0.0.1']), 'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE'], 'max_age' => 8600, 'allowed_headers' => ['X-Request-Headers', 'Content-Type', 'Authorization', 'X-Requested-With'], diff --git a/config/database.php b/config/database.php index 2bb5ceb..ad69ccf 100644 --- a/config/database.php +++ b/config/database.php @@ -3,13 +3,13 @@ declare(strict_types=1); return [ - 'default' => env('DB_CONNECTION', static fn () => 'mysql'), + 'default' => env('DB_CONNECTION', static fn (): string => 'mysql'), 'connections' => [ 'mysql' => [ 'driver' => 'mysql', - 'host' => env('DB_HOST', static fn () => '127.0.0.1'), - 'port' => env('DB_PORT', static fn () => '3306'), + 'host' => env('DB_HOST', static fn (): string => '127.0.0.1'), + 'port' => env('DB_PORT', static fn (): string => '3306'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), @@ -20,8 +20,8 @@ ], 'postgresql' => [ 'driver' => 'postgresql', - 'host' => env('DB_HOST', static fn () => '127.0.0.1'), - 'port' => env('DB_PORT', static fn () => '5432'), + 'host' => env('DB_HOST', static fn (): string => '127.0.0.1'), + 'port' => env('DB_PORT', static fn (): string => '5432'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), @@ -36,12 +36,12 @@ 'redis' => [ 'connections' => [ 'default' => [ - 'scheme' => env('REDIS_SCHEME', static fn () => 'redis'), - 'host' => env('REDIS_HOST', static fn () => '127.0.0.1'), + 'scheme' => env('REDIS_SCHEME', static fn (): string => 'redis'), + 'host' => env('REDIS_HOST', static fn (): string => '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), - 'port' => env('REDIS_PORT', static fn () => '6379'), - 'database' => env('REDIS_DB', static fn () => 0), + 'port' => env('REDIS_PORT', static fn (): string => '6379'), + 'database' => env('REDIS_DB', static fn (): int => 0), ], ], ], diff --git a/config/filesystem.php b/config/filesystem.php index c6e7c5d..7d64aeb 100644 --- a/config/filesystem.php +++ b/config/filesystem.php @@ -3,7 +3,7 @@ declare(strict_types=1); return [ - 'default' => env('FILESYSTEM_DISK', fn () => 'local'), + 'default' => env('FILESYSTEM_DISK', fn (): string => 'local'), 'disks' => [ 'local' => [ 'path' => base_path('storage/app'), diff --git a/config/logging.php b/config/logging.php index cb1b4f8..cc0d9b6 100644 --- a/config/logging.php +++ b/config/logging.php @@ -3,7 +3,7 @@ declare(strict_types=1); return [ - 'default' => env('LOG_CHANNEL', fn () => 'file'), + 'default' => env('LOG_CHANNEL', fn (): string => 'file'), /* |-------------------------------------------------------------------------- diff --git a/config/queue.php b/config/queue.php index 7a46d4d..eaec4a4 100644 --- a/config/queue.php +++ b/config/queue.php @@ -1,27 +1,27 @@ env('QUEUE_DRIVER', fn (): string => 'database'), + 'default' => env('QUEUE_DRIVER', static fn (): string => 'database'), 'drivers' => [ 'parallel' => [ - 'timeout' => env('PARALLEL_QUEUE_TIMEOUT', fn (): int => 2), - 'chunk_processing' => env('PARALLEL_QUEUE_CHUNK_PROCESSING', fn (): bool => true), - 'chunk_size' => env('PARALLEL_QUEUE_CHUNK_SIZE', fn (): int => 10), - 'max_retries' => env('PARALLEL_QUEUE_MAX_RETRIES', fn (): int => 3), - 'retry_delay' => env('PARALLEL_QUEUE_RETRY_DELAY', fn (): int => 2), - 'interval' => env('PARALLEL_QUEUE_INTERVAL', fn (): float => 2.0), + 'timeout' => env('PARALLEL_QUEUE_TIMEOUT', static fn (): int => 2), + 'chunk_processing' => env('PARALLEL_QUEUE_CHUNK_PROCESSING', static fn (): bool => true), + 'chunk_size' => env('PARALLEL_QUEUE_CHUNK_SIZE', static fn (): int => 10), + 'max_retries' => env('PARALLEL_QUEUE_MAX_RETRIES', static fn (): int => 3), + 'retry_delay' => env('PARALLEL_QUEUE_RETRY_DELAY', static fn (): int => 2), + 'interval' => env('PARALLEL_QUEUE_INTERVAL', static fn (): float => 2.0), ], 'database' => [ - 'connection' => env('DB_QUEUE_CONNECTION'), - 'table' => env('DB_QUEUE_TABLE', fn (): string => 'tasks'), - 'queue' => env('DB_QUEUE', fn (): string => 'default'), + 'connection' => env('DB_QUEUE_CONNECTION', static fn (): string => 'mysql'), + 'table' => env('DB_QUEUE_TABLE', static fn (): string => 'tasks'), + 'queue' => env('DB_QUEUE', static fn (): string => 'default'), ], 'redis' => [ - 'connection' => env('REDIS_QUEUE_CONNECTION', fn (): string => 'default'), - 'queue' => env('REDIS_QUEUE', fn (): string => 'default'), + 'connection' => env('REDIS_QUEUE_CONNECTION', static fn (): string => 'default'), + 'queue' => env('REDIS_QUEUE', static fn (): string => 'default'), ], ], ]; diff --git a/config/session.php b/config/session.php index 1230e84..d229735 100644 --- a/config/session.php +++ b/config/session.php @@ -29,11 +29,11 @@ | connection in your database configuration options. */ - 'connection' => env('SESSION_CONNECTION', fn () => 'default'), + 'connection' => env('SESSION_CONNECTION', static fn (): string => 'default'), 'cookie_name' => env( 'SESSION_COOKIE_NAME', - fn () => Str::slug(env('APP_NAME', fn () => 'phenix'), '_') . '_session' + static fn (): string => Str::slug(env('APP_NAME', static fn (): string => 'phenix'), '_') . '_session' ), 'path' => '/', diff --git a/config/view.php b/config/view.php index a8de9c3..6521e24 100644 --- a/config/view.php +++ b/config/view.php @@ -1,7 +1,7 @@ env('VIEW_PATH', static fn () => base_path('resources/views')), + 'path' => env('VIEW_PATH', static fn (): string => base_path('resources/views')), - 'compiled_path' => env('VIEW_COMPILED_PATH', static fn () => base_path('storage/framework/views')), + 'compiled_path' => env('VIEW_COMPILED_PATH', static fn (): string => base_path('storage/framework/views')), ]; From 9a3715b429168bfdc786910d7800a0a881894f9b Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 20 Aug 2025 16:17:57 -0500 Subject: [PATCH 014/133] chore: remove redundant REDIS_USERNAME entry from .env.example --- .env.example | 1 - 1 file changed, 1 deletion(-) diff --git a/.env.example b/.env.example index fff5e03..2c6b6bf 100644 --- a/.env.example +++ b/.env.example @@ -20,4 +20,3 @@ CORS_ORIGIN= REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD=null -REDIS_USERNAME=null From afc7a9cda0105c85a5573cc3c41855eb5783284a Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 22 Aug 2025 08:18:06 -0500 Subject: [PATCH 015/133] docs: add AI coding instructions for Phenix framework --- .github/copilot-instructions.md | 143 ++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..6c8d0b0 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,143 @@ +# Phenix Framework - AI Coding Instructions + +## Architecture Overview + +**Phenix** is an asynchronous PHP web framework built on the [AmPHP](https://amphp.org/) ecosystem. This is a **skeleton application** that depends on `phenixphp/framework` for core functionality. Official documentation can be found at [Phenix Documentation](https://phenix.omarbarbosa.com/). + +### Key Components +- **App Structure**: Standard MVC with `app/` (controllers, tasks), `config/` (service configs), `routes/` (API definitions) +- **Framework Integration**: Core framework lives in `vendor/phenixphp/framework/src/` - reference this for understanding internals +- **Service Providers**: Configured in `config/app.php` - handles DI container, routing, queue, database, etc. +- **Entry Points**: `public/index.php` (HTTP server), `phenix` CLI (console commands) + +## Development Workflow + +### Server & Hot Reloading +```bash +composer dev # Starts development server with file watcher +# OR directly: php server # Custom file watcher that restarts on changes +``` +- Server runs on `APP_URL:APP_PORT` (default: http://127.0.0.1:1337) +- Watches: `app/`, `config/`, `routes/`, `database/`, `composer.json`, `.env` +- Requires Node.js for chokidar file watcher + +### Testing +```bash +composer test # Pest tests (XDEBUG_MODE=off) +composer test:coverage # With coverage reports +composer test:parallel # Parallel execution +``` +- **Test Framework**: Pest PHP with custom HTTP client helpers +- **Test Structure**: `tests/Feature/` and `tests/Unit/` with shared `TestCase` +- **HTTP Testing**: Uses Amp HTTP client with helper functions: `get()`, `post()`, etc. + +### Quality Tools +```bash +composer format # PHP CS Fixer +composer analyze # PHPInsights +composer analyze:static # PHPStan +``` + +## Queue System Architecture + +**Critical Pattern**: This project implements an async task queue system with Redis/Database backends. + +### Task Definition +```php +// Extend QueuableTask for background jobs +class MyTask extends QueuableTask +{ + protected int|null $maxTries = 3; // Configure retries + + protected function handle(Channel $channel, Cancellation $cancellation): Result + { + // Async task logic here + return Result::success('TaskName', 'Success message'); + } +} +``` + +### Task Dispatch +```php +// From controllers/anywhere: +MyTask::dispatch(); // Queue immediately +MyTask::enqueue()->delay(60); // Queue with delay +MyTask::dispatchIf($condition); // Conditional dispatch +``` + +### Queue Workers +```bash +./phenix queue:work redis --queue=default # Process queue +./phenix queue:work --once # Process once and exit +./phenix queue:work --chunks # Batch processing +``` + +## Configuration Patterns + +### Environment-Driven Config +```php +// config/ files use closures for lazy evaluation: +'driver' => env('QUEUE_DRIVER', static fn (): string => 'database'), +'timeout' => env('TIMEOUT', static fn (): int => 30), +``` + +### Service Provider Registration +- All providers registered in `config/app.php` +- Queue system: `QueueServiceProvider`, `TaskServiceProvider` +- Database: Supports MySQL/PostgreSQL with migrations via Phinx + +## Data Layer + +### Database +- **Migrations**: `database/migrations/` using Phinx (not Eloquent) +- **Configuration**: `config/database.php` supports multiple connections +- **CLI**: `./phenix` provides migration commands + +### Queue Backends +- **Redis**: Uses Lua scripts for atomic operations (`LuaScripts.php`) +- **Database**: Uses tasks table with state management +- **Parallel**: AmPHP parallel processing with worker pools + +## HTTP Layer + +### Routing +```php +// routes/api.php - use Facade pattern: +Route::get('/', [WelcomeController::class, 'index']); +Route::post('/tasks', [TaskController::class, 'store']); +``` + +### Controllers +```php +class MyController extends Controller +{ + public function index(): Response + { + return response()->json(['data' => $data]); + // OR: response()->plain('text'); + } +} +``` + +## Key Conventions + +1. **Strict Types**: Always use `declare(strict_types=1);` +2. **Static Factories**: Config uses static closures for defaults +3. **Facade Pattern**: `Phenix\Facades\*` for service access +4. **Result Objects**: Tasks return `Result::success()` or `Result::failure()` +5. **Async First**: Built for non-blocking I/O with AmPHP primitives + +## Critical Files to Reference + +- `config/app.php` - Service provider registration and app config +- `vendor/phenixphp/framework/src/Queue/` - Queue implementation details +- `vendor/phenixphp/framework/src/Tasks/QueuableTask.php` - Base task class +- `tests/Pest.php` - HTTP testing helpers and setup +- `bootstrap/app.php` - Application bootstrap via `AppBuilder` + +## Common Pitfalls + +1. **Queue Retries**: Tasks need explicit `$maxTries` property set +2. **Environment**: Copy `.env.example` to `.env` for local development +3. **CLI vs HTTP**: Different entry points (`phenix` vs `public/index.php`) +4. **Dependencies**: Framework code lives in vendor - check there for implementation details From a8e51342a4639c643f79b16d8a7c7a122ca747bc Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 22 Aug 2025 08:19:59 -0500 Subject: [PATCH 016/133] docs: enhance development instructions for improved performance --- .github/copilot-instructions.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 6c8d0b0..d72657c 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -16,10 +16,12 @@ ```bash composer dev # Starts development server with file watcher # OR directly: php server # Custom file watcher that restarts on changes +XDEBUG_MODE=off php public/index.php # Direct server start (faster, no debugging) ``` - Server runs on `APP_URL:APP_PORT` (default: http://127.0.0.1:1337) - Watches: `app/`, `config/`, `routes/`, `database/`, `composer.json`, `.env` - Requires Node.js for chokidar file watcher +- Use `XDEBUG_MODE=off` for better performance when debugging isn't needed ### Testing ```bash From 2dc8128d82ada7e40e354b897739a552e8ec179d Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 22 Aug 2025 10:03:53 -0500 Subject: [PATCH 017/133] chore: remove nunomaduro/phpinsights and update analyze script to use phpstan --- .github/copilot-instructions.md | 3 +- .github/workflows/run-tests.yml | 4 - composer.json | 4 +- composer.lock | 1192 ++++++------------------------- phpinsights.php | 124 ---- 5 files changed, 208 insertions(+), 1119 deletions(-) delete mode 100644 phpinsights.php diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d72657c..350a36c 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -36,8 +36,7 @@ composer test:parallel # Parallel execution ### Quality Tools ```bash composer format # PHP CS Fixer -composer analyze # PHPInsights -composer analyze:static # PHPStan +composer analyze # PHPStan ``` ## Queue System Architecture diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 7ca6918..49cf7b9 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -36,10 +36,6 @@ jobs: run: | vendor/bin/php-cs-fixer fix --dry-run --diff --ansi - - name: Check quality code with PHPInsights - run: | - vendor/bin/phpinsights -n --ansi --format=github-action - - name: Analyze code statically with PHPStan run: | cp .env.example .env diff --git a/composer.json b/composer.json index 74de825..9898789 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,6 @@ "friendsofphp/php-cs-fixer": "^3.11", "mockery/mockery": "^1.6", "nunomaduro/collision": "^6.3", - "nunomaduro/phpinsights": "^2.6", "pestphp/pest": "^1.22", "pestphp/pest-plugin-faker": "^1.0", "pestphp/pest-plugin-global-assertions": "^1.0", @@ -61,8 +60,7 @@ "test:coverage": "XDEBUG_MODE=coverage vendor/bin/pest --coverage", "test:parallel": "vendor/bin/pest --parallel", "format": "vendor/bin/php-cs-fixer fix", - "analyze": "vendor/bin/phpinsights", - "analyze:static": "vendor/bin/phpstan", + "analyze": "vendor/bin/phpstan", "dev": [ "Composer\\Config::disableProcessTimeout", "@php server" diff --git a/composer.lock b/composer.lock index 509ab67..382ad0a 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": "2ed9708a8850061a7a9063d9d58890cf", + "content-hash": "9199dcf9cdef3aded4b30d156f7d2382", "packages": [ { "name": "adbario/php-dot-notation", @@ -595,16 +595,16 @@ }, { "name": "amphp/http-client", - "version": "v5.3.3", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/amphp/http-client.git", - "reference": "09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc" + "reference": "75ad21574fd632594a2dd914496647816d5106bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-client/zipball/09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc", - "reference": "09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc", + "url": "https://api.github.com/repos/amphp/http-client/zipball/75ad21574fd632594a2dd914496647816d5106bc", + "reference": "75ad21574fd632594a2dd914496647816d5106bc", "shasum": "" }, "require": { @@ -681,7 +681,7 @@ ], "support": { "issues": "https://github.com/amphp/http-client/issues", - "source": "https://github.com/amphp/http-client/tree/v5.3.3" + "source": "https://github.com/amphp/http-client/tree/v5.3.4" }, "funding": [ { @@ -689,7 +689,7 @@ "type": "github" } ], - "time": "2025-05-21T03:24:20+00:00" + "time": "2025-08-16T20:41:23+00:00" }, { "name": "amphp/http-server", @@ -1933,16 +1933,16 @@ }, { "name": "async-aws/core", - "version": "1.26.0", + "version": "1.27.0", "source": { "type": "git", "url": "https://github.com/async-aws/core.git", - "reference": "58ab79116d990e7053b2e31162f47df4223148c5" + "reference": "00b69a04a36b5ba75e0448e46158c9718ac95755" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/core/zipball/58ab79116d990e7053b2e31162f47df4223148c5", - "reference": "58ab79116d990e7053b2e31162f47df4223148c5", + "url": "https://api.github.com/repos/async-aws/core/zipball/00b69a04a36b5ba75e0448e46158c9718ac95755", + "reference": "00b69a04a36b5ba75e0448e46158c9718ac95755", "shasum": "" }, "require": { @@ -1953,7 +1953,7 @@ "psr/cache": "^1.0 || ^2.0 || ^3.0", "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/deprecation-contracts": "^2.1 || ^3.0", - "symfony/http-client": "^4.4.16 || ^5.1.7 || ^6.0 || ^7.0", + "symfony/http-client": "^4.4.16 || ^5.1.7 || ^6.0 || ^7.0 || ^8.0", "symfony/http-client-contracts": "^1.1.8 || ^2.0 || ^3.0", "symfony/service-contracts": "^1.0 || ^2.0 || ^3.0" }, @@ -1964,7 +1964,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.26-dev" + "dev-master": "1.27-dev" } }, "autoload": { @@ -1985,7 +1985,7 @@ "sts" ], "support": { - "source": "https://github.com/async-aws/core/tree/1.26.0" + "source": "https://github.com/async-aws/core/tree/1.27.0" }, "funding": [ { @@ -1997,20 +1997,20 @@ "type": "github" } ], - "time": "2025-05-12T09:35:01+00:00" + "time": "2025-08-11T10:03:27+00:00" }, { "name": "async-aws/ses", - "version": "1.12.0", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/async-aws/ses.git", - "reference": "904ee7b5c07d865c20db4c06c3c0b97e7035673d" + "reference": "e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/ses/zipball/904ee7b5c07d865c20db4c06c3c0b97e7035673d", - "reference": "904ee7b5c07d865c20db4c06c3c0b97e7035673d", + "url": "https://api.github.com/repos/async-aws/ses/zipball/e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42", + "reference": "e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42", "shasum": "" }, "require": { @@ -2021,7 +2021,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -2042,7 +2042,7 @@ "ses" ], "support": { - "source": "https://github.com/async-aws/ses/tree/1.12.0" + "source": "https://github.com/async-aws/ses/tree/1.13.0" }, "funding": [ { @@ -2054,7 +2054,7 @@ "type": "github" } ], - "time": "2025-05-12T09:35:01+00:00" + "time": "2025-08-11T10:03:27+00:00" }, { "name": "cakephp/chronos", @@ -3814,12 +3814,12 @@ "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "5b6914812632e8349dd94e5b5ff2e5540155a713" + "reference": "98400503a3910de75faeb72ef692f81b6cf5a2e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/5b6914812632e8349dd94e5b5ff2e5540155a713", - "reference": "5b6914812632e8349dd94e5b5ff2e5540155a713", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/98400503a3910de75faeb72ef692f81b6cf5a2e2", + "reference": "98400503a3910de75faeb72ef692f81b6cf5a2e2", "shasum": "" }, "require": { @@ -3896,7 +3896,7 @@ "issues": "https://github.com/phenixphp/framework/issues", "source": "https://github.com/phenixphp/framework/tree/feature/queue-system" }, - "time": "2025-08-06T22:41:55+00:00" + "time": "2025-08-21T18:42:11+00:00" }, { "name": "phenixphp/http-cors", @@ -3938,16 +3938,16 @@ }, { "name": "phpoption/phpoption", - "version": "1.9.3", + "version": "1.9.4", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", "shasum": "" }, "require": { @@ -3955,7 +3955,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" }, "type": "library", "extra": { @@ -3997,7 +3997,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" }, "funding": [ { @@ -4009,7 +4009,7 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:41:07+00:00" + "time": "2025-08-21T11:53:16+00:00" }, { "name": "psr/cache", @@ -5768,7 +5768,7 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -5827,7 +5827,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -5838,6 +5838,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5847,16 +5851,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { @@ -5905,7 +5909,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -5916,16 +5920,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -5988,7 +5996,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -5999,6 +6007,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -6008,7 +6020,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -6069,7 +6081,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -6080,6 +6092,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -6089,7 +6105,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -6150,7 +6166,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -6161,6 +6177,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -6170,7 +6190,7 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -6230,7 +6250,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -6241,6 +6261,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -6250,16 +6274,16 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { @@ -6306,7 +6330,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -6317,16 +6341,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-08T02:45:35+00:00" }, { "name": "symfony/polyfill-uuid", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", @@ -6385,7 +6413,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" }, "funding": [ { @@ -6396,6 +6424,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -7285,71 +7317,6 @@ ], "time": "2022-12-23T10:58:28+00:00" }, - { - "name": "cmgmyr/phploc", - "version": "8.0.6", - "source": { - "type": "git", - "url": "https://github.com/cmgmyr/phploc.git", - "reference": "5d785f8fc8b891483cdbee3fb25f2b348c50c03f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/cmgmyr/phploc/zipball/5d785f8fc8b891483cdbee3fb25f2b348c50c03f", - "reference": "5d785f8fc8b891483cdbee3fb25f2b348c50c03f", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "php": "^7.4 || ^8.0", - "phpunit/php-file-iterator": "^3.0|^4.0|^5.0|^6.0", - "sebastian/cli-parser": "^1.0|^2.0|^3.0|^4.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "phpunit/phpunit": "^9.0|^10.0", - "vimeo/psalm": "^5.7" - }, - "bin": [ - "phploc" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "8.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Chris Gmyr", - "email": "cmgmyr@gmail.com", - "role": "lead" - } - ], - "description": "A tool for quickly measuring the size of a PHP project.", - "homepage": "https://github.com/cmgmyr/phploc", - "support": { - "issues": "https://github.com/cmgmyr/phploc/issues", - "source": "https://github.com/cmgmyr/phploc/tree/8.0.6" - }, - "funding": [ - { - "url": "https://github.com/cmgmyr", - "type": "github" - } - ], - "time": "2025-03-29T16:41:46+00:00" - }, { "name": "composer/pcre", "version": "3.3.2", @@ -7431,16 +7398,16 @@ }, { "name": "composer/semver", - "version": "3.4.3", + "version": "3.4.4", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", "shasum": "" }, "require": { @@ -7492,7 +7459,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.3" + "source": "https://github.com/composer/semver/tree/3.4.4" }, "funding": [ { @@ -7502,13 +7469,9 @@ { "url": "https://github.com/composer", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" } ], - "time": "2024-09-19T14:15:21+00:00" + "time": "2025-08-20T19:15:30+00:00" }, { "name": "composer/xdebug-handler", @@ -7576,102 +7539,6 @@ ], "time": "2024-05-06T16:37:16+00:00" }, - { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.1.2", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^2.2", - "php": ">=5.4", - "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" - }, - "require-dev": { - "composer/composer": "^2.2", - "ext-json": "*", - "ext-zip": "*", - "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcompatibility/php-compatibility": "^9.0", - "yoast/phpunit-polyfills": "^1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" - }, - "autoload": { - "psr-4": { - "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Franck Nijhof", - "email": "opensource@frenck.dev", - "homepage": "https://frenck.dev", - "role": "Open source developer" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcbf", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/composer-installer/issues", - "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", - "source": "https://github.com/PHPCSStandards/composer-installer" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-07-17T20:45:56+00:00" - }, { "name": "doctrine/instantiator", "version": "2.0.0", @@ -7791,16 +7658,16 @@ }, { "name": "fidry/cpu-core-counter", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "8520451a140d3f46ac33042715115e290cf5785f" + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", - "reference": "8520451a140d3f46ac33042715115e290cf5785f", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", "shasum": "" }, "require": { @@ -7810,10 +7677,10 @@ "fidry/makefile": "^0.2.0", "fidry/php-cs-fixer-config": "^1.1.2", "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^1.9.2", - "phpstan/phpstan-deprecation-rules": "^1.0.0", - "phpstan/phpstan-phpunit": "^1.2.2", - "phpstan/phpstan-strict-rules": "^1.4.4", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^8.5.31 || ^9.5.26", "webmozarts/strict-phpunit": "^7.5" }, @@ -7840,7 +7707,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" }, "funding": [ { @@ -7848,20 +7715,20 @@ "type": "github" } ], - "time": "2024-08-06T10:04:20+00:00" + "time": "2025-08-14T07:29:31+00:00" }, { "name": "filp/whoops", - "version": "2.18.3", + "version": "2.18.4", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "59a123a3d459c5a23055802237cb317f609867e5" + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5", - "reference": "59a123a3d459c5a23055802237cb317f609867e5", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", "shasum": "" }, "require": { @@ -7911,7 +7778,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.3" + "source": "https://github.com/filp/whoops/tree/2.18.4" }, "funding": [ { @@ -7919,20 +7786,20 @@ "type": "github" } ], - "time": "2025-06-16T00:02:10+00:00" + "time": "2025-08-08T12:00:00+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.85.1", + "version": "v3.86.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba" + "reference": "4a952bd19dc97879b0620f495552ef09b55f7d36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2fb6d7f6c3398dca5786a1635b27405d73a417ba", - "reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/4a952bd19dc97879b0620f495552ef09b55f7d36", + "reference": "4a952bd19dc97879b0620f495552ef09b55f7d36", "shasum": "" }, "require": { @@ -8016,7 +7883,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.85.1" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.86.0" }, "funding": [ { @@ -8024,7 +7891,7 @@ "type": "github" } ], - "time": "2025-07-29T22:22:50+00:00" + "time": "2025-08-13T22:36:21+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -8137,71 +8004,6 @@ }, "time": "2025-03-19T14:43:43+00:00" }, - { - "name": "justinrainbow/json-schema", - "version": "5.3.0", - "source": { - "type": "git", - "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", - "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", - "json-schema/json-schema-test-suite": "1.2.0", - "phpunit/phpunit": "^4.8.35" - }, - "bin": [ - "bin/validate-json" - ], - "type": "library", - "autoload": { - "psr-4": { - "JsonSchema\\": "src/JsonSchema/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bruno Prieto Reis", - "email": "bruno.p.reis@gmail.com" - }, - { - "name": "Justin Rainbow", - "email": "justin.rainbow@gmail.com" - }, - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - }, - { - "name": "Robert Schönthal", - "email": "seroscho@googlemail.com" - } - ], - "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", - "keywords": [ - "json", - "schema" - ], - "support": { - "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" - }, - "time": "2024-07-06T21:00:26+00:00" - }, { "name": "mockery/mockery", "version": "1.6.12", @@ -8347,16 +8149,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.0", + "version": "v5.6.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56" + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56", - "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", "shasum": "" }, "require": { @@ -8375,7 +8177,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "5.x-dev" } }, "autoload": { @@ -8399,9 +8201,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" }, - "time": "2025-07-27T20:03:57+00:00" + "time": "2025-08-13T20:13:15+00:00" }, { "name": "nunomaduro/collision", @@ -8491,112 +8293,6 @@ ], "time": "2023-01-03T12:54:54+00:00" }, - { - "name": "nunomaduro/phpinsights", - "version": "v2.12.0", - "source": { - "type": "git", - "url": "https://github.com/nunomaduro/phpinsights.git", - "reference": "5c12a8d626712de6db5e6d2db52b1eb4e9596650" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/phpinsights/zipball/5c12a8d626712de6db5e6d2db52b1eb4e9596650", - "reference": "5c12a8d626712de6db5e6d2db52b1eb4e9596650", - "shasum": "" - }, - "require": { - "cmgmyr/phploc": "^8.0.3", - "composer/semver": "^3.4", - "ext-iconv": "*", - "ext-json": "*", - "ext-mbstring": "*", - "ext-tokenizer": "*", - "friendsofphp/php-cs-fixer": "^3.40.0", - "justinrainbow/json-schema": "^5.2.13", - "league/container": "^3.2|^4.2", - "php": "^7.4|^8.0", - "php-parallel-lint/php-parallel-lint": "^1.3.2", - "psr/container": "^1.0|^2.0.2", - "psr/simple-cache": "^1.0|^2.0|^3.0", - "sebastian/diff": "^4.0|^5.0.3|^6.0", - "slevomat/coding-standard": "^8.14.1", - "squizlabs/php_codesniffer": "^3.7.2", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.4|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.4|^7.0" - }, - "require-dev": { - "ergebnis/phpstan-rules": "^0.15.3", - "illuminate/console": "^5.8|^6.0|^7.0|^8.0|^9.20|^10.0", - "illuminate/support": "^5.8|^6.0|^7.0|^8.0|^9.52.16|^10.0", - "mockery/mockery": "^1.6.6", - "phpstan/phpstan-strict-rules": "^0.12.11", - "phpunit/phpunit": "^8.0|^9.0|^10.4.2", - "rector/rector": "0.11.56", - "symfony/var-dumper": "^5.4|^6.0|^7.0", - "thecodingmachine/phpstan-strict-rules": "^0.12.2" - }, - "suggest": { - "ext-simplexml": "It is needed for the checkstyle formatter" - }, - "bin": [ - "bin/phpinsights" - ], - "type": "library", - "extra": { - "laravel": { - "providers": [ - "NunoMaduro\\PhpInsights\\Application\\Adapters\\Laravel\\InsightsServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "NunoMaduro\\PhpInsights\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "Instant PHP quality checks from your console.", - "keywords": [ - "Insights", - "code", - "console", - "php", - "quality", - "source" - ], - "support": { - "issues": "https://github.com/nunomaduro/phpinsights/issues", - "source": "https://github.com/nunomaduro/phpinsights/tree/v2.12.0" - }, - "funding": [ - { - "url": "https://github.com/JustSteveKing", - "type": "github" - }, - { - "url": "https://github.com/cmgmyr", - "type": "github" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - } - ], - "time": "2024-11-11T14:42:55+00:00" - }, { "name": "pestphp/pest", "version": "v1.23.1", @@ -9122,78 +8818,17 @@ "time": "2022-02-21T01:04:05+00:00" }, { - "name": "php-parallel-lint/php-parallel-lint", - "version": "v1.4.0", + "name": "phpstan/extension-installer", + "version": "1.4.3", "source": { "type": "git", - "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git", - "reference": "6db563514f27e19595a19f45a4bf757b6401194e" + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6db563514f27e19595a19f45a4bf757b6401194e", - "reference": "6db563514f27e19595a19f45a4bf757b6401194e", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": ">=5.3.0" - }, - "replace": { - "grogy/php-parallel-lint": "*", - "jakub-onderka/php-parallel-lint": "*" - }, - "require-dev": { - "nette/tester": "^1.3 || ^2.0", - "php-parallel-lint/php-console-highlighter": "0.* || ^1.0", - "squizlabs/php_codesniffer": "^3.6" - }, - "suggest": { - "php-parallel-lint/php-console-highlighter": "Highlight syntax in code snippet" - }, - "bin": [ - "parallel-lint" - ], - "type": "library", - "autoload": { - "classmap": [ - "./src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Jakub Onderka", - "email": "ahoj@jakubonderka.cz" - } - ], - "description": "This tool checks the syntax of PHP files about 20x faster than serial check.", - "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint", - "keywords": [ - "lint", - "static analysis" - ], - "support": { - "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues", - "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.4.0" - }, - "time": "2024-03-27T12:14:49+00:00" - }, - { - "name": "phpstan/extension-installer", - "version": "1.4.3", - "source": { - "type": "git", - "url": "https://github.com/phpstan/extension-installer.git", - "reference": "85e90b3942d06b2326fba0403ec24fe912372936" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", - "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", "shasum": "" }, "require": { @@ -9230,53 +8865,6 @@ }, "time": "2024-09-04T20:21:43+00:00" }, - { - "name": "phpstan/phpdoc-parser", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", - "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^5.3.0", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "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/2.2.0" - }, - "time": "2025-07-13T07:04:09+00:00" - }, { "name": "phpstan/phpstan", "version": "1.12.28", @@ -9755,16 +9343,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.23", + "version": "9.6.25", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95" + "reference": "049c011e01be805202d8eebedef49f769a8ec7b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", - "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/049c011e01be805202d8eebedef49f769a8ec7b7", + "reference": "049c011e01be805202d8eebedef49f769a8ec7b7", "shasum": "" }, "require": { @@ -9775,7 +9363,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.1", + "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", @@ -9786,11 +9374,11 @@ "phpunit/php-timer": "^5.0.3", "sebastian/cli-parser": "^1.0.2", "sebastian/code-unit": "^1.0.8", - "sebastian/comparator": "^4.0.8", + "sebastian/comparator": "^4.0.9", "sebastian/diff": "^4.0.6", "sebastian/environment": "^5.1.5", "sebastian/exporter": "^4.0.6", - "sebastian/global-state": "^5.0.7", + "sebastian/global-state": "^5.0.8", "sebastian/object-enumerator": "^4.0.4", "sebastian/resource-operations": "^3.0.4", "sebastian/type": "^3.2.1", @@ -9838,7 +9426,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.23" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.25" }, "funding": [ { @@ -9862,7 +9450,7 @@ "type": "tidelift" } ], - "time": "2025-05-02T06:40:34+00:00" + "time": "2025-08-20T14:38:31+00:00" }, { "name": "react/cache", @@ -10161,23 +9749,23 @@ }, { "name": "react/promise", - "version": "v3.2.0", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", - "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a", "shasum": "" }, "require": { "php": ">=7.1.0" }, "require-dev": { - "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpstan/phpstan": "1.12.28 || 1.4.10", "phpunit/phpunit": "^9.6 || ^7.5" }, "type": "library", @@ -10222,7 +9810,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v3.2.0" + "source": "https://github.com/reactphp/promise/tree/v3.3.0" }, "funding": [ { @@ -10230,7 +9818,7 @@ "type": "open_collective" } ], - "time": "2024-05-24T10:39:05+00:00" + "time": "2025-08-19T18:57:03+00:00" }, { "name": "react/socket", @@ -10559,16 +10147,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.8", + "version": "4.0.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5", + "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5", "shasum": "" }, "require": { @@ -10621,15 +10209,27 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2022-09-14T12:41:17+00:00" + "time": "2025-08-10T06:51:50+00:00" }, { "name": "sebastian/complexity", @@ -10896,16 +10496,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.7", + "version": "5.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6", + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6", "shasum": "" }, "require": { @@ -10948,15 +10548,27 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" } ], - "time": "2024-03-02T06:35:11+00:00" + "time": "2025-08-10T07:10:35+00:00" }, { "name": "sebastian/lines-of-code", @@ -11129,16 +10741,16 @@ }, { "name": "sebastian/recursion-context", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0", + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0", "shasum": "" }, "require": { @@ -11180,15 +10792,27 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" } ], - "time": "2023-02-03T06:07:39+00:00" + "time": "2025-08-10T06:57:39+00:00" }, { "name": "sebastian/resource-operations", @@ -11353,71 +10977,6 @@ ], "time": "2020-09-28T06:39:44+00:00" }, - { - "name": "slevomat/coding-standard", - "version": "8.20.0", - "source": { - "type": "git", - "url": "https://github.com/slevomat/coding-standard.git", - "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b4f9f02edd4e6a586777f0cabe8d05574323f3eb", - "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb", - "shasum": "" - }, - "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2", - "php": "^7.4 || ^8.0", - "phpstan/phpdoc-parser": "^2.2.0", - "squizlabs/php_codesniffer": "^3.13.2" - }, - "require-dev": { - "phing/phing": "3.0.1|3.1.0", - "php-parallel-lint/php-parallel-lint": "1.4.0", - "phpstan/phpstan": "2.1.19", - "phpstan/phpstan-deprecation-rules": "2.0.3", - "phpstan/phpstan-phpunit": "2.0.7", - "phpstan/phpstan-strict-rules": "2.0.6", - "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.27|12.2.7" - }, - "type": "phpcodesniffer-standard", - "extra": { - "branch-alias": { - "dev-master": "8.x-dev" - } - }, - "autoload": { - "psr-4": { - "SlevomatCodingStandard\\": "SlevomatCodingStandard/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", - "keywords": [ - "dev", - "phpcs" - ], - "support": { - "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.20.0" - }, - "funding": [ - { - "url": "https://github.com/kukulich", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", - "type": "tidelift" - } - ], - "time": "2025-07-26T15:35:10+00:00" - }, { "name": "spatie/file-system-watcher", "version": "1.2.0", @@ -11478,268 +11037,6 @@ ], "time": "2023-12-18T14:26:25+00:00" }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.13.2", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-06-17T22:17:01+00:00" - }, - { - "name": "symfony/cache", - "version": "v7.3.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache.git", - "reference": "6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6", - "reference": "6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "psr/cache": "^2.0|^3.0", - "psr/log": "^1.1|^2|^3", - "symfony/cache-contracts": "^3.6", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.4|^7.0" - }, - "conflict": { - "doctrine/dbal": "<3.6", - "symfony/dependency-injection": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/var-dumper": "<6.4" - }, - "provide": { - "psr/cache-implementation": "2.0|3.0", - "psr/simple-cache-implementation": "1.0|2.0|3.0", - "symfony/cache-implementation": "1.1|2.0|3.0" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/dbal": "^3.6|^4", - "predis/predis": "^1.1|^2.0", - "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/filesystem": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Cache\\": "" - }, - "classmap": [ - "Traits/ValueWrapper.php" - ], - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", - "homepage": "https://symfony.com", - "keywords": [ - "caching", - "psr6" - ], - "support": { - "source": "https://github.com/symfony/cache/tree/v7.3.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-07-30T17:13:41+00:00" - }, - { - "name": "symfony/cache-contracts", - "version": "v3.6.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache-contracts.git", - "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", - "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/cache": "^3.0" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Cache\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to caching", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-03-13T15:25:07+00:00" - }, { "name": "symfony/finder", "version": "v7.3.2", @@ -11881,7 +11178,7 @@ }, { "name": "symfony/polyfill-php81", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -11937,7 +11234,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" }, "funding": [ { @@ -11948,6 +11245,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -12078,87 +11379,6 @@ ], "time": "2025-02-24T10:49:57+00:00" }, - { - "name": "symfony/var-exporter", - "version": "v7.3.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-exporter.git", - "reference": "05b3e90654c097817325d6abd284f7938b05f467" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/05b3e90654c097817325d6abd284f7938b05f467", - "reference": "05b3e90654c097817325d6abd284f7938b05f467", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "require-dev": { - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\VarExporter\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Allows exporting any serializable PHP data structure to plain PHP code", - "homepage": "https://symfony.com", - "keywords": [ - "clone", - "construct", - "export", - "hydrate", - "instantiate", - "lazy-loading", - "proxy", - "serialize" - ], - "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.3.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-07-10T08:47:49+00:00" - }, { "name": "theseer/tokenizer", "version": "1.2.3", diff --git a/phpinsights.php b/phpinsights.php deleted file mode 100644 index f89e5d0..0000000 --- a/phpinsights.php +++ /dev/null @@ -1,124 +0,0 @@ - 'default', - - /* - |-------------------------------------------------------------------------- - | IDE - |-------------------------------------------------------------------------- - | - | This options allow to add hyperlinks in your terminal to quickly open - | files in your favorite IDE while browsing your PhpInsights report. - | - | Supported: "textmate", "macvim", "emacs", "sublime", "phpstorm", - | "atom", "vscode". - | - | If you have another IDE that is not in this list but which provide an - | url-handler, you could fill this config with a pattern like this: - | - | myide://open?url=file://%f&line=%l - | - */ - - 'ide' => 'vscode', - - /* - |-------------------------------------------------------------------------- - | Configuration - |-------------------------------------------------------------------------- - | - | Here you may adjust all the various `Insights` that will be used by PHP - | Insights. You can either add, remove or configure `Insights`. Keep in - | mind, that all added `Insights` must belong to a specific `Metric`. - | - */ - - 'exclude' => [ - 'build', - 'public', - 'vendor', - 'storage', - '.vscode', - '.github', - 'phpinsights.php', - ], - - 'add' => [ - // ExampleMetric::class => [ - // ExampleInsight::class, - // ] - ], - - 'remove' => [ - PhpCsFixer\Fixer\Import\OrderedImportsFixer::class, // Collision with PHP CS Fixer - NunoMaduro\PhpInsights\Domain\Insights\ForbiddenTraits::class, - NunoMaduro\PhpInsights\Domain\Metrics\Architecture\Traits::class, - SlevomatCodingStandard\Sniffs\Functions\StaticClosureSniff::class, - NunoMaduro\PhpInsights\Domain\Insights\ForbiddenNormalClasses::class, - NunoMaduro\PhpInsights\Domain\Insights\ForbiddenDefineGlobalConstants::class, - SlevomatCodingStandard\Sniffs\Namespaces\AlphabeticallySortedUsesSniff::class, - ], - - 'config' => [ - \SlevomatCodingStandard\Sniffs\Namespaces\UseSpacingSniff::class => [ - 'linesCountBeforeFirstUse' => 1, - 'linesCountBetweenUseTypes' => 1, - 'linesCountAfterLastUse' => 1, - ], - \PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff::class => [ - 'lineLimit' => 120, - 'absoluteLineLimit' => 120, - 'ignoreComments' => false, - ], - ], - - /* - |-------------------------------------------------------------------------- - | Requirements - |-------------------------------------------------------------------------- - | - | Here you may define a level you want to reach per `Insights` category. - | When a score is lower than the minimum level defined, then an error - | code will be returned. This is optional and individually defined. - | - */ - - 'requirements' => [ -// 'min-quality' => 0, -// 'min-complexity' => 0, -// 'min-architecture' => 0, -// 'min-style' => 0, -// 'disable-security-check' => false, - ], - - /* - |-------------------------------------------------------------------------- - | Threads - |-------------------------------------------------------------------------- - | - | Here you may adjust how many threads (core) PHPInsights can use to perform - | the analyse. This is optional, don't provide it and the tool will guess - | the max core number available. This accept null value or integer > 0. - | - */ - - 'threads' => null, - -]; From 258220106fa41b0cc44fb329f2bb65c024a41d34 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 22 Aug 2025 10:08:36 -0500 Subject: [PATCH 018/133] chore: update guzzlehttp/promises and guzzlehttp/psr7 to latest versions --- composer.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/composer.lock b/composer.lock index 382ad0a..3f19a02 100644 --- a/composer.lock +++ b/composer.lock @@ -2890,16 +2890,16 @@ }, { "name": "guzzlehttp/promises", - "version": "2.2.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" + "reference": "481557b130ef3790cf82b713667b43030dc9c957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", "shasum": "" }, "require": { @@ -2907,7 +2907,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "type": "library", "extra": { @@ -2953,7 +2953,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.2.0" + "source": "https://github.com/guzzle/promises/tree/2.3.0" }, "funding": [ { @@ -2969,7 +2969,7 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:27:01+00:00" + "time": "2025-08-22T14:34:08+00:00" }, { "name": "guzzlehttp/psr7", @@ -3814,12 +3814,12 @@ "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "98400503a3910de75faeb72ef692f81b6cf5a2e2" + "reference": "83aff4c0e74ea49441eeaa53a773b24cd9444d1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/98400503a3910de75faeb72ef692f81b6cf5a2e2", - "reference": "98400503a3910de75faeb72ef692f81b6cf5a2e2", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/83aff4c0e74ea49441eeaa53a773b24cd9444d1f", + "reference": "83aff4c0e74ea49441eeaa53a773b24cd9444d1f", "shasum": "" }, "require": { @@ -3896,7 +3896,7 @@ "issues": "https://github.com/phenixphp/framework/issues", "source": "https://github.com/phenixphp/framework/tree/feature/queue-system" }, - "time": "2025-08-21T18:42:11+00:00" + "time": "2025-08-22T14:32:08+00:00" }, { "name": "phenixphp/http-cors", From 529137469c85d25cf9d849f7f5671d22fc539d17 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 22 Aug 2025 10:56:29 -0500 Subject: [PATCH 019/133] chore: update framework --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 3f19a02..42eaaa9 100644 --- a/composer.lock +++ b/composer.lock @@ -3814,12 +3814,12 @@ "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "83aff4c0e74ea49441eeaa53a773b24cd9444d1f" + "reference": "9e9f80ac01618234ad5e8b67af8f240b3a6cccd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/83aff4c0e74ea49441eeaa53a773b24cd9444d1f", - "reference": "83aff4c0e74ea49441eeaa53a773b24cd9444d1f", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/9e9f80ac01618234ad5e8b67af8f240b3a6cccd3", + "reference": "9e9f80ac01618234ad5e8b67af8f240b3a6cccd3", "shasum": "" }, "require": { @@ -3896,7 +3896,7 @@ "issues": "https://github.com/phenixphp/framework/issues", "source": "https://github.com/phenixphp/framework/tree/feature/queue-system" }, - "time": "2025-08-22T14:32:08+00:00" + "time": "2025-08-22T15:27:40+00:00" }, { "name": "phenixphp/http-cors", From 42096c17343ed5c69b21ec756394a731eb29c887 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 22 Aug 2025 17:56:28 -0500 Subject: [PATCH 020/133] chore: install framework v6 --- composer.json | 2 +- composer.lock | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 9898789..2bba8af 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "dev-feature/queue-system" + "phenixphp/framework": "^0.6.0" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index 42eaaa9..ab84d9f 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": "9199dcf9cdef3aded4b30d156f7d2382", + "content-hash": "38f7078cd1d68343715a254570dfd2fe", "packages": [ { "name": "adbario/php-dot-notation", @@ -3810,16 +3810,16 @@ }, { "name": "phenixphp/framework", - "version": "dev-feature/queue-system", + "version": "0.6.0", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "9e9f80ac01618234ad5e8b67af8f240b3a6cccd3" + "reference": "9c43d8518524928fa5eb6922dbbfed21f1b275cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/9e9f80ac01618234ad5e8b67af8f240b3a6cccd3", - "reference": "9e9f80ac01618234ad5e8b67af8f240b3a6cccd3", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/9c43d8518524928fa5eb6922dbbfed21f1b275cd", + "reference": "9c43d8518524928fa5eb6922dbbfed21f1b275cd", "shasum": "" }, "require": { @@ -3894,9 +3894,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/feature/queue-system" + "source": "https://github.com/phenixphp/framework/tree/0.6.0" }, - "time": "2025-08-22T15:27:40+00:00" + "time": "2025-08-22T22:35:11+00:00" }, { "name": "phenixphp/http-cors", @@ -11432,9 +11432,7 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": { - "phenixphp/framework": 20 - }, + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { From ab8d729ede632497294484f210add76004aca4fa Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 22 Aug 2025 18:00:49 -0500 Subject: [PATCH 021/133] fix: correct namespace import for HttpMethod in Pest.php --- tests/Pest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Pest.php b/tests/Pest.php index 18a31ea..48b715c 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -13,7 +13,7 @@ use Amp\Http\Client\HttpClientBuilder; use Amp\Http\Client\Request; -use Phenix\Constants\HttpMethod; +use Phenix\Http\Constants\HttpMethod; use Phenix\Testing\TestResponse; use Phenix\Util\URL; From e2b07b90dfda88528375309262970df47000f7c9 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 16:33:41 -0500 Subject: [PATCH 022/133] feat: enhance server process management with error handling and health checks --- server | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 169 insertions(+), 24 deletions(-) diff --git a/server b/server index dbd009e..0b83140 100644 --- a/server +++ b/server @@ -18,10 +18,18 @@ $config = Dotenv::createArrayBacked(__DIR__, '.env')->load(); class Watcher extends Watch { protected string $host; + protected int $port; + protected int|null $pid; + protected Process $serverProcess; + protected int $consecutiveErrors = 0; + + protected int $maxConsecutiveErrors = 5; + + public function __construct( array $paths, array $config = [] @@ -38,20 +46,13 @@ class Watcher extends Watch $watcher = $this->getWatchProcess(); while (true) { - if (! $watcher->isRunning()) { - throw CouldNotStartWatcher::make($watcher); - } + $this->ensureWatcherIsRunning($watcher); - if ($output = $watcher->getIncrementalOutput()) { - $this->actOnOutput($output); - } + $this->handleWatcherOutput($watcher); - if ($this->serverProcess->isRunning()) { - echo $this->serverProcess->getIncrementalOutput(); - echo $this->serverProcess->getIncrementalErrorOutput(); - } + $this->handleServerProcess(); - if (! ($this->shouldContinue)()) { + if (!($this->shouldContinue)()) { break; } @@ -59,15 +60,15 @@ class Watcher extends Watch } } - public function watch(): void { + public function watch(): void + { echo "Watching for changes..." . PHP_EOL . PHP_EOL; $this->onAnyChange(function (): void { $this->killExistingProcess(); $this->runServer(); - }) - ->start(); + })->start(); } public function systemIsReady(): bool @@ -100,27 +101,171 @@ class Watcher extends Watch } } - public function runServer(): void { - $this->serverProcess = Process::fromShellCommandline("php public/index.php"); + public function runServer(): void + { + if ($this->consecutiveErrors >= $this->maxConsecutiveErrors) { + echo "Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts." . PHP_EOL; + + return; + } + + $command = "XDEBUG_MODE=off php public/index.php"; + $this->serverProcess = Process::fromShellCommandline($command); $this->serverProcess->setTimeout(null); - $this->serverProcess->start(); - $this->pid = $this->serverProcess->getPid(); + try { + $this->serverProcess->start(); + + usleep(100000); // 100ms + + if (!$this->serverProcess->isRunning()) { + $exitCode = $this->serverProcess->getExitCode(); + $this->consecutiveErrors++; + + echo "Server failed to start. Exit code: {$exitCode}" . PHP_EOL; + echo "Error: " . $this->serverProcess->getErrorOutput() . PHP_EOL; + echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL . PHP_EOL; + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + sleep(2); + + $this->runServer(); + } - echo "Server started on {$this->host}:{$this->port}" . PHP_EOL; - echo "PID: {$this->pid}" . PHP_EOL . PHP_EOL; + return; + } + + $this->consecutiveErrors = 0; + $this->pid = $this->serverProcess->getPid(); + + echo "Server started on {$this->host}:{$this->port}" . PHP_EOL; + echo "PID: {$this->pid}" . PHP_EOL . PHP_EOL; + + } catch (Exception $e) { + $this->consecutiveErrors++; + + echo "Failed to start server: " . $e->getMessage() . PHP_EOL; + echo "Command: {$command}" . PHP_EOL; + echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL . PHP_EOL; + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + sleep(2); + + $this->runServer(); + } + } } - protected function killExistingProcess() + private function ensureWatcherIsRunning(Process $watcher): void { - if ($this->pid) { + if (!$watcher->isRunning()) { + throw CouldNotStartWatcher::make($watcher); + } + } + + private function handleWatcherOutput(Process $watcher): void + { + if ($output = $watcher->getIncrementalOutput()) { + $this->actOnOutput($output); + } + } + + private function handleServerProcess(): void + { + if (!isset($this->serverProcess)) { + return; + } + + if ($this->serverProcess->isRunning()) { + $this->outputServerProcess(); + + $this->periodicHealthCheck(); + } else { + $this->handleServerExit(); + } + } + + private function outputServerProcess(): void + { + echo $this->serverProcess->getIncrementalOutput(); + echo $this->serverProcess->getIncrementalErrorOutput(); + } + + private function periodicHealthCheck(): void + { + static $lastHealthCheck = 0; + if (time() - $lastHealthCheck > 10) { + if (!$this->isServerHealthy()) { + echo "Server health check failed. Restarting..." . PHP_EOL; + $this->killExistingProcess(); + $this->runServer(); + } + $lastHealthCheck = time(); + } + } + + private function handleServerExit(): void + { + $exitCode = $this->serverProcess->getExitCode(); + + if ($exitCode !== null && $exitCode !== 0) { + echo "Server process exited with error code: {$exitCode}" . PHP_EOL; + echo "Error output: " . $this->serverProcess->getErrorOutput() . PHP_EOL; echo "Restarting server..." . PHP_EOL . PHP_EOL; - $killProcess = Process::fromShellCommandline('kill ' . escapeshellarg($this->pid)); - $killProcess->run(); + $this->runServer(); + } + } + + private function killExistingProcess(): void + { + if (!isset($this->serverProcess) || !$this->pid) { + return; + } + + echo "Restarting server..." . PHP_EOL . PHP_EOL; + + try { + // First try graceful termination + $this->serverProcess->stop(3); // 3 second timeout + + // If still running, force kill + if ($this->serverProcess->isRunning()) { + $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); + $killProcess->run(); + } echo "Server was stopped (PID {$this->pid})" . PHP_EOL . PHP_EOL; + + } catch (\Exception $e) { + echo "Error stopping server: " . $e->getMessage() . PHP_EOL; + + // Force kill as last resort + $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); + $killProcess->run(); } + + $this->pid = null; + } + + private function isServerHealthy(): bool + { + if (!isset($this->serverProcess) || !$this->serverProcess->isRunning()) { + return false; + } + + // Check if server is responding by making a simple HTTP request + $context = stream_context_create([ + 'http' => [ + 'timeout' => 1, + 'ignore_errors' => true + ] + ]); + + $url = str_replace(['http://', 'https://'], '', $this->host) . ':' . $this->port; + $result = @file_get_contents("http://{$url}", false, $context); + + return $result !== false; } } From da0b468fe71ea5296dcdace7f43f0a832d87b111 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 16:35:35 -0500 Subject: [PATCH 023/133] feat: implement periodic health check for server process management --- server | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server b/server index 0b83140..ecaa258 100644 --- a/server +++ b/server @@ -29,6 +29,8 @@ class Watcher extends Watch protected int $maxConsecutiveErrors = 5; + protected int $lastHealthCheck = 0; + public function __construct( array $paths, @@ -193,14 +195,15 @@ class Watcher extends Watch private function periodicHealthCheck(): void { - static $lastHealthCheck = 0; - if (time() - $lastHealthCheck > 10) { + if (time() - $this->lastHealthCheck > 10) { if (!$this->isServerHealthy()) { echo "Server health check failed. Restarting..." . PHP_EOL; + $this->killExistingProcess(); $this->runServer(); } - $lastHealthCheck = time(); + + $this->lastHealthCheck = time(); } } From 3d0b6d45c8f3395d9ee34bad44ac6f9a0730cb51 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 16:39:00 -0500 Subject: [PATCH 024/133] fix: improve server termination process and error handling --- server | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/server b/server index ecaa258..80e21f9 100644 --- a/server +++ b/server @@ -229,10 +229,8 @@ class Watcher extends Watch echo "Restarting server..." . PHP_EOL . PHP_EOL; try { - // First try graceful termination $this->serverProcess->stop(3); // 3 second timeout - // If still running, force kill if ($this->serverProcess->isRunning()) { $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); $killProcess->run(); @@ -240,10 +238,9 @@ class Watcher extends Watch echo "Server was stopped (PID {$this->pid})" . PHP_EOL . PHP_EOL; - } catch (\Exception $e) { + } catch (Exception $e) { echo "Error stopping server: " . $e->getMessage() . PHP_EOL; - // Force kill as last resort $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); $killProcess->run(); } @@ -257,7 +254,6 @@ class Watcher extends Watch return false; } - // Check if server is responding by making a simple HTTP request $context = stream_context_create([ 'http' => [ 'timeout' => 1, From aa45281f13dc4585f1c61f6dc89377d4008fbd9b Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 17:01:19 -0500 Subject: [PATCH 025/133] feat: enhance server error handling with stop attempts and health check logic --- server | 67 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/server b/server index 80e21f9..6b5e189 100644 --- a/server +++ b/server @@ -31,6 +31,8 @@ class Watcher extends Watch protected int $lastHealthCheck = 0; + protected bool $stopAttempts = false; + public function __construct( array $paths, @@ -103,10 +105,14 @@ class Watcher extends Watch } } - public function runServer(): void + public function runServer(bool $incrementErrorCounter = true): void { - if ($this->consecutiveErrors >= $this->maxConsecutiveErrors) { - echo "Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts." . PHP_EOL; + if ($this->consecutiveErrors >= $this->maxConsecutiveErrors || $this->stopAttempts) { + if (!$this->stopAttempts) { + echo "Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts." . PHP_EOL; + + $this->stopAttempts = true; + } return; } @@ -122,7 +128,10 @@ class Watcher extends Watch if (!$this->serverProcess->isRunning()) { $exitCode = $this->serverProcess->getExitCode(); - $this->consecutiveErrors++; + + if ($incrementErrorCounter) { + $this->consecutiveErrors++; + } echo "Server failed to start. Exit code: {$exitCode}" . PHP_EOL; echo "Error: " . $this->serverProcess->getErrorOutput() . PHP_EOL; @@ -131,20 +140,24 @@ class Watcher extends Watch if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { sleep(2); - $this->runServer(); + $this->runServer($incrementErrorCounter); } return; } - $this->consecutiveErrors = 0; + if ($incrementErrorCounter) { + $this->consecutiveErrors = 0; + } $this->pid = $this->serverProcess->getPid(); echo "Server started on {$this->host}:{$this->port}" . PHP_EOL; echo "PID: {$this->pid}" . PHP_EOL . PHP_EOL; } catch (Exception $e) { - $this->consecutiveErrors++; + if ($incrementErrorCounter) { + $this->consecutiveErrors++; + } echo "Failed to start server: " . $e->getMessage() . PHP_EOL; echo "Command: {$command}" . PHP_EOL; @@ -153,7 +166,7 @@ class Watcher extends Watch if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { sleep(2); - $this->runServer(); + $this->runServer($incrementErrorCounter); } } } @@ -195,12 +208,33 @@ class Watcher extends Watch private function periodicHealthCheck(): void { + if ($this->stopAttempts) { + return; + } + if (time() - $this->lastHealthCheck > 10) { if (!$this->isServerHealthy()) { echo "Server health check failed. Restarting..." . PHP_EOL; + $this->consecutiveErrors++; + echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL; + $this->killExistingProcess(); - $this->runServer(); + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + $this->runServer(false); + } else { + echo "Maximum consecutive errors reached. Server will not restart automatically." . PHP_EOL; + + $this->stopAttempts = true; + } + } else { + if ($this->consecutiveErrors > 0) { + echo "Server health check passed. Resetting error counter." . PHP_EOL; + + $this->consecutiveErrors = 0; + $this->stopAttempts = false; // Allow attempts again + } } $this->lastHealthCheck = time(); @@ -209,6 +243,10 @@ class Watcher extends Watch private function handleServerExit(): void { + if ($this->stopAttempts) { + return; + } + $exitCode = $this->serverProcess->getExitCode(); if ($exitCode !== null && $exitCode !== 0) { @@ -216,7 +254,16 @@ class Watcher extends Watch echo "Error output: " . $this->serverProcess->getErrorOutput() . PHP_EOL; echo "Restarting server..." . PHP_EOL . PHP_EOL; - $this->runServer(); + $this->consecutiveErrors++; + echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL; + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + $this->runServer(false); + } else { + echo "Maximum consecutive errors reached. Server will not restart automatically." . PHP_EOL; + + $this->stopAttempts = true; + } } } From 96bd1aa53f8ec1b2d69c0c4bac187b3ca0e84734 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 17:39:49 -0500 Subject: [PATCH 026/133] feat: enhance output formatting with colorized messages for server status and errors --- server | 157 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 129 insertions(+), 28 deletions(-) diff --git a/server b/server index 6b5e189..4cee512 100644 --- a/server +++ b/server @@ -13,6 +13,57 @@ if (php_sapi_name() !== 'cli') { exit; } +class Output +{ + public const RESET = "\033[0m"; + public const BOLD = "\033[1m"; + + // Text colors + public const RED = "\033[31m"; + public const GREEN = "\033[32m"; + public const YELLOW = "\033[33m"; + public const BLUE = "\033[34m"; + public const MAGENTA = "\033[35m"; + public const CYAN = "\033[36m"; + public const WHITE = "\033[37m"; + public const GRAY = "\033[90m"; + + // Background colors + public const BG_RED = "\033[41m"; + public const BG_GREEN = "\033[42m"; + public const BG_YELLOW = "\033[43m"; + + public static function colorize(string $text, string $color): string + { + return $color . $text . self::RESET; + } + + public static function success(string $text): string + { + return self::colorize("🚀 " . $text, self::GREEN . self::BOLD); + } + + public static function error(string $text): string + { + return self::colorize("❌ " . $text, self::RED . self::BOLD); + } + + public static function warning(string $text): string + { + return self::colorize("⚠️ " . $text, self::YELLOW . self::BOLD); + } + + public static function info(string $text): string + { + return self::colorize("ℹ️ " . $text, self::CYAN . self::BOLD); + } + + public static function debug(string $text): string + { + return self::colorize($text, self::GRAY); + } +} + $config = Dotenv::createArrayBacked(__DIR__, '.env')->load(); class Watcher extends Watch @@ -66,7 +117,7 @@ class Watcher extends Watch public function watch(): void { - echo "Watching for changes..." . PHP_EOL . PHP_EOL; + echo Output::info("Watching for changes...") . PHP_EOL . PHP_EOL; $this->onAnyChange(function (): void { $this->killExistingProcess(); @@ -86,18 +137,18 @@ class Watcher extends Watch if ($process->isSuccessful() && strpos($process->getOutput(), $packageName) !== false) { return true; } else { - echo "Chokidar is not installed. Installing..." . PHP_EOL; + echo Output::warning("Chokidar is not installed. Installing...") . PHP_EOL; $installCommand = 'npm install ' . escapeshellarg($packageName); $installProcess = Process::fromShellCommandline($installCommand); $installProcess->run(); if ($installProcess->isSuccessful()) { - echo "Chokidar installed successfully." . PHP_EOL; + echo Output::success("Chokidar installed successfully.") . PHP_EOL; return true; } else { - echo "Failed to install chokidar. Please check your npm configuration." . PHP_EOL; + echo Output::error("Failed to install chokidar. Please check your npm configuration.") . PHP_EOL; echo $installProcess->getErrorOutput(); return false; @@ -109,7 +160,7 @@ class Watcher extends Watch { if ($this->consecutiveErrors >= $this->maxConsecutiveErrors || $this->stopAttempts) { if (!$this->stopAttempts) { - echo "Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts." . PHP_EOL; + echo Output::error("Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts.") . PHP_EOL; $this->stopAttempts = true; } @@ -133,9 +184,9 @@ class Watcher extends Watch $this->consecutiveErrors++; } - echo "Server failed to start. Exit code: {$exitCode}" . PHP_EOL; - echo "Error: " . $this->serverProcess->getErrorOutput() . PHP_EOL; - echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL . PHP_EOL; + echo Output::error("Server failed to start. Exit code: {$exitCode}") . PHP_EOL; + echo Output::debug("Error: " . $this->serverProcess->getErrorOutput()) . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL . PHP_EOL; if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { sleep(2); @@ -151,17 +202,17 @@ class Watcher extends Watch } $this->pid = $this->serverProcess->getPid(); - echo "Server started on {$this->host}:{$this->port}" . PHP_EOL; - echo "PID: {$this->pid}" . PHP_EOL . PHP_EOL; + echo Output::success("Server started on {$this->host}:{$this->port}") . PHP_EOL; + echo Output::info("PID: {$this->pid}") . PHP_EOL . PHP_EOL; } catch (Exception $e) { if ($incrementErrorCounter) { $this->consecutiveErrors++; } - echo "Failed to start server: " . $e->getMessage() . PHP_EOL; - echo "Command: {$command}" . PHP_EOL; - echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL . PHP_EOL; + echo Output::error("Failed to start server: " . $e->getMessage()) . PHP_EOL; + echo Output::debug("Command: {$command}") . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL . PHP_EOL; if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { sleep(2); @@ -202,8 +253,58 @@ class Watcher extends Watch private function outputServerProcess(): void { - echo $this->serverProcess->getIncrementalOutput(); - echo $this->serverProcess->getIncrementalErrorOutput(); + $output = $this->serverProcess->getIncrementalOutput(); + $errorOutput = $this->serverProcess->getIncrementalErrorOutput(); + + if ($output) { + echo $this->colorizeServerOutput($output); + } + + if ($errorOutput) { + echo Output::colorize($errorOutput, Output::RED); + } + } + + private function colorizeServerOutput(string $output): string + { + $lines = explode("\n", $output); + $colorizedLines = []; + + foreach ($lines as $line) { + if (empty(trim($line))) { + $colorizedLines[] = $line; + + continue; + } + + if (strpos($line, '.NOTICE:') !== false) { + $colorizedLines[] = Output::colorize($line, Output::CYAN); + } elseif (strpos($line, '.WARNING:') !== false) { + $colorizedLines[] = Output::colorize($line, Output::YELLOW); + } elseif (strpos($line, '.ERROR:') !== false) { + $colorizedLines[] = Output::colorize($line, Output::RED); + } elseif (strpos($line, '.DEBUG:') !== false) { + $colorizedLines[] = Output::colorize($line, Output::GRAY); + } elseif (strpos($line, '.INFO:') !== false) { + $colorizedLines[] = Output::colorize($line, Output::GREEN); + } elseif (strpos($line, 'Started server') !== false || strpos($line, 'Listening on') !== false) { + $colorizedLines[] = Output::colorize($line, Output::GREEN . Output::BOLD); + } elseif (strpos($line, 'GET') !== false || strpos($line, 'POST') !== false || strpos($line, 'PUT') !== false) { + if (strpos($line, ' 200 ') !== false) { + $colorizedLines[] = Output::colorize($line, Output::GREEN); + } elseif (strpos($line, ' 404 ') !== false) { + $colorizedLines[] = Output::colorize($line, Output::YELLOW); + } elseif (strpos($line, ' 500 ') !== false) { + $colorizedLines[] = Output::colorize($line, Output::RED); + } else { + $colorizedLines[] = Output::colorize($line, Output::BLUE); + } + } else { + $colorizedLines[] = $line; + } + } + + return implode("\n", $colorizedLines); } private function periodicHealthCheck(): void @@ -214,23 +315,23 @@ class Watcher extends Watch if (time() - $this->lastHealthCheck > 10) { if (!$this->isServerHealthy()) { - echo "Server health check failed. Restarting..." . PHP_EOL; + echo Output::warning("Server health check failed. Restarting...") . PHP_EOL; $this->consecutiveErrors++; - echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL; $this->killExistingProcess(); if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { $this->runServer(false); } else { - echo "Maximum consecutive errors reached. Server will not restart automatically." . PHP_EOL; + echo Output::error("Maximum consecutive errors reached. Server will not restart automatically.") . PHP_EOL; $this->stopAttempts = true; } } else { if ($this->consecutiveErrors > 0) { - echo "Server health check passed. Resetting error counter." . PHP_EOL; + echo Output::success("Server health check passed. Resetting error counter.") . PHP_EOL; $this->consecutiveErrors = 0; $this->stopAttempts = false; // Allow attempts again @@ -250,17 +351,17 @@ class Watcher extends Watch $exitCode = $this->serverProcess->getExitCode(); if ($exitCode !== null && $exitCode !== 0) { - echo "Server process exited with error code: {$exitCode}" . PHP_EOL; - echo "Error output: " . $this->serverProcess->getErrorOutput() . PHP_EOL; - echo "Restarting server..." . PHP_EOL . PHP_EOL; + echo Output::error("Server process exited with error code: {$exitCode}") . PHP_EOL; + echo Output::debug("Error output: " . $this->serverProcess->getErrorOutput()) . PHP_EOL; + echo Output::info("Restarting server...") . PHP_EOL . PHP_EOL; $this->consecutiveErrors++; - echo "Consecutive errors: {$this->consecutiveErrors}" . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL; if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { $this->runServer(false); } else { - echo "Maximum consecutive errors reached. Server will not restart automatically." . PHP_EOL; + echo Output::error("Maximum consecutive errors reached. Server will not restart automatically.") . PHP_EOL; $this->stopAttempts = true; } @@ -273,7 +374,7 @@ class Watcher extends Watch return; } - echo "Restarting server..." . PHP_EOL . PHP_EOL; + echo Output::info("Restarting server...") . PHP_EOL . PHP_EOL; try { $this->serverProcess->stop(3); // 3 second timeout @@ -283,10 +384,10 @@ class Watcher extends Watch $killProcess->run(); } - echo "Server was stopped (PID {$this->pid})" . PHP_EOL . PHP_EOL; + echo Output::success("Server was stopped (PID {$this->pid})") . PHP_EOL . PHP_EOL; } catch (Exception $e) { - echo "Error stopping server: " . $e->getMessage() . PHP_EOL; + echo Output::error("Error stopping server: " . $e->getMessage()) . PHP_EOL; $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); $killProcess->run(); @@ -330,7 +431,7 @@ try { $watcher->watch(); } else { - echo "System is not ready. Exiting..." . PHP_EOL . PHP_EOL; + echo Output::error("System is not ready. Exiting...") . PHP_EOL . PHP_EOL; } } catch (Throwable $th) { echo $th->getMessage(); From 0538f1d2c485a6e67c8bb61fee44c28ee905bae5 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 23 Aug 2025 17:43:38 -0500 Subject: [PATCH 027/133] feat: refactor line colorization logic for improved readability and maintainability --- server | 78 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/server b/server index 4cee512..328ab9d 100644 --- a/server +++ b/server @@ -271,40 +271,58 @@ class Watcher extends Watch $colorizedLines = []; foreach ($lines as $line) { - if (empty(trim($line))) { - $colorizedLines[] = $line; + $colorizedLines[] = $this->colorizeLine($line); + } - continue; - } + return implode("\n", $colorizedLines); + } - if (strpos($line, '.NOTICE:') !== false) { - $colorizedLines[] = Output::colorize($line, Output::CYAN); - } elseif (strpos($line, '.WARNING:') !== false) { - $colorizedLines[] = Output::colorize($line, Output::YELLOW); - } elseif (strpos($line, '.ERROR:') !== false) { - $colorizedLines[] = Output::colorize($line, Output::RED); - } elseif (strpos($line, '.DEBUG:') !== false) { - $colorizedLines[] = Output::colorize($line, Output::GRAY); - } elseif (strpos($line, '.INFO:') !== false) { - $colorizedLines[] = Output::colorize($line, Output::GREEN); - } elseif (strpos($line, 'Started server') !== false || strpos($line, 'Listening on') !== false) { - $colorizedLines[] = Output::colorize($line, Output::GREEN . Output::BOLD); - } elseif (strpos($line, 'GET') !== false || strpos($line, 'POST') !== false || strpos($line, 'PUT') !== false) { - if (strpos($line, ' 200 ') !== false) { - $colorizedLines[] = Output::colorize($line, Output::GREEN); - } elseif (strpos($line, ' 404 ') !== false) { - $colorizedLines[] = Output::colorize($line, Output::YELLOW); - } elseif (strpos($line, ' 500 ') !== false) { - $colorizedLines[] = Output::colorize($line, Output::RED); - } else { - $colorizedLines[] = Output::colorize($line, Output::BLUE); - } - } else { - $colorizedLines[] = $line; - } + private function colorizeLine(string $line): string + { + $trimmed = trim($line); + $result = $line; + + if ($trimmed === '') { + // leave $result as $line + } elseif (strpos($line, '.NOTICE:') !== false) { + $result = Output::colorize($line, Output::CYAN); + } elseif (strpos($line, '.WARNING:') !== false) { + $result = Output::colorize($line, Output::YELLOW); + } elseif (strpos($line, '.ERROR:') !== false) { + $result = Output::colorize($line, Output::RED); + } elseif (strpos($line, '.DEBUG:') !== false) { + $result = Output::colorize($line, Output::GRAY); + } elseif (strpos($line, '.INFO:') !== false) { + $result = Output::colorize($line, Output::GREEN); + } elseif (strpos($line, 'Started server') !== false || strpos($line, 'Listening on') !== false) { + $result = Output::colorize($line, Output::GREEN . Output::BOLD); + } elseif ($this->isHttpMethodLine($line)) { + $result = $this->colorizeHttpStatusLine($line); } - return implode("\n", $colorizedLines); + return $result; + } + + private function isHttpMethodLine(string $line): bool + { + return strpos($line, 'GET') !== false + || strpos($line, 'POST') !== false + || strpos($line, 'PUT') !== false; + } + + private function colorizeHttpStatusLine(string $line): string + { + $colorized = Output::colorize($line, Output::BLUE); + + if (strpos($line, ' 200 ') !== false) { + $colorized = Output::colorize($line, Output::GREEN); + } elseif (strpos($line, ' 404 ') !== false) { + $colorized = Output::colorize($line, Output::YELLOW); + } elseif (strpos($line, ' 500 ') !== false) { + $colorized = Output::colorize($line, Output::RED); + } + + return $colorized; } private function periodicHealthCheck(): void From 4b473f802d3d9c0745015c64f78b554b505ed5f9 Mon Sep 17 00:00:00 2001 From: FSHLL Date: Sun, 24 Aug 2025 19:04:54 -0500 Subject: [PATCH 028/133] Merge branch 'develop' into feature/docker-config --- .env.example | 11 + .github/copilot-instructions.md | 144 + .github/workflows/run-tests.yml | 4 - composer.json | 6 +- composer.lock | 6292 ++++++++++++++++--------------- config/app.php | 27 +- config/cors.php | 2 +- config/database.php | 34 +- config/filesystem.php | 2 +- config/logging.php | 2 +- config/mail.php | 30 + config/queue.php | 27 + config/services.php | 13 + config/session.php | 4 +- config/view.php | 7 + phpinsights.php | 124 - server | 369 +- tests/Pest.php | 2 +- 18 files changed, 3872 insertions(+), 3228 deletions(-) create mode 100644 .github/copilot-instructions.md create mode 100644 config/mail.php create mode 100644 config/queue.php create mode 100644 config/services.php create mode 100644 config/view.php delete mode 100644 phpinsights.php diff --git a/.env.example b/.env.example index 73b7c36..958f968 100644 --- a/.env.example +++ b/.env.example @@ -1,14 +1,25 @@ APP_NAME=Phenix +APP_KEY= APP_DEBUG=true APP_URL=http://127.0.0.1 APP_PORT=1337 DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 DB_DATABASE=phenix DB_USERNAME=phenix DB_PASSWORD=secret LOG_CHANNEL=stream +QUEUE_DRIVER=parallel + +CORS_ORIGIN= + +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +REDIS_PASSWORD=null + USER_UID=1000 USER_GID=1000 \ No newline at end of file diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..350a36c --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,144 @@ +# Phenix Framework - AI Coding Instructions + +## Architecture Overview + +**Phenix** is an asynchronous PHP web framework built on the [AmPHP](https://amphp.org/) ecosystem. This is a **skeleton application** that depends on `phenixphp/framework` for core functionality. Official documentation can be found at [Phenix Documentation](https://phenix.omarbarbosa.com/). + +### Key Components +- **App Structure**: Standard MVC with `app/` (controllers, tasks), `config/` (service configs), `routes/` (API definitions) +- **Framework Integration**: Core framework lives in `vendor/phenixphp/framework/src/` - reference this for understanding internals +- **Service Providers**: Configured in `config/app.php` - handles DI container, routing, queue, database, etc. +- **Entry Points**: `public/index.php` (HTTP server), `phenix` CLI (console commands) + +## Development Workflow + +### Server & Hot Reloading +```bash +composer dev # Starts development server with file watcher +# OR directly: php server # Custom file watcher that restarts on changes +XDEBUG_MODE=off php public/index.php # Direct server start (faster, no debugging) +``` +- Server runs on `APP_URL:APP_PORT` (default: http://127.0.0.1:1337) +- Watches: `app/`, `config/`, `routes/`, `database/`, `composer.json`, `.env` +- Requires Node.js for chokidar file watcher +- Use `XDEBUG_MODE=off` for better performance when debugging isn't needed + +### Testing +```bash +composer test # Pest tests (XDEBUG_MODE=off) +composer test:coverage # With coverage reports +composer test:parallel # Parallel execution +``` +- **Test Framework**: Pest PHP with custom HTTP client helpers +- **Test Structure**: `tests/Feature/` and `tests/Unit/` with shared `TestCase` +- **HTTP Testing**: Uses Amp HTTP client with helper functions: `get()`, `post()`, etc. + +### Quality Tools +```bash +composer format # PHP CS Fixer +composer analyze # PHPStan +``` + +## Queue System Architecture + +**Critical Pattern**: This project implements an async task queue system with Redis/Database backends. + +### Task Definition +```php +// Extend QueuableTask for background jobs +class MyTask extends QueuableTask +{ + protected int|null $maxTries = 3; // Configure retries + + protected function handle(Channel $channel, Cancellation $cancellation): Result + { + // Async task logic here + return Result::success('TaskName', 'Success message'); + } +} +``` + +### Task Dispatch +```php +// From controllers/anywhere: +MyTask::dispatch(); // Queue immediately +MyTask::enqueue()->delay(60); // Queue with delay +MyTask::dispatchIf($condition); // Conditional dispatch +``` + +### Queue Workers +```bash +./phenix queue:work redis --queue=default # Process queue +./phenix queue:work --once # Process once and exit +./phenix queue:work --chunks # Batch processing +``` + +## Configuration Patterns + +### Environment-Driven Config +```php +// config/ files use closures for lazy evaluation: +'driver' => env('QUEUE_DRIVER', static fn (): string => 'database'), +'timeout' => env('TIMEOUT', static fn (): int => 30), +``` + +### Service Provider Registration +- All providers registered in `config/app.php` +- Queue system: `QueueServiceProvider`, `TaskServiceProvider` +- Database: Supports MySQL/PostgreSQL with migrations via Phinx + +## Data Layer + +### Database +- **Migrations**: `database/migrations/` using Phinx (not Eloquent) +- **Configuration**: `config/database.php` supports multiple connections +- **CLI**: `./phenix` provides migration commands + +### Queue Backends +- **Redis**: Uses Lua scripts for atomic operations (`LuaScripts.php`) +- **Database**: Uses tasks table with state management +- **Parallel**: AmPHP parallel processing with worker pools + +## HTTP Layer + +### Routing +```php +// routes/api.php - use Facade pattern: +Route::get('/', [WelcomeController::class, 'index']); +Route::post('/tasks', [TaskController::class, 'store']); +``` + +### Controllers +```php +class MyController extends Controller +{ + public function index(): Response + { + return response()->json(['data' => $data]); + // OR: response()->plain('text'); + } +} +``` + +## Key Conventions + +1. **Strict Types**: Always use `declare(strict_types=1);` +2. **Static Factories**: Config uses static closures for defaults +3. **Facade Pattern**: `Phenix\Facades\*` for service access +4. **Result Objects**: Tasks return `Result::success()` or `Result::failure()` +5. **Async First**: Built for non-blocking I/O with AmPHP primitives + +## Critical Files to Reference + +- `config/app.php` - Service provider registration and app config +- `vendor/phenixphp/framework/src/Queue/` - Queue implementation details +- `vendor/phenixphp/framework/src/Tasks/QueuableTask.php` - Base task class +- `tests/Pest.php` - HTTP testing helpers and setup +- `bootstrap/app.php` - Application bootstrap via `AppBuilder` + +## Common Pitfalls + +1. **Queue Retries**: Tasks need explicit `$maxTries` property set +2. **Environment**: Copy `.env.example` to `.env` for local development +3. **CLI vs HTTP**: Different entry points (`phenix` vs `public/index.php`) +4. **Dependencies**: Framework code lives in vendor - check there for implementation details diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 7ca6918..49cf7b9 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -36,10 +36,6 @@ jobs: run: | vendor/bin/php-cs-fixer fix --dry-run --diff --ansi - - name: Check quality code with PHPInsights - run: | - vendor/bin/phpinsights -n --ansi --format=github-action - - name: Analyze code statically with PHPStan run: | cp .env.example .env diff --git a/composer.json b/composer.json index 68c5d7c..2bba8af 100644 --- a/composer.json +++ b/composer.json @@ -20,14 +20,13 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "^0.5.2" + "phenixphp/framework": "^0.6.0" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", "friendsofphp/php-cs-fixer": "^3.11", "mockery/mockery": "^1.6", "nunomaduro/collision": "^6.3", - "nunomaduro/phpinsights": "^2.6", "pestphp/pest": "^1.22", "pestphp/pest-plugin-faker": "^1.0", "pestphp/pest-plugin-global-assertions": "^1.0", @@ -61,8 +60,7 @@ "test:coverage": "XDEBUG_MODE=coverage vendor/bin/pest --coverage", "test:parallel": "vendor/bin/pest --parallel", "format": "vendor/bin/php-cs-fixer fix", - "analyze": "vendor/bin/phpinsights", - "analyze:static": "vendor/bin/phpstan", + "analyze": "vendor/bin/phpstan", "dev": [ "Composer\\Config::disableProcessTimeout", "@php server" diff --git a/composer.lock b/composer.lock index fa1276d..ab84d9f 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": "fa526c576a1c4753394c6ac3820d4f9c", + "content-hash": "38f7078cd1d68343715a254570dfd2fe", "packages": [ { "name": "adbario/php-dot-notation", @@ -62,16 +62,16 @@ }, { "name": "amphp/amp", - "version": "v3.0.2", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "138801fb68cfc9c329da8a7b39d01ce7291ee4b0" + "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/138801fb68cfc9c329da8a7b39d01ce7291ee4b0", - "reference": "138801fb68cfc9c329da8a7b39d01ce7291ee4b0", + "url": "https://api.github.com/repos/amphp/amp/zipball/7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9", + "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9", "shasum": "" }, "require": { @@ -131,7 +131,7 @@ ], "support": { "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v3.0.2" + "source": "https://github.com/amphp/amp/tree/v3.1.0" }, "funding": [ { @@ -139,20 +139,20 @@ "type": "github" } ], - "time": "2024-05-10T21:37:46+00:00" + "time": "2025-01-26T16:07:39+00:00" }, { "name": "amphp/byte-stream", - "version": "v2.1.1", + "version": "v2.1.2", "source": { "type": "git", "url": "https://github.com/amphp/byte-stream.git", - "reference": "daa00f2efdbd71565bf64ffefa89e37542addf93" + "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/daa00f2efdbd71565bf64ffefa89e37542addf93", - "reference": "daa00f2efdbd71565bf64ffefa89e37542addf93", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/55a6bd071aec26fa2a3e002618c20c35e3df1b46", + "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46", "shasum": "" }, "require": { @@ -206,7 +206,7 @@ ], "support": { "issues": "https://github.com/amphp/byte-stream/issues", - "source": "https://github.com/amphp/byte-stream/tree/v2.1.1" + "source": "https://github.com/amphp/byte-stream/tree/v2.1.2" }, "funding": [ { @@ -214,7 +214,7 @@ "type": "github" } ], - "time": "2024-02-17T04:49:38+00:00" + "time": "2025-03-16T17:10:27+00:00" }, { "name": "amphp/cache", @@ -283,16 +283,16 @@ }, { "name": "amphp/dns", - "version": "v2.3.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/amphp/dns.git", - "reference": "166c43737cef1b77782c648a9d9ed11ee0c9859f" + "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/dns/zipball/166c43737cef1b77782c648a9d9ed11ee0c9859f", - "reference": "166c43737cef1b77782c648a9d9ed11ee0c9859f", + "url": "https://api.github.com/repos/amphp/dns/zipball/78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", + "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", "shasum": "" }, "require": { @@ -360,7 +360,7 @@ ], "support": { "issues": "https://github.com/amphp/dns/issues", - "source": "https://github.com/amphp/dns/tree/v2.3.0" + "source": "https://github.com/amphp/dns/tree/v2.4.0" }, "funding": [ { @@ -368,7 +368,7 @@ "type": "github" } ], - "time": "2024-12-21T01:15:34+00:00" + "time": "2025-01-19T15:43:40+00:00" }, { "name": "amphp/file", @@ -595,16 +595,16 @@ }, { "name": "amphp/http-client", - "version": "v5.2.1", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/amphp/http-client.git", - "reference": "2117f7e7cd1ecf35d4d0daea1ba5dc6fd318b114" + "reference": "75ad21574fd632594a2dd914496647816d5106bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-client/zipball/2117f7e7cd1ecf35d4d0daea1ba5dc6fd318b114", - "reference": "2117f7e7cd1ecf35d4d0daea1ba5dc6fd318b114", + "url": "https://api.github.com/repos/amphp/http-client/zipball/75ad21574fd632594a2dd914496647816d5106bc", + "reference": "75ad21574fd632594a2dd914496647816d5106bc", "shasum": "" }, "require": { @@ -622,8 +622,11 @@ "psr/http-message": "^1 | ^2", "revolt/event-loop": "^1" }, + "conflict": { + "amphp/file": "<3 | >=5" + }, "require-dev": { - "amphp/file": "^3", + "amphp/file": "^3 | ^4", "amphp/http-server": "^3", "amphp/php-cs-fixer-config": "^2", "amphp/phpunit-util": "^3", @@ -678,7 +681,7 @@ ], "support": { "issues": "https://github.com/amphp/http-client/issues", - "source": "https://github.com/amphp/http-client/tree/v5.2.1" + "source": "https://github.com/amphp/http-client/tree/v5.3.4" }, "funding": [ { @@ -686,20 +689,20 @@ "type": "github" } ], - "time": "2024-12-13T16:16:08+00:00" + "time": "2025-08-16T20:41:23+00:00" }, { "name": "amphp/http-server", - "version": "v3.4.2", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/amphp/http-server.git", - "reference": "c60cde9a1e331f539b7ef5a7705f42092e646f90" + "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-server/zipball/c60cde9a1e331f539b7ef5a7705f42092e646f90", - "reference": "c60cde9a1e331f539b7ef5a7705f42092e646f90", + "url": "https://api.github.com/repos/amphp/http-server/zipball/7aa962b0569f664af3ba23bc819f2a69884329cd", + "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd", "shasum": "" }, "require": { @@ -775,7 +778,7 @@ ], "support": { "issues": "https://github.com/amphp/http-server/issues", - "source": "https://github.com/amphp/http-server/tree/v3.4.2" + "source": "https://github.com/amphp/http-server/tree/v3.4.3" }, "funding": [ { @@ -783,7 +786,7 @@ "type": "github" } ], - "time": "2024-12-31T16:35:28+00:00" + "time": "2025-05-18T15:43:42+00:00" }, { "name": "amphp/http-server-form-parser", @@ -1315,16 +1318,16 @@ }, { "name": "amphp/pipeline", - "version": "v1.2.1", + "version": "v1.2.3", "source": { "type": "git", "url": "https://github.com/amphp/pipeline.git", - "reference": "66c095673aa5b6e689e63b52d19e577459129ab3" + "reference": "7b52598c2e9105ebcddf247fc523161581930367" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/pipeline/zipball/66c095673aa5b6e689e63b52d19e577459129ab3", - "reference": "66c095673aa5b6e689e63b52d19e577459129ab3", + "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367", + "reference": "7b52598c2e9105ebcddf247fc523161581930367", "shasum": "" }, "require": { @@ -1370,7 +1373,7 @@ ], "support": { "issues": "https://github.com/amphp/pipeline/issues", - "source": "https://github.com/amphp/pipeline/tree/v1.2.1" + "source": "https://github.com/amphp/pipeline/tree/v1.2.3" }, "funding": [ { @@ -1378,7 +1381,7 @@ "type": "github" } ], - "time": "2024-07-04T00:56:47+00:00" + "time": "2025-03-16T16:33:53+00:00" }, { "name": "amphp/postgres", @@ -1522,16 +1525,16 @@ }, { "name": "amphp/redis", - "version": "v2.0.1", + "version": "v2.0.3", "source": { "type": "git", "url": "https://github.com/amphp/redis.git", - "reference": "679350556def8f8b412a15a4b82651c4a5caa597" + "reference": "1572c2fec2849d272570919e998f9a3c1a5b1703" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/redis/zipball/679350556def8f8b412a15a4b82651c4a5caa597", - "reference": "679350556def8f8b412a15a4b82651c4a5caa597", + "url": "https://api.github.com/repos/amphp/redis/zipball/1572c2fec2849d272570919e998f9a3c1a5b1703", + "reference": "1572c2fec2849d272570919e998f9a3c1a5b1703", "shasum": "" }, "require": { @@ -1543,7 +1546,7 @@ "amphp/serialization": "^1", "amphp/socket": "^2", "amphp/sync": "^2", - "league/uri": "^6.5|^7", + "league/uri": "^7", "php": ">=8.1", "psr/log": "^1|^2|^3", "revolt/event-loop": "^1" @@ -1591,7 +1594,7 @@ ], "support": { "issues": "https://github.com/amphp/redis/issues", - "source": "https://github.com/amphp/redis/tree/v2.0.1" + "source": "https://github.com/amphp/redis/tree/v2.0.3" }, "funding": [ { @@ -1599,7 +1602,7 @@ "type": "github" } ], - "time": "2024-08-03T18:48:06+00:00" + "time": "2025-01-15T04:14:11+00:00" }, { "name": "amphp/serialization", @@ -1799,16 +1802,16 @@ }, { "name": "amphp/sql-common", - "version": "v2.0.2", + "version": "v2.0.3", "source": { "type": "git", "url": "https://github.com/amphp/sql-common.git", - "reference": "069183d57f17f85c60842ea3a8ce5ff52dba5399" + "reference": "0c926e0348c238c61bead25af5c2fa0d5afaed8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/sql-common/zipball/069183d57f17f85c60842ea3a8ce5ff52dba5399", - "reference": "069183d57f17f85c60842ea3a8ce5ff52dba5399", + "url": "https://api.github.com/repos/amphp/sql-common/zipball/0c926e0348c238c61bead25af5c2fa0d5afaed8d", + "reference": "0c926e0348c238c61bead25af5c2fa0d5afaed8d", "shasum": "" }, "require": { @@ -1843,7 +1846,7 @@ ], "support": { "issues": "https://github.com/amphp/sql-common/issues", - "source": "https://github.com/amphp/sql-common/tree/v2.0.2" + "source": "https://github.com/amphp/sql-common/tree/v2.0.3" }, "funding": [ { @@ -1851,7 +1854,7 @@ "type": "github" } ], - "time": "2024-10-27T16:04:14+00:00" + "time": "2025-06-07T15:35:29+00:00" }, { "name": "amphp/sync", @@ -1928,18 +1931,143 @@ ], "time": "2024-08-03T19:31:26+00:00" }, + { + "name": "async-aws/core", + "version": "1.27.0", + "source": { + "type": "git", + "url": "https://github.com/async-aws/core.git", + "reference": "00b69a04a36b5ba75e0448e46158c9718ac95755" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/async-aws/core/zipball/00b69a04a36b5ba75e0448e46158c9718ac95755", + "reference": "00b69a04a36b5ba75e0448e46158c9718ac95755", + "shasum": "" + }, + "require": { + "ext-hash": "*", + "ext-json": "*", + "ext-simplexml": "*", + "php": "^7.2.5 || ^8.0", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/http-client": "^4.4.16 || ^5.1.7 || ^6.0 || ^7.0 || ^8.0", + "symfony/http-client-contracts": "^1.1.8 || ^2.0 || ^3.0", + "symfony/service-contracts": "^1.0 || ^2.0 || ^3.0" + }, + "conflict": { + "async-aws/s3": "<1.1", + "symfony/http-client": "5.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.27-dev" + } + }, + "autoload": { + "psr-4": { + "AsyncAws\\Core\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Core package to integrate with AWS. This is a lightweight AWS SDK provider by AsyncAws.", + "keywords": [ + "amazon", + "async-aws", + "aws", + "sdk", + "sts" + ], + "support": { + "source": "https://github.com/async-aws/core/tree/1.27.0" + }, + "funding": [ + { + "url": "https://github.com/jderusse", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2025-08-11T10:03:27+00:00" + }, + { + "name": "async-aws/ses", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/async-aws/ses.git", + "reference": "e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/async-aws/ses/zipball/e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42", + "reference": "e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42", + "shasum": "" + }, + "require": { + "async-aws/core": "^1.9", + "ext-json": "*", + "php": "^7.2.5 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13-dev" + } + }, + "autoload": { + "psr-4": { + "AsyncAws\\Ses\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "SES client, part of the AWS SDK provided by AsyncAws.", + "keywords": [ + "amazon", + "async-aws", + "aws", + "sdk", + "ses" + ], + "support": { + "source": "https://github.com/async-aws/ses/tree/1.13.0" + }, + "funding": [ + { + "url": "https://github.com/jderusse", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2025-08-11T10:03:27+00:00" + }, { "name": "cakephp/chronos", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/cakephp/chronos.git", - "reference": "786d69e1ee4b735765cbdb5521b9603e9b98d650" + "reference": "6c820947bc1372a250288ab164ec1b3bb7afab39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/chronos/zipball/786d69e1ee4b735765cbdb5521b9603e9b98d650", - "reference": "786d69e1ee4b735765cbdb5521b9603e9b98d650", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/6c820947bc1372a250288ab164ec1b3bb7afab39", + "reference": "6c820947bc1372a250288ab164ec1b3bb7afab39", "shasum": "" }, "require": { @@ -1985,24 +2113,24 @@ "issues": "https://github.com/cakephp/chronos/issues", "source": "https://github.com/cakephp/chronos" }, - "time": "2024-07-18T03:18:04+00:00" + "time": "2025-06-28T11:35:59+00:00" }, { "name": "cakephp/core", - "version": "5.1.4", + "version": "5.2.6", "source": { "type": "git", "url": "https://github.com/cakephp/core.git", - "reference": "fdd2ab323284cc8475decaeaad4a3398aa90ff91" + "reference": "93f395b6d741775320c4b782ddb47b5c2906e7ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/core/zipball/fdd2ab323284cc8475decaeaad4a3398aa90ff91", - "reference": "fdd2ab323284cc8475decaeaad4a3398aa90ff91", + "url": "https://api.github.com/repos/cakephp/core/zipball/93f395b6d741775320c4b782ddb47b5c2906e7ad", + "reference": "93f395b6d741775320c4b782ddb47b5c2906e7ad", "shasum": "" }, "require": { - "cakephp/utility": "^5.1", + "cakephp/utility": "5.2.*@dev", "league/container": "^4.2", "php": ">=8.1", "psr/container": "^1.1 || ^2.0" @@ -2016,6 +2144,11 @@ "league/container": "To use Container and ServiceProvider classes" }, "type": "library", + "extra": { + "branch-alias": { + "dev-5.x": "5.2.x-dev" + } + }, "autoload": { "files": [ "functions.php" @@ -2047,38 +2180,43 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/core" }, - "time": "2024-11-30T18:47:29+00:00" + "time": "2025-07-20T02:02:49+00:00" }, { "name": "cakephp/database", - "version": "5.1.4", + "version": "5.2.6", "source": { "type": "git", "url": "https://github.com/cakephp/database.git", - "reference": "3a872d4ef14424679d30d2045eaca2643c967d64" + "reference": "1a2b357ed2deae8797c4ccb7a8062b1bdb5e27a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/database/zipball/3a872d4ef14424679d30d2045eaca2643c967d64", - "reference": "3a872d4ef14424679d30d2045eaca2643c967d64", + "url": "https://api.github.com/repos/cakephp/database/zipball/1a2b357ed2deae8797c4ccb7a8062b1bdb5e27a2", + "reference": "1a2b357ed2deae8797c4ccb7a8062b1bdb5e27a2", "shasum": "" }, "require": { "cakephp/chronos": "^3.1", - "cakephp/core": "^5.1", - "cakephp/datasource": "^5.1", + "cakephp/core": "5.2.*@dev", + "cakephp/datasource": "5.2.*@dev", "php": ">=8.1", "psr/log": "^3.0" }, "require-dev": { - "cakephp/i18n": "^5.1", - "cakephp/log": "^5.1" + "cakephp/i18n": "5.2.*@dev", + "cakephp/log": "5.2.*@dev" }, "suggest": { "cakephp/i18n": "If you are using locale-aware datetime formats.", "cakephp/log": "If you want to use query logging without providing a logger yourself." }, "type": "library", + "extra": { + "branch-alias": { + "dev-5.x": "5.2.x-dev" + } + }, "autoload": { "psr-4": { "Cake\\Database\\": "." @@ -2109,31 +2247,31 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/database" }, - "time": "2024-12-12T13:08:46+00:00" + "time": "2025-07-20T02:02:49+00:00" }, { "name": "cakephp/datasource", - "version": "5.1.4", + "version": "5.2.6", "source": { "type": "git", "url": "https://github.com/cakephp/datasource.git", - "reference": "34b9617febd47649011e8914a4dbb21194a78504" + "reference": "4d40b398897ada47569e82b351cabf00e37b2ba1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/datasource/zipball/34b9617febd47649011e8914a4dbb21194a78504", - "reference": "34b9617febd47649011e8914a4dbb21194a78504", + "url": "https://api.github.com/repos/cakephp/datasource/zipball/4d40b398897ada47569e82b351cabf00e37b2ba1", + "reference": "4d40b398897ada47569e82b351cabf00e37b2ba1", "shasum": "" }, "require": { - "cakephp/core": "^5.1", + "cakephp/core": "5.2.*@dev", "php": ">=8.1", "psr/simple-cache": "^2.0 || ^3.0" }, "require-dev": { - "cakephp/cache": "^5.1", - "cakephp/collection": "^5.1", - "cakephp/utility": "^5.1" + "cakephp/cache": "5.2.*@dev", + "cakephp/collection": "5.2.*@dev", + "cakephp/utility": "5.2.*@dev" }, "suggest": { "cakephp/cache": "If you decide to use Query caching.", @@ -2141,6 +2279,11 @@ "cakephp/utility": "If you decide to use EntityTrait." }, "type": "library", + "extra": { + "branch-alias": { + "dev-5.x": "5.2.x-dev" + } + }, "autoload": { "psr-4": { "Cake\\Datasource\\": "." @@ -2171,24 +2314,24 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/datasource" }, - "time": "2024-12-12T02:27:02+00:00" + "time": "2025-07-20T02:02:49+00:00" }, { "name": "cakephp/utility", - "version": "5.1.4", + "version": "5.2.6", "source": { "type": "git", "url": "https://github.com/cakephp/utility.git", - "reference": "943342ca3c0fc3cccb9f789340ff7eb5eceb1839" + "reference": "3188be6abdbe27f85a44c2d317477dc7b43582eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/utility/zipball/943342ca3c0fc3cccb9f789340ff7eb5eceb1839", - "reference": "943342ca3c0fc3cccb9f789340ff7eb5eceb1839", + "url": "https://api.github.com/repos/cakephp/utility/zipball/3188be6abdbe27f85a44c2d317477dc7b43582eb", + "reference": "3188be6abdbe27f85a44c2d317477dc7b43582eb", "shasum": "" }, "require": { - "cakephp/core": "^5.1", + "cakephp/core": "5.2.*@dev", "php": ">=8.1" }, "suggest": { @@ -2196,6 +2339,11 @@ "lib-ICU": "To use Text::transliterate() or Text::slug()" }, "type": "library", + "extra": { + "branch-alias": { + "dev-5.x": "5.2.x-dev" + } + }, "autoload": { "files": [ "bootstrap.php" @@ -2230,7 +2378,7 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/utility" }, - "time": "2024-11-30T18:47:29+00:00" + "time": "2025-07-20T02:02:49+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -2424,16 +2572,16 @@ }, { "name": "egulias/email-validator", - "version": "4.0.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "b115554301161fa21467629f1e1391c1936de517" + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517", - "reference": "b115554301161fa21467629f1e1391c1936de517", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", "shasum": "" }, "require": { @@ -2479,7 +2627,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.3" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" }, "funding": [ { @@ -2487,7 +2635,7 @@ "type": "github" } ], - "time": "2024-12-27T00:36:43+00:00" + "time": "2025-03-06T22:45:56+00:00" }, { "name": "fakerphp/faker", @@ -2615,36 +2763,56 @@ "time": "2024-07-20T21:45:45+00:00" }, { - "name": "kelunik/certificate", - "version": "v1.1.3", + "name": "guzzlehttp/guzzle", + "version": "7.9.3", "source": { "type": "git", - "url": "https://github.com/kelunik/certificate.git", - "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e" + "url": "https://github.com/guzzle/guzzle.git", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e", - "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", "shasum": "" }, "require": { - "ext-openssl": "*", - "php": ">=7.0" + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "phpunit/phpunit": "^6 | 7 | ^8 | ^9" + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.x-dev" + "bamarni-bin": { + "bin-links": true, + "forward-command": false } }, "autoload": { + "files": [ + "src/functions_include.php" + ], "psr-4": { - "Kelunik\\Certificate\\": "src" + "GuzzleHttp\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2653,71 +2821,104 @@ ], "authors": [ { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], - "description": "Access certificate details and transform between different formats.", + "description": "Guzzle is a PHP HTTP client library", "keywords": [ - "DER", - "certificate", - "certificates", - "openssl", - "pem", - "x509" + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" ], "support": { - "issues": "https://github.com/kelunik/certificate/issues", - "source": "https://github.com/kelunik/certificate/tree/v1.1.3" + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.3" }, - "time": "2023-02-03T21:26:53+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2025-03-27T13:37:11+00:00" }, { - "name": "league/container", - "version": "4.2.4", + "name": "guzzlehttp/promises", + "version": "2.3.0", "source": { "type": "git", - "url": "https://github.com/thephpleague/container.git", - "reference": "7ea728b013b9a156c409c6f0fc3624071b742dec" + "url": "https://github.com/guzzle/promises.git", + "reference": "481557b130ef3790cf82b713667b43030dc9c957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/container/zipball/7ea728b013b9a156c409c6f0fc3624071b742dec", - "reference": "7ea728b013b9a156c409c6f0fc3624071b742dec", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "psr/container": "^1.1 || ^2.0" - }, - "provide": { - "psr/container-implementation": "^1.0" - }, - "replace": { - "orno/di": "~2.0" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "nette/php-generator": "^3.4", - "nikic/php-parser": "^4.10", - "phpstan/phpstan": "^0.12.47", - "phpunit/phpunit": "^8.5.17", - "roave/security-advisories": "dev-latest", - "scrutinizer/ocular": "^1.8", - "squizlabs/php_codesniffer": "^3.6" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "type": "library", "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev", - "dev-2.x": "2.x-dev", - "dev-3.x": "3.x-dev", - "dev-4.x": "4.x-dev", - "dev-master": "4.x-dev" + "bamarni-bin": { + "bin-links": true, + "forward-command": false } }, "autoload": { "psr-4": { - "League\\Container\\": "src" + "GuzzleHttp\\Promise\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2726,57 +2927,329 @@ ], "authors": [ { - "name": "Phil Bennett", - "email": "mail@philbennett.co.uk", - "role": "Developer" + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], - "description": "A fast and intuitive dependency injection container.", - "homepage": "https://github.com/thephpleague/container", + "description": "Guzzle promises library", "keywords": [ - "container", - "dependency", - "di", - "injection", - "league", - "provider", - "service" + "promise" ], "support": { - "issues": "https://github.com/thephpleague/container/issues", - "source": "https://github.com/thephpleague/container/tree/4.2.4" + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.3.0" }, "funding": [ { - "url": "https://github.com/philipobenito", + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" } ], - "time": "2024-11-10T12:42:13+00:00" + "time": "2025-08-22T14:34:08+00:00" }, { - "name": "league/uri", - "version": "7.5.1", + "name": "guzzlehttp/psr7", + "version": "2.7.1", "source": { "type": "git", - "url": "https://github.com/thephpleague/uri.git", - "reference": "81fb5145d2644324614cc532b28efd0215bda430" + "url": "https://github.com/guzzle/psr7.git", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", - "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.5", - "php": "^8.1" + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" }, - "conflict": { - "league/uri-schemes": "^1.0" + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "suggest": { - "ext-bcmath": "to improve IPV4 host parsing", + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-03-27T12:30:47+00:00" + }, + { + "name": "kelunik/certificate", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/kelunik/certificate.git", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=7.0" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^6 | 7 | ^8 | ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Kelunik\\Certificate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Access certificate details and transform between different formats.", + "keywords": [ + "DER", + "certificate", + "certificates", + "openssl", + "pem", + "x509" + ], + "support": { + "issues": "https://github.com/kelunik/certificate/issues", + "source": "https://github.com/kelunik/certificate/tree/v1.1.3" + }, + "time": "2023-02-03T21:26:53+00:00" + }, + { + "name": "league/container", + "version": "4.2.5", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/container.git", + "reference": "d3cebb0ff4685ff61c749e54b27db49319e2ec00" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/container/zipball/d3cebb0ff4685ff61c749e54b27db49319e2ec00", + "reference": "d3cebb0ff4685ff61c749e54b27db49319e2ec00", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "psr/container": "^1.1 || ^2.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "replace": { + "orno/di": "~2.0" + }, + "require-dev": { + "nette/php-generator": "^3.4", + "nikic/php-parser": "^4.10", + "phpstan/phpstan": "^0.12.47", + "phpunit/phpunit": "^8.5.17", + "roave/security-advisories": "dev-latest", + "scrutinizer/ocular": "^1.8", + "squizlabs/php_codesniffer": "^3.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev", + "dev-2.x": "2.x-dev", + "dev-3.x": "3.x-dev", + "dev-4.x": "4.x-dev", + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Container\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Phil Bennett", + "email": "mail@philbennett.co.uk", + "role": "Developer" + } + ], + "description": "A fast and intuitive dependency injection container.", + "homepage": "https://github.com/thephpleague/container", + "keywords": [ + "container", + "dependency", + "di", + "injection", + "league", + "provider", + "service" + ], + "support": { + "issues": "https://github.com/thephpleague/container/issues", + "source": "https://github.com/thephpleague/container/tree/4.2.5" + }, + "funding": [ + { + "url": "https://github.com/philipobenito", + "type": "github" + } + ], + "time": "2025-05-20T12:55:37+00:00" + }, + { + "name": "league/uri", + "version": "7.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "81fb5145d2644324614cc532b28efd0215bda430" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", + "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.5", + "php": "^8.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", "ext-fileinfo": "to create Data URI from file contennts", "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", @@ -3012,16 +3485,16 @@ }, { "name": "monolog/monolog", - "version": "3.8.1", + "version": "3.9.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4" + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/aef6ee73a77a66e404dd6540934a9ef1b3c855b4", - "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", "shasum": "" }, "require": { @@ -3099,7 +3572,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.8.1" + "source": "https://github.com/Seldaek/monolog/tree/3.9.0" }, "funding": [ { @@ -3111,20 +3584,20 @@ "type": "tidelift" } ], - "time": "2024-12-05T17:15:07+00:00" + "time": "2025-03-24T10:02:05+00:00" }, { "name": "nesbot/carbon", - "version": "3.8.4", + "version": "3.10.2", "source": { "type": "git", - "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "129700ed449b1f02d70272d2ac802357c8c30c58" + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", - "reference": "129700ed449b1f02d70272d2ac802357c8c30c58", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", "shasum": "" }, "require": { @@ -3132,9 +3605,9 @@ "ext-json": "*", "php": "^8.1", "psr/clock": "^1.0", - "symfony/clock": "^6.3 || ^7.0", + "symfony/clock": "^6.3.12 || ^7.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" }, "provide": { "psr/clock-implementation": "1.0" @@ -3142,14 +3615,13 @@ "require-dev": { "doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/orm": "^2.15.2 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.57.2", + "friendsofphp/php-cs-fixer": "^3.75.0", "kylekatarnls/multi-tester": "^2.5.3", - "ondrejmirtes/better-reflection": "^6.25.0.4", "phpmd/phpmd": "^2.15.0", - "phpstan/extension-installer": "^1.3.1", - "phpstan/phpstan": "^1.11.2", - "phpunit/phpunit": "^10.5.20", - "squizlabs/php_codesniffer": "^3.9.0" + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.17", + "phpunit/phpunit": "^10.5.46", + "squizlabs/php_codesniffer": "^3.13.0" }, "bin": [ "bin/carbon" @@ -3200,8 +3672,8 @@ ], "support": { "docs": "https://carbon.nesbot.com/docs", - "issues": "https://github.com/briannesbitt/Carbon/issues", - "source": "https://github.com/briannesbitt/Carbon" + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" }, "funding": [ { @@ -3217,7 +3689,7 @@ "type": "tidelift" } ], - "time": "2024-12-27T09:25:35+00:00" + "time": "2025-08-02T09:36:06+00:00" }, { "name": "nikic/fast-route", @@ -3338,16 +3810,16 @@ }, { "name": "phenixphp/framework", - "version": "0.5.2", + "version": "0.6.0", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "066d5bd27e309a09c78c2b0f7db0b747ea3c184a" + "reference": "9c43d8518524928fa5eb6922dbbfed21f1b275cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/066d5bd27e309a09c78c2b0f7db0b747ea3c184a", - "reference": "066d5bd27e309a09c78c2b0f7db0b747ea3c184a", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/9c43d8518524928fa5eb6922dbbfed21f1b275cd", + "reference": "9c43d8518524928fa5eb6922dbbfed21f1b275cd", "shasum": "" }, "require": { @@ -3361,6 +3833,7 @@ "amphp/http-server-session": "^3.0", "amphp/log": "^v2.0.0", "amphp/mysql": "^v3.0.0", + "amphp/parallel": "^2.3", "amphp/postgres": "v2.0.0", "amphp/redis": "^2.0", "amphp/socket": "^2.1.0", @@ -3372,10 +3845,14 @@ "phenixphp/http-cors": "^0.1.0", "php": "^8.2", "ramsey/collection": "^2.0", + "resend/resend-php": "^0.16.0", "robmorgan/phinx": "^0.15.2", + "symfony/amazon-mailer": "^7.2", "symfony/console": "^6.1", + "symfony/mailer": "^7.2", + "symfony/resend-mailer": "^7.2", "symfony/uid": "^7.1", - "symfony/var-dumper": "^7.0", + "symfony/var-dumper": "^7.2.0", "vlucas/phpdotenv": "^5.4" }, "require-dev": { @@ -3383,7 +3860,6 @@ "friendsofphp/php-cs-fixer": "^3.11", "mockery/mockery": "^1.6", "nunomaduro/collision": "^6.3", - "nunomaduro/phpinsights": "^2.6", "pestphp/pest": "^1.22", "pestphp/pest-plugin-faker": "^1.0", "pestphp/pest-plugin-global-assertions": "^1.0", @@ -3418,9 +3894,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/0.5.2" + "source": "https://github.com/phenixphp/framework/tree/0.6.0" }, - "time": "2025-01-03T16:51:53+00:00" + "time": "2025-08-22T22:35:11+00:00" }, { "name": "phenixphp/http-cors", @@ -3462,16 +3938,16 @@ }, { "name": "phpoption/phpoption", - "version": "1.9.3", + "version": "1.9.4", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", "shasum": "" }, "require": { @@ -3479,7 +3955,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" }, "type": "library", "extra": { @@ -3521,7 +3997,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" }, "funding": [ { @@ -3533,29 +4009,34 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:41:07+00:00" + "time": "2025-08-21T11:53:16+00:00" }, { - "name": "psr/clock", - "version": "1.0.0", + "name": "psr/cache", + "version": "3.0.0", "source": { "type": "git", - "url": "https://github.com/php-fig/clock.git", - "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", - "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", "shasum": "" }, "require": { - "php": "^7.0 || ^8.0" + "php": ">=8.0.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "Psr\\Clock\\": "src/" + "Psr\\Cache\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3568,24 +4049,68 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interface for reading the clock.", - "homepage": "https://github.com/php-fig/clock", + "description": "Common interface for caching libraries", "keywords": [ - "clock", - "now", + "cache", "psr", - "psr-20", - "time" + "psr-6" ], "support": { - "issues": "https://github.com/php-fig/clock/issues", - "source": "https://github.com/php-fig/clock/tree/1.0.0" + "source": "https://github.com/php-fig/cache/tree/3.0.0" }, - "time": "2022-11-25T14:36:26+00:00" + "time": "2021-02-03T23:26:27+00:00" }, { - "name": "psr/container", - "version": "2.0.2", + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", @@ -3636,6 +4161,108 @@ }, "time": "2021-11-05T16:47:00+00:00" }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, { "name": "psr/http-factory", "version": "1.1.0", @@ -3845,18 +4472,62 @@ }, "time": "2021-10-29T13:26:27+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "ramsey/collection", - "version": "2.0.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5" + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", - "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", + "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2", "shasum": "" }, "require": { @@ -3864,25 +4535,22 @@ }, "require-dev": { "captainhook/plugin-composer": "^5.3", - "ergebnis/composer-normalize": "^2.28.3", - "fakerphp/faker": "^1.21", + "ergebnis/composer-normalize": "^2.45", + "fakerphp/faker": "^1.24", "hamcrest/hamcrest-php": "^2.0", - "jangregor/phpstan-prophecy": "^1.0", - "mockery/mockery": "^1.5", + "jangregor/phpstan-prophecy": "^2.1", + "mockery/mockery": "^1.6", "php-parallel-lint/php-console-highlighter": "^1.0", - "php-parallel-lint/php-parallel-lint": "^1.3", - "phpcsstandards/phpcsutils": "^1.0.0-rc1", - "phpspec/prophecy-phpunit": "^2.0", - "phpstan/extension-installer": "^1.2", - "phpstan/phpstan": "^1.9", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5", - "psalm/plugin-mockery": "^1.1", - "psalm/plugin-phpunit": "^0.18.4", - "ramsey/coding-standard": "^2.0.3", - "ramsey/conventional-commits": "^1.3", - "vimeo/psalm": "^5.4" + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpspec/prophecy-phpunit": "^2.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5", + "ramsey/coding-standard": "^2.3", + "ramsey/conventional-commits": "^1.6", + "roave/security-advisories": "dev-latest" }, "type": "library", "extra": { @@ -3920,32 +4588,79 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/2.0.0" + "source": "https://github.com/ramsey/collection/tree/2.1.1" }, - "funding": [ - { - "url": "https://github.com/ramsey", - "type": "github" - }, + "time": "2025-03-22T05:38:12+00:00" + }, + { + "name": "resend/resend-php", + "version": "v0.16.0", + "source": { + "type": "git", + "url": "https://github.com/resend/resend-php.git", + "reference": "6e9be898c9e0035a5da3c2904e86d0b12999c2fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/resend/resend-php/zipball/6e9be898c9e0035a5da3c2904e86d0b12999c2fc", + "reference": "6e9be898c9e0035a5da3c2904e86d0b12999c2fc", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^7.5", + "php": "^8.1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.13", + "mockery/mockery": "^1.6", + "pestphp/pest": "^2.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Resend.php" + ], + "psr-4": { + "Resend\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", - "type": "tidelift" + "name": "Resend and contributors", + "homepage": "https://github.com/resend/resend-php/contributors" } ], - "time": "2022-12-31T21:50:55+00:00" + "description": "Resend PHP library.", + "homepage": "https://resend.com/", + "keywords": [ + "api", + "client", + "php", + "resend", + "sdk" + ], + "support": { + "issues": "https://github.com/resend/resend-php/issues", + "source": "https://github.com/resend/resend-php/tree/v0.16.0" + }, + "time": "2025-03-24T22:12:48+00:00" }, { "name": "revolt/event-loop", - "version": "v1.0.6", + "version": "v1.0.7", "source": { "type": "git", "url": "https://github.com/revoltphp/event-loop.git", - "reference": "25de49af7223ba039f64da4ae9a28ec2d10d0254" + "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/25de49af7223ba039f64da4ae9a28ec2d10d0254", - "reference": "25de49af7223ba039f64da4ae9a28ec2d10d0254", + "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3", + "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3", "shasum": "" }, "require": { @@ -4002,9 +4717,9 @@ ], "support": { "issues": "https://github.com/revoltphp/event-loop/issues", - "source": "https://github.com/revoltphp/event-loop/tree/v1.0.6" + "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7" }, - "time": "2023-11-30T05:34:44+00:00" + "time": "2025-01-25T19:27:39+00:00" }, { "name": "robmorgan/phinx", @@ -4093,34 +4808,31 @@ "time": "2023-12-05T13:24:00+00:00" }, { - "name": "symfony/clock", - "version": "v7.2.0", + "name": "symfony/amazon-mailer", + "version": "v7.3.0", "source": { "type": "git", - "url": "https://github.com/symfony/clock.git", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + "url": "https://github.com/symfony/amazon-mailer.git", + "reference": "7266d4285147c890f4f7f42dc875fe5a6df8006c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/7266d4285147c890f4f7f42dc875fe5a6df8006c", + "reference": "7266d4285147c890f4f7f42dc875fe5a6df8006c", "shasum": "" }, "require": { + "async-aws/ses": "^1.8", "php": ">=8.2", - "psr/clock": "^1.0", - "symfony/polyfill-php83": "^1.28" + "symfony/mailer": "^7.2" }, - "provide": { - "psr/clock-implementation": "1.0" + "require-dev": { + "symfony/http-client": "^6.4|^7.0" }, - "type": "library", + "type": "symfony-mailer-bridge", "autoload": { - "files": [ - "Resources/now.php" - ], "psr-4": { - "Symfony\\Component\\Clock\\": "" + "Symfony\\Component\\Mailer\\Bridge\\Amazon\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4132,23 +4844,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Decouples applications from the system clock", + "description": "Symfony Amazon Mailer Bridge", "homepage": "https://symfony.com", - "keywords": [ - "clock", - "psr20", - "time" - ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.2.0" + "source": "https://github.com/symfony/amazon-mailer/tree/v7.3.0" }, "funding": [ { @@ -4164,36 +4871,110 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-02-26T16:10:57+00:00" }, { - "name": "symfony/config", - "version": "v7.2.0", + "name": "symfony/clock", + "version": "v7.3.0", "source": { "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "bcd3c4adf0144dee5011bb35454728c38adec055" + "url": "https://github.com/symfony/clock.git", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/bcd3c4adf0144dee5011bb35454728c38adec055", - "reference": "bcd3c4adf0144dee5011bb35454728c38adec055", + "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^7.1", - "symfony/polyfill-ctype": "~1.8" + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" }, - "conflict": { - "symfony/finder": "<6.4", - "symfony/service-contracts": "<2.5" + "provide": { + "psr/clock-implementation": "1.0" }, - "require-dev": { - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/config", + "version": "v7.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "faef36e271bbeb74a9d733be4b56419b157762e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/faef36e271bbeb74a9d733be4b56419b157762e2", + "reference": "faef36e271bbeb74a9d733be4b56419b157762e2", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^7.1", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "require-dev": { + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", "symfony/service-contracts": "^2.5|^3", "symfony/yaml": "^6.4|^7.0" }, @@ -4223,7 +5004,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.2.0" + "source": "https://github.com/symfony/config/tree/v7.3.2" }, "funding": [ { @@ -4234,25 +5015,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-04T11:36:24+00:00" + "time": "2025-07-26T13:55:06+00:00" }, { "name": "symfony/console", - "version": "v6.4.17", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04" + "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04", + "url": "https://api.github.com/repos/symfony/console/zipball/59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", + "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", "shasum": "" }, "require": { @@ -4317,7 +5102,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.17" + "source": "https://github.com/symfony/console/tree/v6.4.24" }, "funding": [ { @@ -4328,25 +5113,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-07T12:07:30+00:00" + "time": "2025-07-30T10:38:54+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -4359,7 +5148,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -4384,7 +5173,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -4400,34 +5189,48 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { - "name": "symfony/filesystem", - "version": "v7.2.0", + "name": "symfony/event-dispatcher", + "version": "v7.3.0", "source": { "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", - "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8" + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" }, "require-dev": { - "symfony/process": "^6.4|^7.0" + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Filesystem\\": "" + "Symfony\\Component\\EventDispatcher\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4447,10 +5250,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Provides basic utilities for the filesystem", + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.2.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" }, "funding": [ { @@ -4466,44 +5269,39 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:15:23+00:00" + "time": "2025-04-22T09:11:45+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.31.0", + "name": "symfony/event-dispatcher-contracts", + "version": "v3.6.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", "shasum": "" }, "require": { - "php": ">=7.2" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" + "php": ">=8.1", + "psr/event-dispatcher": "^1" }, "type": "library", "extra": { "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" + "Symfony\\Contracts\\EventDispatcher\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -4512,24 +5310,26 @@ ], "authors": [ { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for ctype functions", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" }, "funding": [ { @@ -4545,42 +5345,38 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.31.0", + "name": "symfony/filesystem", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "url": "https://github.com/symfony/filesystem.git", + "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" }, - "suggest": { - "ext-intl": "For best performance" + "require-dev": { + "symfony/process": "^6.4|^7.0" }, "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4588,26 +5384,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's grapheme_* functions", + "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + "source": "https://github.com/symfony/filesystem/tree/v7.3.2" }, "funding": [ { @@ -4618,48 +5406,73 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-07T08:17:47+00:00" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.31.0", + "name": "symfony/http-client", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + "url": "https://github.com/symfony/http-client.git", + "reference": "1c064a0c67749923483216b081066642751cc2c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "url": "https://api.github.com/repos/symfony/http-client/zipball/1c064a0c67749923483216b081066642751cc2c7", + "reference": "1c064a0c67749923483216b081066642751cc2c7", "shasum": "" }, "require": { - "php": ">=7.2", - "symfony/polyfill-intl-normalizer": "^1.10" + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/service-contracts": "^2.5|^3" }, - "suggest": { - "ext-intl": "For best performance" + "conflict": { + "amphp/amp": "<2.5", + "amphp/socket": "<1.1", + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^2.0", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/amphp-http-client-meta": "^1.0|^2.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0" }, + "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - } + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4667,30 +5480,21 @@ ], "authors": [ { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" - }, - { - "name": "Trevor Rowbotham", - "email": "trevor.rowbotham@pm.me" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "idn", - "intl", - "polyfill", - "portable", - "shim" + "http" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + "source": "https://github.com/symfony/http-client/tree/v7.3.2" }, "funding": [ { @@ -4701,49 +5505,50 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-15T11:36:08+00:00" }, { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.31.0", + "name": "symfony/http-client-contracts", + "version": "v3.6.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "75d7043853a42837e68111812f4d964b01e5101c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", + "reference": "75d7043853a42837e68111812f4d964b01e5101c", "shasum": "" }, "require": { - "php": ">=7.2" - }, - "suggest": { - "ext-intl": "For best performance" + "php": ">=8.1" }, "type": "library", "extra": { "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + "Symfony\\Contracts\\HttpClient\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Test/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -4760,18 +5565,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", + "description": "Generic abstractions related to HTTP clients", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0" }, "funding": [ { @@ -4787,45 +5592,52 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-04-29T11:18:49+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", + "name": "symfony/mailer", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + "url": "https://github.com/symfony/mailer.git", + "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "url": "https://api.github.com/repos/symfony/mailer/zipball/d43e84d9522345f96ad6283d5dfccc8c1cfc299b", + "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b", "shasum": "" }, "require": { - "php": ">=7.2" + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.2", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/mime": "^7.2", + "symfony/service-contracts": "^2.5|^3" }, - "provide": { - "ext-mbstring": "*" + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/twig-bridge": "<6.4" }, - "suggest": { - "ext-mbstring": "For best performance" + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/twig-bridge": "^6.4|^7.0" }, "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4833,25 +5645,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Helps sending emails", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + "source": "https://github.com/symfony/mailer/tree/v7.3.2" }, "funding": [ { @@ -4862,46 +5667,60 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-15T11:36:08+00:00" }, { - "name": "symfony/polyfill-php80", - "version": "v1.31.0", + "name": "symfony/mime", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + "url": "https://github.com/symfony/mime.git", + "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "url": "https://api.github.com/repos/symfony/mime/zipball/e0a0f859148daf1edf6c60b398eb40bfc96697d1", + "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=8.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" }, + "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" + "Symfony\\Component\\Mime\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -4910,28 +5729,22 @@ ], "authors": [ { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Allows manipulating MIME messages", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" + "mime", + "mime-type" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + "source": "https://github.com/symfony/mime/tree/v7.3.2" }, "funding": [ { @@ -4942,30 +5755,40 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { - "name": "symfony/polyfill-php83", - "version": "v1.31.0", + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { "php": ">=7.2" }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, "type": "library", "extra": { "thanks": { @@ -4978,11 +5801,8 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php83\\": "" - }, - "classmap": [ - "Resources/stubs" - ] + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4990,24 +5810,24 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "ctype", "polyfill", - "portable", - "shim" + "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -5018,6 +5838,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5026,27 +5850,24 @@ "time": "2024-09-09T11:45:10+00:00" }, { - "name": "symfony/polyfill-uuid", - "version": "v1.31.0", + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-uuid.git", - "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", - "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { "php": ">=7.2" }, - "provide": { - "ext-uuid": "*" - }, "suggest": { - "ext-uuid": "For best performance" + "ext-intl": "For best performance" }, "type": "library", "extra": { @@ -5060,7 +5881,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Uuid\\": "" + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -5069,24 +5890,26 @@ ], "authors": [ { - "name": "Grégoire Pineau", - "email": "lyrixx@lyrixx.info" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for uuid functions", + "description": "Symfony polyfill for intl's grapheme_* functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "grapheme", + "intl", "polyfill", "portable", - "uuid" + "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -5097,52 +5920,52 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { - "name": "symfony/service-contracts", - "version": "v3.5.1", + "name": "symfony/polyfill-intl-idn", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", "shasum": "" }, "require": { - "php": ">=8.1", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3" + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" }, - "conflict": { - "ext-psr": "<1.1|>=2" + "suggest": { + "ext-intl": "For best performance" }, "type": "library", "extra": { "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.5-dev" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Contracts\\Service\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5150,26 +5973,30 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to writing services", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", "homepage": "https://symfony.com", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -5180,55 +6007,53 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-10T14:38:51+00:00" }, { - "name": "symfony/string", - "version": "v7.2.0", + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", - "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/translation-contracts": "<2.5" + "php": ">=7.2" }, - "require-dev": { - "symfony/emoji": "^7.1", - "symfony/error-handler": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", - "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "suggest": { + "ext-intl": "For best performance" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { "files": [ - "Resources/functions.php" + "bootstrap.php" ], "psr-4": { - "Symfony\\Component\\String\\": "" + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5245,18 +6070,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "description": "Symfony polyfill for intl's Normalizer class and related functions", "homepage": "https://symfony.com", "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.2.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -5267,72 +6092,55 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-13T13:31:26+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { - "name": "symfony/translation", - "version": "v7.2.2", + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "e2674a30132b7cc4d74540d6c2573aa363f05923" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e2674a30132b7cc4d74540d6c2573aa363f05923", - "reference": "e2674a30132b7cc4d74540d6c2573aa363f05923", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5|^3.0" - }, - "conflict": { - "symfony/config": "<6.4", - "symfony/console": "<6.4", - "symfony/dependency-injection": "<6.4", - "symfony/http-client-contracts": "<2.5", - "symfony/http-kernel": "<6.4", - "symfony/service-contracts": "<2.5", - "symfony/twig-bundle": "<6.4", - "symfony/yaml": "<6.4" + "ext-iconv": "*", + "php": ">=7.2" }, "provide": { - "symfony/translation-implementation": "2.3|3.0" + "ext-mbstring": "*" }, - "require-dev": { - "nikic/php-parser": "^4.18|^5.0", - "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", - "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", - "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^6.4|^7.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0" + "suggest": { + "ext-mbstring": "For best performance" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { "files": [ - "Resources/functions.php" + "bootstrap.php" ], "psr-4": { - "Symfony\\Component\\Translation\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5340,18 +6148,25 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Provides tools to internationalize your application", + "description": "Symfony polyfill for the Mbstring extension", "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], "support": { - "source": "https://github.com/symfony/translation/tree/v7.2.2" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -5362,46 +6177,50 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-07T08:18:10+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { - "name": "symfony/translation-contracts", - "version": "v3.5.1", + "name": "symfony/polyfill-php80", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/translation-contracts.git", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=7.2" }, "type": "library", "extra": { "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.5-dev" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Contracts\\Translation\\": "" + "Symfony\\Polyfill\\Php80\\": "" }, - "exclude-from-classmap": [ - "/Test/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5409,6 +6228,10 @@ "MIT" ], "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -5418,18 +6241,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to translation", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "compatibility", + "polyfill", + "portable", + "shim" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -5440,41 +6261,50 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-01-02T08:10:11+00:00" }, { - "name": "symfony/uid", - "version": "v7.2.0", + "name": "symfony/polyfill-php83", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/uid.git", - "reference": "2d294d0c48df244c71c105a169d0190bfb080426" + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/2d294d0c48df244c71c105a169d0190bfb080426", - "reference": "2d294d0c48df244c71c105a169d0190bfb080426", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/polyfill-uuid": "^1.15" - }, - "require-dev": { - "symfony/console": "^6.4|^7.0" + "php": ">=7.2" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Component\\Uid\\": "" + "Symfony\\Polyfill\\Php83\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5482,10 +6312,6 @@ "MIT" ], "authors": [ - { - "name": "Grégoire Pineau", - "email": "lyrixx@lyrixx.info" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -5495,15 +6321,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Provides an object-oriented API to generate and represent UIDs", + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ - "UID", - "ulid", - "uuid" + "compatibility", + "polyfill", + "portable", + "shim" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.2.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -5514,56 +6341,54 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-07-08T02:45:35+00:00" }, { - "name": "symfony/var-dumper", - "version": "v7.2.0", + "name": "symfony/polyfill-uuid", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "c6a22929407dec8765d6e2b6ff85b800b245879c" + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c6a22929407dec8765d6e2b6ff85b800b245879c", - "reference": "c6a22929407dec8765d6e2b6ff85b800b245879c", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=7.2" }, - "conflict": { - "symfony/console": "<6.4" + "provide": { + "ext-uuid": "*" }, - "require-dev": { - "ext-iconv": "*", - "symfony/console": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/uid": "^6.4|^7.0", - "twig/twig": "^3.12" + "suggest": { + "ext-uuid": "For best performance" }, - "bin": [ - "Resources/bin/var-dump-server" - ], "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { "files": [ - "Resources/functions/dump.php" + "bootstrap.php" ], "psr-4": { - "Symfony\\Component\\VarDumper\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Polyfill\\Uuid\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5571,22 +6396,24 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "description": "Symfony polyfill for uuid functions", "homepage": "https://symfony.com", "keywords": [ - "debug", - "dump" + "compatibility", + "polyfill", + "portable", + "uuid" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.2.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" }, "funding": [ { @@ -5597,127 +6424,126 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-08T15:48:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { - "name": "vlucas/phpdotenv", - "version": "v5.6.1", + "name": "symfony/resend-mailer", + "version": "v7.3.0", "source": { "type": "git", - "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" + "url": "https://github.com/symfony/resend-mailer.git", + "reference": "591d06a6603845933e921c10cedb2afb97376c50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", - "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "url": "https://api.github.com/repos/symfony/resend-mailer/zipball/591d06a6603845933e921c10cedb2afb97376c50", + "reference": "591d06a6603845933e921c10cedb2afb97376c50", "shasum": "" }, "require": { - "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.3", - "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3", - "symfony/polyfill-ctype": "^1.24", - "symfony/polyfill-mbstring": "^1.24", - "symfony/polyfill-php80": "^1.24" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "ext-filter": "*", - "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + "php": ">=8.1", + "symfony/mailer": "^7.2" }, - "suggest": { - "ext-filter": "Required to use the boolean validator." + "conflict": { + "symfony/http-foundation": "<7.1" }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - }, - "branch-alias": { - "dev-master": "5.6-dev" - } + "require-dev": { + "symfony/http-client": "^6.4|^7.0", + "symfony/http-foundation": "^7.1", + "symfony/webhook": "^6.4|^7.0" }, + "type": "symfony-mailer-bridge", "autoload": { "psr-4": { - "Dotenv\\": "src/" - } + "Symfony\\Component\\Mailer\\Bridge\\Resend\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" + "name": "Mathieu Santostefano", + "homepage": "https://github.com/welcoMattic" }, { - "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "https://github.com/vlucas" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", - "keywords": [ - "dotenv", - "env", - "environment" - ], + "description": "Symfony Resend Mailer Bridge", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" + "source": "https://github.com/symfony/resend-mailer/tree/v7.3.0" }, "funding": [ { - "url": "https://github.com/GrahamCampbell", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-07-20T21:52:34+00:00" - } - ], - "packages-dev": [ + "time": "2024-09-28T08:24:38+00:00" + }, { - "name": "amphp/phpunit-util", - "version": "v3.0.0", + "name": "symfony/service-contracts", + "version": "v3.6.0", "source": { "type": "git", - "url": "https://github.com/amphp/phpunit-util.git", - "reference": "14d1c36ec0c72fe76b301a17af1d52330cc61d0c" + "url": "https://github.com/symfony/service-contracts.git", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/phpunit-util/zipball/14d1c36ec0c72fe76b301a17af1d52330cc61d0c", - "reference": "14d1c36ec0c72fe76b301a17af1d52330cc61d0c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { - "amphp/amp": "^3", "php": ">=8.1", - "phpunit/phpunit": "^9", - "revolt/event-loop": "^1 || ^0.2" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2" + "conflict": { + "ext-psr": "<1.1|>=2" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, "autoload": { "psr-4": { - "Amp\\PHPUnit\\": "src" - } + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5725,79 +6551,86 @@ ], "authors": [ { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Helper package to ease testing with PHPUnit.", - "homepage": "https://amphp.org/phpunit-util", + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], "support": { - "issues": "https://github.com/amphp/phpunit-util/issues", - "source": "https://github.com/amphp/phpunit-util/tree/v3.0.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { - "url": "https://github.com/amphp", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2022-12-18T17:47:31+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { - "name": "brianium/paratest", - "version": "v6.11.1", + "name": "symfony/string", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/paratestphp/paratest.git", - "reference": "78e297a969049ca7cc370e80ff5e102921ef39a3" + "url": "https://github.com/symfony/string.git", + "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/78e297a969049ca7cc370e80ff5e102921ef39a3", - "reference": "78e297a969049ca7cc370e80ff5e102921ef39a3", + "url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca", + "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-simplexml": "*", - "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0", - "jean85/pretty-package-versions": "^2.0.5", - "php": "^7.3 || ^8.0", - "phpunit/php-code-coverage": "^9.2.25", - "phpunit/php-file-iterator": "^3.0.6", - "phpunit/php-timer": "^5.0.3", - "phpunit/phpunit": "^9.6.4", - "sebastian/environment": "^5.1.5", - "symfony/console": "^5.4.28 || ^6.3.4 || ^7.0.0", - "symfony/process": "^5.4.28 || ^6.3.4 || ^7.0.0" + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" }, "require-dev": { - "doctrine/coding-standard": "^12.0.0", - "ext-pcov": "*", - "ext-posix": "*", - "infection/infection": "^0.27.6", - "squizlabs/php_codesniffer": "^3.7.2", - "symfony/filesystem": "^5.4.25 || ^6.3.1 || ^7.0.0", - "vimeo/psalm": "^5.7.7" + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" }, - "bin": [ - "bin/paratest", - "bin/paratest.bat", - "bin/paratest_for_phpstorm" - ], "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { - "ParaTest\\": [ - "src/" - ] - } + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5805,67 +6638,107 @@ ], "authors": [ { - "name": "Brian Scaturro", - "email": "scaturrob@gmail.com", - "role": "Developer" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Filippo Tessarotto", - "email": "zoeslam@gmail.com", - "role": "Developer" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Parallel testing for PHP", - "homepage": "https://github.com/paratestphp/paratest", + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", "keywords": [ - "concurrent", - "parallel", - "phpunit", - "testing" + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" ], "support": { - "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v6.11.1" + "source": "https://github.com/symfony/string/tree/v7.3.2" }, "funding": [ { - "url": "https://github.com/sponsors/Slamdunk", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://paypal.me/filippotessarotto", - "type": "paypal" + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2024-03-13T06:54:29+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { - "name": "clue/ndjson-react", - "version": "v1.3.0", + "name": "symfony/translation", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/clue/reactphp-ndjson.git", - "reference": "392dc165fce93b5bb5c637b67e59619223c931b0" + "url": "https://github.com/symfony/translation.git", + "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0", - "reference": "392dc165fce93b5bb5c637b67e59619223c931b0", + "url": "https://api.github.com/repos/symfony/translation/zipball/81b48f4daa96272efcce9c7a6c4b58e629df3c90", + "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90", "shasum": "" }, "require": { - "php": ">=5.3", - "react/stream": "^1.2" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5|^3.0" + }, + "conflict": { + "nikic/php-parser": "<5.0", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" }, "require-dev": { - "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", - "react/event-loop": "^1.2" + "nikic/php-parser": "^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { - "Clue\\React\\NDJson\\": "src/" - } + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5873,141 +6746,146 @@ ], "authors": [ { - "name": "Christian Lück", - "email": "christian@clue.engineering" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.", - "homepage": "https://github.com/clue/reactphp-ndjson", - "keywords": [ - "NDJSON", - "json", - "jsonlines", - "newline", - "reactphp", - "streaming" - ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/clue/reactphp-ndjson/issues", - "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0" + "source": "https://github.com/symfony/translation/tree/v7.3.2" }, "funding": [ { - "url": "https://clue.engineering/support", + "url": "https://symfony.com/sponsor", "type": "custom" }, { - "url": "https://github.com/clue", + "url": "https://github.com/fabpot", "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2022-12-23T10:58:28+00:00" + "time": "2025-07-30T17:31:46+00:00" }, { - "name": "cmgmyr/phploc", - "version": "8.0.4", + "name": "symfony/translation-contracts", + "version": "v3.6.0", "source": { "type": "git", - "url": "https://github.com/cmgmyr/phploc.git", - "reference": "b0c4ec71f40ef84c9893e1a7212a72e1098b90f7" + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cmgmyr/phploc/zipball/b0c4ec71f40ef84c9893e1a7212a72e1098b90f7", - "reference": "b0c4ec71f40ef84c9893e1a7212a72e1098b90f7", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-json": "*", - "php": "^7.4 || ^8.0", - "phpunit/php-file-iterator": "^3.0|^4.0|^5.0", - "sebastian/cli-parser": "^1.0|^2.0|^3.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "phpunit/phpunit": "^9.0|^10.0", - "vimeo/psalm": "^5.7" + "php": ">=8.1" }, - "bin": [ - "phploc" - ], "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { - "dev-main": "8.0-dev" + "dev-main": "3.6-dev" } }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Chris Gmyr", - "email": "cmgmyr@gmail.com", - "role": "lead" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "A tool for quickly measuring the size of a PHP project.", - "homepage": "https://github.com/cmgmyr/phploc", + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], "support": { - "issues": "https://github.com/cmgmyr/phploc/issues", - "source": "https://github.com/cmgmyr/phploc/tree/8.0.4" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" }, "funding": [ { - "url": "https://github.com/cmgmyr", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2024-10-31T19:26:53+00:00" + "time": "2024-09-27T08:32:26+00:00" }, { - "name": "composer/pcre", - "version": "3.3.2", + "name": "symfony/uid", + "version": "v7.3.1", "source": { "type": "git", - "url": "https://github.com/composer/pcre.git", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + "url": "https://github.com/symfony/uid.git", + "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "url": "https://api.github.com/repos/symfony/uid/zipball/a69f69f3159b852651a6bf45a9fdd149520525bb", + "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb", "shasum": "" }, "require": { - "php": "^7.4 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<1.11.10" + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" }, "require-dev": { - "phpstan/phpstan": "^1.12 || ^2", - "phpstan/phpstan-strict-rules": "^1 || ^2", - "phpunit/phpunit": "^8 || ^9" + "symfony/console": "^6.4|^7.0" }, "type": "library", - "extra": { - "phpstan": { - "includes": [ - "extension.neon" - ] - }, - "branch-alias": { - "dev-main": "3.x-dev" - } - }, "autoload": { "psr-4": { - "Composer\\Pcre\\": "src" - } + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6015,69 +6893,87 @@ ], "authors": [ { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", "keywords": [ - "PCRE", - "preg", - "regex", - "regular expression" + "UID", + "ulid", + "uuid" ], "support": { - "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.3.2" + "source": "https://github.com/symfony/uid/tree/v7.3.1" }, "funding": [ { - "url": "https://packagist.com", + "url": "https://symfony.com/sponsor", "type": "custom" }, { - "url": "https://github.com/composer", + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-12T16:29:46+00:00" + "time": "2025-06-27T19:55:54+00:00" }, { - "name": "composer/semver", - "version": "3.4.3", + "name": "symfony/var-dumper", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + "url": "https://github.com/symfony/var-dumper.git", + "reference": "53205bea27450dc5c65377518b3275e126d45e75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/53205bea27450dc5c65377518b3275e126d45e75", + "reference": "53205bea27450dc5c65377518b3275e126d45e75", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" }, "require-dev": { - "phpstan/phpstan": "^1.11", - "symfony/phpunit-bridge": "^3 || ^7" + "symfony/console": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0", + "twig/twig": "^3.12" }, + "bin": [ + "Resources/bin/var-dump-server" + ], "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, "autoload": { + "files": [ + "Resources/functions/dump.php" + ], "psr-4": { - "Composer\\Semver\\": "src" - } + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6085,149 +6981,156 @@ ], "authors": [ { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], + "debug", + "dump" + ], "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.3" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.2" }, "funding": [ { - "url": "https://packagist.com", + "url": "https://symfony.com/sponsor", "type": "custom" }, { - "url": "https://github.com/composer", + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-19T14:15:21+00:00" + "time": "2025-07-29T20:02:46+00:00" }, { - "name": "composer/xdebug-handler", - "version": "3.0.5", + "name": "vlucas/phpdotenv", + "version": "v5.6.2", "source": { "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", - "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af", "shasum": "" }, "require": { - "composer/pcre": "^1 || ^2 || ^3", + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", "php": "^7.2.5 || ^8.0", - "psr/log": "^1 || ^2 || ^3" + "phpoption/phpoption": "^1.9.3", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" }, "require-dev": { - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-strict-rules": "^1.1", - "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." }, "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, "autoload": { "psr-4": { - "Composer\\XdebugHandler\\": "src" + "Dotenv\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" } ], - "description": "Restarts a process without Xdebug.", + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", "keywords": [ - "Xdebug", - "performance" + "dotenv", + "env", + "environment" ], "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2" }, "funding": [ { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", + "url": "https://github.com/GrahamCampbell", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", "type": "tidelift" } ], - "time": "2024-05-06T16:37:16+00:00" - }, + "time": "2025-04-30T23:37:27+00:00" + } + ], + "packages-dev": [ { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.0.0", + "name": "amphp/phpunit-util", + "version": "v3.0.0", "source": { "type": "git", - "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "4be43904336affa5c2f70744a348312336afd0da" + "url": "https://github.com/amphp/phpunit-util.git", + "reference": "14d1c36ec0c72fe76b301a17af1d52330cc61d0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", - "reference": "4be43904336affa5c2f70744a348312336afd0da", + "url": "https://api.github.com/repos/amphp/phpunit-util/zipball/14d1c36ec0c72fe76b301a17af1d52330cc61d0c", + "reference": "14d1c36ec0c72fe76b301a17af1d52330cc61d0c", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.4", - "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + "amphp/amp": "^3", + "php": ">=8.1", + "phpunit/phpunit": "^9", + "revolt/event-loop": "^1 || ^0.2" }, "require-dev": { - "composer/composer": "*", - "ext-json": "*", - "ext-zip": "*", - "php-parallel-lint/php-parallel-lint": "^1.3.1", - "phpcompatibility/php-compatibility": "^9.0", - "yoast/phpunit-polyfills": "^1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + "amphp/php-cs-fixer-config": "^2" }, + "type": "library", "autoload": { "psr-4": { - "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + "Amp\\PHPUnit\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -6236,73 +7139,78 @@ ], "authors": [ { - "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" + "name": "Niklas Keller", + "email": "me@kelunik.com" }, { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" } ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", - "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcbf", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" - ], + "description": "Helper package to ease testing with PHPUnit.", + "homepage": "https://amphp.org/phpunit-util", "support": { - "issues": "https://github.com/PHPCSStandards/composer-installer/issues", - "source": "https://github.com/PHPCSStandards/composer-installer" + "issues": "https://github.com/amphp/phpunit-util/issues", + "source": "https://github.com/amphp/phpunit-util/tree/v3.0.0" }, - "time": "2023-01-05T11:28:13+00:00" + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2022-12-18T17:47:31+00:00" }, { - "name": "doctrine/instantiator", - "version": "2.0.0", + "name": "brianium/paratest", + "version": "v6.11.1", "source": { "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + "url": "https://github.com/paratestphp/paratest.git", + "reference": "78e297a969049ca7cc370e80ff5e102921ef39a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/78e297a969049ca7cc370e80ff5e102921ef39a3", + "reference": "78e297a969049ca7cc370e80ff5e102921ef39a3", "shasum": "" }, "require": { - "php": "^8.1" + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-simplexml": "*", + "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0", + "jean85/pretty-package-versions": "^2.0.5", + "php": "^7.3 || ^8.0", + "phpunit/php-code-coverage": "^9.2.25", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-timer": "^5.0.3", + "phpunit/phpunit": "^9.6.4", + "sebastian/environment": "^5.1.5", + "symfony/console": "^5.4.28 || ^6.3.4 || ^7.0.0", + "symfony/process": "^5.4.28 || ^6.3.4 || ^7.0.0" }, "require-dev": { - "doctrine/coding-standard": "^11", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.9.4", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^5.4" + "doctrine/coding-standard": "^12.0.0", + "ext-pcov": "*", + "ext-posix": "*", + "infection/infection": "^0.27.6", + "squizlabs/php_codesniffer": "^3.7.2", + "symfony/filesystem": "^5.4.25 || ^6.3.1 || ^7.0.0", + "vimeo/psalm": "^5.7.7" }, + "bin": [ + "bin/paratest", + "bin/paratest.bat", + "bin/paratest_for_phpstorm" + ], "type": "library", "autoload": { "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + "ParaTest\\": [ + "src/" + ] } }, "notification-url": "https://packagist.org/downloads/", @@ -6311,61 +7219,66 @@ ], "authors": [ { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" + "name": "Brian Scaturro", + "email": "scaturrob@gmail.com", + "role": "Developer" + }, + { + "name": "Filippo Tessarotto", + "email": "zoeslam@gmail.com", + "role": "Developer" } ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "description": "Parallel testing for PHP", + "homepage": "https://github.com/paratestphp/paratest", "keywords": [ - "constructor", - "instantiate" + "concurrent", + "parallel", + "phpunit", + "testing" ], "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + "issues": "https://github.com/paratestphp/paratest/issues", + "source": "https://github.com/paratestphp/paratest/tree/v6.11.1" }, "funding": [ { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" + "url": "https://github.com/sponsors/Slamdunk", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" + "url": "https://paypal.me/filippotessarotto", + "type": "paypal" } ], - "time": "2022-12-30T00:23:10+00:00" + "time": "2024-03-13T06:54:29+00:00" }, { - "name": "evenement/evenement", - "version": "v3.0.2", + "name": "clue/ndjson-react", + "version": "v1.3.0", "source": { "type": "git", - "url": "https://github.com/igorw/evenement.git", - "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + "url": "https://github.com/clue/reactphp-ndjson.git", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", - "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0", "shasum": "" }, "require": { - "php": ">=7.0" + "php": ">=5.3", + "react/stream": "^1.2" }, "require-dev": { - "phpunit/phpunit": "^9 || ^6" + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", + "react/event-loop": "^1.2" }, "type": "library", "autoload": { "psr-4": { - "Evenement\\": "src/" + "Clue\\React\\NDJson\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -6374,53 +7287,75 @@ ], "authors": [ { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" + "name": "Christian Lück", + "email": "christian@clue.engineering" } ], - "description": "Événement is a very simple event dispatching library for PHP", + "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.", + "homepage": "https://github.com/clue/reactphp-ndjson", "keywords": [ - "event-dispatcher", - "event-emitter" + "NDJSON", + "json", + "jsonlines", + "newline", + "reactphp", + "streaming" ], "support": { - "issues": "https://github.com/igorw/evenement/issues", - "source": "https://github.com/igorw/evenement/tree/v3.0.2" + "issues": "https://github.com/clue/reactphp-ndjson/issues", + "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0" }, - "time": "2023-08-08T05:53:35+00:00" - }, - { - "name": "fidry/cpu-core-counter", - "version": "1.2.0", + "funding": [ + { + "url": "https://clue.engineering/support", + "type": "custom" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-12-23T10:58:28+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", "source": { "type": "git", - "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "8520451a140d3f46ac33042715115e290cf5785f" + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", - "reference": "8520451a140d3f46ac33042715115e290cf5785f", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" }, "require-dev": { - "fidry/makefile": "^0.2.0", - "fidry/php-cs-fixer-config": "^1.1.2", - "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^1.9.2", - "phpstan/phpstan-deprecation-rules": "^1.0.0", - "phpstan/phpstan-phpunit": "^1.2.2", - "phpstan/phpstan-strict-rules": "^1.4.4", - "phpunit/phpunit": "^8.5.31 || ^9.5.26", - "webmozarts/strict-phpunit": "^7.5" + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" }, "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, "autoload": { "psr-4": { - "Fidry\\CpuCoreCounter\\": "src/" + "Composer\\Pcre\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -6429,63 +7364,68 @@ ], "authors": [ { - "name": "Théo FIDRY", - "email": "theo.fidry@gmail.com" + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" } ], - "description": "Tiny utility to get the number of CPU cores.", + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", "keywords": [ - "CPU", - "core" + "PCRE", + "preg", + "regex", + "regular expression" ], "support": { - "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" }, "funding": [ { - "url": "https://github.com/theofidry", + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" } ], - "time": "2024-08-06T10:04:20+00:00" + "time": "2024-11-12T16:29:46+00:00" }, { - "name": "filp/whoops", - "version": "2.16.0", + "name": "composer/semver", + "version": "3.4.4", "source": { "type": "git", - "url": "https://github.com/filp/whoops.git", - "reference": "befcdc0e5dce67252aa6322d82424be928214fa2" + "url": "https://github.com/composer/semver.git", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/befcdc0e5dce67252aa6322d82424be928214fa2", - "reference": "befcdc0e5dce67252aa6322d82424be928214fa2", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0", - "psr/log": "^1.0.1 || ^2.0 || ^3.0" + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", - "symfony/var-dumper": "^4.0 || ^5.0" - }, - "suggest": { - "symfony/var-dumper": "Pretty print complex values better with var-dumper available", - "whoops/soap": "Formats errors as SOAP responses" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-main": "3.x-dev" } }, "autoload": { "psr-4": { - "Whoops\\": "src/Whoops/" + "Composer\\Semver\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -6494,102 +7434,74 @@ ], "authors": [ { - "name": "Filipe Dobreira", - "homepage": "https://github.com/filp", - "role": "Developer" + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" } ], - "description": "php error handling for cool kids", - "homepage": "https://filp.github.io/whoops/", + "description": "Semver library that offers utilities, version constraint parsing and validation.", "keywords": [ - "error", - "exception", - "handling", - "library", - "throwable", - "whoops" + "semantic", + "semver", + "validation", + "versioning" ], "support": { - "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.16.0" + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.4" }, "funding": [ { - "url": "https://github.com/denis-sokolov", + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", "type": "github" } ], - "time": "2024-09-25T12:00:00+00:00" + "time": "2025-08-20T19:15:30+00:00" }, { - "name": "friendsofphp/php-cs-fixer", - "version": "v3.66.0", + "name": "composer/xdebug-handler", + "version": "3.0.5", "source": { "type": "git", - "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6" + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/5f5f2a142ff36b93c41885bca29cc5f861c013e6", - "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { - "clue/ndjson-react": "^1.0", - "composer/semver": "^3.4", - "composer/xdebug-handler": "^3.0.3", - "ext-filter": "*", - "ext-json": "*", - "ext-tokenizer": "*", - "fidry/cpu-core-counter": "^1.2", - "php": "^7.4 || ^8.0", - "react/child-process": "^0.6.5", - "react/event-loop": "^1.0", - "react/promise": "^2.0 || ^3.0", - "react/socket": "^1.0", - "react/stream": "^1.0", - "sebastian/diff": "^4.0 || ^5.0 || ^6.0", - "symfony/console": "^5.4 || ^6.0 || ^7.0", - "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0", - "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", - "symfony/finder": "^5.4 || ^6.0 || ^7.0", - "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0", - "symfony/polyfill-mbstring": "^1.28", - "symfony/polyfill-php80": "^1.28", - "symfony/polyfill-php81": "^1.28", - "symfony/process": "^5.4 || ^6.0 || ^7.0 <7.2", - "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" }, "require-dev": { - "facile-it/paraunit": "^1.3.1 || ^2.4", - "infection/infection": "^0.29.8", - "justinrainbow/json-schema": "^5.3 || ^6.0", - "keradus/cli-executor": "^2.1", - "mikey179/vfsstream": "^1.6.12", - "php-coveralls/php-coveralls": "^2.7", - "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5", - "phpunit/phpunit": "^9.6.21 || ^10.5.38 || ^11.4.3", - "symfony/var-dumper": "^5.4.47 || ^6.4.15 || ^7.1.8", - "symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.1.6" - }, - "suggest": { - "ext-dom": "For handling output formats in XML", - "ext-mbstring": "For handling non-UTF8 characters." + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" }, - "bin": [ - "php-cs-fixer" - ], - "type": "application", + "type": "library", "autoload": { "psr-4": { - "PhpCsFixer\\": "src/" - }, - "exclude-from-classmap": [ - "src/Fixer/Internal/*" - ] + "Composer\\XdebugHandler\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6597,118 +7509,130 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Dariusz Rumiński", - "email": "dariusz.ruminski@gmail.com" + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" } ], - "description": "A tool to automatically fix PHP code style", + "description": "Restarts a process without Xdebug.", "keywords": [ - "Static code analysis", - "fixer", - "standards", - "static analysis" + "Xdebug", + "performance" ], "support": { - "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.66.0" + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { - "url": "https://github.com/keradus", + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" } ], - "time": "2024-12-29T13:46:23+00:00" + "time": "2024-05-06T16:37:16+00:00" }, { - "name": "hamcrest/hamcrest-php", - "version": "v2.0.1", + "name": "doctrine/instantiator", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3" + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", - "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "php": "^5.3|^7.0|^8.0" - }, - "replace": { - "cordoval/hamcrest-php": "*", - "davedevelopment/hamcrest-php": "*", - "kodova/hamcrest-php": "*" + "php": "^8.1" }, "require-dev": { - "phpunit/php-file-iterator": "^1.4 || ^2.0", - "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0" + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1-dev" - } - }, "autoload": { - "classmap": [ - "hamcrest" - ] + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], - "description": "This is the PHP port of Hamcrest Matchers", + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ - "test" + "constructor", + "instantiate" ], "support": { - "issues": "https://github.com/hamcrest/hamcrest-php/issues", - "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1" + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" }, - "time": "2020-07-09T08:09:16+00:00" - }, - { - "name": "jean85/pretty-package-versions", - "version": "2.1.0", + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "evenement/evenement", + "version": "v3.0.2", "source": { "type": "git", - "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10" + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", - "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", "shasum": "" }, "require": { - "composer-runtime-api": "^2.1.0", - "php": "^7.4|^8.0" + "php": ">=7.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^1.4", - "phpunit/phpunit": "^7.5|^8.5|^9.6", - "vimeo/psalm": "^4.3 || ^5.0" + "phpunit/phpunit": "^9 || ^6" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, "autoload": { "psr-4": { - "Jean85\\": "src/" + "Evenement\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -6717,52 +7641,53 @@ ], "authors": [ { - "name": "Alessandro Lai", - "email": "alessandro.lai85@gmail.com" + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" } ], - "description": "A library to get pretty versions strings of installed dependencies", + "description": "Événement is a very simple event dispatching library for PHP", "keywords": [ - "composer", - "package", - "release", - "versions" + "event-dispatcher", + "event-emitter" ], "support": { - "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0" + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" }, - "time": "2024-11-18T16:19:46+00:00" + "time": "2023-08-08T05:53:35+00:00" }, { - "name": "justinrainbow/json-schema", - "version": "5.3.0", + "name": "fidry/cpu-core-counter", + "version": "1.3.0", "source": { "type": "git", - "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8" + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", - "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", "shasum": "" }, "require": { - "php": ">=7.1" + "php": "^7.2 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", - "json-schema/json-schema-test-suite": "1.2.0", - "phpunit/phpunit": "^4.8.35" + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" }, - "bin": [ - "bin/validate-json" - ], "type": "library", "autoload": { "psr-4": { - "JsonSchema\\": "src/JsonSchema/" + "Fidry\\CpuCoreCounter\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -6771,200 +7696,480 @@ ], "authors": [ { - "name": "Bruno Prieto Reis", - "email": "bruno.p.reis@gmail.com" - }, - { - "name": "Justin Rainbow", - "email": "justin.rainbow@gmail.com" - }, - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - }, - { - "name": "Robert Schönthal", - "email": "seroscho@googlemail.com" + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" } ], - "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", + "description": "Tiny utility to get the number of CPU cores.", "keywords": [ - "json", - "schema" + "CPU", + "core" ], "support": { - "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" }, - "time": "2024-07-06T21:00:26+00:00" + "funding": [ + { + "url": "https://github.com/theofidry", + "type": "github" + } + ], + "time": "2025-08-14T07:29:31+00:00" }, { - "name": "mockery/mockery", - "version": "1.6.12", + "name": "filp/whoops", + "version": "2.18.4", "source": { "type": "git", - "url": "https://github.com/mockery/mockery.git", - "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + "url": "https://github.com/filp/whoops.git", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", - "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", "shasum": "" }, "require": { - "hamcrest/hamcrest-php": "^2.0.1", - "lib-pcre": ">=7.0", - "php": ">=7.3" - }, - "conflict": { - "phpunit/phpunit": "<8.0" + "php": "^7.1 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { - "phpunit/phpunit": "^8.5 || ^9.6.17", - "symplify/easy-coding-standard": "^12.1.14" + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, "autoload": { - "files": [ - "library/helpers.php", - "library/Mockery.php" - ], "psr-4": { - "Mockery\\": "library/Mockery" + "Whoops\\": "src/Whoops/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Pádraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "https://github.com/padraic", - "role": "Author" - }, - { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "https://davedevelopment.co.uk", + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", "role": "Developer" - }, - { - "name": "Nathanael Esayeas", - "email": "nathanael.esayeas@protonmail.com", - "homepage": "https://github.com/ghostwriter", - "role": "Lead Developer" } ], - "description": "Mockery is a simple yet flexible PHP mock object framework", - "homepage": "https://github.com/mockery/mockery", + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", "keywords": [ - "BDD", - "TDD", + "error", + "exception", + "handling", "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" + "throwable", + "whoops" ], "support": { - "docs": "https://docs.mockery.io/", - "issues": "https://github.com/mockery/mockery/issues", - "rss": "https://github.com/mockery/mockery/releases.atom", - "security": "https://github.com/mockery/mockery/security/advisories", - "source": "https://github.com/mockery/mockery" + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.18.4" }, - "time": "2024-05-16T03:13:13+00:00" + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2025-08-08T12:00:00+00:00" }, { - "name": "myclabs/deep-copy", - "version": "1.12.1", + "name": "friendsofphp/php-cs-fixer", + "version": "v3.86.0", "source": { "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" + "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", + "reference": "4a952bd19dc97879b0620f495552ef09b55f7d36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", - "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/4a952bd19dc97879b0620f495552ef09b55f7d36", + "reference": "4a952bd19dc97879b0620f495552ef09b55f7d36", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" + "clue/ndjson-react": "^1.3", + "composer/semver": "^3.4", + "composer/xdebug-handler": "^3.0.5", + "ext-filter": "*", + "ext-hash": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "fidry/cpu-core-counter": "^1.2", + "php": "^7.4 || ^8.0", + "react/child-process": "^0.6.6", + "react/event-loop": "^1.5", + "react/promise": "^3.2", + "react/socket": "^1.16", + "react/stream": "^1.4", + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", + "symfony/console": "^5.4.47 || ^6.4.13 || ^7.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", + "symfony/polyfill-mbstring": "^1.32", + "symfony/polyfill-php80": "^1.32", + "symfony/polyfill-php81": "^1.32", + "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", + "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" }, "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + "facile-it/paraunit": "^1.3.1 || ^2.6", + "infection/infection": "^0.29.14", + "justinrainbow/json-schema": "^5.3 || ^6.4", + "keradus/cli-executor": "^2.2", + "mikey179/vfsstream": "^1.6.12", + "php-coveralls/php-coveralls": "^2.8", + "php-cs-fixer/accessible-object": "^1.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", + "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", + "symfony/polyfill-php84": "^1.32", + "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", + "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" }, - "type": "library", + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } + "PhpCsFixer\\": "src/" + }, + "exclude-from-classmap": [ + "src/Fixer/Internal/*" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Create deep copies (clones) of your objects", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" + "Static code analysis", + "fixer", + "standards", + "static analysis" ], "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" + "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.86.0" }, "funding": [ { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" + "url": "https://github.com/keradus", + "type": "github" } ], - "time": "2024-11-08T17:47:46+00:00" + "time": "2025-08-13T22:36:21+00:00" }, { - "name": "nikic/php-parser", - "version": "v5.4.0", + "name": "hamcrest/hamcrest-php", + "version": "v2.1.1", "source": { "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", "shasum": "" }, "require": { - "ext-ctype": "*", - "ext-json": "*", - "ext-tokenizer": "*", - "php": ">=7.4" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^9.0" + "php": "^7.4|^8.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "support": { + "issues": "https://github.com/hamcrest/hamcrest-php/issues", + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.1.1" + }, + "time": "2025-04-30T06:54:44+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a", + "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.1.0", + "php": "^7.4|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^7.5|^8.5|^9.6", + "rector/rector": "^2.0", + "vimeo/psalm": "^4.3 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1" + }, + "time": "2025-03-19T14:43:43+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.6.12", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "^2.0.1", + "lib-pcre": ">=7.0", + "php": ">=7.3" + }, + "conflict": { + "phpunit/phpunit": "<8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" + }, + "type": "library", + "autoload": { + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "https://github.com/padraic", + "role": "Author" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "docs": "https://docs.mockery.io/", + "issues": "https://github.com/mockery/mockery/issues", + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" + }, + "time": "2024-05-16T03:13:13+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -6972,7 +8177,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "5.x-dev" } }, "autoload": { @@ -6996,9 +8201,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" }, - "time": "2024-12-30T11:07:19+00:00" + "time": "2025-08-13T20:13:15+00:00" }, { "name": "nunomaduro/collision", @@ -7089,123 +8294,17 @@ "time": "2023-01-03T12:54:54+00:00" }, { - "name": "nunomaduro/phpinsights", - "version": "v2.12.0", + "name": "pestphp/pest", + "version": "v1.23.1", "source": { "type": "git", - "url": "https://github.com/nunomaduro/phpinsights.git", - "reference": "5c12a8d626712de6db5e6d2db52b1eb4e9596650" + "url": "https://github.com/pestphp/pest.git", + "reference": "5c56ad8772b89611c72a07e23f6e30aa29dc677a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/phpinsights/zipball/5c12a8d626712de6db5e6d2db52b1eb4e9596650", - "reference": "5c12a8d626712de6db5e6d2db52b1eb4e9596650", - "shasum": "" - }, - "require": { - "cmgmyr/phploc": "^8.0.3", - "composer/semver": "^3.4", - "ext-iconv": "*", - "ext-json": "*", - "ext-mbstring": "*", - "ext-tokenizer": "*", - "friendsofphp/php-cs-fixer": "^3.40.0", - "justinrainbow/json-schema": "^5.2.13", - "league/container": "^3.2|^4.2", - "php": "^7.4|^8.0", - "php-parallel-lint/php-parallel-lint": "^1.3.2", - "psr/container": "^1.0|^2.0.2", - "psr/simple-cache": "^1.0|^2.0|^3.0", - "sebastian/diff": "^4.0|^5.0.3|^6.0", - "slevomat/coding-standard": "^8.14.1", - "squizlabs/php_codesniffer": "^3.7.2", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.4|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.4|^7.0" - }, - "require-dev": { - "ergebnis/phpstan-rules": "^0.15.3", - "illuminate/console": "^5.8|^6.0|^7.0|^8.0|^9.20|^10.0", - "illuminate/support": "^5.8|^6.0|^7.0|^8.0|^9.52.16|^10.0", - "mockery/mockery": "^1.6.6", - "phpstan/phpstan-strict-rules": "^0.12.11", - "phpunit/phpunit": "^8.0|^9.0|^10.4.2", - "rector/rector": "0.11.56", - "symfony/var-dumper": "^5.4|^6.0|^7.0", - "thecodingmachine/phpstan-strict-rules": "^0.12.2" - }, - "suggest": { - "ext-simplexml": "It is needed for the checkstyle formatter" - }, - "bin": [ - "bin/phpinsights" - ], - "type": "library", - "extra": { - "laravel": { - "providers": [ - "NunoMaduro\\PhpInsights\\Application\\Adapters\\Laravel\\InsightsServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "NunoMaduro\\PhpInsights\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "Instant PHP quality checks from your console.", - "keywords": [ - "Insights", - "code", - "console", - "php", - "quality", - "source" - ], - "support": { - "issues": "https://github.com/nunomaduro/phpinsights/issues", - "source": "https://github.com/nunomaduro/phpinsights/tree/v2.12.0" - }, - "funding": [ - { - "url": "https://github.com/JustSteveKing", - "type": "github" - }, - { - "url": "https://github.com/cmgmyr", - "type": "github" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - } - ], - "time": "2024-11-11T14:42:55+00:00" - }, - { - "name": "pestphp/pest", - "version": "v1.23.1", - "source": { - "type": "git", - "url": "https://github.com/pestphp/pest.git", - "reference": "5c56ad8772b89611c72a07e23f6e30aa29dc677a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/5c56ad8772b89611c72a07e23f6e30aa29dc677a", - "reference": "5c56ad8772b89611c72a07e23f6e30aa29dc677a", + "url": "https://api.github.com/repos/pestphp/pest/zipball/5c56ad8772b89611c72a07e23f6e30aa29dc677a", + "reference": "5c56ad8772b89611c72a07e23f6e30aa29dc677a", "shasum": "" }, "require": { @@ -7718,67 +8817,6 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "php-parallel-lint/php-parallel-lint", - "version": "v1.4.0", - "source": { - "type": "git", - "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git", - "reference": "6db563514f27e19595a19f45a4bf757b6401194e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6db563514f27e19595a19f45a4bf757b6401194e", - "reference": "6db563514f27e19595a19f45a4bf757b6401194e", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": ">=5.3.0" - }, - "replace": { - "grogy/php-parallel-lint": "*", - "jakub-onderka/php-parallel-lint": "*" - }, - "require-dev": { - "nette/tester": "^1.3 || ^2.0", - "php-parallel-lint/php-console-highlighter": "0.* || ^1.0", - "squizlabs/php_codesniffer": "^3.6" - }, - "suggest": { - "php-parallel-lint/php-console-highlighter": "Highlight syntax in code snippet" - }, - "bin": [ - "parallel-lint" - ], - "type": "library", - "autoload": { - "classmap": [ - "./src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Jakub Onderka", - "email": "ahoj@jakubonderka.cz" - } - ], - "description": "This tool checks the syntax of PHP files about 20x faster than serial check.", - "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint", - "keywords": [ - "lint", - "static analysis" - ], - "support": { - "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues", - "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.4.0" - }, - "time": "2024-03-27T12:14:49+00:00" - }, { "name": "phpstan/extension-installer", "version": "1.4.3", @@ -7827,65 +8865,18 @@ }, "time": "2024-09-04T20:21:43+00:00" }, - { - "name": "phpstan/phpdoc-parser", - "version": "1.33.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", - "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", - "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", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "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.33.0" - }, - "time": "2024-10-13T11:25:22+00:00" - }, { "name": "phpstan/phpstan", - "version": "1.12.14", + "version": "1.12.28", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e73868f809e68fff33be961ad4946e2e43ec9e38" + "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e73868f809e68fff33be961ad4946e2e43ec9e38", - "reference": "e73868f809e68fff33be961ad4946e2e43ec9e38", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", + "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", "shasum": "" }, "require": { @@ -7930,7 +8921,7 @@ "type": "github" } ], - "time": "2024-12-31T07:26:13+00:00" + "time": "2025-07-17T17:15:39+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -8352,16 +9343,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.22", + "version": "9.6.25", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c" + "reference": "049c011e01be805202d8eebedef49f769a8ec7b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c", - "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/049c011e01be805202d8eebedef49f769a8ec7b7", + "reference": "049c011e01be805202d8eebedef49f769a8ec7b7", "shasum": "" }, "require": { @@ -8372,7 +9363,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.1", + "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", @@ -8383,11 +9374,11 @@ "phpunit/php-timer": "^5.0.3", "sebastian/cli-parser": "^1.0.2", "sebastian/code-unit": "^1.0.8", - "sebastian/comparator": "^4.0.8", + "sebastian/comparator": "^4.0.9", "sebastian/diff": "^4.0.6", "sebastian/environment": "^5.1.5", "sebastian/exporter": "^4.0.6", - "sebastian/global-state": "^5.0.7", + "sebastian/global-state": "^5.0.8", "sebastian/object-enumerator": "^4.0.4", "sebastian/resource-operations": "^3.0.4", "sebastian/type": "^3.2.1", @@ -8435,7 +9426,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.22" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.25" }, "funding": [ { @@ -8447,110 +9438,19 @@ "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" - } - ], - "time": "2024-12-05T13:48:26+00:00" - }, - { - "name": "psr/cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for caching libraries", - "keywords": [ - "cache", - "psr", - "psr-6" - ], - "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" - }, - "time": "2021-02-03T23:26:27+00:00" - }, - { - "name": "psr/event-dispatcher", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\EventDispatcher\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" } ], - "description": "Standard interfaces for event handling.", - "keywords": [ - "events", - "psr", - "psr-14" - ], - "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" - }, - "time": "2019-01-08T18:20:26+00:00" + "time": "2025-08-20T14:38:31+00:00" }, { "name": "react/cache", @@ -8849,23 +9749,23 @@ }, { "name": "react/promise", - "version": "v3.2.0", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", - "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a", "shasum": "" }, "require": { "php": ">=7.1.0" }, "require-dev": { - "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpstan/phpstan": "1.12.28 || 1.4.10", "phpunit/phpunit": "^9.6 || ^7.5" }, "type": "library", @@ -8910,7 +9810,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v3.2.0" + "source": "https://github.com/reactphp/promise/tree/v3.3.0" }, "funding": [ { @@ -8918,7 +9818,7 @@ "type": "open_collective" } ], - "time": "2024-05-24T10:39:05+00:00" + "time": "2025-08-19T18:57:03+00:00" }, { "name": "react/socket", @@ -8977,641 +9877,131 @@ { "name": "Chris Boden", "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", - "keywords": [ - "Connection", - "Socket", - "async", - "reactphp", - "stream" - ], - "support": { - "issues": "https://github.com/reactphp/socket/issues", - "source": "https://github.com/reactphp/socket/tree/v1.16.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2024-07-26T10:38:09+00:00" - }, - { - "name": "react/stream", - "version": "v1.4.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/stream.git", - "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", - "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", - "shasum": "" - }, - "require": { - "evenement/evenement": "^3.0 || ^2.0 || ^1.0", - "php": ">=5.3.8", - "react/event-loop": "^1.2" - }, - "require-dev": { - "clue/stream-filter": "~1.2", - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Stream\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", - "keywords": [ - "event-driven", - "io", - "non-blocking", - "pipe", - "reactphp", - "readable", - "stream", - "writable" - ], - "support": { - "issues": "https://github.com/reactphp/stream/issues", - "source": "https://github.com/reactphp/stream/tree/v1.4.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2024-06-11T12:45:25+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", - "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:27:43+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:08:54+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:30:19+00:00" - }, - { - "name": "sebastian/comparator", - "version": "4.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2022-09-14T12:41:17+00:00" - }, - { - "name": "sebastian/complexity", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:19:30+00:00" - }, - { - "name": "sebastian/diff", - "version": "4.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", - "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T06:30:58+00:00" - }, - { - "name": "sebastian/environment", - "version": "5.1.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "homepage": "https://cboden.dev/" } ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", "keywords": [ - "Xdebug", - "environment", - "hhvm" + "Connection", + "Socket", + "async", + "reactphp", + "stream" ], "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.16.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://opencollective.com/reactphp", + "type": "open_collective" } ], - "time": "2023-02-03T06:03:51+00:00" + "time": "2024-07-26T10:38:09+00:00" }, { - "name": "sebastian/exporter", - "version": "4.0.6", + "name": "react/stream", + "version": "v1.4.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" }, "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "React\\Stream\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" }, { - "name": "Volker Dusch", - "email": "github@wallbash.com" + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" }, { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" }, { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" } ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", "keywords": [ - "export", - "exporter" + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" ], "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://opencollective.com/reactphp", + "type": "open_collective" } ], - "time": "2024-03-02T06:33:00+00:00" + "time": "2024-06-11T12:45:25+00:00" }, { - "name": "sebastian/global-state", - "version": "5.0.7", + "name": "sebastian/cli-parser", + "version": "1.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", - "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=7.3" }, "require-dev": { - "ext-dom": "*", "phpunit/phpunit": "^9.3" }, - "suggest": { - "ext-uopz": "*" - }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -9626,17 +10016,15 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -9644,24 +10032,23 @@ "type": "github" } ], - "time": "2024-03-02T06:35:11+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { - "name": "sebastian/lines-of-code", - "version": "1.0.4", + "name": "sebastian/code-unit", + "version": "1.0.8", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", "shasum": "" }, "require": { - "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -9689,11 +10076,11 @@ "role": "lead" } ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" }, "funding": [ { @@ -9701,26 +10088,24 @@ "type": "github" } ], - "time": "2023-12-22T06:20:34+00:00" + "time": "2020-10-26T13:08:54+00:00" }, { - "name": "sebastian/object-enumerator", - "version": "4.0.4", + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=7.3" }, "require-dev": { "phpunit/phpunit": "^9.3" @@ -9728,7 +10113,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -9746,11 +10131,11 @@ "email": "sebastian@phpunit.de" } ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" }, "funding": [ { @@ -9758,24 +10143,26 @@ "type": "github" } ], - "time": "2020-10-26T13:12:34+00:00" + "time": "2020-09-28T05:30:19+00:00" }, { - "name": "sebastian/object-reflector", - "version": "2.0.4", + "name": "sebastian/comparator", + "version": "4.0.9", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5", + "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" }, "require-dev": { "phpunit/phpunit": "^9.3" @@ -9783,7 +10170,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -9799,37 +10186,67 @@ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" } ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2020-10-26T13:14:26+00:00" + "time": "2025-08-10T06:51:50+00:00" }, { - "name": "sebastian/recursion-context", - "version": "4.0.5", + "name": "sebastian/complexity", + "version": "2.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -9838,7 +10255,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -9846,29 +10263,22 @@ "src/" ] }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -9876,32 +10286,33 @@ "type": "github" } ], - "time": "2023-02-03T06:07:39+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { - "name": "sebastian/resource-operations", - "version": "3.0.4", + "name": "sebastian/diff", + "version": "4.0.6", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", - "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -9917,12 +10328,23 @@ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], "support": { - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -9930,32 +10352,35 @@ "type": "github" } ], - "time": "2024-03-14T16:00:52+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { - "name": "sebastian/type", - "version": "3.2.1", + "name": "sebastian/environment", + "version": "5.1.5", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -9970,15 +10395,19 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" }, "funding": [ { @@ -9986,29 +10415,34 @@ "type": "github" } ], - "time": "2023-02-03T06:13:03+00:00" + "time": "2023-02-03T06:03:51+00:00" }, { - "name": "sebastian/version", - "version": "3.0.2", + "name": "sebastian/exporter", + "version": "4.0.6", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -10023,15 +10457,34 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" }, "funding": [ { @@ -10039,663 +10492,521 @@ "type": "github" } ], - "time": "2020-09-28T06:39:44+00:00" + "time": "2024-03-02T06:33:00+00:00" }, { - "name": "slevomat/coding-standard", - "version": "8.15.0", + "name": "sebastian/global-state", + "version": "5.0.8", "source": { "type": "git", - "url": "https://github.com/slevomat/coding-standard.git", - "reference": "7d1d957421618a3803b593ec31ace470177d7817" + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817", - "reference": "7d1d957421618a3803b593ec31ace470177d7817", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6", + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", - "php": "^7.2 || ^8.0", - "phpstan/phpdoc-parser": "^1.23.1", - "squizlabs/php_codesniffer": "^3.9.0" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phing/phing": "2.17.4", - "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "1.10.60", - "phpstan/phpstan-deprecation-rules": "1.1.4", - "phpstan/phpstan-phpunit": "1.3.16", - "phpstan/phpstan-strict-rules": "1.5.2", - "phpunit/phpunit": "8.5.21|9.6.8|10.5.11" - }, - "type": "phpcodesniffer-standard", + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", "extra": { "branch-alias": { - "dev-master": "8.x-dev" + "dev-master": "5.0-dev" } }, "autoload": { - "psr-4": { - "SlevomatCodingStandard\\": "SlevomatCodingStandard/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } ], - "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", "keywords": [ - "dev", - "phpcs" + "global state" ], "support": { - "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.15.0" + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8" }, "funding": [ { - "url": "https://github.com/kukulich", + "url": "https://github.com/sebastianbergmann", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", "type": "tidelift" } ], - "time": "2024-03-09T15:20:58+00:00" + "time": "2025-08-10T07:10:35+00:00" }, { - "name": "spatie/file-system-watcher", - "version": "1.2.0", + "name": "sebastian/lines-of-code", + "version": "1.0.4", "source": { "type": "git", - "url": "https://github.com/spatie/file-system-watcher.git", - "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/file-system-watcher/zipball/d9511ecbd266f190c4abce88516c3f231fcb6bfe", - "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "php": "^8.0", - "symfony/process": "^5.2|^6.0|^7.0" + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" }, "require-dev": { - "pestphp/pest": "^1.22", - "phpunit/phpunit": "^9.5", - "spatie/ray": "^1.22", - "spatie/temporary-directory": "^2.0", - "vimeo/psalm": "^4.3" + "phpunit/phpunit": "^9.3" }, "type": "library", - "autoload": { - "psr-4": { - "Spatie\\Watcher\\": "src" + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "role": "Developer" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Watch changes in the file system using PHP", - "homepage": "https://github.com/spatie/file-system-watcher", - "keywords": [ - "file-system-watcher", - "spatie" - ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { - "issues": "https://github.com/spatie/file-system-watcher/issues", - "source": "https://github.com/spatie/file-system-watcher/tree/1.2.0" + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { - "url": "https://github.com/spatie", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2023-12-18T14:26:25+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { - "name": "squizlabs/php_codesniffer", - "version": "3.11.2", + "name": "sebastian/object-enumerator", + "version": "4.0.4", "source": { "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079" + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1368f4a58c3c52114b86b1abe8f4098869cb0079", - "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", "shasum": "" }, "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], + "phpunit/phpunit": "^9.3" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-master": "4.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" }, "funding": [ { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" } ], - "time": "2024-12-11T16:04:26+00:00" + "time": "2020-10-26T13:12:34+00:00" }, { - "name": "symfony/cache", - "version": "v7.2.1", + "name": "sebastian/object-reflector", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/symfony/cache.git", - "reference": "e7e983596b744c4539f31e79b0350a6cf5878a20" + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/e7e983596b744c4539f31e79b0350a6cf5878a20", - "reference": "e7e983596b744c4539f31e79b0350a6cf5878a20", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "php": ">=8.2", - "psr/cache": "^2.0|^3.0", - "psr/log": "^1.1|^2|^3", - "symfony/cache-contracts": "^2.5|^3", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.4|^7.0" - }, - "conflict": { - "doctrine/dbal": "<3.6", - "symfony/dependency-injection": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/var-dumper": "<6.4" - }, - "provide": { - "psr/cache-implementation": "2.0|3.0", - "psr/simple-cache-implementation": "1.0|2.0|3.0", - "symfony/cache-implementation": "1.1|2.0|3.0" + "php": ">=7.3" }, "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/dbal": "^3.6|^4", - "predis/predis": "^1.1|^2.0", - "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/filesystem": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "phpunit/phpunit": "^9.3" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, "autoload": { - "psr-4": { - "Symfony\\Component\\Cache\\": "" - }, "classmap": [ - "Traits/ValueWrapper.php" - ], - "exclude-from-classmap": [ - "/Tests/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", - "homepage": "https://symfony.com", - "keywords": [ - "caching", - "psr6" - ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { - "source": "https://github.com/symfony/cache/tree/v7.2.1" + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2024-12-07T08:08:50+00:00" + "time": "2020-10-26T13:14:26+00:00" }, { - "name": "symfony/cache-contracts", - "version": "v3.5.1", + "name": "sebastian/recursion-context", + "version": "4.0.6", "source": { "type": "git", - "url": "https://github.com/symfony/cache-contracts.git", - "reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b" + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b", - "reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0", + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0", "shasum": "" }, "require": { - "php": ">=8.1", - "psr/cache": "^3.0" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-master": "4.0-dev" } }, "autoload": { - "psr-4": { - "Symfony\\Contracts\\Cache\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" } ], - "description": "Generic abstractions related to caching", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.5.1" + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" + "url": "https://github.com/sebastianbergmann", + "type": "github" }, { - "url": "https://github.com/fabpot", - "type": "github" + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-08-10T06:57:39+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v7.2.0", + "name": "sebastian/resource-operations", + "version": "3.0.4", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", - "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/event-dispatcher-contracts": "^2.5|^3" - }, - "conflict": { - "symfony/dependency-injection": "<6.4", - "symfony/service-contracts": "<2.5" - }, - "provide": { - "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0|3.0" + "php": ">=7.3" }, "require-dev": { - "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "phpunit/phpunit": "^9.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", - "homepage": "https://symfony.com", + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.2.0" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { - "name": "symfony/event-dispatcher-contracts", - "version": "v3.5.1", + "name": "sebastian/type", + "version": "3.2.1", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { - "php": ">=8.1", - "psr/event-dispatcher": "^1" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" }, "type": "library", "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-master": "3.2-dev" } }, "autoload": { - "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to dispatching event", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2023-02-03T06:13:03+00:00" }, { - "name": "symfony/finder", - "version": "v7.2.2", + "name": "sebastian/version", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", - "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": ">=8.2" - }, - "require-dev": { - "symfony/filesystem": "^6.4|^7.0" + "php": ">=7.3" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Finds files and directories via an intuitive fluent interface", - "homepage": "https://symfony.com", + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", "support": { - "source": "https://github.com/symfony/finder/tree/v7.2.2" + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2024-12-30T19:00:17+00:00" + "time": "2020-09-28T06:39:44+00:00" }, { - "name": "symfony/http-client", - "version": "v7.2.2", + "name": "spatie/file-system-watcher", + "version": "1.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/http-client.git", - "reference": "339ba21476eb184290361542f732ad12c97591ec" + "url": "https://github.com/spatie/file-system-watcher.git", + "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/339ba21476eb184290361542f732ad12c97591ec", - "reference": "339ba21476eb184290361542f732ad12c97591ec", + "url": "https://api.github.com/repos/spatie/file-system-watcher/zipball/d9511ecbd266f190c4abce88516c3f231fcb6bfe", + "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe", "shasum": "" }, "require": { - "php": ">=8.2", - "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "~3.4.4|^3.5.2", - "symfony/service-contracts": "^2.5|^3" - }, - "conflict": { - "amphp/amp": "<2.5", - "php-http/discovery": "<1.15", - "symfony/http-foundation": "<6.4" - }, - "provide": { - "php-http/async-client-implementation": "*", - "php-http/client-implementation": "*", - "psr/http-client-implementation": "1.0", - "symfony/http-client-implementation": "3.0" + "php": "^8.0", + "symfony/process": "^5.2|^6.0|^7.0" }, "require-dev": { - "amphp/http-client": "^4.2.1|^5.0", - "amphp/http-tunnel": "^1.0|^2.0", - "amphp/socket": "^1.1", - "guzzlehttp/promises": "^1.4|^2.0", - "nyholm/psr7": "^1.0", - "php-http/httplug": "^1.0|^2.0", - "psr/http-client": "^1.0", - "symfony/amphp-http-client-meta": "^1.0|^2.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0" + "pestphp/pest": "^1.22", + "phpunit/phpunit": "^9.5", + "spatie/ray": "^1.22", + "spatie/temporary-directory": "^2.0", + "vimeo/psalm": "^4.3" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\HttpClient\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Spatie\\Watcher\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -10703,71 +11014,56 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" } ], - "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", - "homepage": "https://symfony.com", + "description": "Watch changes in the file system using PHP", + "homepage": "https://github.com/spatie/file-system-watcher", "keywords": [ - "http" + "file-system-watcher", + "spatie" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.2.2" + "issues": "https://github.com/spatie/file-system-watcher/issues", + "source": "https://github.com/spatie/file-system-watcher/tree/1.2.0" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/spatie", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2024-12-30T18:35:15+00:00" + "time": "2023-12-18T14:26:25+00:00" }, { - "name": "symfony/http-client-contracts", - "version": "v3.5.2", + "name": "symfony/finder", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645" + "url": "https://github.com/symfony/finder.git", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645", - "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645", + "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.5-dev" - } + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" }, + "type": "library", "autoload": { "psr-4": { - "Symfony\\Contracts\\HttpClient\\": "" + "Symfony\\Component\\Finder\\": "" }, "exclude-from-classmap": [ - "/Test/" + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -10776,26 +11072,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to HTTP clients", + "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2" + "source": "https://github.com/symfony/finder/tree/v7.3.2" }, "funding": [ { @@ -10806,25 +11094,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-07T08:49:48+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.2.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" + "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37", + "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37", "shasum": "" }, "require": { @@ -10862,7 +11154,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" + "source": "https://github.com/symfony/options-resolver/tree/v7.3.2" }, "funding": [ { @@ -10873,16 +11165,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-20T11:17:29+00:00" + "time": "2025-07-15T11:36:08+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -10938,7 +11234,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" }, "funding": [ { @@ -10949,6 +11245,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -10958,16 +11258,16 @@ }, { "name": "symfony/process", - "version": "v7.1.8", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892" + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/42783370fda6e538771f7c7a36e9fa2ee3a84892", - "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892", + "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "shasum": "" }, "require": { @@ -10999,7 +11299,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.8" + "source": "https://github.com/symfony/process/tree/v7.3.0" }, "funding": [ { @@ -11015,20 +11315,20 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:23:19+00:00" + "time": "2025-04-17T09:11:12+00:00" }, { "name": "symfony/stopwatch", - "version": "v7.2.2", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df" + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/e46690d5b9d7164a6d061cab1e8d46141b9f49df", - "reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", "shasum": "" }, "require": { @@ -11061,83 +11361,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.2.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-12-18T14:28:33+00:00" - }, - { - "name": "symfony/var-exporter", - "version": "v7.2.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-exporter.git", - "reference": "1a6a89f95a46af0f142874c9d650a6358d13070d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/1a6a89f95a46af0f142874c9d650a6358d13070d", - "reference": "1a6a89f95a46af0f142874c9d650a6358d13070d", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\VarExporter\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Allows exporting any serializable PHP data structure to plain PHP code", - "homepage": "https://symfony.com", - "keywords": [ - "clone", - "construct", - "export", - "hydrate", - "instantiate", - "lazy-loading", - "proxy", - "serialize" - ], - "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.2.0" + "source": "https://github.com/symfony/stopwatch/tree/v7.3.0" }, "funding": [ { @@ -11153,7 +11377,7 @@ "type": "tidelift" } ], - "time": "2024-10-18T07:58:17+00:00" + "time": "2025-02-24T10:49:57+00:00" }, { "name": "theseer/tokenizer", diff --git a/config/app.php b/config/app.php index 2b501f2..6393975 100644 --- a/config/app.php +++ b/config/app.php @@ -3,20 +3,29 @@ declare(strict_types=1); return [ - 'name' => env('APP_NAME', fn () => 'Phenix'), - 'env' => env('APP_ENV', fn () => 'local'), - 'url' => env('APP_URL', fn () => '0.0.0.0'), - 'port' => env('APP_PORT', fn () => 1337), + 'name' => env('APP_NAME', static fn (): string => 'Phenix'), + 'env' => env('APP_ENV', static fn (): string => 'local'), + 'url' => env('APP_URL', static fn (): string => 'http://127.0.0.1'), + 'port' => env('APP_PORT', static fn (): int => 1337), + 'key' => env('APP_KEY'), + 'previous_key' => env('APP_PREVIOUS_KEY'), + 'debug' => env('APP_DEBUG', static fn (): bool => true), 'middlewares' => [ 'global' => [ - \App\Http\Middleware\HandleCors::class, + \Phenix\Http\Middlewares\HandleCors::class, ], 'router' => [], ], 'providers' => [ - Phenix\Providers\CommandsServiceProvider::class, - Phenix\Providers\RouteServiceProvider::class, - Phenix\Providers\DatabaseServiceProvider::class, - Phenix\Providers\FilesystemServiceProvider::class, + \Phenix\Console\CommandsServiceProvider::class, + \Phenix\Routing\RouteServiceProvider::class, + \Phenix\Database\DatabaseServiceProvider::class, + \Phenix\Redis\RedisServiceProvider::class, + \Phenix\Filesystem\FilesystemServiceProvider::class, + \Phenix\Tasks\TaskServiceProvider::class, + \Phenix\Views\ViewServiceProvider::class, + \Phenix\Mail\MailServiceProvider::class, + \Phenix\Crypto\CryptoServiceProvider::class, + \Phenix\Queue\QueueServiceProvider::class, ], ]; diff --git a/config/cors.php b/config/cors.php index afc624b..d191010 100644 --- a/config/cors.php +++ b/config/cors.php @@ -1,7 +1,7 @@ env('CORS_ORIGIN', fn () => ['http://localhost', 'http://127.0.0.1']), + 'origins' => env('CORS_ORIGIN', fn (): array => ['http://localhost', 'http://127.0.0.1']), 'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE'], 'max_age' => 8600, 'allowed_headers' => ['X-Request-Headers', 'Content-Type', 'Authorization', 'X-Requested-With'], diff --git a/config/database.php b/config/database.php index 68a7ea1..ad69ccf 100644 --- a/config/database.php +++ b/config/database.php @@ -2,16 +2,14 @@ declare(strict_types=1); -use Phenix\Database\Constants\Driver; - return [ - 'default' => env('DB_CONNECTION', fn () => 'mysql'), + 'default' => env('DB_CONNECTION', static fn (): string => 'mysql'), 'connections' => [ 'mysql' => [ - 'driver' => Driver::MYSQL, - 'host' => env('DB_HOST', fn () => '127.0.0.1'), - 'port' => env('DB_PORT', fn () => '3306'), + 'driver' => 'mysql', + 'host' => env('DB_HOST', static fn (): string => '127.0.0.1'), + 'port' => env('DB_PORT', static fn (): string => '3306'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), @@ -21,30 +19,30 @@ 'prefix' => '', ], 'postgresql' => [ - 'driver' => Driver::POSTGRESQL, - 'host' => env('DB_HOST', fn () => '127.0.0.1'), - 'port' => env('DB_PORT', fn () => '3306'), + 'driver' => 'postgresql', + 'host' => env('DB_HOST', static fn (): string => '127.0.0.1'), + 'port' => env('DB_PORT', static fn (): string => '5432'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), ], ], + 'paths' => [ + 'migrations' => base_path('database' . DIRECTORY_SEPARATOR . 'migrations'), + 'seeds' => base_path('database' . DIRECTORY_SEPARATOR . 'seeds'), + ], + 'redis' => [ 'connections' => [ 'default' => [ - 'scheme' => env('REDIS_SCHEME', fn () => 'redis'), - 'host' => env('REDIS_HOST', fn () => '127.0.0.1'), + 'scheme' => env('REDIS_SCHEME', static fn (): string => 'redis'), + 'host' => env('REDIS_HOST', static fn (): string => '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), - 'port' => env('REDIS_PORT', fn () => '6379'), - 'database' => env('REDIS_DB', fn () => 0), + 'port' => env('REDIS_PORT', static fn (): string => '6379'), + 'database' => env('REDIS_DB', static fn (): int => 0), ], ], ], - - 'paths' => [ - 'migrations' => base_path('database' . DIRECTORY_SEPARATOR . 'migrations'), - 'seeds' => base_path('database' . DIRECTORY_SEPARATOR . 'seeds'), - ], ]; diff --git a/config/filesystem.php b/config/filesystem.php index c6e7c5d..7d64aeb 100644 --- a/config/filesystem.php +++ b/config/filesystem.php @@ -3,7 +3,7 @@ declare(strict_types=1); return [ - 'default' => env('FILESYSTEM_DISK', fn () => 'local'), + 'default' => env('FILESYSTEM_DISK', fn (): string => 'local'), 'disks' => [ 'local' => [ 'path' => base_path('storage/app'), diff --git a/config/logging.php b/config/logging.php index cb1b4f8..cc0d9b6 100644 --- a/config/logging.php +++ b/config/logging.php @@ -3,7 +3,7 @@ declare(strict_types=1); return [ - 'default' => env('LOG_CHANNEL', fn () => 'file'), + 'default' => env('LOG_CHANNEL', fn (): string => 'file'), /* |-------------------------------------------------------------------------- diff --git a/config/mail.php b/config/mail.php new file mode 100644 index 0000000..bdef847 --- /dev/null +++ b/config/mail.php @@ -0,0 +1,30 @@ + env('MAIL_MAILER', static fn (): string => 'smtp'), + + 'mailers' => [ + 'smtp' => [ + 'transport' => 'smtp', + 'host' => env('MAIL_HOST', static fn (): string => 'smtp.mailgun.org'), + 'port' => env('MAIL_PORT', static fn (): int => 587), + 'encryption' => env('MAIL_ENCRYPTION', static fn (): string => 'tls'), + 'username' => env('MAIL_USERNAME'), + 'password' => env('MAIL_PASSWORD'), + 'timeout' => null, + ], + + 'ses' => [ + 'transport' => 'ses', + ], + + 'resend' => [ + 'transport' => 'resend', + ], + ], + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', static fn (): string => 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', static fn (): string => 'Example'), + ], +]; diff --git a/config/queue.php b/config/queue.php new file mode 100644 index 0000000..eaec4a4 --- /dev/null +++ b/config/queue.php @@ -0,0 +1,27 @@ + env('QUEUE_DRIVER', static fn (): string => 'database'), + + 'drivers' => [ + 'parallel' => [ + 'timeout' => env('PARALLEL_QUEUE_TIMEOUT', static fn (): int => 2), + 'chunk_processing' => env('PARALLEL_QUEUE_CHUNK_PROCESSING', static fn (): bool => true), + 'chunk_size' => env('PARALLEL_QUEUE_CHUNK_SIZE', static fn (): int => 10), + 'max_retries' => env('PARALLEL_QUEUE_MAX_RETRIES', static fn (): int => 3), + 'retry_delay' => env('PARALLEL_QUEUE_RETRY_DELAY', static fn (): int => 2), + 'interval' => env('PARALLEL_QUEUE_INTERVAL', static fn (): float => 2.0), + ], + + 'database' => [ + 'connection' => env('DB_QUEUE_CONNECTION', static fn (): string => 'mysql'), + 'table' => env('DB_QUEUE_TABLE', static fn (): string => 'tasks'), + 'queue' => env('DB_QUEUE', static fn (): string => 'default'), + ], + + 'redis' => [ + 'connection' => env('REDIS_QUEUE_CONNECTION', static fn (): string => 'default'), + 'queue' => env('REDIS_QUEUE', static fn (): string => 'default'), + ], + ], +]; diff --git a/config/services.php b/config/services.php new file mode 100644 index 0000000..f382b6a --- /dev/null +++ b/config/services.php @@ -0,0 +1,13 @@ + [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', static fn (): string => 'us-east-1'), + ], + + 'resend' => [ + 'key' => env('RESEND_API_KEY'), + ], +]; diff --git a/config/session.php b/config/session.php index 1230e84..d229735 100644 --- a/config/session.php +++ b/config/session.php @@ -29,11 +29,11 @@ | connection in your database configuration options. */ - 'connection' => env('SESSION_CONNECTION', fn () => 'default'), + 'connection' => env('SESSION_CONNECTION', static fn (): string => 'default'), 'cookie_name' => env( 'SESSION_COOKIE_NAME', - fn () => Str::slug(env('APP_NAME', fn () => 'phenix'), '_') . '_session' + static fn (): string => Str::slug(env('APP_NAME', static fn (): string => 'phenix'), '_') . '_session' ), 'path' => '/', diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000..6521e24 --- /dev/null +++ b/config/view.php @@ -0,0 +1,7 @@ + env('VIEW_PATH', static fn (): string => base_path('resources/views')), + + 'compiled_path' => env('VIEW_COMPILED_PATH', static fn (): string => base_path('storage/framework/views')), +]; diff --git a/phpinsights.php b/phpinsights.php deleted file mode 100644 index f89e5d0..0000000 --- a/phpinsights.php +++ /dev/null @@ -1,124 +0,0 @@ - 'default', - - /* - |-------------------------------------------------------------------------- - | IDE - |-------------------------------------------------------------------------- - | - | This options allow to add hyperlinks in your terminal to quickly open - | files in your favorite IDE while browsing your PhpInsights report. - | - | Supported: "textmate", "macvim", "emacs", "sublime", "phpstorm", - | "atom", "vscode". - | - | If you have another IDE that is not in this list but which provide an - | url-handler, you could fill this config with a pattern like this: - | - | myide://open?url=file://%f&line=%l - | - */ - - 'ide' => 'vscode', - - /* - |-------------------------------------------------------------------------- - | Configuration - |-------------------------------------------------------------------------- - | - | Here you may adjust all the various `Insights` that will be used by PHP - | Insights. You can either add, remove or configure `Insights`. Keep in - | mind, that all added `Insights` must belong to a specific `Metric`. - | - */ - - 'exclude' => [ - 'build', - 'public', - 'vendor', - 'storage', - '.vscode', - '.github', - 'phpinsights.php', - ], - - 'add' => [ - // ExampleMetric::class => [ - // ExampleInsight::class, - // ] - ], - - 'remove' => [ - PhpCsFixer\Fixer\Import\OrderedImportsFixer::class, // Collision with PHP CS Fixer - NunoMaduro\PhpInsights\Domain\Insights\ForbiddenTraits::class, - NunoMaduro\PhpInsights\Domain\Metrics\Architecture\Traits::class, - SlevomatCodingStandard\Sniffs\Functions\StaticClosureSniff::class, - NunoMaduro\PhpInsights\Domain\Insights\ForbiddenNormalClasses::class, - NunoMaduro\PhpInsights\Domain\Insights\ForbiddenDefineGlobalConstants::class, - SlevomatCodingStandard\Sniffs\Namespaces\AlphabeticallySortedUsesSniff::class, - ], - - 'config' => [ - \SlevomatCodingStandard\Sniffs\Namespaces\UseSpacingSniff::class => [ - 'linesCountBeforeFirstUse' => 1, - 'linesCountBetweenUseTypes' => 1, - 'linesCountAfterLastUse' => 1, - ], - \PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff::class => [ - 'lineLimit' => 120, - 'absoluteLineLimit' => 120, - 'ignoreComments' => false, - ], - ], - - /* - |-------------------------------------------------------------------------- - | Requirements - |-------------------------------------------------------------------------- - | - | Here you may define a level you want to reach per `Insights` category. - | When a score is lower than the minimum level defined, then an error - | code will be returned. This is optional and individually defined. - | - */ - - 'requirements' => [ -// 'min-quality' => 0, -// 'min-complexity' => 0, -// 'min-architecture' => 0, -// 'min-style' => 0, -// 'disable-security-check' => false, - ], - - /* - |-------------------------------------------------------------------------- - | Threads - |-------------------------------------------------------------------------- - | - | Here you may adjust how many threads (core) PHPInsights can use to perform - | the analyse. This is optional, don't provide it and the tool will guess - | the max core number available. This accept null value or integer > 0. - | - */ - - 'threads' => null, - -]; diff --git a/server b/server index 1f8834f..328ab9d 100644 --- a/server +++ b/server @@ -13,15 +13,78 @@ if (php_sapi_name() !== 'cli') { exit; } +class Output +{ + public const RESET = "\033[0m"; + public const BOLD = "\033[1m"; + + // Text colors + public const RED = "\033[31m"; + public const GREEN = "\033[32m"; + public const YELLOW = "\033[33m"; + public const BLUE = "\033[34m"; + public const MAGENTA = "\033[35m"; + public const CYAN = "\033[36m"; + public const WHITE = "\033[37m"; + public const GRAY = "\033[90m"; + + // Background colors + public const BG_RED = "\033[41m"; + public const BG_GREEN = "\033[42m"; + public const BG_YELLOW = "\033[43m"; + + public static function colorize(string $text, string $color): string + { + return $color . $text . self::RESET; + } + + public static function success(string $text): string + { + return self::colorize("🚀 " . $text, self::GREEN . self::BOLD); + } + + public static function error(string $text): string + { + return self::colorize("❌ " . $text, self::RED . self::BOLD); + } + + public static function warning(string $text): string + { + return self::colorize("⚠️ " . $text, self::YELLOW . self::BOLD); + } + + public static function info(string $text): string + { + return self::colorize("ℹ️ " . $text, self::CYAN . self::BOLD); + } + + public static function debug(string $text): string + { + return self::colorize($text, self::GRAY); + } +} + $config = Dotenv::createArrayBacked(__DIR__, '.env')->load(); class Watcher extends Watch { protected string $host; + protected int $port; + protected int|null $pid; + protected Process $serverProcess; + protected int $consecutiveErrors = 0; + + protected int $maxConsecutiveErrors = 5; + + protected int $lastHealthCheck = 0; + + protected bool $stopAttempts = false; + + public function __construct( array $paths, array $config = [] @@ -38,20 +101,13 @@ class Watcher extends Watch $watcher = $this->getWatchProcess(); while (true) { - if (! $watcher->isRunning()) { - throw CouldNotStartWatcher::make($watcher); - } + $this->ensureWatcherIsRunning($watcher); - if ($output = $watcher->getIncrementalOutput()) { - $this->actOnOutput($output); - } + $this->handleWatcherOutput($watcher); - if ($this->serverProcess->isRunning()) { - echo $this->serverProcess->getIncrementalOutput(); - echo $this->serverProcess->getIncrementalErrorOutput(); - } + $this->handleServerProcess(); - if (! ($this->shouldContinue)()) { + if (!($this->shouldContinue)()) { break; } @@ -59,15 +115,15 @@ class Watcher extends Watch } } - public function watch(): void { - echo "Watching for changes..." . PHP_EOL . PHP_EOL; + public function watch(): void + { + echo Output::info("Watching for changes...") . PHP_EOL . PHP_EOL; $this->onAnyChange(function (): void { $this->killExistingProcess(); $this->runServer(); - }) - ->start(); + })->start(); } public function systemIsReady(): bool @@ -81,18 +137,18 @@ class Watcher extends Watch if ($process->isSuccessful() && strpos($process->getOutput(), $packageName) !== false) { return true; } else { - echo "Chokidar is not installed. Installing..." . PHP_EOL; + echo Output::warning("Chokidar is not installed. Installing...") . PHP_EOL; $installCommand = 'npm install ' . escapeshellarg($packageName); $installProcess = Process::fromShellCommandline($installCommand); $installProcess->run(); if ($installProcess->isSuccessful()) { - echo "Chokidar installed successfully." . PHP_EOL; + echo Output::success("Chokidar installed successfully.") . PHP_EOL; return true; } else { - echo "Failed to install chokidar. Please check your npm configuration." . PHP_EOL; + echo Output::error("Failed to install chokidar. Please check your npm configuration.") . PHP_EOL; echo $installProcess->getErrorOutput(); return false; @@ -100,26 +156,281 @@ class Watcher extends Watch } } - public function runServer(): void { - $this->serverProcess = Process::fromShellCommandline("php public/index.php"); + public function runServer(bool $incrementErrorCounter = true): void + { + if ($this->consecutiveErrors >= $this->maxConsecutiveErrors || $this->stopAttempts) { + if (!$this->stopAttempts) { + echo Output::error("Too many consecutive errors ({$this->consecutiveErrors}). Stopping server attempts.") . PHP_EOL; + + $this->stopAttempts = true; + } + + return; + } + + $command = "XDEBUG_MODE=off php public/index.php"; + $this->serverProcess = Process::fromShellCommandline($command); $this->serverProcess->setTimeout(null); - $this->serverProcess->start(); - $this->pid = $this->serverProcess->getPid(); + try { + $this->serverProcess->start(); + + usleep(100000); // 100ms + + if (!$this->serverProcess->isRunning()) { + $exitCode = $this->serverProcess->getExitCode(); + + if ($incrementErrorCounter) { + $this->consecutiveErrors++; + } + + echo Output::error("Server failed to start. Exit code: {$exitCode}") . PHP_EOL; + echo Output::debug("Error: " . $this->serverProcess->getErrorOutput()) . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL . PHP_EOL; + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + sleep(2); + + $this->runServer($incrementErrorCounter); + } + + return; + } + + if ($incrementErrorCounter) { + $this->consecutiveErrors = 0; + } + $this->pid = $this->serverProcess->getPid(); + + echo Output::success("Server started on {$this->host}:{$this->port}") . PHP_EOL; + echo Output::info("PID: {$this->pid}") . PHP_EOL . PHP_EOL; + + } catch (Exception $e) { + if ($incrementErrorCounter) { + $this->consecutiveErrors++; + } + + echo Output::error("Failed to start server: " . $e->getMessage()) . PHP_EOL; + echo Output::debug("Command: {$command}") . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL . PHP_EOL; - echo "Server started on {$this->host}:{$this->port}" . PHP_EOL . PHP_EOL; + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + sleep(2); + + $this->runServer($incrementErrorCounter); + } + } } - protected function killExistingProcess() + private function ensureWatcherIsRunning(Process $watcher): void { - if ($this->pid) { - echo "Restarting server..." . PHP_EOL . PHP_EOL; + if (!$watcher->isRunning()) { + throw CouldNotStartWatcher::make($watcher); + } + } + + private function handleWatcherOutput(Process $watcher): void + { + if ($output = $watcher->getIncrementalOutput()) { + $this->actOnOutput($output); + } + } + + private function handleServerProcess(): void + { + if (!isset($this->serverProcess)) { + return; + } + + if ($this->serverProcess->isRunning()) { + $this->outputServerProcess(); + + $this->periodicHealthCheck(); + } else { + $this->handleServerExit(); + } + } - $killProcess = Process::fromShellCommandline('kill ' . escapeshellarg($this->pid)); + private function outputServerProcess(): void + { + $output = $this->serverProcess->getIncrementalOutput(); + $errorOutput = $this->serverProcess->getIncrementalErrorOutput(); + + if ($output) { + echo $this->colorizeServerOutput($output); + } + + if ($errorOutput) { + echo Output::colorize($errorOutput, Output::RED); + } + } + + private function colorizeServerOutput(string $output): string + { + $lines = explode("\n", $output); + $colorizedLines = []; + + foreach ($lines as $line) { + $colorizedLines[] = $this->colorizeLine($line); + } + + return implode("\n", $colorizedLines); + } + + private function colorizeLine(string $line): string + { + $trimmed = trim($line); + $result = $line; + + if ($trimmed === '') { + // leave $result as $line + } elseif (strpos($line, '.NOTICE:') !== false) { + $result = Output::colorize($line, Output::CYAN); + } elseif (strpos($line, '.WARNING:') !== false) { + $result = Output::colorize($line, Output::YELLOW); + } elseif (strpos($line, '.ERROR:') !== false) { + $result = Output::colorize($line, Output::RED); + } elseif (strpos($line, '.DEBUG:') !== false) { + $result = Output::colorize($line, Output::GRAY); + } elseif (strpos($line, '.INFO:') !== false) { + $result = Output::colorize($line, Output::GREEN); + } elseif (strpos($line, 'Started server') !== false || strpos($line, 'Listening on') !== false) { + $result = Output::colorize($line, Output::GREEN . Output::BOLD); + } elseif ($this->isHttpMethodLine($line)) { + $result = $this->colorizeHttpStatusLine($line); + } + + return $result; + } + + private function isHttpMethodLine(string $line): bool + { + return strpos($line, 'GET') !== false + || strpos($line, 'POST') !== false + || strpos($line, 'PUT') !== false; + } + + private function colorizeHttpStatusLine(string $line): string + { + $colorized = Output::colorize($line, Output::BLUE); + + if (strpos($line, ' 200 ') !== false) { + $colorized = Output::colorize($line, Output::GREEN); + } elseif (strpos($line, ' 404 ') !== false) { + $colorized = Output::colorize($line, Output::YELLOW); + } elseif (strpos($line, ' 500 ') !== false) { + $colorized = Output::colorize($line, Output::RED); + } + + return $colorized; + } + + private function periodicHealthCheck(): void + { + if ($this->stopAttempts) { + return; + } + + if (time() - $this->lastHealthCheck > 10) { + if (!$this->isServerHealthy()) { + echo Output::warning("Server health check failed. Restarting...") . PHP_EOL; + + $this->consecutiveErrors++; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL; + + $this->killExistingProcess(); + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + $this->runServer(false); + } else { + echo Output::error("Maximum consecutive errors reached. Server will not restart automatically.") . PHP_EOL; + + $this->stopAttempts = true; + } + } else { + if ($this->consecutiveErrors > 0) { + echo Output::success("Server health check passed. Resetting error counter.") . PHP_EOL; + + $this->consecutiveErrors = 0; + $this->stopAttempts = false; // Allow attempts again + } + } + + $this->lastHealthCheck = time(); + } + } + + private function handleServerExit(): void + { + if ($this->stopAttempts) { + return; + } + + $exitCode = $this->serverProcess->getExitCode(); + + if ($exitCode !== null && $exitCode !== 0) { + echo Output::error("Server process exited with error code: {$exitCode}") . PHP_EOL; + echo Output::debug("Error output: " . $this->serverProcess->getErrorOutput()) . PHP_EOL; + echo Output::info("Restarting server...") . PHP_EOL . PHP_EOL; + + $this->consecutiveErrors++; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL; + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + $this->runServer(false); + } else { + echo Output::error("Maximum consecutive errors reached. Server will not restart automatically.") . PHP_EOL; + + $this->stopAttempts = true; + } + } + } + + private function killExistingProcess(): void + { + if (!isset($this->serverProcess) || !$this->pid) { + return; + } + + echo Output::info("Restarting server...") . PHP_EOL . PHP_EOL; + + try { + $this->serverProcess->stop(3); // 3 second timeout + + if ($this->serverProcess->isRunning()) { + $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); + $killProcess->run(); + } + + echo Output::success("Server was stopped (PID {$this->pid})") . PHP_EOL . PHP_EOL; + + } catch (Exception $e) { + echo Output::error("Error stopping server: " . $e->getMessage()) . PHP_EOL; + + $killProcess = Process::fromShellCommandline('kill -9 ' . escapeshellarg($this->pid)); $killProcess->run(); + } + + $this->pid = null; + } - echo "Server was stopped (PID {$this->pid})" . PHP_EOL . PHP_EOL; + private function isServerHealthy(): bool + { + if (!isset($this->serverProcess) || !$this->serverProcess->isRunning()) { + return false; } + + $context = stream_context_create([ + 'http' => [ + 'timeout' => 1, + 'ignore_errors' => true + ] + ]); + + $url = str_replace(['http://', 'https://'], '', $this->host) . ':' . $this->port; + $result = @file_get_contents("http://{$url}", false, $context); + + return $result !== false; } } @@ -138,7 +449,7 @@ try { $watcher->watch(); } else { - echo "System is not ready. Exiting..." . PHP_EOL . PHP_EOL; + echo Output::error("System is not ready. Exiting...") . PHP_EOL . PHP_EOL; } } catch (Throwable $th) { echo $th->getMessage(); diff --git a/tests/Pest.php b/tests/Pest.php index 18a31ea..48b715c 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -13,7 +13,7 @@ use Amp\Http\Client\HttpClientBuilder; use Amp\Http\Client\Request; -use Phenix\Constants\HttpMethod; +use Phenix\Http\Constants\HttpMethod; use Phenix\Testing\TestResponse; use Phenix\Util\URL; From 592eda4f79dd33a5ae0999330d11bfb16f8c037c Mon Sep 17 00:00:00 2001 From: FSHLL Date: Sun, 24 Aug 2025 20:28:05 -0500 Subject: [PATCH 029/133] fix: use node lts in dockerfile image --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index ebf570d..42338a0 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -8,7 +8,7 @@ RUN groupadd -g ${USER_GID} phenix_group && useradd -ms /bin/bash -u ${USER_UID} RUN docker-php-ext-install pcntl pdo pdo_mysql -RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \ +RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \ apt-get install -y nodejs USER phenix_user From 38c4bf6f364eba7a1ce7d0bfe0608abe0341bc79 Mon Sep 17 00:00:00 2001 From: FSHLL Date: Sun, 24 Aug 2025 21:13:20 -0500 Subject: [PATCH 030/133] feat: default environment app name in .env.example --- .env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/.env.example b/.env.example index 958f968..bce63d1 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ APP_NAME=Phenix APP_KEY= +APP_ENV=local APP_DEBUG=true APP_URL=http://127.0.0.1 APP_PORT=1337 From 67f77bc66b4400215c6ef9e26b85da68504f4778 Mon Sep 17 00:00:00 2001 From: FSHLL Date: Sun, 24 Aug 2025 21:14:37 -0500 Subject: [PATCH 031/133] fix: use default process class for execute server and get correct PDI --- server | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server b/server index 328ab9d..6909fcf 100644 --- a/server +++ b/server @@ -6,6 +6,7 @@ use Dotenv\Dotenv; use Spatie\Watcher\Watch; use Symfony\Component\Process\Process; use Spatie\Watcher\Exceptions\CouldNotStartWatcher; +use Symfony\Component\Process\PhpExecutableFinder; require_once __DIR__ . '/vendor/autoload.php'; @@ -92,7 +93,7 @@ class Watcher extends Watch parent::__construct(); $this->setPaths($paths); - $this->host = $config['APP_URL'] ?? 'http://127.0.0.1'; + $this->host = $config['APP_HOST'] ?? '0.0.0.0'; $this->port = $config['APP_PORT'] ?? 1337; } @@ -169,7 +170,10 @@ class Watcher extends Watch } $command = "XDEBUG_MODE=off php public/index.php"; - $this->serverProcess = Process::fromShellCommandline($command); + $this->serverProcess = new Process( + command:[(new PhpExecutableFinder)->find(), 'public/index.php', "--host={$this->host}", "--port={$this->port}"], + env:['XDEBUG_MODE' => 'off'] + ); $this->serverProcess->setTimeout(null); try { From a9189dce916b5a4f646a19e53af11182252a5694 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 25 Aug 2025 11:02:26 -0500 Subject: [PATCH 032/133] refactor: update Docker configuration and environment variables for consistency --- .env.example | 5 +---- docker-compose.yml | 20 ++++++++++++-------- docker/Dockerfile | 28 +++++++++++++++++----------- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/.env.example b/.env.example index e892f6a..98c1e66 100644 --- a/.env.example +++ b/.env.example @@ -10,7 +10,7 @@ DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=phenix DB_USERNAME=phenix -DB_PASSWORD=secret +DB_PASSWORD= LOG_CHANNEL=stream @@ -21,6 +21,3 @@ CORS_ORIGIN= REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD=null - -USER_UID=1000 -USER_GID=1000 diff --git a/docker-compose.yml b/docker-compose.yml index dffd3bd..1bcef15 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,19 +2,20 @@ services: app: build: context: ./docker - args: - - USER_UID=${USER_UID} - - USER_GID=${USER_GID} + target: development volumes: - - .:/usr/src/phenix:rw - working_dir: /usr/src/phenix + - .:/var/www:rw + working_dir: /var/www extra_hosts: - 'host.docker.internal:host-gateway' environment: - - APP_PORT=${APP_PORT} - - APP_ENV=${APP_ENV} + - APP_PORT=${APP_PORT:-8080} + - APP_ENV=${APP_ENV:-development} ports: - - '${APP_PORT}:${APP_PORT}' + - '${APP_PORT:-8080}:${APP_PORT:-8080}' + networks: + - phenix + mysql: image: mysql:8.0 ports: @@ -25,6 +26,9 @@ services: MYSQL_USER: '${DB_USERNAME}' MYSQL_PASSWORD: '${DB_PASSWORD}' MYSQL_ALLOW_EMPTY_PASSWORD: 1 + networks: + - phenix + networks: phenix: driver: bridge \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index 42338a0..9c5c302 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,22 +1,28 @@ -FROM php:8.2-cli -WORKDIR /usr/src/phenix +FROM php:8.2-cli AS development -ARG USER_UID -ARG USER_GID +WORKDIR /var/www/ -RUN groupadd -g ${USER_GID} phenix_group && useradd -ms /bin/bash -u ${USER_UID} -g ${USER_GID} phenix_user +RUN apt-get update \ + && apt-get install -y curl \ + && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* RUN docker-php-ext-install pcntl pdo pdo_mysql -RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \ - apt-get install -y nodejs +COPY . /var/www/ -USER phenix_user +FROM php:8.2-cli AS production -COPY . /usr/src/phenix +WORKDIR /var/www/ -ENV APP_PORT=${APP_PORT} +RUN docker-php-ext-install pcntl pdo pdo_mysql + +COPY . /var/www/ + +USER www-data -EXPOSE ${APP_PORT} +EXPOSE 8080 ENTRYPOINT ["docker/entrypoint.sh"] From a3f2fb1acc97c78c5c89330aff079cb99f058a77 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 25 Aug 2025 11:06:11 -0500 Subject: [PATCH 033/133] refactor: reorganize Dockerfile stages and improve package installation --- docker/Dockerfile | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 9c5c302..8eb6a5f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,28 +1,40 @@ -FROM php:8.2-cli AS development +FROM php:8.2-cli AS base WORKDIR /var/www/ RUN apt-get update \ - && apt-get install -y curl \ - && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ - && apt-get install -y nodejs \ + && apt-get install -y curl git unzip \ + && docker-php-ext-install pcntl pdo pdo_mysql \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -RUN docker-php-ext-install pcntl pdo pdo_mysql +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +FROM base AS development + +RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs COPY . /var/www/ -FROM php:8.2-cli AS production +RUN composer install --no-scripts --no-autoloader -WORKDIR /var/www/ +RUN composer dump-autoload --optimize -RUN docker-php-ext-install pcntl pdo pdo_mysql +EXPOSE ${APP_PORT:-1337} + +ENTRYPOINT ["docker/entrypoint.sh"] + +FROM base AS production COPY . /var/www/ +RUN composer install --no-dev --optimize-autoloader --no-scripts \ + && chown -R www-data:www-data /var/www \ + && chmod -R 755 /var/www/storage + USER www-data -EXPOSE 8080 +EXPOSE ${APP_PORT:-1337} ENTRYPOINT ["docker/entrypoint.sh"] From 4679ca12dbdc5f22d025a81f6c18940b79d1616c Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 25 Aug 2025 11:07:10 -0500 Subject: [PATCH 034/133] refactor: update docker-compose configuration for app and mysql services --- docker-compose.yml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1bcef15..4e02366 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,27 @@ services: app: build: - context: ./docker + context: . + dockerfile: docker/Dockerfile target: development volumes: - .:/var/www:rw + - /var/www/vendor working_dir: /var/www extra_hosts: - 'host.docker.internal:host-gateway' environment: - - APP_PORT=${APP_PORT:-8080} + - APP_PORT=${APP_PORT:-1337} - APP_ENV=${APP_ENV:-development} + - DB_HOST=mysql + - DB_PORT=3306 + - DB_DATABASE=${DB_DATABASE} + - DB_USERNAME=${DB_USERNAME} + - DB_PASSWORD=${DB_PASSWORD} ports: - - '${APP_PORT:-8080}:${APP_PORT:-8080}' + - '${APP_PORT:-1337}:${APP_PORT:-1337}' + depends_on: + - mysql networks: - phenix @@ -26,9 +35,14 @@ services: MYSQL_USER: '${DB_USERNAME}' MYSQL_PASSWORD: '${DB_PASSWORD}' MYSQL_ALLOW_EMPTY_PASSWORD: 1 + volumes: + - mysql_data:/var/lib/mysql networks: - phenix +volumes: + mysql_data: + networks: phenix: driver: bridge \ No newline at end of file From 32ac6781c787e53373a3629029d8c452ea9aabdd Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 25 Aug 2025 11:08:17 -0500 Subject: [PATCH 035/133] refactor: update entrypoint script to use bash and improve environment handling --- docker/entrypoint.sh | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 29a2f45..e5888b4 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,7 +1,26 @@ -#!/bin/sh +#!/bin/bash + +set -e + +chmod +x ./phenix + +if [ "$APP_ENV" != "production" ]; then + echo "Waiting for MySQL to be ready..." + while ! nc -z mysql 3306; do + sleep 1 + done + echo "MySQL is ready!" +fi + +if [ "$APP_ENV" = "development" ]; then + echo "Running migrations..." + ./phenix migrate:run || true +fi if [ "$APP_ENV" = "production" ]; then - php public/index.php --host=0.0.0.0 --port=${APP_PORT} + echo "Starting production server..." + php public/index.php --host=0.0.0.0 --port=${APP_PORT:-1337} else - php ./server --host=0.0.0.0 --port=${APP_PORT} + echo "Starting development server with file watcher..." + php ./server --host=0.0.0.0 --port=${APP_PORT:-1337} fi \ No newline at end of file From 346f510eca470d3fbeb7b5e628783a0d584440a3 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 25 Aug 2025 11:12:17 -0500 Subject: [PATCH 036/133] refactor: change environment target from development to local in Docker configuration --- docker-compose.yml | 2 +- docker/Dockerfile | 2 +- docker/entrypoint.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4e02366..d65d027 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: build: context: . dockerfile: docker/Dockerfile - target: development + target: local volumes: - .:/var/www:rw - /var/www/vendor diff --git a/docker/Dockerfile b/docker/Dockerfile index 8eb6a5f..df0ba19 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -10,7 +10,7 @@ RUN apt-get update \ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer -FROM base AS development +FROM base AS local RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ && apt-get install -y nodejs diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index e5888b4..48cb1df 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -12,7 +12,7 @@ if [ "$APP_ENV" != "production" ]; then echo "MySQL is ready!" fi -if [ "$APP_ENV" = "development" ]; then +if [ "$APP_ENV" = "local" ]; then echo "Running migrations..." ./phenix migrate:run || true fi From 6434677089b2a10d95b682992b32e1d7316dc514 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 25 Aug 2025 11:22:39 -0500 Subject: [PATCH 037/133] refactor: add .dockerignore file to exclude unnecessary files from Docker context --- .dockerignore | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4ff7ed4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,49 @@ +.git +.gitignore +.gitattributes + +Dockerfile +docker-compose.yml +.dockerignore + +README.md +CHANGELOG.md +LICENSE.md +docs/ + +.vscode/ +.idea/ +*.swp +*.swo + +.DS_Store +Thumbs.db + +storage/logs/* +storage/framework/logs/* +storage/app/public/* +storage/framework/cache/* +storage/framework/sessions/* +storage/framework/testing/* +storage/framework/views/* + +node_modules/ +vendor/ + +.env + +build/ +coverage/ + +*.tmp +*.log +*.pid +*.seed +*.pid.lock + +.phpunit.result.cache +.pest +.php_cs.cache + +dist/ +public/build/ From 856b343b4a69d78bb03a1e663f953c9e902f0af3 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 25 Aug 2025 11:30:29 -0500 Subject: [PATCH 038/133] refactor: simplify entrypoint script by removing MySQL readiness check for local environment --- docker/entrypoint.sh | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 48cb1df..4c5b3b7 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -4,18 +4,8 @@ set -e chmod +x ./phenix -if [ "$APP_ENV" != "production" ]; then - echo "Waiting for MySQL to be ready..." - while ! nc -z mysql 3306; do - sleep 1 - done - echo "MySQL is ready!" -fi - -if [ "$APP_ENV" = "local" ]; then - echo "Running migrations..." - ./phenix migrate:run || true -fi +echo "Running migrations..." +./phenix migrate:run || true if [ "$APP_ENV" = "production" ]; then echo "Starting production server..." From d7baef3ebac0d59088b49f99651726eb3d26a6bc Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 25 Aug 2025 11:39:45 -0500 Subject: [PATCH 039/133] refactor: remove unnecessary executable permission change for phenix in entrypoint script --- docker/entrypoint.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 4c5b3b7..2ceb2a2 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -2,8 +2,6 @@ set -e -chmod +x ./phenix - echo "Running migrations..." ./phenix migrate:run || true From f5379fe53c6352aa686be5faea56fbabd786616e Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 25 Aug 2025 18:00:06 -0500 Subject: [PATCH 040/133] refactor: set default values for MySQL environment variables in docker-compose --- docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index d65d027..c0b2024 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,9 +31,9 @@ services: - "${MYSQL_PORT:-3307}:3306" environment: MYSQL_ROOT_HOST: "%" - MYSQL_DATABASE: '${DB_DATABASE}' - MYSQL_USER: '${DB_USERNAME}' - MYSQL_PASSWORD: '${DB_PASSWORD}' + MYSQL_DATABASE: '${DB_DATABASE:-phenix}' + MYSQL_USER: '${DB_USERNAME:-phenix}' + MYSQL_PASSWORD: '${DB_PASSWORD:-secret}' MYSQL_ALLOW_EMPTY_PASSWORD: 1 volumes: - mysql_data:/var/lib/mysql From 1b39555813022c151e1ff0f8b5f3c98f8d65768b Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 25 Aug 2025 18:01:19 -0500 Subject: [PATCH 041/133] refactor: update MySQL username in environment configuration to 'root' --- .env.example | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 98c1e66..a0e04ad 100644 --- a/.env.example +++ b/.env.example @@ -9,7 +9,7 @@ DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=phenix -DB_USERNAME=phenix +DB_USERNAME=root DB_PASSWORD= LOG_CHANNEL=stream diff --git a/docker-compose.yml b/docker-compose.yml index c0b2024..a6939b3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,7 +32,7 @@ services: environment: MYSQL_ROOT_HOST: "%" MYSQL_DATABASE: '${DB_DATABASE:-phenix}' - MYSQL_USER: '${DB_USERNAME:-phenix}' + MYSQL_USER: '${DB_USERNAME:-root}' MYSQL_PASSWORD: '${DB_PASSWORD:-secret}' MYSQL_ALLOW_EMPTY_PASSWORD: 1 volumes: From c833f59a684ed1b5666257268c885b9a4949ebba Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 26 Aug 2025 10:39:43 -0500 Subject: [PATCH 042/133] refactor: remove .env from .dockerignore to allow environment variable configuration --- .dockerignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 4ff7ed4..c024240 100644 --- a/.dockerignore +++ b/.dockerignore @@ -30,8 +30,6 @@ storage/framework/views/* node_modules/ vendor/ -.env - build/ coverage/ From 1abd4efd090e91e0235ab143720790712515aaad Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 26 Aug 2025 10:40:11 -0500 Subject: [PATCH 043/133] refactor: improve database configuration --- .env.example | 2 +- docker-compose.yml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index a0e04ad..98c1e66 100644 --- a/.env.example +++ b/.env.example @@ -9,7 +9,7 @@ DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=phenix -DB_USERNAME=root +DB_USERNAME=phenix DB_PASSWORD= LOG_CHANNEL=stream diff --git a/docker-compose.yml b/docker-compose.yml index a6939b3..d36d887 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,12 +12,12 @@ services: - 'host.docker.internal:host-gateway' environment: - APP_PORT=${APP_PORT:-1337} - - APP_ENV=${APP_ENV:-development} + - APP_ENV=${APP_ENV:-local} - DB_HOST=mysql - DB_PORT=3306 - - DB_DATABASE=${DB_DATABASE} - - DB_USERNAME=${DB_USERNAME} - - DB_PASSWORD=${DB_PASSWORD} + - DB_DATABASE=${DB_DATABASE:-phenix} + - DB_USERNAME=${DB_USERNAME:-phenix} + - DB_PASSWORD=${DB_PASSWORD:-secret} ports: - '${APP_PORT:-1337}:${APP_PORT:-1337}' depends_on: @@ -32,7 +32,7 @@ services: environment: MYSQL_ROOT_HOST: "%" MYSQL_DATABASE: '${DB_DATABASE:-phenix}' - MYSQL_USER: '${DB_USERNAME:-root}' + MYSQL_USER: '${DB_USERNAME:-phenix}' MYSQL_PASSWORD: '${DB_PASSWORD:-secret}' MYSQL_ALLOW_EMPTY_PASSWORD: 1 volumes: From c7d386d790ecf8f0cb1ae3359e331898c1e2637f Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 26 Aug 2025 10:41:23 -0500 Subject: [PATCH 044/133] refactor: add .env to .dockerignore to prevent environment variable exposure --- .dockerignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.dockerignore b/.dockerignore index c024240..4ff7ed4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -30,6 +30,8 @@ storage/framework/views/* node_modules/ vendor/ +.env + build/ coverage/ From 003e0f6ba7eda4acc45d55c217b914e86dcbbe3f Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 26 Aug 2025 10:46:12 -0500 Subject: [PATCH 045/133] refactor: use static function syntax for environment variable defaults in configuration files --- config/cors.php | 2 +- config/logging.php | 2 +- config/session.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/cors.php b/config/cors.php index d191010..105b1ab 100644 --- a/config/cors.php +++ b/config/cors.php @@ -1,7 +1,7 @@ env('CORS_ORIGIN', fn (): array => ['http://localhost', 'http://127.0.0.1']), + 'origins' => env('CORS_ORIGIN', static fn (): array => ['http://localhost', 'http://127.0.0.1']), 'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE'], 'max_age' => 8600, 'allowed_headers' => ['X-Request-Headers', 'Content-Type', 'Authorization', 'X-Requested-With'], diff --git a/config/logging.php b/config/logging.php index cc0d9b6..cb63722 100644 --- a/config/logging.php +++ b/config/logging.php @@ -3,7 +3,7 @@ declare(strict_types=1); return [ - 'default' => env('LOG_CHANNEL', fn (): string => 'file'), + 'default' => env('LOG_CHANNEL', static fn (): string => 'file'), /* |-------------------------------------------------------------------------- diff --git a/config/session.php b/config/session.php index d229735..87ed685 100644 --- a/config/session.php +++ b/config/session.php @@ -15,9 +15,9 @@ | */ - 'driver' => env('SESSION_DRIVER', fn (): string => 'redis'), + 'driver' => env('SESSION_DRIVER', static fn (): string => 'redis'), - 'lifetime' => env('SESSION_LIFETIME', fn () => 120), + 'lifetime' => env('SESSION_LIFETIME', static fn (): int => 120), /* |-------------------------------------------------------------------------- From 39fc14978d52356ab971f5c24154dfc04997eeda Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 26 Aug 2025 17:56:34 -0500 Subject: [PATCH 046/133] refactor: update docker-compose and Dockerfile for improved structure and Redis integration --- docker-compose.yml | 21 ++++++++++++++++++--- docker/Dockerfile | 31 ++++++++++++++++--------------- docker/entrypoint.sh | 5 +---- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index d36d887..b94c63f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,9 +5,9 @@ services: dockerfile: docker/Dockerfile target: local volumes: - - .:/var/www:rw - - /var/www/vendor - working_dir: /var/www + - .:/var/www/html:rw + - /var/www/html/vendor + working_dir: /var/www/html extra_hosts: - 'host.docker.internal:host-gateway' environment: @@ -18,10 +18,14 @@ services: - DB_DATABASE=${DB_DATABASE:-phenix} - DB_USERNAME=${DB_USERNAME:-phenix} - DB_PASSWORD=${DB_PASSWORD:-secret} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD} ports: - '${APP_PORT:-1337}:${APP_PORT:-1337}' depends_on: - mysql + - redis networks: - phenix @@ -40,8 +44,19 @@ services: networks: - phenix + redis: + image: redis:7-alpine + ports: + - "${REDIS_PORT:-6379}:6379" + command: redis-server --appendonly yes + volumes: + - redis_data:/data + networks: + - phenix + volumes: mysql_data: + redis_data: networks: phenix: diff --git a/docker/Dockerfile b/docker/Dockerfile index df0ba19..a69a17a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,24 +1,25 @@ -FROM php:8.2-cli AS base +FROM serversideup/php:8.2-cli-alpine AS base -WORKDIR /var/www/ +USER root -RUN apt-get update \ - && apt-get install -y curl git unzip \ - && docker-php-ext-install pcntl pdo pdo_mysql \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* +RUN apk add --no-cache \ + curl \ + git \ + unzip COPY --from=composer:latest /usr/bin/composer /usr/bin/composer FROM base AS local -RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ - && apt-get install -y nodejs +RUN apk add --no-cache nodejs npm -COPY . /var/www/ +COPY --chown=www-data:www-data . /var/www/html -RUN composer install --no-scripts --no-autoloader +RUN chmod -R 755 /var/www/html/storage + +USER www-data +RUN composer install --no-scripts --no-autoloader RUN composer dump-autoload --optimize EXPOSE ${APP_PORT:-1337} @@ -27,14 +28,14 @@ ENTRYPOINT ["docker/entrypoint.sh"] FROM base AS production -COPY . /var/www/ +COPY --chown=www-data:www-data . /var/www/html -RUN composer install --no-dev --optimize-autoloader --no-scripts \ - && chown -R www-data:www-data /var/www \ - && chmod -R 755 /var/www/storage +RUN chmod -R 755 /var/www/html/storage USER www-data +RUN composer install --no-dev --optimize-autoloader --no-scripts + EXPOSE ${APP_PORT:-1337} ENTRYPOINT ["docker/entrypoint.sh"] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 2ceb2a2..c7313ff 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,10 +1,7 @@ -#!/bin/bash +#!/bin/sh set -e -echo "Running migrations..." -./phenix migrate:run || true - if [ "$APP_ENV" = "production" ]; then echo "Starting production server..." php public/index.php --host=0.0.0.0 --port=${APP_PORT:-1337} From 502bb6575cf83efc2163e79e07db0b7a48af85d4 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 26 Aug 2025 18:03:41 -0500 Subject: [PATCH 047/133] refactor: update database and Redis configuration in .env.example for consistency --- .env.example | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.env.example b/.env.example index 98c1e66..b73e8db 100644 --- a/.env.example +++ b/.env.example @@ -21,3 +21,5 @@ CORS_ORIGIN= REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD=null + +SESSION_DRIVER=local \ No newline at end of file From f4af1f8852d746beea62f8ab01c4cd067daf338b Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 26 Aug 2025 18:05:20 -0500 Subject: [PATCH 048/133] feat: add .env.example.docker for Docker environment configuration --- .env.example.docker | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .env.example.docker diff --git a/.env.example.docker b/.env.example.docker new file mode 100644 index 0000000..b5fffa1 --- /dev/null +++ b/.env.example.docker @@ -0,0 +1,26 @@ +APP_NAME=Phenix +APP_KEY= +APP_ENV=local +APP_DEBUG=true +APP_URL=http://127.0.0.1 +APP_PORT=1337 + +DB_CONNECTION=mysql +DB_HOST=mysql +DB_PORT=3306 +DB_DATABASE=phenix +DB_USERNAME=phenix +DB_PASSWORD=secret +MYSQL_PORT=3307 + +LOG_CHANNEL=stream + +QUEUE_DRIVER=parallel + +CORS_ORIGIN= + +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_PASSWORD=null + +SESSION_DRIVER=redis \ No newline at end of file From 69a2c2f14451639bc605578778b250c6813a40d6 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 27 Aug 2025 08:32:15 -0500 Subject: [PATCH 049/133] refactor: ensure proper newline at end of files in configuration and entrypoint scripts --- .env.example | 2 +- .env.example.docker | 2 +- docker-compose.yml | 2 +- docker/entrypoint.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index b73e8db..58cb2fe 100644 --- a/.env.example +++ b/.env.example @@ -22,4 +22,4 @@ REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD=null -SESSION_DRIVER=local \ No newline at end of file +SESSION_DRIVER=local diff --git a/.env.example.docker b/.env.example.docker index b5fffa1..d54502b 100644 --- a/.env.example.docker +++ b/.env.example.docker @@ -23,4 +23,4 @@ REDIS_HOST=redis REDIS_PORT=6379 REDIS_PASSWORD=null -SESSION_DRIVER=redis \ No newline at end of file +SESSION_DRIVER=redis diff --git a/docker-compose.yml b/docker-compose.yml index b94c63f..93eb9de 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -60,4 +60,4 @@ volumes: networks: phenix: - driver: bridge \ No newline at end of file + driver: bridge diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index c7313ff..9828907 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -8,4 +8,4 @@ if [ "$APP_ENV" = "production" ]; then else echo "Starting development server with file watcher..." php ./server --host=0.0.0.0 --port=${APP_PORT:-1337} -fi \ No newline at end of file +fi From 08714c776755408f987c575419528d068dd78be1 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 27 Aug 2025 08:46:17 -0500 Subject: [PATCH 050/133] refactor: change QUEUE_DRIVER from parallel to database in .env.example.docker --- .env.example.docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example.docker b/.env.example.docker index d54502b..0f2aa3b 100644 --- a/.env.example.docker +++ b/.env.example.docker @@ -15,7 +15,7 @@ MYSQL_PORT=3307 LOG_CHANNEL=stream -QUEUE_DRIVER=parallel +QUEUE_DRIVER=database CORS_ORIGIN= From 3693f8527e966408aae50241d4420f4988a2ce6c Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 6 Aug 2025 07:22:42 -0500 Subject: [PATCH 051/133] feat: add process ID output when server starts --- server | 47 ++--------------------------------------------- 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/server b/server index 3a3cddd..4cb4786 100644 --- a/server +++ b/server @@ -178,51 +178,8 @@ class Watcher extends Watch try { $this->serverProcess->start(); - usleep(100000); // 100ms - - if (!$this->serverProcess->isRunning()) { - $exitCode = $this->serverProcess->getExitCode(); - - if ($incrementErrorCounter) { - $this->consecutiveErrors++; - } - - echo Output::error("Server failed to start. Exit code: {$exitCode}") . PHP_EOL; - echo Output::debug("Error: " . $this->serverProcess->getErrorOutput()) . PHP_EOL; - echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL . PHP_EOL; - - if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { - sleep(2); - - $this->runServer($incrementErrorCounter); - } - - return; - } - - if ($incrementErrorCounter) { - $this->consecutiveErrors = 0; - } - $this->pid = $this->serverProcess->getPid(); - - echo Output::success("Server started on {$this->host}:{$this->port}") . PHP_EOL; - echo Output::info("PID: {$this->pid}") . PHP_EOL . PHP_EOL; - - } catch (Exception $e) { - if ($incrementErrorCounter) { - $this->consecutiveErrors++; - } - - echo Output::error("Failed to start server: " . $e->getMessage()) . PHP_EOL; - echo Output::debug("Command: {$command}") . PHP_EOL; - echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL . PHP_EOL; - - if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { - sleep(2); - - $this->runServer($incrementErrorCounter); - } - } + echo "Server started on {$this->host}:{$this->port}" . PHP_EOL . PHP_EOL; + echo "Process ID is {$this->pid}" . PHP_EOL . PHP_EOL; } private function ensureWatcherIsRunning(Process $watcher): void From 86db3152d85da4ee97b8b0e75ba5fc4e9f55dced Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 6 Aug 2025 07:25:01 -0500 Subject: [PATCH 052/133] fix: update phenixphp/framework requirement to dev-feature/users-module --- composer.json | 2 +- composer.lock | 101 +++++++++++++++++++++++++------------------------- 2 files changed, 52 insertions(+), 51 deletions(-) diff --git a/composer.json b/composer.json index 2bba8af..91c765d 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "^0.6.0" + "phenixphp/framework": "dev-feature/users-module" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index ab84d9f..0acc902 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": "38f7078cd1d68343715a254570dfd2fe", + "content-hash": "1ffbd7bbd278f7df6db710f2f81a4e8f", "packages": [ { "name": "adbario/php-dot-notation", @@ -3592,12 +3592,12 @@ "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" + "reference": "129700ed449b1f02d70272d2ac802357c8c30c58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", - "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", + "reference": "129700ed449b1f02d70272d2ac802357c8c30c58", "shasum": "" }, "require": { @@ -3810,16 +3810,16 @@ }, { "name": "phenixphp/framework", - "version": "0.6.0", + "version": "dev-feature/users-module", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "9c43d8518524928fa5eb6922dbbfed21f1b275cd" + "reference": "5085a294483cd2287a4c94131539347530e29078" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/9c43d8518524928fa5eb6922dbbfed21f1b275cd", - "reference": "9c43d8518524928fa5eb6922dbbfed21f1b275cd", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/5085a294483cd2287a4c94131539347530e29078", + "reference": "5085a294483cd2287a4c94131539347530e29078", "shasum": "" }, "require": { @@ -3894,9 +3894,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/0.6.0" + "source": "https://github.com/phenixphp/framework/tree/develop" }, - "time": "2025-08-22T22:35:11+00:00" + "time": "2025-01-13T21:17:21+00:00" }, { "name": "phenixphp/http-cors", @@ -7790,16 +7790,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.86.0", + "version": "v3.68.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "4a952bd19dc97879b0620f495552ef09b55f7d36" + "reference": "73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/4a952bd19dc97879b0620f495552ef09b55f7d36", - "reference": "4a952bd19dc97879b0620f495552ef09b55f7d36", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c", + "reference": "73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c", "shasum": "" }, "require": { @@ -7812,22 +7812,22 @@ "ext-tokenizer": "*", "fidry/cpu-core-counter": "^1.2", "php": "^7.4 || ^8.0", - "react/child-process": "^0.6.6", - "react/event-loop": "^1.5", - "react/promise": "^3.2", - "react/socket": "^1.16", - "react/stream": "^1.4", - "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", - "symfony/console": "^5.4.47 || ^6.4.13 || ^7.0", - "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", - "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", - "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", - "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", - "symfony/polyfill-mbstring": "^1.32", - "symfony/polyfill-php80": "^1.32", - "symfony/polyfill-php81": "^1.32", - "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", - "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" + "react/child-process": "^0.6.5", + "react/event-loop": "^1.0", + "react/promise": "^2.0 || ^3.0", + "react/socket": "^1.0", + "react/stream": "^1.0", + "sebastian/diff": "^4.0 || ^5.1 || ^6.0", + "symfony/console": "^5.4 || ^6.4 || ^7.0", + "symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", + "symfony/filesystem": "^5.4 || ^6.4 || ^7.0", + "symfony/finder": "^5.4 || ^6.4 || ^7.0", + "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0", + "symfony/polyfill-mbstring": "^1.31", + "symfony/polyfill-php80": "^1.31", + "symfony/polyfill-php81": "^1.31", + "symfony/process": "^5.4 || ^6.4 || ^7.2", + "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" }, "require-dev": { "facile-it/paraunit": "^1.3.1 || ^2.6", @@ -7837,12 +7837,11 @@ "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.8", "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", - "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", - "symfony/polyfill-php84": "^1.32", - "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", - "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5", + "phpunit/phpunit": "^9.6.22 || ^10.5.40 || ^11.5.2", + "symfony/var-dumper": "^5.4.48 || ^6.4.15 || ^7.2.0", + "symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.2.0" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -7883,7 +7882,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.86.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.0" }, "funding": [ { @@ -7891,7 +7890,7 @@ "type": "github" } ], - "time": "2025-08-13T22:36:21+00:00" + "time": "2025-01-13T17:01:01+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -8867,16 +8866,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.28", + "version": "1.12.15", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9" + "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", - "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c91d4e8bc056f46cf653656e6f71004b254574d1", + "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1", "shasum": "" }, "require": { @@ -8921,7 +8920,7 @@ "type": "github" } ], - "time": "2025-07-17T17:15:39+00:00" + "time": "2025-01-05T16:40:22+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -11258,16 +11257,16 @@ }, { "name": "symfony/process", - "version": "v7.3.0", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" + "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", + "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", "shasum": "" }, "require": { @@ -11299,7 +11298,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.0" + "source": "https://github.com/symfony/process/tree/v7.2.0" }, "funding": [ { @@ -11315,7 +11314,7 @@ "type": "tidelift" } ], - "time": "2025-04-17T09:11:12+00:00" + "time": "2024-11-06T14:24:19+00:00" }, { "name": "symfony/stopwatch", @@ -11432,7 +11431,9 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": {}, + "stability-flags": { + "phenixphp/framework": 20 + }, "prefer-stable": true, "prefer-lowest": false, "platform": { From c31266a1a62fec500461f061c6a7be441eba0059 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 6 Aug 2025 07:25:13 -0500 Subject: [PATCH 053/133] feat: implement user management with CRUD operations and user table migration --- app/Collections/UserCollection.php | 12 ++++ app/Http/Controllers/UserController.php | 60 +++++++++++++++++++ app/Http/Requests/StoreUserRequest.php | 20 +++++++ app/Models/User.php | 41 +++++++++++++ app/Queries/UserQuery.php | 12 ++++ .../20241217160717_create_user_table.php | 24 ++++++++ routes/api.php | 7 +++ 7 files changed, 176 insertions(+) create mode 100644 app/Collections/UserCollection.php create mode 100644 app/Http/Controllers/UserController.php create mode 100644 app/Http/Requests/StoreUserRequest.php create mode 100644 app/Models/User.php create mode 100644 app/Queries/UserQuery.php create mode 100644 database/migrations/20241217160717_create_user_table.php diff --git a/app/Collections/UserCollection.php b/app/Collections/UserCollection.php new file mode 100644 index 0000000..22bfdd8 --- /dev/null +++ b/app/Collections/UserCollection.php @@ -0,0 +1,12 @@ +paginate($request->getUri()); + + dump('Freder H'); + + return response()->json($users); + } + + public function store(StoreUserRequest $request): Response + { + $user = new User(); + $user->name = $request->body('name'); + $user->email = $request->body('email'); + + if ($user->save()) { + return response()->json($user, HttpStatus::CREATED); + } + + return response()->json([], HttpStatus::INTERNAL_SERVER_ERROR); + } + + public function show(Request $request): Response + { + $user = User::find($request->route('user'), ['id', 'name', 'email']); + + if ($user) { + return response()->json($user); + } + + return response()->json([], HttpStatus::NOT_FOUND); + } + + public function update(Request $request): Response + { + return response()->json([]); + } + + public function delete(Request $request): Response + { + return response()->json([]); + } +} diff --git a/app/Http/Requests/StoreUserRequest.php b/app/Http/Requests/StoreUserRequest.php new file mode 100644 index 0000000..f0eaa60 --- /dev/null +++ b/app/Http/Requests/StoreUserRequest.php @@ -0,0 +1,20 @@ + Str::required()->max(10), + 'email' => Email::required(), + ]; + } +} diff --git a/app/Models/User.php b/app/Models/User.php new file mode 100644 index 0000000..3936086 --- /dev/null +++ b/app/Models/User.php @@ -0,0 +1,41 @@ +table('users'); + $table->addColumn('name', 'string', ['limit' => 100]); + $table->addColumn('email', 'string', ['limit' => 100]); + $table->addColumn('password', 'string', ['limit' => 255]); + $table->addColumn('created_at', 'datetime', ['null' => true]); + $table->addColumn('updated_at', 'datetime', ['null' => true]); + $table->create(); + } + + public function down(): void + { + $this->table('users')->drop()->save(); + } +} diff --git a/routes/api.php b/routes/api.php index 78c6136..2fa9b9c 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,7 +2,14 @@ declare(strict_types=1); +use App\Http\Controllers\UserController; use App\Http\Controllers\WelcomeController; use Phenix\Facades\Route; Route::get('/', [WelcomeController::class, 'index']); + +Route::get('/users', [UserController::class, 'index']); + +Route::get('/users/{user}', [UserController::class, 'show']); + +Route::post('/users', [UserController::class, 'store']); From 8b517536fac50f8b583a72b7b31712a181b79a72 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 6 Aug 2025 18:12:49 -0500 Subject: [PATCH 054/133] Implement code changes to enhance functionality and improve performance --- composer.json | 2 +- composer.lock | 1013 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 871 insertions(+), 144 deletions(-) diff --git a/composer.json b/composer.json index 91c765d..9898789 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "dev-feature/users-module" + "phenixphp/framework": "dev-feature/queue-system" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index 0acc902..c62c414 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": "1ffbd7bbd278f7df6db710f2f81a4e8f", + "content-hash": "2ed9708a8850061a7a9063d9d58890cf", "packages": [ { "name": "adbario/php-dot-notation", @@ -595,16 +595,16 @@ }, { "name": "amphp/http-client", - "version": "v5.3.4", + "version": "v5.3.3", "source": { "type": "git", "url": "https://github.com/amphp/http-client.git", - "reference": "75ad21574fd632594a2dd914496647816d5106bc" + "reference": "09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-client/zipball/75ad21574fd632594a2dd914496647816d5106bc", - "reference": "75ad21574fd632594a2dd914496647816d5106bc", + "url": "https://api.github.com/repos/amphp/http-client/zipball/09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc", + "reference": "09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc", "shasum": "" }, "require": { @@ -681,7 +681,7 @@ ], "support": { "issues": "https://github.com/amphp/http-client/issues", - "source": "https://github.com/amphp/http-client/tree/v5.3.4" + "source": "https://github.com/amphp/http-client/tree/v5.3.3" }, "funding": [ { @@ -689,7 +689,7 @@ "type": "github" } ], - "time": "2025-08-16T20:41:23+00:00" + "time": "2025-05-21T03:24:20+00:00" }, { "name": "amphp/http-server", @@ -1933,16 +1933,16 @@ }, { "name": "async-aws/core", - "version": "1.27.0", + "version": "1.26.0", "source": { "type": "git", "url": "https://github.com/async-aws/core.git", - "reference": "00b69a04a36b5ba75e0448e46158c9718ac95755" + "reference": "58ab79116d990e7053b2e31162f47df4223148c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/core/zipball/00b69a04a36b5ba75e0448e46158c9718ac95755", - "reference": "00b69a04a36b5ba75e0448e46158c9718ac95755", + "url": "https://api.github.com/repos/async-aws/core/zipball/58ab79116d990e7053b2e31162f47df4223148c5", + "reference": "58ab79116d990e7053b2e31162f47df4223148c5", "shasum": "" }, "require": { @@ -1953,7 +1953,7 @@ "psr/cache": "^1.0 || ^2.0 || ^3.0", "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/deprecation-contracts": "^2.1 || ^3.0", - "symfony/http-client": "^4.4.16 || ^5.1.7 || ^6.0 || ^7.0 || ^8.0", + "symfony/http-client": "^4.4.16 || ^5.1.7 || ^6.0 || ^7.0", "symfony/http-client-contracts": "^1.1.8 || ^2.0 || ^3.0", "symfony/service-contracts": "^1.0 || ^2.0 || ^3.0" }, @@ -1964,7 +1964,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.27-dev" + "dev-master": "1.26-dev" } }, "autoload": { @@ -1985,7 +1985,7 @@ "sts" ], "support": { - "source": "https://github.com/async-aws/core/tree/1.27.0" + "source": "https://github.com/async-aws/core/tree/1.26.0" }, "funding": [ { @@ -1997,20 +1997,20 @@ "type": "github" } ], - "time": "2025-08-11T10:03:27+00:00" + "time": "2025-05-12T09:35:01+00:00" }, { "name": "async-aws/ses", - "version": "1.13.0", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/async-aws/ses.git", - "reference": "e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42" + "reference": "904ee7b5c07d865c20db4c06c3c0b97e7035673d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/ses/zipball/e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42", - "reference": "e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42", + "url": "https://api.github.com/repos/async-aws/ses/zipball/904ee7b5c07d865c20db4c06c3c0b97e7035673d", + "reference": "904ee7b5c07d865c20db4c06c3c0b97e7035673d", "shasum": "" }, "require": { @@ -2021,7 +2021,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -2042,7 +2042,7 @@ "ses" ], "support": { - "source": "https://github.com/async-aws/ses/tree/1.13.0" + "source": "https://github.com/async-aws/ses/tree/1.12.0" }, "funding": [ { @@ -2054,7 +2054,7 @@ "type": "github" } ], - "time": "2025-08-11T10:03:27+00:00" + "time": "2025-05-12T09:35:01+00:00" }, { "name": "cakephp/chronos", @@ -2890,16 +2890,16 @@ }, { "name": "guzzlehttp/promises", - "version": "2.3.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "481557b130ef3790cf82b713667b43030dc9c957" + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", - "reference": "481557b130ef3790cf82b713667b43030dc9c957", + "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", "shasum": "" }, "require": { @@ -2907,7 +2907,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.44 || ^9.6.25" + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "type": "library", "extra": { @@ -2953,7 +2953,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.3.0" + "source": "https://github.com/guzzle/promises/tree/2.2.0" }, "funding": [ { @@ -2969,7 +2969,7 @@ "type": "tidelift" } ], - "time": "2025-08-22T14:34:08+00:00" + "time": "2025-03-27T13:27:01+00:00" }, { "name": "guzzlehttp/psr7", @@ -3592,12 +3592,12 @@ "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "129700ed449b1f02d70272d2ac802357c8c30c58" + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", - "reference": "129700ed449b1f02d70272d2ac802357c8c30c58", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", "shasum": "" }, "require": { @@ -3810,16 +3810,16 @@ }, { "name": "phenixphp/framework", - "version": "dev-feature/users-module", + "version": "dev-feature/queue-system", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "5085a294483cd2287a4c94131539347530e29078" + "reference": "5b6914812632e8349dd94e5b5ff2e5540155a713" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/5085a294483cd2287a4c94131539347530e29078", - "reference": "5085a294483cd2287a4c94131539347530e29078", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/5b6914812632e8349dd94e5b5ff2e5540155a713", + "reference": "5b6914812632e8349dd94e5b5ff2e5540155a713", "shasum": "" }, "require": { @@ -3894,9 +3894,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/develop" + "source": "https://github.com/phenixphp/framework/tree/feature/queue-system" }, - "time": "2025-01-13T21:17:21+00:00" + "time": "2025-08-06T22:41:55+00:00" }, { "name": "phenixphp/http-cors", @@ -4060,6 +4060,55 @@ }, "time": "2021-02-03T23:26:27+00:00" }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, { "name": "psr/clock", "version": "1.0.0", @@ -5768,7 +5817,7 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.33.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -5827,7 +5876,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" }, "funding": [ { @@ -5851,7 +5900,7 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.33.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", @@ -5909,7 +5958,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" }, "funding": [ { @@ -5933,7 +5982,7 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.33.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -5996,7 +6045,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" }, "funding": [ { @@ -6020,7 +6069,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.33.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -6081,7 +6130,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" }, "funding": [ { @@ -6105,7 +6154,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -6166,7 +6215,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" }, "funding": [ { @@ -6190,7 +6239,7 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.33.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -6250,7 +6299,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" }, "funding": [ { @@ -6274,7 +6323,7 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.33.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", @@ -6330,7 +6379,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" }, "funding": [ { @@ -6354,7 +6403,7 @@ }, { "name": "symfony/polyfill-uuid", - "version": "v1.33.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", @@ -6413,7 +6462,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" }, "funding": [ { @@ -6424,16 +6473,12 @@ "url": "https://github.com/fabpot", "type": "github" }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-09-28T08:24:38+00:00" }, { "name": "symfony/resend-mailer", @@ -7317,6 +7362,71 @@ ], "time": "2022-12-23T10:58:28+00:00" }, + { + "name": "cmgmyr/phploc", + "version": "8.0.6", + "source": { + "type": "git", + "url": "https://github.com/cmgmyr/phploc.git", + "reference": "5d785f8fc8b891483cdbee3fb25f2b348c50c03f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cmgmyr/phploc/zipball/5d785f8fc8b891483cdbee3fb25f2b348c50c03f", + "reference": "5d785f8fc8b891483cdbee3fb25f2b348c50c03f", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "php": "^7.4 || ^8.0", + "phpunit/php-file-iterator": "^3.0|^4.0|^5.0|^6.0", + "sebastian/cli-parser": "^1.0|^2.0|^3.0|^4.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpunit/phpunit": "^9.0|^10.0", + "vimeo/psalm": "^5.7" + }, + "bin": [ + "phploc" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Chris Gmyr", + "email": "cmgmyr@gmail.com", + "role": "lead" + } + ], + "description": "A tool for quickly measuring the size of a PHP project.", + "homepage": "https://github.com/cmgmyr/phploc", + "support": { + "issues": "https://github.com/cmgmyr/phploc/issues", + "source": "https://github.com/cmgmyr/phploc/tree/8.0.6" + }, + "funding": [ + { + "url": "https://github.com/cmgmyr", + "type": "github" + } + ], + "time": "2025-03-29T16:41:46+00:00" + }, { "name": "composer/pcre", "version": "3.3.2", @@ -7539,6 +7649,102 @@ ], "time": "2024-05-06T16:37:16+00:00" }, + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.1.2", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", + "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.2", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "^2.2", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "opensource@frenck.dev", + "homepage": "https://frenck.dev", + "role": "Open source developer" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-07-17T20:45:56+00:00" + }, { "name": "doctrine/instantiator", "version": "2.0.0", @@ -7719,16 +7925,16 @@ }, { "name": "filp/whoops", - "version": "2.18.4", + "version": "2.18.3", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" + "reference": "59a123a3d459c5a23055802237cb317f609867e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", - "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5", + "reference": "59a123a3d459c5a23055802237cb317f609867e5", "shasum": "" }, "require": { @@ -7778,7 +7984,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.4" + "source": "https://github.com/filp/whoops/tree/2.18.3" }, "funding": [ { @@ -7786,20 +7992,20 @@ "type": "github" } ], - "time": "2025-08-08T12:00:00+00:00" + "time": "2025-06-16T00:02:10+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.68.0", + "version": "v3.85.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c" + "reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c", - "reference": "73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2fb6d7f6c3398dca5786a1635b27405d73a417ba", + "reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba", "shasum": "" }, "require": { @@ -7812,22 +8018,22 @@ "ext-tokenizer": "*", "fidry/cpu-core-counter": "^1.2", "php": "^7.4 || ^8.0", - "react/child-process": "^0.6.5", - "react/event-loop": "^1.0", - "react/promise": "^2.0 || ^3.0", - "react/socket": "^1.0", - "react/stream": "^1.0", - "sebastian/diff": "^4.0 || ^5.1 || ^6.0", - "symfony/console": "^5.4 || ^6.4 || ^7.0", - "symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", - "symfony/filesystem": "^5.4 || ^6.4 || ^7.0", - "symfony/finder": "^5.4 || ^6.4 || ^7.0", - "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0", - "symfony/polyfill-mbstring": "^1.31", - "symfony/polyfill-php80": "^1.31", - "symfony/polyfill-php81": "^1.31", - "symfony/process": "^5.4 || ^6.4 || ^7.2", - "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" + "react/child-process": "^0.6.6", + "react/event-loop": "^1.5", + "react/promise": "^3.2", + "react/socket": "^1.16", + "react/stream": "^1.4", + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", + "symfony/console": "^5.4.47 || ^6.4.13 || ^7.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", + "symfony/polyfill-mbstring": "^1.32", + "symfony/polyfill-php80": "^1.32", + "symfony/polyfill-php81": "^1.32", + "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", + "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" }, "require-dev": { "facile-it/paraunit": "^1.3.1 || ^2.6", @@ -7837,11 +8043,12 @@ "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.8", "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5", - "phpunit/phpunit": "^9.6.22 || ^10.5.40 || ^11.5.2", - "symfony/var-dumper": "^5.4.48 || ^6.4.15 || ^7.2.0", - "symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.2.0" + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", + "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", + "symfony/polyfill-php84": "^1.32", + "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", + "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -7882,7 +8089,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.85.1" }, "funding": [ { @@ -7890,7 +8097,7 @@ "type": "github" } ], - "time": "2025-01-13T17:01:01+00:00" + "time": "2025-07-29T22:22:50+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -8003,6 +8210,71 @@ }, "time": "2025-03-19T14:43:43+00:00" }, + { + "name": "justinrainbow/json-schema", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/jsonrainbow/json-schema.git", + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "support": { + "issues": "https://github.com/jsonrainbow/json-schema/issues", + "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" + }, + "time": "2024-07-06T21:00:26+00:00" + }, { "name": "mockery/mockery", "version": "1.6.12", @@ -8148,16 +8420,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.1", + "version": "v5.6.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56", + "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56", "shasum": "" }, "require": { @@ -8200,9 +8472,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0" }, - "time": "2025-08-13T20:13:15+00:00" + "time": "2025-07-27T20:03:57+00:00" }, { "name": "nunomaduro/collision", @@ -8864,18 +9136,65 @@ }, "time": "2024-09-04T20:21:43+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "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/2.2.0" + }, + "time": "2025-07-13T07:04:09+00:00" + }, { "name": "phpstan/phpstan", - "version": "1.12.15", + "version": "1.12.28", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1" + "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c91d4e8bc056f46cf653656e6f71004b254574d1", - "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", + "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", "shasum": "" }, "require": { @@ -8920,7 +9239,7 @@ "type": "github" } ], - "time": "2025-01-05T16:40:22+00:00" + "time": "2025-07-17T17:15:39+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -9342,16 +9661,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.25", + "version": "9.6.23", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "049c011e01be805202d8eebedef49f769a8ec7b7" + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/049c011e01be805202d8eebedef49f769a8ec7b7", - "reference": "049c011e01be805202d8eebedef49f769a8ec7b7", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", "shasum": "" }, "require": { @@ -9362,7 +9681,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.4", + "myclabs/deep-copy": "^1.13.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", @@ -9425,7 +9744,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.25" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.23" }, "funding": [ { @@ -9449,7 +9768,7 @@ "type": "tidelift" } ], - "time": "2025-08-20T14:38:31+00:00" + "time": "2025-05-02T06:40:34+00:00" }, { "name": "react/cache", @@ -10977,51 +11296,116 @@ "time": "2020-09-28T06:39:44+00:00" }, { - "name": "spatie/file-system-watcher", - "version": "1.2.0", + "name": "slevomat/coding-standard", + "version": "8.20.0", "source": { "type": "git", - "url": "https://github.com/spatie/file-system-watcher.git", - "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe" + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/file-system-watcher/zipball/d9511ecbd266f190c4abce88516c3f231fcb6bfe", - "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b4f9f02edd4e6a586777f0cabe8d05574323f3eb", + "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb", "shasum": "" }, "require": { - "php": "^8.0", - "symfony/process": "^5.2|^6.0|^7.0" + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2", + "php": "^7.4 || ^8.0", + "phpstan/phpdoc-parser": "^2.2.0", + "squizlabs/php_codesniffer": "^3.13.2" }, "require-dev": { - "pestphp/pest": "^1.22", - "phpunit/phpunit": "^9.5", - "spatie/ray": "^1.22", - "spatie/temporary-directory": "^2.0", - "vimeo/psalm": "^4.3" + "phing/phing": "3.0.1|3.1.0", + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpstan/phpstan": "2.1.19", + "phpstan/phpstan-deprecation-rules": "2.0.3", + "phpstan/phpstan-phpunit": "2.0.7", + "phpstan/phpstan-strict-rules": "2.0.6", + "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.27|12.2.7" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } }, - "type": "library", "autoload": { "psr-4": { - "Spatie\\Watcher\\": "src" + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "role": "Developer" - } - ], - "description": "Watch changes in the file system using PHP", - "homepage": "https://github.com/spatie/file-system-watcher", + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", "keywords": [ - "file-system-watcher", + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.20.0" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2025-07-26T15:35:10+00:00" + }, + { + "name": "spatie/file-system-watcher", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/file-system-watcher.git", + "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/file-system-watcher/zipball/d9511ecbd266f190c4abce88516c3f231fcb6bfe", + "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe", + "shasum": "" + }, + "require": { + "php": "^8.0", + "symfony/process": "^5.2|^6.0|^7.0" + }, + "require-dev": { + "pestphp/pest": "^1.22", + "phpunit/phpunit": "^9.5", + "spatie/ray": "^1.22", + "spatie/temporary-directory": "^2.0", + "vimeo/psalm": "^4.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Watcher\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Watch changes in the file system using PHP", + "homepage": "https://github.com/spatie/file-system-watcher", + "keywords": [ + "file-system-watcher", "spatie" ], "support": { @@ -11036,6 +11420,268 @@ ], "time": "2023-12-18T14:26:25+00:00" }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.13.2", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-06-17T22:17:01+00:00" + }, + { + "name": "symfony/cache", + "version": "v7.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6", + "reference": "6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^3.6", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/dependency-injection": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v7.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-30T17:13:41+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^3.0" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-13T15:25:07+00:00" + }, { "name": "symfony/finder", "version": "v7.3.2", @@ -11177,7 +11823,7 @@ }, { "name": "symfony/polyfill-php81", - "version": "v1.33.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -11233,7 +11879,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0" }, "funding": [ { @@ -11257,16 +11903,16 @@ }, { "name": "symfony/process", - "version": "v7.2.0", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", - "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", + "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "shasum": "" }, "require": { @@ -11298,7 +11944,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.0" + "source": "https://github.com/symfony/process/tree/v7.3.0" }, "funding": [ { @@ -11314,7 +11960,7 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:24:19+00:00" + "time": "2025-04-17T09:11:12+00:00" }, { "name": "symfony/stopwatch", @@ -11378,6 +12024,87 @@ ], "time": "2025-02-24T10:49:57+00:00" }, + { + "name": "symfony/var-exporter", + "version": "v7.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "05b3e90654c097817325d6abd284f7938b05f467" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/05b3e90654c097817325d6abd284f7938b05f467", + "reference": "05b3e90654c097817325d6abd284f7938b05f467", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v7.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-10T08:47:49+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.3", From 8c6f9b54c46cb4d1666891c2fceab5b2e3d95c30 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 6 Aug 2025 07:25:01 -0500 Subject: [PATCH 055/133] fix: update phenixphp/framework requirement to dev-feature/users-module --- composer.json | 2 +- composer.lock | 97 +++++++++++++++++++++++++-------------------------- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/composer.json b/composer.json index 9898789..91c765d 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "dev-feature/queue-system" + "phenixphp/framework": "dev-feature/users-module" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index c62c414..6333268 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": "2ed9708a8850061a7a9063d9d58890cf", + "content-hash": "1ffbd7bbd278f7df6db710f2f81a4e8f", "packages": [ { "name": "adbario/php-dot-notation", @@ -3592,12 +3592,12 @@ "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" + "reference": "129700ed449b1f02d70272d2ac802357c8c30c58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", - "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", + "reference": "129700ed449b1f02d70272d2ac802357c8c30c58", "shasum": "" }, "require": { @@ -3810,16 +3810,16 @@ }, { "name": "phenixphp/framework", - "version": "dev-feature/queue-system", + "version": "dev-feature/users-module", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "5b6914812632e8349dd94e5b5ff2e5540155a713" + "reference": "5085a294483cd2287a4c94131539347530e29078" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/5b6914812632e8349dd94e5b5ff2e5540155a713", - "reference": "5b6914812632e8349dd94e5b5ff2e5540155a713", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/5085a294483cd2287a4c94131539347530e29078", + "reference": "5085a294483cd2287a4c94131539347530e29078", "shasum": "" }, "require": { @@ -3894,9 +3894,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/feature/queue-system" + "source": "https://github.com/phenixphp/framework/tree/develop" }, - "time": "2025-08-06T22:41:55+00:00" + "time": "2025-01-13T21:17:21+00:00" }, { "name": "phenixphp/http-cors", @@ -7996,16 +7996,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.85.1", + "version": "v3.68.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba" + "reference": "73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2fb6d7f6c3398dca5786a1635b27405d73a417ba", - "reference": "2fb6d7f6c3398dca5786a1635b27405d73a417ba", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c", + "reference": "73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c", "shasum": "" }, "require": { @@ -8018,22 +8018,22 @@ "ext-tokenizer": "*", "fidry/cpu-core-counter": "^1.2", "php": "^7.4 || ^8.0", - "react/child-process": "^0.6.6", - "react/event-loop": "^1.5", - "react/promise": "^3.2", - "react/socket": "^1.16", - "react/stream": "^1.4", - "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", - "symfony/console": "^5.4.47 || ^6.4.13 || ^7.0", - "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", - "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", - "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", - "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", - "symfony/polyfill-mbstring": "^1.32", - "symfony/polyfill-php80": "^1.32", - "symfony/polyfill-php81": "^1.32", - "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", - "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" + "react/child-process": "^0.6.5", + "react/event-loop": "^1.0", + "react/promise": "^2.0 || ^3.0", + "react/socket": "^1.0", + "react/stream": "^1.0", + "sebastian/diff": "^4.0 || ^5.1 || ^6.0", + "symfony/console": "^5.4 || ^6.4 || ^7.0", + "symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", + "symfony/filesystem": "^5.4 || ^6.4 || ^7.0", + "symfony/finder": "^5.4 || ^6.4 || ^7.0", + "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0", + "symfony/polyfill-mbstring": "^1.31", + "symfony/polyfill-php80": "^1.31", + "symfony/polyfill-php81": "^1.31", + "symfony/process": "^5.4 || ^6.4 || ^7.2", + "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" }, "require-dev": { "facile-it/paraunit": "^1.3.1 || ^2.6", @@ -8043,12 +8043,11 @@ "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.8", "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", - "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", - "symfony/polyfill-php84": "^1.32", - "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", - "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5", + "phpunit/phpunit": "^9.6.22 || ^10.5.40 || ^11.5.2", + "symfony/var-dumper": "^5.4.48 || ^6.4.15 || ^7.2.0", + "symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.2.0" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -8089,7 +8088,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.85.1" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.0" }, "funding": [ { @@ -8097,7 +8096,7 @@ "type": "github" } ], - "time": "2025-07-29T22:22:50+00:00" + "time": "2025-01-13T17:01:01+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -9185,16 +9184,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.28", + "version": "1.12.15", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9" + "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", - "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c91d4e8bc056f46cf653656e6f71004b254574d1", + "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1", "shasum": "" }, "require": { @@ -9239,7 +9238,7 @@ "type": "github" } ], - "time": "2025-07-17T17:15:39+00:00" + "time": "2025-01-05T16:40:22+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -11903,16 +11902,16 @@ }, { "name": "symfony/process", - "version": "v7.3.0", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" + "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", + "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", "shasum": "" }, "require": { @@ -11944,7 +11943,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.0" + "source": "https://github.com/symfony/process/tree/v7.2.0" }, "funding": [ { @@ -11960,7 +11959,7 @@ "type": "tidelift" } ], - "time": "2025-04-17T09:11:12+00:00" + "time": "2024-11-06T14:24:19+00:00" }, { "name": "symfony/stopwatch", From 0331ccfc3983ee5ad51b484afa0c850206795623 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 22 Aug 2025 21:27:39 -0500 Subject: [PATCH 056/133] fix: revert phenixphp/framework requirement to stable version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 91c765d..2bba8af 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "dev-feature/users-module" + "phenixphp/framework": "^0.6.0" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", From 09c9519dc4ff36ea369fb3439fbca434a5b23fb9 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 22 Aug 2025 21:27:49 -0500 Subject: [PATCH 057/133] chore: update dependencies --- composer.lock | 999 +++++++------------------------------------------- 1 file changed, 136 insertions(+), 863 deletions(-) diff --git a/composer.lock b/composer.lock index 6333268..ab84d9f 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": "1ffbd7bbd278f7df6db710f2f81a4e8f", + "content-hash": "38f7078cd1d68343715a254570dfd2fe", "packages": [ { "name": "adbario/php-dot-notation", @@ -595,16 +595,16 @@ }, { "name": "amphp/http-client", - "version": "v5.3.3", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/amphp/http-client.git", - "reference": "09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc" + "reference": "75ad21574fd632594a2dd914496647816d5106bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-client/zipball/09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc", - "reference": "09212ebc2f34efb5e1eaac4374fef6b11a7d2fbc", + "url": "https://api.github.com/repos/amphp/http-client/zipball/75ad21574fd632594a2dd914496647816d5106bc", + "reference": "75ad21574fd632594a2dd914496647816d5106bc", "shasum": "" }, "require": { @@ -681,7 +681,7 @@ ], "support": { "issues": "https://github.com/amphp/http-client/issues", - "source": "https://github.com/amphp/http-client/tree/v5.3.3" + "source": "https://github.com/amphp/http-client/tree/v5.3.4" }, "funding": [ { @@ -689,7 +689,7 @@ "type": "github" } ], - "time": "2025-05-21T03:24:20+00:00" + "time": "2025-08-16T20:41:23+00:00" }, { "name": "amphp/http-server", @@ -1933,16 +1933,16 @@ }, { "name": "async-aws/core", - "version": "1.26.0", + "version": "1.27.0", "source": { "type": "git", "url": "https://github.com/async-aws/core.git", - "reference": "58ab79116d990e7053b2e31162f47df4223148c5" + "reference": "00b69a04a36b5ba75e0448e46158c9718ac95755" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/core/zipball/58ab79116d990e7053b2e31162f47df4223148c5", - "reference": "58ab79116d990e7053b2e31162f47df4223148c5", + "url": "https://api.github.com/repos/async-aws/core/zipball/00b69a04a36b5ba75e0448e46158c9718ac95755", + "reference": "00b69a04a36b5ba75e0448e46158c9718ac95755", "shasum": "" }, "require": { @@ -1953,7 +1953,7 @@ "psr/cache": "^1.0 || ^2.0 || ^3.0", "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/deprecation-contracts": "^2.1 || ^3.0", - "symfony/http-client": "^4.4.16 || ^5.1.7 || ^6.0 || ^7.0", + "symfony/http-client": "^4.4.16 || ^5.1.7 || ^6.0 || ^7.0 || ^8.0", "symfony/http-client-contracts": "^1.1.8 || ^2.0 || ^3.0", "symfony/service-contracts": "^1.0 || ^2.0 || ^3.0" }, @@ -1964,7 +1964,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.26-dev" + "dev-master": "1.27-dev" } }, "autoload": { @@ -1985,7 +1985,7 @@ "sts" ], "support": { - "source": "https://github.com/async-aws/core/tree/1.26.0" + "source": "https://github.com/async-aws/core/tree/1.27.0" }, "funding": [ { @@ -1997,20 +1997,20 @@ "type": "github" } ], - "time": "2025-05-12T09:35:01+00:00" + "time": "2025-08-11T10:03:27+00:00" }, { "name": "async-aws/ses", - "version": "1.12.0", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/async-aws/ses.git", - "reference": "904ee7b5c07d865c20db4c06c3c0b97e7035673d" + "reference": "e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/ses/zipball/904ee7b5c07d865c20db4c06c3c0b97e7035673d", - "reference": "904ee7b5c07d865c20db4c06c3c0b97e7035673d", + "url": "https://api.github.com/repos/async-aws/ses/zipball/e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42", + "reference": "e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42", "shasum": "" }, "require": { @@ -2021,7 +2021,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -2042,7 +2042,7 @@ "ses" ], "support": { - "source": "https://github.com/async-aws/ses/tree/1.12.0" + "source": "https://github.com/async-aws/ses/tree/1.13.0" }, "funding": [ { @@ -2054,7 +2054,7 @@ "type": "github" } ], - "time": "2025-05-12T09:35:01+00:00" + "time": "2025-08-11T10:03:27+00:00" }, { "name": "cakephp/chronos", @@ -2890,16 +2890,16 @@ }, { "name": "guzzlehttp/promises", - "version": "2.2.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" + "reference": "481557b130ef3790cf82b713667b43030dc9c957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", "shasum": "" }, "require": { @@ -2907,7 +2907,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "type": "library", "extra": { @@ -2953,7 +2953,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.2.0" + "source": "https://github.com/guzzle/promises/tree/2.3.0" }, "funding": [ { @@ -2969,7 +2969,7 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:27:01+00:00" + "time": "2025-08-22T14:34:08+00:00" }, { "name": "guzzlehttp/psr7", @@ -3592,12 +3592,12 @@ "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "129700ed449b1f02d70272d2ac802357c8c30c58" + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", - "reference": "129700ed449b1f02d70272d2ac802357c8c30c58", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", "shasum": "" }, "require": { @@ -3810,16 +3810,16 @@ }, { "name": "phenixphp/framework", - "version": "dev-feature/users-module", + "version": "0.6.0", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "5085a294483cd2287a4c94131539347530e29078" + "reference": "9c43d8518524928fa5eb6922dbbfed21f1b275cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/5085a294483cd2287a4c94131539347530e29078", - "reference": "5085a294483cd2287a4c94131539347530e29078", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/9c43d8518524928fa5eb6922dbbfed21f1b275cd", + "reference": "9c43d8518524928fa5eb6922dbbfed21f1b275cd", "shasum": "" }, "require": { @@ -3894,9 +3894,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/develop" + "source": "https://github.com/phenixphp/framework/tree/0.6.0" }, - "time": "2025-01-13T21:17:21+00:00" + "time": "2025-08-22T22:35:11+00:00" }, { "name": "phenixphp/http-cors", @@ -4060,55 +4060,6 @@ }, "time": "2021-02-03T23:26:27+00:00" }, - { - "name": "psr/cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for caching libraries", - "keywords": [ - "cache", - "psr", - "psr-6" - ], - "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" - }, - "time": "2021-02-03T23:26:27+00:00" - }, { "name": "psr/clock", "version": "1.0.0", @@ -5817,7 +5768,7 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -5876,7 +5827,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -5900,7 +5851,7 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", @@ -5958,7 +5909,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -5982,7 +5933,7 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -6045,7 +5996,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -6069,7 +6020,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -6130,7 +6081,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -6154,7 +6105,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -6215,7 +6166,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -6239,7 +6190,7 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -6299,7 +6250,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -6323,7 +6274,7 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", @@ -6379,7 +6330,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -6403,7 +6354,7 @@ }, { "name": "symfony/polyfill-uuid", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", @@ -6462,7 +6413,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" }, "funding": [ { @@ -6473,12 +6424,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-28T08:24:38+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/resend-mailer", @@ -7362,71 +7317,6 @@ ], "time": "2022-12-23T10:58:28+00:00" }, - { - "name": "cmgmyr/phploc", - "version": "8.0.6", - "source": { - "type": "git", - "url": "https://github.com/cmgmyr/phploc.git", - "reference": "5d785f8fc8b891483cdbee3fb25f2b348c50c03f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/cmgmyr/phploc/zipball/5d785f8fc8b891483cdbee3fb25f2b348c50c03f", - "reference": "5d785f8fc8b891483cdbee3fb25f2b348c50c03f", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "php": "^7.4 || ^8.0", - "phpunit/php-file-iterator": "^3.0|^4.0|^5.0|^6.0", - "sebastian/cli-parser": "^1.0|^2.0|^3.0|^4.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "phpunit/phpunit": "^9.0|^10.0", - "vimeo/psalm": "^5.7" - }, - "bin": [ - "phploc" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "8.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Chris Gmyr", - "email": "cmgmyr@gmail.com", - "role": "lead" - } - ], - "description": "A tool for quickly measuring the size of a PHP project.", - "homepage": "https://github.com/cmgmyr/phploc", - "support": { - "issues": "https://github.com/cmgmyr/phploc/issues", - "source": "https://github.com/cmgmyr/phploc/tree/8.0.6" - }, - "funding": [ - { - "url": "https://github.com/cmgmyr", - "type": "github" - } - ], - "time": "2025-03-29T16:41:46+00:00" - }, { "name": "composer/pcre", "version": "3.3.2", @@ -7649,102 +7539,6 @@ ], "time": "2024-05-06T16:37:16+00:00" }, - { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.1.2", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^2.2", - "php": ">=5.4", - "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" - }, - "require-dev": { - "composer/composer": "^2.2", - "ext-json": "*", - "ext-zip": "*", - "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcompatibility/php-compatibility": "^9.0", - "yoast/phpunit-polyfills": "^1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" - }, - "autoload": { - "psr-4": { - "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Franck Nijhof", - "email": "opensource@frenck.dev", - "homepage": "https://frenck.dev", - "role": "Open source developer" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcbf", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/composer-installer/issues", - "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", - "source": "https://github.com/PHPCSStandards/composer-installer" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-07-17T20:45:56+00:00" - }, { "name": "doctrine/instantiator", "version": "2.0.0", @@ -7925,16 +7719,16 @@ }, { "name": "filp/whoops", - "version": "2.18.3", + "version": "2.18.4", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "59a123a3d459c5a23055802237cb317f609867e5" + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5", - "reference": "59a123a3d459c5a23055802237cb317f609867e5", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", "shasum": "" }, "require": { @@ -7984,7 +7778,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.3" + "source": "https://github.com/filp/whoops/tree/2.18.4" }, "funding": [ { @@ -7992,20 +7786,20 @@ "type": "github" } ], - "time": "2025-06-16T00:02:10+00:00" + "time": "2025-08-08T12:00:00+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.68.0", + "version": "v3.86.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c" + "reference": "4a952bd19dc97879b0620f495552ef09b55f7d36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c", - "reference": "73f78d8b2b34a0dd65fedb434a602ee4c2c8ad4c", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/4a952bd19dc97879b0620f495552ef09b55f7d36", + "reference": "4a952bd19dc97879b0620f495552ef09b55f7d36", "shasum": "" }, "require": { @@ -8018,22 +7812,22 @@ "ext-tokenizer": "*", "fidry/cpu-core-counter": "^1.2", "php": "^7.4 || ^8.0", - "react/child-process": "^0.6.5", - "react/event-loop": "^1.0", - "react/promise": "^2.0 || ^3.0", - "react/socket": "^1.0", - "react/stream": "^1.0", - "sebastian/diff": "^4.0 || ^5.1 || ^6.0", - "symfony/console": "^5.4 || ^6.4 || ^7.0", - "symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", - "symfony/filesystem": "^5.4 || ^6.4 || ^7.0", - "symfony/finder": "^5.4 || ^6.4 || ^7.0", - "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0", - "symfony/polyfill-mbstring": "^1.31", - "symfony/polyfill-php80": "^1.31", - "symfony/polyfill-php81": "^1.31", - "symfony/process": "^5.4 || ^6.4 || ^7.2", - "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" + "react/child-process": "^0.6.6", + "react/event-loop": "^1.5", + "react/promise": "^3.2", + "react/socket": "^1.16", + "react/stream": "^1.4", + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", + "symfony/console": "^5.4.47 || ^6.4.13 || ^7.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", + "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", + "symfony/polyfill-mbstring": "^1.32", + "symfony/polyfill-php80": "^1.32", + "symfony/polyfill-php81": "^1.32", + "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", + "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" }, "require-dev": { "facile-it/paraunit": "^1.3.1 || ^2.6", @@ -8043,11 +7837,12 @@ "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.8", "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5", - "phpunit/phpunit": "^9.6.22 || ^10.5.40 || ^11.5.2", - "symfony/var-dumper": "^5.4.48 || ^6.4.15 || ^7.2.0", - "symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.2.0" + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", + "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", + "symfony/polyfill-php84": "^1.32", + "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", + "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -8088,7 +7883,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.86.0" }, "funding": [ { @@ -8096,7 +7891,7 @@ "type": "github" } ], - "time": "2025-01-13T17:01:01+00:00" + "time": "2025-08-13T22:36:21+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -8209,71 +8004,6 @@ }, "time": "2025-03-19T14:43:43+00:00" }, - { - "name": "justinrainbow/json-schema", - "version": "5.3.0", - "source": { - "type": "git", - "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", - "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", - "json-schema/json-schema-test-suite": "1.2.0", - "phpunit/phpunit": "^4.8.35" - }, - "bin": [ - "bin/validate-json" - ], - "type": "library", - "autoload": { - "psr-4": { - "JsonSchema\\": "src/JsonSchema/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bruno Prieto Reis", - "email": "bruno.p.reis@gmail.com" - }, - { - "name": "Justin Rainbow", - "email": "justin.rainbow@gmail.com" - }, - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - }, - { - "name": "Robert Schönthal", - "email": "seroscho@googlemail.com" - } - ], - "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", - "keywords": [ - "json", - "schema" - ], - "support": { - "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" - }, - "time": "2024-07-06T21:00:26+00:00" - }, { "name": "mockery/mockery", "version": "1.6.12", @@ -8419,16 +8149,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.0", + "version": "v5.6.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56" + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56", - "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", "shasum": "" }, "require": { @@ -8471,9 +8201,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" }, - "time": "2025-07-27T20:03:57+00:00" + "time": "2025-08-13T20:13:15+00:00" }, { "name": "nunomaduro/collision", @@ -9135,65 +8865,18 @@ }, "time": "2024-09-04T20:21:43+00:00" }, - { - "name": "phpstan/phpdoc-parser", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", - "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^5.3.0", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "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/2.2.0" - }, - "time": "2025-07-13T07:04:09+00:00" - }, { "name": "phpstan/phpstan", - "version": "1.12.15", + "version": "1.12.28", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1" + "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c91d4e8bc056f46cf653656e6f71004b254574d1", - "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", + "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", "shasum": "" }, "require": { @@ -9238,7 +8921,7 @@ "type": "github" } ], - "time": "2025-01-05T16:40:22+00:00" + "time": "2025-07-17T17:15:39+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -9660,16 +9343,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.23", + "version": "9.6.25", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95" + "reference": "049c011e01be805202d8eebedef49f769a8ec7b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", - "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/049c011e01be805202d8eebedef49f769a8ec7b7", + "reference": "049c011e01be805202d8eebedef49f769a8ec7b7", "shasum": "" }, "require": { @@ -9680,7 +9363,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.1", + "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", @@ -9743,7 +9426,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.23" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.25" }, "funding": [ { @@ -9767,7 +9450,7 @@ "type": "tidelift" } ], - "time": "2025-05-02T06:40:34+00:00" + "time": "2025-08-20T14:38:31+00:00" }, { "name": "react/cache", @@ -11295,106 +10978,41 @@ "time": "2020-09-28T06:39:44+00:00" }, { - "name": "slevomat/coding-standard", - "version": "8.20.0", + "name": "spatie/file-system-watcher", + "version": "1.2.0", "source": { "type": "git", - "url": "https://github.com/slevomat/coding-standard.git", - "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb" + "url": "https://github.com/spatie/file-system-watcher.git", + "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b4f9f02edd4e6a586777f0cabe8d05574323f3eb", - "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb", + "url": "https://api.github.com/repos/spatie/file-system-watcher/zipball/d9511ecbd266f190c4abce88516c3f231fcb6bfe", + "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2", - "php": "^7.4 || ^8.0", - "phpstan/phpdoc-parser": "^2.2.0", - "squizlabs/php_codesniffer": "^3.13.2" + "php": "^8.0", + "symfony/process": "^5.2|^6.0|^7.0" }, "require-dev": { - "phing/phing": "3.0.1|3.1.0", - "php-parallel-lint/php-parallel-lint": "1.4.0", - "phpstan/phpstan": "2.1.19", - "phpstan/phpstan-deprecation-rules": "2.0.3", - "phpstan/phpstan-phpunit": "2.0.7", - "phpstan/phpstan-strict-rules": "2.0.6", - "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.27|12.2.7" - }, - "type": "phpcodesniffer-standard", - "extra": { - "branch-alias": { - "dev-master": "8.x-dev" - } + "pestphp/pest": "^1.22", + "phpunit/phpunit": "^9.5", + "spatie/ray": "^1.22", + "spatie/temporary-directory": "^2.0", + "vimeo/psalm": "^4.3" }, + "type": "library", "autoload": { "psr-4": { - "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + "Spatie\\Watcher\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", - "keywords": [ - "dev", - "phpcs" - ], - "support": { - "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.20.0" - }, - "funding": [ - { - "url": "https://github.com/kukulich", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", - "type": "tidelift" - } - ], - "time": "2025-07-26T15:35:10+00:00" - }, - { - "name": "spatie/file-system-watcher", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/spatie/file-system-watcher.git", - "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/file-system-watcher/zipball/d9511ecbd266f190c4abce88516c3f231fcb6bfe", - "reference": "d9511ecbd266f190c4abce88516c3f231fcb6bfe", - "shasum": "" - }, - "require": { - "php": "^8.0", - "symfony/process": "^5.2|^6.0|^7.0" - }, - "require-dev": { - "pestphp/pest": "^1.22", - "phpunit/phpunit": "^9.5", - "spatie/ray": "^1.22", - "spatie/temporary-directory": "^2.0", - "vimeo/psalm": "^4.3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Spatie\\Watcher\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "authors": [ { "name": "Freek Van der Herten", "email": "freek@spatie.be", @@ -11419,268 +11037,6 @@ ], "time": "2023-12-18T14:26:25+00:00" }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.13.2", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-06-17T22:17:01+00:00" - }, - { - "name": "symfony/cache", - "version": "v7.3.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache.git", - "reference": "6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6", - "reference": "6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "psr/cache": "^2.0|^3.0", - "psr/log": "^1.1|^2|^3", - "symfony/cache-contracts": "^3.6", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.4|^7.0" - }, - "conflict": { - "doctrine/dbal": "<3.6", - "symfony/dependency-injection": "<6.4", - "symfony/http-kernel": "<6.4", - "symfony/var-dumper": "<6.4" - }, - "provide": { - "psr/cache-implementation": "2.0|3.0", - "psr/simple-cache-implementation": "1.0|2.0|3.0", - "symfony/cache-implementation": "1.1|2.0|3.0" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/dbal": "^3.6|^4", - "predis/predis": "^1.1|^2.0", - "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/filesystem": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Cache\\": "" - }, - "classmap": [ - "Traits/ValueWrapper.php" - ], - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", - "homepage": "https://symfony.com", - "keywords": [ - "caching", - "psr6" - ], - "support": { - "source": "https://github.com/symfony/cache/tree/v7.3.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-07-30T17:13:41+00:00" - }, - { - "name": "symfony/cache-contracts", - "version": "v3.6.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache-contracts.git", - "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", - "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/cache": "^3.0" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Cache\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to caching", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-03-13T15:25:07+00:00" - }, { "name": "symfony/finder", "version": "v7.3.2", @@ -11822,7 +11178,7 @@ }, { "name": "symfony/polyfill-php81", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -11878,7 +11234,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" }, "funding": [ { @@ -11902,16 +11258,16 @@ }, { "name": "symfony/process", - "version": "v7.2.0", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", - "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", + "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "shasum": "" }, "require": { @@ -11943,7 +11299,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.0" + "source": "https://github.com/symfony/process/tree/v7.3.0" }, "funding": [ { @@ -11959,7 +11315,7 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:24:19+00:00" + "time": "2025-04-17T09:11:12+00:00" }, { "name": "symfony/stopwatch", @@ -12023,87 +11379,6 @@ ], "time": "2025-02-24T10:49:57+00:00" }, - { - "name": "symfony/var-exporter", - "version": "v7.3.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-exporter.git", - "reference": "05b3e90654c097817325d6abd284f7938b05f467" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/05b3e90654c097817325d6abd284f7938b05f467", - "reference": "05b3e90654c097817325d6abd284f7938b05f467", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "require-dev": { - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\VarExporter\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Allows exporting any serializable PHP data structure to plain PHP code", - "homepage": "https://symfony.com", - "keywords": [ - "clone", - "construct", - "export", - "hydrate", - "instantiate", - "lazy-loading", - "proxy", - "serialize" - ], - "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.3.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-07-10T08:47:49+00:00" - }, { "name": "theseer/tokenizer", "version": "1.2.3", @@ -12157,9 +11432,7 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": { - "phenixphp/framework": 20 - }, + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { From 0976b4bd08448d480f6e42777e87e87a841cffe7 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 27 Aug 2025 10:09:29 -0500 Subject: [PATCH 058/133] chore: restore code --- server | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/server b/server index 4cb4786..8bb53a3 100644 --- a/server +++ b/server @@ -178,8 +178,50 @@ class Watcher extends Watch try { $this->serverProcess->start(); - echo "Server started on {$this->host}:{$this->port}" . PHP_EOL . PHP_EOL; - echo "Process ID is {$this->pid}" . PHP_EOL . PHP_EOL; + usleep(100000); // 100ms + + if (!$this->serverProcess->isRunning()) { + $exitCode = $this->serverProcess->getExitCode(); + + if ($incrementErrorCounter) { + $this->consecutiveErrors++; + } + + echo Output::error("Server failed to start. Exit code: {$exitCode}") . PHP_EOL; + echo Output::debug("Error: " . $this->serverProcess->getErrorOutput()) . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL . PHP_EOL; + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + sleep(2); + + $this->runServer($incrementErrorCounter); + } + + return; + } + + if ($incrementErrorCounter) { + $this->consecutiveErrors = 0; + } + $this->pid = $this->serverProcess->getPid(); + + echo Output::success("Server started on {$this->host}:{$this->port}") . PHP_EOL; + echo Output::info("PID: {$this->pid}") . PHP_EOL . PHP_EOL; + + } catch (Exception $e) { + if ($incrementErrorCounter) { + $this->consecutiveErrors++; + } + + echo Output::error("Failed to start server: " . $e->getMessage()) . PHP_EOL; + echo Output::warning("Consecutive errors: {$this->consecutiveErrors}") . PHP_EOL . PHP_EOL; + + if ($this->consecutiveErrors < $this->maxConsecutiveErrors) { + sleep(2); + + $this->runServer($incrementErrorCounter); + } + } } private function ensureWatcherIsRunning(Process $watcher): void @@ -413,4 +455,4 @@ try { } } catch (Throwable $th) { echo $th->getMessage(); -} +} \ No newline at end of file From 2140e896c6678ae7977df2674faf9a212c905691 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 27 Aug 2025 10:12:52 -0500 Subject: [PATCH 059/133] refactor: remove non required classes and code --- app/Collections/UserCollection.php | 12 ----- app/Http/Controllers/UserController.php | 60 ------------------------- app/Http/Requests/StoreUserRequest.php | 20 --------- routes/api.php | 7 --- 4 files changed, 99 deletions(-) delete mode 100644 app/Collections/UserCollection.php delete mode 100644 app/Http/Controllers/UserController.php delete mode 100644 app/Http/Requests/StoreUserRequest.php diff --git a/app/Collections/UserCollection.php b/app/Collections/UserCollection.php deleted file mode 100644 index 22bfdd8..0000000 --- a/app/Collections/UserCollection.php +++ /dev/null @@ -1,12 +0,0 @@ -paginate($request->getUri()); - - dump('Freder H'); - - return response()->json($users); - } - - public function store(StoreUserRequest $request): Response - { - $user = new User(); - $user->name = $request->body('name'); - $user->email = $request->body('email'); - - if ($user->save()) { - return response()->json($user, HttpStatus::CREATED); - } - - return response()->json([], HttpStatus::INTERNAL_SERVER_ERROR); - } - - public function show(Request $request): Response - { - $user = User::find($request->route('user'), ['id', 'name', 'email']); - - if ($user) { - return response()->json($user); - } - - return response()->json([], HttpStatus::NOT_FOUND); - } - - public function update(Request $request): Response - { - return response()->json([]); - } - - public function delete(Request $request): Response - { - return response()->json([]); - } -} diff --git a/app/Http/Requests/StoreUserRequest.php b/app/Http/Requests/StoreUserRequest.php deleted file mode 100644 index f0eaa60..0000000 --- a/app/Http/Requests/StoreUserRequest.php +++ /dev/null @@ -1,20 +0,0 @@ - Str::required()->max(10), - 'email' => Email::required(), - ]; - } -} diff --git a/routes/api.php b/routes/api.php index 2fa9b9c..78c6136 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,14 +2,7 @@ declare(strict_types=1); -use App\Http\Controllers\UserController; use App\Http\Controllers\WelcomeController; use Phenix\Facades\Route; Route::get('/', [WelcomeController::class, 'index']); - -Route::get('/users', [UserController::class, 'index']); - -Route::get('/users/{user}', [UserController::class, 'show']); - -Route::post('/users', [UserController::class, 'store']); From 423cfc0a0765ed4b0f472eff210282ed6683495f Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 7 Oct 2025 14:15:17 -0500 Subject: [PATCH 060/133] feat: install dev branch of framework --- composer.json | 2 +- composer.lock | 492 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 297 insertions(+), 197 deletions(-) diff --git a/composer.json b/composer.json index 2bba8af..bbe927b 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "^0.6.0" + "phenixphp/framework": "dev-develop" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index ab84d9f..239624b 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": "38f7078cd1d68343715a254570dfd2fe", + "content-hash": "906da3eaf71f2cab3278bedec76f5f31", "packages": [ { "name": "adbario/php-dot-notation", @@ -62,16 +62,16 @@ }, { "name": "amphp/amp", - "version": "v3.1.0", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9" + "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9", - "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9", + "url": "https://api.github.com/repos/amphp/amp/zipball/fa0ab33a6f47a82929c38d03ca47ebb71086a93f", + "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f", "shasum": "" }, "require": { @@ -131,7 +131,7 @@ ], "support": { "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v3.1.0" + "source": "https://github.com/amphp/amp/tree/v3.1.1" }, "funding": [ { @@ -139,7 +139,7 @@ "type": "github" } ], - "time": "2025-01-26T16:07:39+00:00" + "time": "2025-08-27T21:42:00+00:00" }, { "name": "amphp/byte-stream", @@ -1172,16 +1172,16 @@ }, { "name": "amphp/parallel", - "version": "v2.3.1", + "version": "v2.3.2", "source": { "type": "git", "url": "https://github.com/amphp/parallel.git", - "reference": "5113111de02796a782f5d90767455e7391cca190" + "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parallel/zipball/5113111de02796a782f5d90767455e7391cca190", - "reference": "5113111de02796a782f5d90767455e7391cca190", + "url": "https://api.github.com/repos/amphp/parallel/zipball/321b45ae771d9c33a068186b24117e3cd1c48dce", + "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce", "shasum": "" }, "require": { @@ -1244,7 +1244,7 @@ ], "support": { "issues": "https://github.com/amphp/parallel/issues", - "source": "https://github.com/amphp/parallel/tree/v2.3.1" + "source": "https://github.com/amphp/parallel/tree/v2.3.2" }, "funding": [ { @@ -1252,7 +1252,7 @@ "type": "github" } ], - "time": "2024-12-21T01:56:09+00:00" + "time": "2025-08-27T21:55:40+00:00" }, { "name": "amphp/parser", @@ -1933,16 +1933,16 @@ }, { "name": "async-aws/core", - "version": "1.27.0", + "version": "1.27.1", "source": { "type": "git", "url": "https://github.com/async-aws/core.git", - "reference": "00b69a04a36b5ba75e0448e46158c9718ac95755" + "reference": "5b8e35c8df94990161e2c9750c9ba1683d0b48b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/core/zipball/00b69a04a36b5ba75e0448e46158c9718ac95755", - "reference": "00b69a04a36b5ba75e0448e46158c9718ac95755", + "url": "https://api.github.com/repos/async-aws/core/zipball/5b8e35c8df94990161e2c9750c9ba1683d0b48b8", + "reference": "5b8e35c8df94990161e2c9750c9ba1683d0b48b8", "shasum": "" }, "require": { @@ -1985,7 +1985,7 @@ "sts" ], "support": { - "source": "https://github.com/async-aws/core/tree/1.27.0" + "source": "https://github.com/async-aws/core/tree/1.27.1" }, "funding": [ { @@ -1997,7 +1997,7 @@ "type": "github" } ], - "time": "2025-08-11T10:03:27+00:00" + "time": "2025-09-08T07:05:54+00:00" }, { "name": "async-aws/ses", @@ -2117,16 +2117,16 @@ }, { "name": "cakephp/core", - "version": "5.2.6", + "version": "5.2.8", "source": { "type": "git", "url": "https://github.com/cakephp/core.git", - "reference": "93f395b6d741775320c4b782ddb47b5c2906e7ad" + "reference": "231d67d9e192491e80f8e3f367822dbadcb6d15a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/core/zipball/93f395b6d741775320c4b782ddb47b5c2906e7ad", - "reference": "93f395b6d741775320c4b782ddb47b5c2906e7ad", + "url": "https://api.github.com/repos/cakephp/core/zipball/231d67d9e192491e80f8e3f367822dbadcb6d15a", + "reference": "231d67d9e192491e80f8e3f367822dbadcb6d15a", "shasum": "" }, "require": { @@ -2180,20 +2180,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/core" }, - "time": "2025-07-20T02:02:49+00:00" + "time": "2025-08-30T05:23:22+00:00" }, { "name": "cakephp/database", - "version": "5.2.6", + "version": "5.2.8", "source": { "type": "git", "url": "https://github.com/cakephp/database.git", - "reference": "1a2b357ed2deae8797c4ccb7a8062b1bdb5e27a2" + "reference": "e0ac72732221e74a66398ca71e4b5f56e76130fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/database/zipball/1a2b357ed2deae8797c4ccb7a8062b1bdb5e27a2", - "reference": "1a2b357ed2deae8797c4ccb7a8062b1bdb5e27a2", + "url": "https://api.github.com/repos/cakephp/database/zipball/e0ac72732221e74a66398ca71e4b5f56e76130fc", + "reference": "e0ac72732221e74a66398ca71e4b5f56e76130fc", "shasum": "" }, "require": { @@ -2247,20 +2247,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/database" }, - "time": "2025-07-20T02:02:49+00:00" + "time": "2025-09-24T02:31:06+00:00" }, { "name": "cakephp/datasource", - "version": "5.2.6", + "version": "5.2.8", "source": { "type": "git", "url": "https://github.com/cakephp/datasource.git", - "reference": "4d40b398897ada47569e82b351cabf00e37b2ba1" + "reference": "35cd45fdea18854e4f8fd7bdb5fa487d104a8efd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/datasource/zipball/4d40b398897ada47569e82b351cabf00e37b2ba1", - "reference": "4d40b398897ada47569e82b351cabf00e37b2ba1", + "url": "https://api.github.com/repos/cakephp/datasource/zipball/35cd45fdea18854e4f8fd7bdb5fa487d104a8efd", + "reference": "35cd45fdea18854e4f8fd7bdb5fa487d104a8efd", "shasum": "" }, "require": { @@ -2314,20 +2314,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/datasource" }, - "time": "2025-07-20T02:02:49+00:00" + "time": "2025-09-04T00:13:11+00:00" }, { "name": "cakephp/utility", - "version": "5.2.6", + "version": "5.2.8", "source": { "type": "git", "url": "https://github.com/cakephp/utility.git", - "reference": "3188be6abdbe27f85a44c2d317477dc7b43582eb" + "reference": "9d2bafa62f457084b7ce4737f2f71d2a40fc6812" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/utility/zipball/3188be6abdbe27f85a44c2d317477dc7b43582eb", - "reference": "3188be6abdbe27f85a44c2d317477dc7b43582eb", + "url": "https://api.github.com/repos/cakephp/utility/zipball/9d2bafa62f457084b7ce4737f2f71d2a40fc6812", + "reference": "9d2bafa62f457084b7ce4737f2f71d2a40fc6812", "shasum": "" }, "require": { @@ -2378,7 +2378,7 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/utility" }, - "time": "2025-07-20T02:02:49+00:00" + "time": "2025-09-06T07:02:20+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -2764,22 +2764,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.9.3", + "version": "7.10.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.3", - "guzzlehttp/psr7": "^2.7.0", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -2870,7 +2870,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.9.3" + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" }, "funding": [ { @@ -2886,7 +2886,7 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:37:11+00:00" + "time": "2025-08-23T22:36:01+00:00" }, { "name": "guzzlehttp/promises", @@ -2973,16 +2973,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.7.1", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" + "reference": "21dc724a0583619cd1652f673303492272778051" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", - "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", "shasum": "" }, "require": { @@ -2998,7 +2998,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -3069,7 +3069,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.1" + "source": "https://github.com/guzzle/psr7/tree/2.8.0" }, "funding": [ { @@ -3085,7 +3085,7 @@ "type": "tidelift" } ], - "time": "2025-03-27T12:30:47+00:00" + "time": "2025-08-23T21:21:41+00:00" }, { "name": "kelunik/certificate", @@ -3588,16 +3588,16 @@ }, { "name": "nesbot/carbon", - "version": "3.10.2", + "version": "3.10.3", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" + "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", - "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", + "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", "shasum": "" }, "require": { @@ -3615,13 +3615,13 @@ "require-dev": { "doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/orm": "^2.15.2 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.75.0", + "friendsofphp/php-cs-fixer": "^v3.87.1", "kylekatarnls/multi-tester": "^2.5.3", "phpmd/phpmd": "^2.15.0", "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^2.1.17", - "phpunit/phpunit": "^10.5.46", - "squizlabs/php_codesniffer": "^3.13.0" + "phpstan/phpstan": "^2.1.22", + "phpunit/phpunit": "^10.5.53", + "squizlabs/php_codesniffer": "^3.13.4" }, "bin": [ "bin/carbon" @@ -3689,7 +3689,7 @@ "type": "tidelift" } ], - "time": "2025-08-02T09:36:06+00:00" + "time": "2025-09-06T13:39:36+00:00" }, { "name": "nikic/fast-route", @@ -3743,16 +3743,16 @@ }, { "name": "paragonie/constant_time_encoding", - "version": "v2.7.0", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105" + "reference": "e30811f7bc69e4b5b6d5783e712c06c8eabf0226" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105", - "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/e30811f7bc69e4b5b6d5783e712c06c8eabf0226", + "reference": "e30811f7bc69e4b5b6d5783e712c06c8eabf0226", "shasum": "" }, "require": { @@ -3806,20 +3806,20 @@ "issues": "https://github.com/paragonie/constant_time_encoding/issues", "source": "https://github.com/paragonie/constant_time_encoding" }, - "time": "2024-05-08T12:18:48+00:00" + "time": "2025-09-24T15:12:37+00:00" }, { "name": "phenixphp/framework", - "version": "0.6.0", + "version": "dev-develop", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "9c43d8518524928fa5eb6922dbbfed21f1b275cd" + "reference": "2f7223b6b4789e8bee4c4971a10f915636766c65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/9c43d8518524928fa5eb6922dbbfed21f1b275cd", - "reference": "9c43d8518524928fa5eb6922dbbfed21f1b275cd", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/2f7223b6b4789e8bee4c4971a10f915636766c65", + "reference": "2f7223b6b4789e8bee4c4971a10f915636766c65", "shasum": "" }, "require": { @@ -3894,9 +3894,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/0.6.0" + "source": "https://github.com/phenixphp/framework/tree/develop" }, - "time": "2025-08-22T22:35:11+00:00" + "time": "2025-10-07T17:16:04+00:00" }, { "name": "phenixphp/http-cors", @@ -4949,16 +4949,16 @@ }, { "name": "symfony/config", - "version": "v7.3.2", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "faef36e271bbeb74a9d733be4b56419b157762e2" + "reference": "8a09223170046d2cfda3d2e11af01df2c641e961" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/faef36e271bbeb74a9d733be4b56419b157762e2", - "reference": "faef36e271bbeb74a9d733be4b56419b157762e2", + "url": "https://api.github.com/repos/symfony/config/zipball/8a09223170046d2cfda3d2e11af01df2c641e961", + "reference": "8a09223170046d2cfda3d2e11af01df2c641e961", "shasum": "" }, "require": { @@ -5004,7 +5004,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.3.2" + "source": "https://github.com/symfony/config/tree/v7.3.4" }, "funding": [ { @@ -5024,20 +5024,20 @@ "type": "tidelift" } ], - "time": "2025-07-26T13:55:06+00:00" + "time": "2025-09-22T12:46:16+00:00" }, { "name": "symfony/console", - "version": "v6.4.24", + "version": "v6.4.26", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350" + "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", - "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", + "url": "https://api.github.com/repos/symfony/console/zipball/492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f", + "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f", "shasum": "" }, "require": { @@ -5102,7 +5102,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.24" + "source": "https://github.com/symfony/console/tree/v6.4.26" }, "funding": [ { @@ -5122,7 +5122,7 @@ "type": "tidelift" } ], - "time": "2025-07-30T10:38:54+00:00" + "time": "2025-09-26T12:13:46+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5193,16 +5193,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" + "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", - "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", "shasum": "" }, "require": { @@ -5253,7 +5253,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" }, "funding": [ { @@ -5264,12 +5264,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-22T09:11:45+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5419,16 +5423,16 @@ }, { "name": "symfony/http-client", - "version": "v7.3.2", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "1c064a0c67749923483216b081066642751cc2c7" + "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/1c064a0c67749923483216b081066642751cc2c7", - "reference": "1c064a0c67749923483216b081066642751cc2c7", + "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62", + "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62", "shasum": "" }, "require": { @@ -5436,6 +5440,7 @@ "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/polyfill-php83": "^1.29", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -5494,7 +5499,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.2" + "source": "https://github.com/symfony/http-client/tree/v7.3.4" }, "funding": [ { @@ -5514,7 +5519,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:36:08+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { "name": "symfony/http-client-contracts", @@ -5596,16 +5601,16 @@ }, { "name": "symfony/mailer", - "version": "v7.3.2", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b" + "reference": "ab97ef2f7acf0216955f5845484235113047a31d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/d43e84d9522345f96ad6283d5dfccc8c1cfc299b", - "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b", + "url": "https://api.github.com/repos/symfony/mailer/zipball/ab97ef2f7acf0216955f5845484235113047a31d", + "reference": "ab97ef2f7acf0216955f5845484235113047a31d", "shasum": "" }, "require": { @@ -5656,7 +5661,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.2" + "source": "https://github.com/symfony/mailer/tree/v7.3.4" }, "funding": [ { @@ -5676,20 +5681,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:36:08+00:00" + "time": "2025-09-17T05:51:54+00:00" }, { "name": "symfony/mime", - "version": "v7.3.2", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1" + "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/e0a0f859148daf1edf6c60b398eb40bfc96697d1", - "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1", + "url": "https://api.github.com/repos/symfony/mime/zipball/b1b828f69cbaf887fa835a091869e55df91d0e35", + "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35", "shasum": "" }, "require": { @@ -5744,7 +5749,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.2" + "source": "https://github.com/symfony/mime/tree/v7.3.4" }, "funding": [ { @@ -5764,7 +5769,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2025-09-16T08:38:17+00:00" }, { "name": "symfony/polyfill-ctype", @@ -6437,16 +6442,16 @@ }, { "name": "symfony/resend-mailer", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/resend-mailer.git", - "reference": "591d06a6603845933e921c10cedb2afb97376c50" + "reference": "dffa55453571e3a6c161f1c12ee402ca19cb4dd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/resend-mailer/zipball/591d06a6603845933e921c10cedb2afb97376c50", - "reference": "591d06a6603845933e921c10cedb2afb97376c50", + "url": "https://api.github.com/repos/symfony/resend-mailer/zipball/dffa55453571e3a6c161f1c12ee402ca19cb4dd1", + "reference": "dffa55453571e3a6c161f1c12ee402ca19cb4dd1", "shasum": "" }, "require": { @@ -6487,7 +6492,7 @@ "description": "Symfony Resend Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/resend-mailer/tree/v7.3.0" + "source": "https://github.com/symfony/resend-mailer/tree/v7.3.3" }, "funding": [ { @@ -6498,12 +6503,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-28T08:24:38+00:00" + "time": "2025-08-05T11:38:12+00:00" }, { "name": "symfony/service-contracts", @@ -6590,16 +6599,16 @@ }, { "name": "symfony/string", - "version": "v7.3.2", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca" + "reference": "f96476035142921000338bad71e5247fbc138872" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca", - "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca", + "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", + "reference": "f96476035142921000338bad71e5247fbc138872", "shasum": "" }, "require": { @@ -6614,7 +6623,6 @@ }, "require-dev": { "symfony/emoji": "^7.1", - "symfony/error-handler": "^6.4|^7.0", "symfony/http-client": "^6.4|^7.0", "symfony/intl": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3.0", @@ -6657,7 +6665,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.2" + "source": "https://github.com/symfony/string/tree/v7.3.4" }, "funding": [ { @@ -6677,20 +6685,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:47:49+00:00" + "time": "2025-09-11T14:36:48+00:00" }, { "name": "symfony/translation", - "version": "v7.3.2", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90" + "reference": "ec25870502d0c7072d086e8ffba1420c85965174" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/81b48f4daa96272efcce9c7a6c4b58e629df3c90", - "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90", + "url": "https://api.github.com/repos/symfony/translation/zipball/ec25870502d0c7072d086e8ffba1420c85965174", + "reference": "ec25870502d0c7072d086e8ffba1420c85965174", "shasum": "" }, "require": { @@ -6757,7 +6765,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.2" + "source": "https://github.com/symfony/translation/tree/v7.3.4" }, "funding": [ { @@ -6777,7 +6785,7 @@ "type": "tidelift" } ], - "time": "2025-07-30T17:31:46+00:00" + "time": "2025-09-07T11:39:36+00:00" }, { "name": "symfony/translation-contracts", @@ -6933,16 +6941,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.3.2", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "53205bea27450dc5c65377518b3275e126d45e75" + "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/53205bea27450dc5c65377518b3275e126d45e75", - "reference": "53205bea27450dc5c65377518b3275e126d45e75", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb", + "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb", "shasum": "" }, "require": { @@ -6996,7 +7004,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.2" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.4" }, "funding": [ { @@ -7016,7 +7024,7 @@ "type": "tidelift" } ], - "time": "2025-07-29T20:02:46+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { "name": "vlucas/phpdotenv", @@ -7790,16 +7798,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.86.0", + "version": "v3.88.2", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "4a952bd19dc97879b0620f495552ef09b55f7d36" + "reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/4a952bd19dc97879b0620f495552ef09b55f7d36", - "reference": "4a952bd19dc97879b0620f495552ef09b55f7d36", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a8d15584bafb0f0d9d938827840060fd4a3ebc99", + "reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99", "shasum": "" }, "require": { @@ -7810,39 +7818,38 @@ "ext-hash": "*", "ext-json": "*", "ext-tokenizer": "*", - "fidry/cpu-core-counter": "^1.2", + "fidry/cpu-core-counter": "^1.3", "php": "^7.4 || ^8.0", "react/child-process": "^0.6.6", "react/event-loop": "^1.5", - "react/promise": "^3.2", + "react/promise": "^3.3", "react/socket": "^1.16", "react/stream": "^1.4", "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", - "symfony/console": "^5.4.47 || ^6.4.13 || ^7.0", - "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", - "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", - "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", - "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", - "symfony/polyfill-mbstring": "^1.32", - "symfony/polyfill-php80": "^1.32", - "symfony/polyfill-php81": "^1.32", - "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", - "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" + "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0", + "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0", + "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0", + "symfony/polyfill-mbstring": "^1.33", + "symfony/polyfill-php80": "^1.33", + "symfony/polyfill-php81": "^1.33", + "symfony/polyfill-php84": "^1.33", + "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2", + "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0" }, "require-dev": { - "facile-it/paraunit": "^1.3.1 || ^2.6", - "infection/infection": "^0.29.14", - "justinrainbow/json-schema": "^5.3 || ^6.4", + "facile-it/paraunit": "^1.3.1 || ^2.7", + "infection/infection": "^0.31.0", + "justinrainbow/json-schema": "^6.5", "keradus/cli-executor": "^2.2", "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.8", - "php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", - "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", - "symfony/polyfill-php84": "^1.32", - "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", - "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" + "phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34", + "symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2", + "symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -7883,7 +7890,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.86.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.88.2" }, "funding": [ { @@ -7891,7 +7898,7 @@ "type": "github" } ], - "time": "2025-08-13T22:36:21+00:00" + "time": "2025-09-27T00:24:15+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -8867,16 +8874,11 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.28", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9" - }, + "version": "1.12.32", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", - "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8", + "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8", "shasum": "" }, "require": { @@ -8921,7 +8923,7 @@ "type": "github" } ], - "time": "2025-07-17T17:15:39+00:00" + "time": "2025-09-30T10:16:31+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -9343,16 +9345,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.25", + "version": "9.6.29", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "049c011e01be805202d8eebedef49f769a8ec7b7" + "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/049c011e01be805202d8eebedef49f769a8ec7b7", - "reference": "049c011e01be805202d8eebedef49f769a8ec7b7", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9ecfec57835a5581bc888ea7e13b51eb55ab9dd3", + "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3", "shasum": "" }, "require": { @@ -9377,7 +9379,7 @@ "sebastian/comparator": "^4.0.9", "sebastian/diff": "^4.0.6", "sebastian/environment": "^5.1.5", - "sebastian/exporter": "^4.0.6", + "sebastian/exporter": "^4.0.8", "sebastian/global-state": "^5.0.8", "sebastian/object-enumerator": "^4.0.4", "sebastian/resource-operations": "^3.0.4", @@ -9426,7 +9428,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.25" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.29" }, "funding": [ { @@ -9450,7 +9452,7 @@ "type": "tidelift" } ], - "time": "2025-08-20T14:38:31+00:00" + "time": "2025-09-24T06:29:11+00:00" }, { "name": "react/cache", @@ -10419,16 +10421,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.6", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" + "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", - "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c", + "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c", "shasum": "" }, "require": { @@ -10484,15 +10486,27 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.8" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" } ], - "time": "2024-03-02T06:33:00+00:00" + "time": "2025-09-24T06:03:27+00:00" }, { "name": "sebastian/global-state", @@ -11107,16 +11121,16 @@ }, { "name": "symfony/options-resolver", - "version": "v7.3.2", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37" + "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37", - "reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d", + "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d", "shasum": "" }, "require": { @@ -11154,7 +11168,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.3.2" + "source": "https://github.com/symfony/options-resolver/tree/v7.3.3" }, "funding": [ { @@ -11174,7 +11188,7 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:36:08+00:00" + "time": "2025-08-05T10:16:07+00:00" }, { "name": "symfony/polyfill-php81", @@ -11256,18 +11270,98 @@ ], "time": "2024-09-09T11:45:10+00:00" }, + { + "name": "symfony/polyfill-php84", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php84\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-24T13:30:11+00:00" + }, { "name": "symfony/process", - "version": "v7.3.0", + "version": "v7.3.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" + "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b", + "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b", "shasum": "" }, "require": { @@ -11299,7 +11393,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.0" + "source": "https://github.com/symfony/process/tree/v7.3.4" }, "funding": [ { @@ -11310,12 +11404,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-17T09:11:12+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { "name": "symfony/stopwatch", @@ -11432,7 +11530,9 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": {}, + "stability-flags": { + "phenixphp/framework": 20 + }, "prefer-stable": true, "prefer-lowest": false, "platform": { From 33150e22c1127ec76c12aec29bb62948a83bcb79 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 7 Oct 2025 14:16:26 -0500 Subject: [PATCH 061/133] feat: register available app configs --- config/app.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/app.php b/config/app.php index 6393975..d0b5a58 100644 --- a/config/app.php +++ b/config/app.php @@ -10,6 +10,8 @@ 'key' => env('APP_KEY'), 'previous_key' => env('APP_PREVIOUS_KEY'), 'debug' => env('APP_DEBUG', static fn (): bool => true), + 'locale' => 'en', + 'fallback_locale' => 'en', 'middlewares' => [ 'global' => [ \Phenix\Http\Middlewares\HandleCors::class, @@ -27,5 +29,7 @@ \Phenix\Mail\MailServiceProvider::class, \Phenix\Crypto\CryptoServiceProvider::class, \Phenix\Queue\QueueServiceProvider::class, + \Phenix\Events\EventServiceProvider::class, + \Phenix\Translation\TranslationServiceProvider::class, ], ]; From a5c47341de5ed836ae8e66110e5a3b252fdb10e7 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 7 Oct 2025 14:16:52 -0500 Subject: [PATCH 062/133] feat: add translations for validation --- lang/en/validation.php | 75 ++++++++++++++++++++++++++++++++++++++++++ server | 1 + 2 files changed, 76 insertions(+) create mode 100644 lang/en/validation.php diff --git a/lang/en/validation.php b/lang/en/validation.php new file mode 100644 index 0000000..ce3df5f --- /dev/null +++ b/lang/en/validation.php @@ -0,0 +1,75 @@ + 'The :field is invalid.', + 'required' => 'The :field field is required.', + 'string' => 'The :field must be a string.', + 'array' => 'The :field must be an array.', + 'boolean' => 'The :field field must be true or false.', + 'file' => 'The :field must be a file.', + 'url' => 'The :field must be a valid URL.', + 'email' => 'The :field must be a valid email address.', + 'uuid' => 'The :field must be a valid UUID.', + 'ulid' => 'The :field must be a valid ULID.', + 'integer' => 'The :field must be an integer.', + 'numeric' => 'The :field must be a number.', + 'float' => 'The :field must be a float.', + 'dictionary' => 'The :field field must be a dictionary.', + 'collection' => 'The :field must be a collection.', + 'list' => 'The :field must be a list.', + 'confirmed' => 'The :field must be confirmed with :other.', + 'in' => 'The selected :field is invalid. Allowed: :values.', + 'not_in' => 'The selected :field is invalid. Disallowed: :values.', + 'exists' => 'The selected :field is invalid.', + 'unique' => 'The selected :field is invalid.', + 'mimes' => 'The :field must be a file of type: :values.', + 'regex' => 'The :field format is invalid.', + 'starts_with' => 'The :field must start with: :values.', + 'ends_with' => 'The :field must end with: :values.', + 'does_not_start_with' => 'The :field must not start with: :values.', + 'does_not_end_with' => 'The :field must not end with: :values.', + 'digits' => 'The :field must be :digits digits.', + 'digits_between' => 'The :field must be between :min and :max digits.', + 'size' => [ + 'numeric' => 'The :field must be :size.', + 'string' => 'The :field must be :size characters.', + 'array' => 'The :field must contain :size items.', + 'file' => 'The :field must be :size kilobytes.', + ], + 'min' => [ + 'numeric' => 'The :field must be at least :min.', + 'string' => 'The :field must be at least :min characters.', + 'array' => 'The :field must have at least :min items.', + 'file' => 'The :field must be at least :min kilobytes.', + ], + 'max' => [ + 'numeric' => 'The :field may not be greater than :max.', + 'string' => 'The :field may not be greater than :max characters.', + 'array' => 'The :field may not have more than :max items.', + 'file' => 'The :field may not be greater than :max kilobytes.', + ], + 'between' => [ + 'numeric' => 'The :field must be between :min and :max.', + 'string' => 'The :field must be between :min and :max characters.', + 'array' => 'The :field must have between :min and :max items.', + 'file' => 'The :field must be between :min and :max kilobytes.', + ], + 'date' => [ + 'is_date' => 'The :field is not a valid date.', + 'after' => 'The :field must be a date after the specified date.', + 'format' => 'The :field does not match the format :format.', + 'equal_to' => 'The :field must be a date equal to :other.', + 'after_to' => 'The :field must be a date after :other.', + 'after_or_equal_to' => 'The :field must be a date after or equal to :other.', + 'before_or_equal_to' => 'The :field must be a date before or equal to :other.', + 'after_or_equal' => 'The :field must be a date after or equal to the specified date.', + 'before_or_equal' => 'The :field must be a date before or equal to the specified date.', + 'equal' => 'The :field must be a date equal to the specified date.', + 'before_to' => 'The :field must be a date before :other.', + 'before' => 'The :field must be a date before the specified date.', + ], + + 'fields' => [ + // + ], +]; diff --git a/server b/server index 8bb53a3..b990720 100644 --- a/server +++ b/server @@ -442,6 +442,7 @@ try { __DIR__ . '/config', __DIR__ . '/routes', __DIR__ . '/database', + __DIR__ . '/lang', __DIR__ . '/composer.json', __DIR__ . '/.env', ], $config); From ca064b127e1c4a0deab0a95d47a94c6cb2be9f51 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 7 Oct 2025 14:19:14 -0500 Subject: [PATCH 063/133] feat: registration feature --- .../Controllers/Auth/RegisterController.php | 39 +++++++++++++++++++ .../Middleware/RedirectIfAuthenticated.php | 18 +++++++++ app/Models/User.php | 17 ++++---- routes/api.php | 7 ++++ 4 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 app/Http/Controllers/Auth/RegisterController.php create mode 100644 app/Http/Middleware/RedirectIfAuthenticated.php diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php new file mode 100644 index 0000000..4f71a4c --- /dev/null +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -0,0 +1,39 @@ +setRules([ + 'name' => Str::required()->min(3)->max(20)->unique('users', 'name'), + 'email' => Email::required()->max(100)->unique('users', 'email'), + 'password' => Password::required()->secure(static fn (): bool => App::isProduction())->confirmed(), + ]); + + if ($validator->fails()) { + return response()->json([ + 'errors' => $validator->failing(), + ], HttpStatus::UNPROCESSABLE_ENTITY); + } + + $user = User::create($validator->validated()); + + return response()->json($user, HttpStatus::CREATED); + } +} diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php new file mode 100644 index 0000000..0725db9 --- /dev/null +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -0,0 +1,18 @@ +handleRequest($request); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 3936086..881f0d6 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,11 +4,13 @@ namespace App\Models; -use App\Collections\UserCollection; use App\Queries\UserQuery; use Phenix\Database\Models\Attributes\Column; +use Phenix\Database\Models\Attributes\DateTime; +use Phenix\Database\Models\Attributes\Hidden; use Phenix\Database\Models\Attributes\Id; use Phenix\Database\Models\DatabaseModel; +use Phenix\Util\Date; class User extends DatabaseModel { @@ -21,9 +23,15 @@ class User extends DatabaseModel #[Column] public string $email; - #[Column] + #[Hidden] public string $password; + #[DateTime(name: 'created_at', autoInit: true)] + public Date $createdAt; + + #[DateTime(name: 'updated_at')] + public Date|null $updatedAt = null; + public static function table(): string { return 'users'; @@ -33,9 +41,4 @@ protected static function newQueryBuilder(): UserQuery { return new UserQuery(); } - - public function newCollection(): UserCollection - { - return new UserCollection(); - } } diff --git a/routes/api.php b/routes/api.php index 78c6136..e2b082b 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,7 +2,14 @@ declare(strict_types=1); +use App\Http\Controllers\Auth\RegisterController; use App\Http\Controllers\WelcomeController; +use App\Http\Middleware\RedirectIfAuthenticated; use Phenix\Facades\Route; +use Phenix\Routing\Route as Router; Route::get('/', [WelcomeController::class, 'index']); + +Route::middleware(RedirectIfAuthenticated::class)->group(function (Router $router): void { + $router->post('register', [RegisterController::class, 'store']); +}); From 32615ba3659854fcb2f90402d3768c7cf34ca7e6 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 24 Oct 2025 14:58:57 -0500 Subject: [PATCH 064/133] feat: add user registration test --- composer.lock | 49 ++++++++++++++--------------- tests/Feature/Auth/RegisterTest.php | 29 +++++++++++++++++ 2 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 tests/Feature/Auth/RegisterTest.php diff --git a/composer.lock b/composer.lock index 239624b..18ca3da 100644 --- a/composer.lock +++ b/composer.lock @@ -2117,7 +2117,7 @@ }, { "name": "cakephp/core", - "version": "5.2.8", + "version": "5.2.9", "source": { "type": "git", "url": "https://github.com/cakephp/core.git", @@ -2184,16 +2184,16 @@ }, { "name": "cakephp/database", - "version": "5.2.8", + "version": "5.2.9", "source": { "type": "git", "url": "https://github.com/cakephp/database.git", - "reference": "e0ac72732221e74a66398ca71e4b5f56e76130fc" + "reference": "3027321fdd696cba09b1cad536f89e90f6c6693f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/database/zipball/e0ac72732221e74a66398ca71e4b5f56e76130fc", - "reference": "e0ac72732221e74a66398ca71e4b5f56e76130fc", + "url": "https://api.github.com/repos/cakephp/database/zipball/3027321fdd696cba09b1cad536f89e90f6c6693f", + "reference": "3027321fdd696cba09b1cad536f89e90f6c6693f", "shasum": "" }, "require": { @@ -2247,11 +2247,11 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/database" }, - "time": "2025-09-24T02:31:06+00:00" + "time": "2025-10-15T09:58:33+00:00" }, { "name": "cakephp/datasource", - "version": "5.2.8", + "version": "5.2.9", "source": { "type": "git", "url": "https://github.com/cakephp/datasource.git", @@ -2318,7 +2318,7 @@ }, { "name": "cakephp/utility", - "version": "5.2.8", + "version": "5.2.9", "source": { "type": "git", "url": "https://github.com/cakephp/utility.git", @@ -3814,12 +3814,12 @@ "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "2f7223b6b4789e8bee4c4971a10f915636766c65" + "reference": "9a078e26ee528b136bb99d9aaa3d6eecb3592571" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/2f7223b6b4789e8bee4c4971a10f915636766c65", - "reference": "2f7223b6b4789e8bee4c4971a10f915636766c65", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/9a078e26ee528b136bb99d9aaa3d6eecb3592571", + "reference": "9a078e26ee528b136bb99d9aaa3d6eecb3592571", "shasum": "" }, "require": { @@ -3896,7 +3896,7 @@ "issues": "https://github.com/phenixphp/framework/issues", "source": "https://github.com/phenixphp/framework/tree/develop" }, - "time": "2025-10-07T17:16:04+00:00" + "time": "2025-10-24T19:45:28+00:00" }, { "name": "phenixphp/http-cors", @@ -7798,16 +7798,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.88.2", + "version": "v3.89.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99" + "reference": "f34967da2866ace090a2b447de1f357356474573" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a8d15584bafb0f0d9d938827840060fd4a3ebc99", - "reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/f34967da2866ace090a2b447de1f357356474573", + "reference": "f34967da2866ace090a2b447de1f357356474573", "shasum": "" }, "require": { @@ -7822,7 +7822,6 @@ "php": "^7.4 || ^8.0", "react/child-process": "^0.6.6", "react/event-loop": "^1.5", - "react/promise": "^3.3", "react/socket": "^1.16", "react/stream": "^1.4", "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", @@ -7890,7 +7889,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.88.2" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.89.1" }, "funding": [ { @@ -7898,7 +7897,7 @@ "type": "github" } ], - "time": "2025-09-27T00:24:15+00:00" + "time": "2025-10-24T12:05:10+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -8156,16 +8155,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.1", + "version": "v5.6.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + "reference": "3a454ca033b9e06b63282ce19562e892747449bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb", "shasum": "" }, "require": { @@ -8208,9 +8207,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" }, - "time": "2025-08-13T20:13:15+00:00" + "time": "2025-10-21T19:32:17+00:00" }, { "name": "nunomaduro/collision", diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php new file mode 100644 index 0000000..859de63 --- /dev/null +++ b/tests/Feature/Auth/RegisterTest.php @@ -0,0 +1,29 @@ + faker()->name(), + 'email' => faker()->email(), + 'password' => 'P@ssw0rd', + 'password_confirmation' => 'P@ssw0rd', + ]; + + $response = post('/register', $data); + + $response->assertCreated() + ->assertJsonContains([ + 'name' => $data['name'], + 'email' => $data['email'], + ], 'data'); + + $this->assertDatabaseHas('users', [ + 'email' => $data['email'], + ]); +}); From 6aa75c1943872c55c2dd407b6034ed96c682d671 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 27 Oct 2025 15:09:47 -0500 Subject: [PATCH 065/133] feat: implement email verification for user registration --- .../Controllers/Auth/RegisterController.php | 1 + app/Mail/VerifyEmail.php | 21 +++++++++++++++++++ app/Models/User.php | 8 +++++++ resources/views/emails/email.php | 13 ++++++++++++ resources/views/emails/verify.php | 13 ++++++++++++ storage/framework/views/.gitignore | 2 ++ tests/Feature/Auth/RegisterTest.php | 9 +++++++- 7 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 app/Mail/VerifyEmail.php create mode 100644 resources/views/emails/email.php create mode 100644 resources/views/emails/verify.php create mode 100644 storage/framework/views/.gitignore diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 4f71a4c..338e1b6 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -33,6 +33,7 @@ public function store(Request $request): Response } $user = User::create($validator->validated()); + $user->sendVerificationEmail(); return response()->json($user, HttpStatus::CREATED); } diff --git a/app/Mail/VerifyEmail.php b/app/Mail/VerifyEmail.php new file mode 100644 index 0000000..d5aaab3 --- /dev/null +++ b/app/Mail/VerifyEmail.php @@ -0,0 +1,21 @@ +view('emails.verify', [ + 'title' => 'Verify Your Email Address', + 'message' => 'Please click the button below to verify your email address.', + 'actionText' => 'Verify Email', + 'actionUrl' => 'https://example.com/verify?token=some-token', + ]) + ->subject('Verify Your Email Address'); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 881f0d6..636bb01 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,12 +4,14 @@ namespace App\Models; +use App\Mail\VerifyEmail; use App\Queries\UserQuery; use Phenix\Database\Models\Attributes\Column; use Phenix\Database\Models\Attributes\DateTime; use Phenix\Database\Models\Attributes\Hidden; use Phenix\Database\Models\Attributes\Id; use Phenix\Database\Models\DatabaseModel; +use Phenix\Facades\Mail; use Phenix\Util\Date; class User extends DatabaseModel @@ -37,6 +39,12 @@ public static function table(): string return 'users'; } + public function sendVerificationEmail(): void + { + Mail::to($this->email) + ->send(new VerifyEmail()); + } + protected static function newQueryBuilder(): UserQuery { return new UserQuery(); diff --git a/resources/views/emails/email.php b/resources/views/emails/email.php new file mode 100644 index 0000000..5f4fb78 --- /dev/null +++ b/resources/views/emails/email.php @@ -0,0 +1,13 @@ + + + + + @yield('title') + + + + + @yield('content') + + + diff --git a/resources/views/emails/verify.php b/resources/views/emails/verify.php new file mode 100644 index 0000000..c4671ac --- /dev/null +++ b/resources/views/emails/verify.php @@ -0,0 +1,13 @@ +@extends('emails.email') + +@section('title', $title) + +@section('content') +

{{ $title }}

+

{{ $message }}

+

+ + {{ $actionText }} + +

+@endsection diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php index 859de63..6c97a12 100644 --- a/tests/Feature/Auth/RegisterTest.php +++ b/tests/Feature/Auth/RegisterTest.php @@ -2,12 +2,17 @@ declare(strict_types=1); -use function Pest\Faker\faker; +use App\Mail\VerifyEmail; +use Phenix\Facades\Mail; use Phenix\Testing\Concerns\InteractWithDatabase; +use function Pest\Faker\faker; + uses(InteractWithDatabase::class); it('registers a user', function (): void { + Mail::fake(); + $data = [ 'name' => faker()->name(), 'email' => faker()->email(), @@ -26,4 +31,6 @@ $this->assertDatabaseHas('users', [ 'email' => $data['email'], ]); + + Mail::expect(VerifyEmail::class)->toBeSent(); }); From cb7756973a30817cb23e8d7520d4f2b4dc32ede6 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 27 Oct 2025 15:09:55 -0500 Subject: [PATCH 066/133] feat: add mail configuration to .env.example --- .env.example | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.env.example b/.env.example index 58cb2fe..63f1619 100644 --- a/.env.example +++ b/.env.example @@ -23,3 +23,12 @@ REDIS_PORT=6379 REDIS_PASSWORD=null SESSION_DRIVER=local + +MAIL_MAILER=smtp +MAIL_HOST=127.0.0.1 +MAIL_PORT=587 +MAIL_ENCRYPTION=tls +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_FROM_ADDRESS=hello@example.com +MAIL_FROM_NAME="Example" From 1e3f5d0b2e0be2633320c4f20b08892699b6f9a7 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 27 Oct 2025 17:07:09 -0500 Subject: [PATCH 067/133] feat: add RefreshDatabase trait to RegisterTest for improved test isolation --- tests/Feature/Auth/RegisterTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php index 6c97a12..d8c6275 100644 --- a/tests/Feature/Auth/RegisterTest.php +++ b/tests/Feature/Auth/RegisterTest.php @@ -5,10 +5,12 @@ use App\Mail\VerifyEmail; use Phenix\Facades\Mail; use Phenix\Testing\Concerns\InteractWithDatabase; +use Phenix\Testing\Concerns\RefreshDatabase; use function Pest\Faker\faker; uses(InteractWithDatabase::class); +uses(RefreshDatabase::class); it('registers a user', function (): void { Mail::fake(); From b16f4fcb2ac29c5e4d52a997ecd673b41e12c820 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 27 Oct 2025 18:13:35 -0500 Subject: [PATCH 068/133] refactor: improve readability of getEnvFile method in TestCase --- tests/TestCase.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index c96c53b..d7e6396 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -29,6 +29,8 @@ protected function getAppDir(): string protected function getEnvFile(): string|null { - return file_exists($this->getAppDir() . '/.env.testing') ? 'testing' : null; + $path = $this->getAppDir() . DIRECTORY_SEPARATOR . '.env.testing'; + + return file_exists($path) ? 'testing' : null; } } From 5f087eb53e370e3c2363e32a230f1c475d12983e Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 5 Nov 2025 18:14:17 -0500 Subject: [PATCH 069/133] refactor: remove unused InteractWithDatabase trait from RegisterTest --- tests/Feature/Auth/RegisterTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php index d8c6275..db3c564 100644 --- a/tests/Feature/Auth/RegisterTest.php +++ b/tests/Feature/Auth/RegisterTest.php @@ -4,12 +4,10 @@ use App\Mail\VerifyEmail; use Phenix\Facades\Mail; -use Phenix\Testing\Concerns\InteractWithDatabase; use Phenix\Testing\Concerns\RefreshDatabase; use function Pest\Faker\faker; -uses(InteractWithDatabase::class); uses(RefreshDatabase::class); it('registers a user', function (): void { From 4c50b45f396a0321fdef187406c84a4348f78cef Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 5 Nov 2025 18:14:22 -0500 Subject: [PATCH 070/133] refactor: update test case binding to use AsyncTestCase for unit tests --- tests/Pest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Pest.php b/tests/Pest.php index 48b715c..706f81d 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -16,8 +16,9 @@ use Phenix\Http\Constants\HttpMethod; use Phenix\Testing\TestResponse; use Phenix\Util\URL; +use Amp\PHPUnit\AsyncTestCase; -uses(Tests\TestCase::class)->in('Unit'); +uses(AsyncTestCase::class)->in('Unit'); uses(Tests\TestCase::class)->in('Feature'); /* From 29c22240cd2bb28a5f8bee0d068449aeeec6da3d Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 7 Nov 2025 07:39:58 -0500 Subject: [PATCH 071/133] feat: enhance email validation in RegisterController with DNS and RFC checks --- app/Http/Controllers/Auth/RegisterController.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 338e1b6..be5c672 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -5,6 +5,8 @@ namespace App\Http\Controllers\Auth; use App\Models\User; +use Egulias\EmailValidator\Validation\DNSCheckValidation; +use Egulias\EmailValidator\Validation\NoRFCWarningsValidation; use Phenix\App; use Phenix\Http\Constants\HttpStatus; use Phenix\Http\Controller; @@ -22,7 +24,10 @@ public function store(Request $request): Response $validator = new Validator($request); $validator->setRules([ 'name' => Str::required()->min(3)->max(20)->unique('users', 'name'), - 'email' => Email::required()->max(100)->unique('users', 'email'), + 'email' => Email::required()->validations( + new DNSCheckValidation(), + new NoRFCWarningsValidation() + )->max(100)->unique('users', 'email'), 'password' => Password::required()->secure(static fn (): bool => App::isProduction())->confirmed(), ]); From 1f5a66b44fbbdbb556b5648c1d6cd9622eb402e5 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 7 Nov 2025 07:40:16 -0500 Subject: [PATCH 072/133] refactor: update user table migration to use fluent column definitions for improved clarity --- .../migrations/20241217160717_create_user_table.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/database/migrations/20241217160717_create_user_table.php b/database/migrations/20241217160717_create_user_table.php index 3f136c4..3ee9474 100644 --- a/database/migrations/20241217160717_create_user_table.php +++ b/database/migrations/20241217160717_create_user_table.php @@ -9,11 +9,11 @@ class CreateUserTable extends Migration public function up(): void { $table = $this->table('users'); - $table->addColumn('name', 'string', ['limit' => 100]); - $table->addColumn('email', 'string', ['limit' => 100]); - $table->addColumn('password', 'string', ['limit' => 255]); - $table->addColumn('created_at', 'datetime', ['null' => true]); - $table->addColumn('updated_at', 'datetime', ['null' => true]); + $table->string('name', 100); + $table->string('email', 124)->unique(); + $table->string('password', 255); + $table->dateTime('email_verified_at')->nullable(); + $table->timestamps(); $table->create(); } From 1498ae32867217225fdb72732727cabdada4e7ea Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 7 Nov 2025 07:51:43 -0500 Subject: [PATCH 073/133] feat: implement OneTimePasswordScope enum and UserOtp model with migration --- app/Constants/OneTimePasswordScope.php | 21 +++++++++++++++ app/Models/UserOtp.php | 21 +++++++++++++++ app/Queries/UserOtpQuery.php | 12 +++++++++ ...20251028132601_user_one_time_passwords.php | 26 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 app/Constants/OneTimePasswordScope.php create mode 100644 app/Models/UserOtp.php create mode 100644 app/Queries/UserOtpQuery.php create mode 100644 database/migrations/20251028132601_user_one_time_passwords.php diff --git a/app/Constants/OneTimePasswordScope.php b/app/Constants/OneTimePasswordScope.php new file mode 100644 index 0000000..a979f1b --- /dev/null +++ b/app/Constants/OneTimePasswordScope.php @@ -0,0 +1,21 @@ +table('user_one_time_passwords'); + $table->enum('scope', OneTimePasswordScope::toArray()); + $table->string('code', 255); + $table->unsignedInteger('user_id'); + $table->datetime('expires_at'); + $table->datetime('used_at')->nullable(); + $table->timestamps(); + $table->create(); + } + + public function down(): void + { + $this->table('user_one_time_passwords')->drop(); + } +} \ No newline at end of file From 5ea3721517bf5bcc6618340152e8e3765d434211 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 7 Nov 2025 08:39:25 -0500 Subject: [PATCH 074/133] refactor: enhance user_one_time_passwords migration with primary key and foreign key constraints --- .../migrations/20251028132601_user_one_time_passwords.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/database/migrations/20251028132601_user_one_time_passwords.php b/database/migrations/20251028132601_user_one_time_passwords.php index 03db619..8703985 100644 --- a/database/migrations/20251028132601_user_one_time_passwords.php +++ b/database/migrations/20251028132601_user_one_time_passwords.php @@ -3,16 +3,22 @@ declare(strict_types=1); use App\Constants\OneTimePasswordScope; +use Phenix\Database\Constants\ColumnAction; use Phenix\Database\Migration; class UserOneTimePasswords extends Migration { public function up(): void { - $table = $this->table('user_one_time_passwords'); + $table = $this->table('user_one_time_passwords', ['id' => false, 'primary_key' => 'id']); + $table->uuid('id'); $table->enum('scope', OneTimePasswordScope::toArray()); $table->string('code', 255); $table->unsignedInteger('user_id'); + $table->foreign('user_id') + ->references('id') + ->on('users') + ->onDelete(ColumnAction::CASCADE); $table->datetime('expires_at'); $table->datetime('used_at')->nullable(); $table->timestamps(); From 966e083e2d79b2794e02b3ea3168579966b32e65 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 7 Nov 2025 17:24:51 -0500 Subject: [PATCH 075/133] refactor: update user creation logic in RegisterController to use explicit property assignment --- app/Http/Controllers/Auth/RegisterController.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index be5c672..96a228c 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -4,10 +4,12 @@ namespace App\Http\Controllers\Auth; +use App\Constants\OneTimePasswordScope; use App\Models\User; use Egulias\EmailValidator\Validation\DNSCheckValidation; use Egulias\EmailValidator\Validation\NoRFCWarningsValidation; use Phenix\App; +use Phenix\Facades\Hash; use Phenix\Http\Constants\HttpStatus; use Phenix\Http\Controller; use Phenix\Http\Request; @@ -37,8 +39,13 @@ public function store(Request $request): Response ], HttpStatus::UNPROCESSABLE_ENTITY); } - $user = User::create($validator->validated()); - $user->sendVerificationEmail(); + $user = new User(); + $user->name = $request->body('name'); + $user->email = $request->body('email'); + $user->password = Hash::make($request->body('password')); + $user->save(); + + $user->sendOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); return response()->json($user, HttpStatus::CREATED); } From ff616511d12c86711f488ef18c8e31450aa65293 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 7 Nov 2025 17:27:00 -0500 Subject: [PATCH 076/133] feat: implement One-Time Password (OTP) functionality with email verification and login support --- app/Mail/SendEmailVerificationOtp.php | 26 +++++ app/Mail/SendLoginOtp.php | 26 +++++ app/Mail/VerifyEmail.php | 21 ---- app/Models/User.php | 33 +++++- app/Models/UserOtp.php | 54 ++++++++++ app/lang/en/auth.php | 35 +++++++ config/auth.php | 9 ++ resources/views/emails/email.php | 143 +++++++++++++++++++++++++- resources/views/emails/otp.php | 13 +++ resources/views/emails/verify.php | 13 --- 10 files changed, 331 insertions(+), 42 deletions(-) create mode 100644 app/Mail/SendEmailVerificationOtp.php create mode 100644 app/Mail/SendLoginOtp.php delete mode 100644 app/Mail/VerifyEmail.php create mode 100644 app/lang/en/auth.php create mode 100644 config/auth.php create mode 100644 resources/views/emails/otp.php delete mode 100644 resources/views/emails/verify.php diff --git a/app/Mail/SendEmailVerificationOtp.php b/app/Mail/SendEmailVerificationOtp.php new file mode 100644 index 0000000..818e516 --- /dev/null +++ b/app/Mail/SendEmailVerificationOtp.php @@ -0,0 +1,26 @@ +view('emails.otp', [ + 'title' => trans('auth.otp.email_verification.title'), + 'message' => trans('auth.otp.email_verification.message'), + 'otp' => $this->userOtp->otp, + ]) + ->subject(trans('auth.otp.email_verification.subject')); + } +} diff --git a/app/Mail/SendLoginOtp.php b/app/Mail/SendLoginOtp.php new file mode 100644 index 0000000..863a1a1 --- /dev/null +++ b/app/Mail/SendLoginOtp.php @@ -0,0 +1,26 @@ +view('emails.otp', [ + 'title' => trans('auth.otp.login.title'), + 'message' => trans('auth.otp.login.message'), + 'otp' => $this->userOtp->otp, + ]) + ->subject(trans('auth.otp.login.subject')); + } +} diff --git a/app/Mail/VerifyEmail.php b/app/Mail/VerifyEmail.php deleted file mode 100644 index d5aaab3..0000000 --- a/app/Mail/VerifyEmail.php +++ /dev/null @@ -1,21 +0,0 @@ -view('emails.verify', [ - 'title' => 'Verify Your Email Address', - 'message' => 'Please click the button below to verify your email address.', - 'actionText' => 'Verify Email', - 'actionUrl' => 'https://example.com/verify?token=some-token', - ]) - ->subject('Verify Your Email Address'); - } -} diff --git a/app/Models/User.php b/app/Models/User.php index 636bb01..bc59c53 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,7 +4,9 @@ namespace App\Models; -use App\Mail\VerifyEmail; +use App\Constants\OneTimePasswordScope; +use App\Mail\SendEmailVerificationOtp; +use App\Mail\SendLoginOtp; use App\Queries\UserQuery; use Phenix\Database\Models\Attributes\Column; use Phenix\Database\Models\Attributes\DateTime; @@ -12,6 +14,7 @@ use Phenix\Database\Models\Attributes\Id; use Phenix\Database\Models\DatabaseModel; use Phenix\Facades\Mail; +use Phenix\Mail\Mailable; use Phenix\Util\Date; class User extends DatabaseModel @@ -39,14 +42,34 @@ public static function table(): string return 'users'; } - public function sendVerificationEmail(): void + protected static function newQueryBuilder(): UserQuery + { + return new UserQuery(); + } + + public function createOneTimePassword(OneTimePasswordScope $scope): UserOtp + { + $userOtp = UserOtp::make($scope); + $userOtp->userId = $this->id; + $userOtp->save(); + + return $userOtp; + } + + public function sendOneTimePassword(OneTimePasswordScope $scope): void { + $userOtp = $this->createOneTimePassword($scope); + $mailable = $this->resolveMailable($scope, $userOtp); + Mail::to($this->email) - ->send(new VerifyEmail()); + ->send($mailable); } - protected static function newQueryBuilder(): UserQuery + protected function resolveMailable(OneTimePasswordScope $scope, UserOtp $userOtp): Mailable { - return new UserQuery(); + return match ($scope) { + OneTimePasswordScope::VERIFY_EMAIL => new SendEmailVerificationOtp($userOtp), + OneTimePasswordScope::LOGIN => new SendLoginOtp($userOtp), + }; } } diff --git a/app/Models/UserOtp.php b/app/Models/UserOtp.php index 3b6cd66..4d35eec 100644 --- a/app/Models/UserOtp.php +++ b/app/Models/UserOtp.php @@ -4,11 +4,47 @@ namespace App\Models; +use App\Constants\OneTimePasswordScope; use App\Queries\UserOtpQuery; +use Phenix\Database\Models\Attributes\BelongsTo; +use Phenix\Database\Models\Attributes\Column; +use Phenix\Database\Models\Attributes\DateTime; +use Phenix\Database\Models\Attributes\ForeignKey; +use Phenix\Database\Models\Attributes\Id; use Phenix\Database\Models\DatabaseModel; +use Phenix\Util\Date; class UserOtp extends DatabaseModel { + #[Id] + public string $id; + + #[Column] + public string $scope; + + #[Column] + public string $code; + + #[ForeignKey(name: 'user_id')] + public int $userId; + + #[BelongsTo(foreignProperty: 'userId')] + public User $user; + + #[DateTime(name: 'expires_at')] + public Date $expiresAt; + + #[DateTime(name: 'used_at')] + public Date|null $usedAt = null; + + #[DateTime(name: 'created_at', autoInit: true)] + public Date $createdAt; + + #[DateTime(name: 'updated_at')] + public Date|null $updatedAt = null; + + public int $otp; + public static function table(): string { return 'user_one_time_passwords'; @@ -18,4 +54,22 @@ protected static function newQueryBuilder(): UserOtpQuery { return new UserOtpQuery(); } + + public static function make(OneTimePasswordScope $scope): self + { + $value = random_int(100000, 999999); + + $otp = new self(); + $otp->scope = $scope->value; + $otp->code = hash('sha256', (string) $value); + $otp->expiresAt = Date::now()->addMinutes(env('')); + $otp->otp = $value; + + return $otp; + } + + public function getScope(): OneTimePasswordScope + { + return OneTimePasswordScope::from($this->scope); + } } diff --git a/app/lang/en/auth.php b/app/lang/en/auth.php new file mode 100644 index 0000000..b90644c --- /dev/null +++ b/app/lang/en/auth.php @@ -0,0 +1,35 @@ + [ + 'email_verification' => [ + 'title' => 'Verify Your Email Address', + 'subject' => 'Verify Your Email Address', + 'message' => 'Please use the following One-Time Password (OTP) to verify your email address:', + ], + 'login' => [ + 'title' => 'Login Verification Code', + 'subject' => 'Login Verification Code', + 'message' => 'Please use the following One-Time Password (OTP) to log in to your account:', + ], + 'label' => 'Your one-time password code', + 'expiry' => 'Valid for :minutes minutes', + 'sent' => 'A verification code has been sent to your email address.', + 'verified' => 'Your verification code has been confirmed successfully.', + 'expired' => 'The verification code has expired. Please request a new one.', + 'invalid' => 'The verification code is invalid.', + 'already_used' => 'This verification code has already been used.', + ], + + 'security' => [ + 'warning' => '⚠️ For your security:', + 'never_share' => 'Never share this code with anyone. Our team will never ask you for your verification code.', + 'ignore_if_not_requested' => 'If you didn\'t request this verification, please ignore this email.', + ], + + 'footer' => [ + 'copyright' => ':year :appName. All rights reserved.', + ], +]; diff --git a/config/auth.php b/config/auth.php new file mode 100644 index 0000000..5667c14 --- /dev/null +++ b/config/auth.php @@ -0,0 +1,9 @@ + [ + 'expiration' => 10, // in minutes + ], +]; diff --git a/resources/views/emails/email.php b/resources/views/emails/email.php index 5f4fb78..3b797de 100644 --- a/resources/views/emails/email.php +++ b/resources/views/emails/email.php @@ -2,12 +2,149 @@ - @yield('title') + + @yield('title') + - @yield('content') - + + diff --git a/resources/views/emails/otp.php b/resources/views/emails/otp.php new file mode 100644 index 0000000..9573d99 --- /dev/null +++ b/resources/views/emails/otp.php @@ -0,0 +1,13 @@ +@extends('emails.email') + +@section('title', $title) + +@section('content') +

{{ $message }}

+ +
+ {{ trans('auth.otp.label') }} +
{{ $otp }}
+

{{ trans('auth.otp.expiry', ['minutes' => config('auth.otp.expiration')]) }}

+
+@endsection diff --git a/resources/views/emails/verify.php b/resources/views/emails/verify.php deleted file mode 100644 index c4671ac..0000000 --- a/resources/views/emails/verify.php +++ /dev/null @@ -1,13 +0,0 @@ -@extends('emails.email') - -@section('title', $title) - -@section('content') -

{{ $title }}

-

{{ $message }}

-

- - {{ $actionText }} - -

-@endsection From f342fc41d7f5a93c7f4d4343a253b2471b8b5bbe Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 7 Nov 2025 17:27:05 -0500 Subject: [PATCH 077/133] refactor: update email verification mail class in RegisterTest to use SendEmailVerificationOtp --- tests/Feature/Auth/RegisterTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php index db3c564..772dc43 100644 --- a/tests/Feature/Auth/RegisterTest.php +++ b/tests/Feature/Auth/RegisterTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use App\Mail\VerifyEmail; +use App\Mail\SendEmailVerificationOtp; use Phenix\Facades\Mail; use Phenix\Testing\Concerns\RefreshDatabase; @@ -32,5 +32,5 @@ 'email' => $data['email'], ]); - Mail::expect(VerifyEmail::class)->toBeSent(); + Mail::expect(SendEmailVerificationOtp::class)->toBeSent(); }); From cf127d6ee7a37d456e812de909646b64bb18b84f Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 7 Nov 2025 17:27:11 -0500 Subject: [PATCH 078/133] style: php cs --- tests/Pest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Pest.php b/tests/Pest.php index 706f81d..22f4a36 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -13,10 +13,10 @@ use Amp\Http\Client\HttpClientBuilder; use Amp\Http\Client\Request; +use Amp\PHPUnit\AsyncTestCase; use Phenix\Http\Constants\HttpMethod; use Phenix\Testing\TestResponse; use Phenix\Util\URL; -use Amp\PHPUnit\AsyncTestCase; uses(AsyncTestCase::class)->in('Unit'); uses(Tests\TestCase::class)->in('Feature'); From 287d1abc1dbc2bcd4589685b4e8ff91af0000e95 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 5 Jan 2026 17:47:39 -0500 Subject: [PATCH 079/133] refactor: update config files --- config/app.php | 66 ++++++++++++++++++++++++++++++++++++++++++--- config/auth.php | 12 +++++++++ config/cache.php | 55 +++++++++++++++++++++++++++++++++++++ config/cors.php | 4 ++- config/database.php | 22 ++++++++------- config/mail.php | 4 ++- config/queue.php | 2 ++ config/services.php | 2 ++ config/session.php | 6 ++--- 9 files changed, 156 insertions(+), 17 deletions(-) create mode 100644 config/cache.php diff --git a/config/app.php b/config/app.php index d0b5a58..0a3f2bd 100644 --- a/config/app.php +++ b/config/app.php @@ -7,29 +7,89 @@ 'env' => env('APP_ENV', static fn (): string => 'local'), 'url' => env('APP_URL', static fn (): string => 'http://127.0.0.1'), 'port' => env('APP_PORT', static fn (): int => 1337), + 'cert_path' => env('APP_CERT_PATH', static fn (): string|null => null), 'key' => env('APP_KEY'), 'previous_key' => env('APP_PREVIOUS_KEY'), + + /* + |-------------------------------------------------------------------------- + | App mode + |-------------------------------------------------------------------------- + | Controls how the HTTP server determines client connection details. + | + | direct: + | The server is exposed directly to clients. Remote address, scheme, + | and host are taken from the TCP connection and request line. + | + | proxied: + | The server runs behind a reverse proxy or load balancer (e.g., Nginx, + | HAProxy, AWS ALB). Client information is derived from standard + | forwarding headers only when the request comes from a trusted proxy. + | Configure trusted proxies in `trusted_proxies` (IP addresses or CIDRs). + | When enabled, the server will honor `Forwarded`, `X-Forwarded-For`, + | `X-Forwarded-Proto`, and `X-Forwarded-Host` headers from trusted + | sources, matching Amphp's behind-proxy behavior. + | + | Supported values: "direct", "proxied" + | + */ + + 'app_mode' => env('APP_MODE', static fn (): string => 'direct'), + 'trusted_proxies' => env('APP_TRUSTED_PROXIES', static fn (): array => []), + + /* + |-------------------------------------------------------------------------- + | Server runtime mode + |-------------------------------------------------------------------------- + | Controls whether the HTTP server runs as a single process (default) or + | under amphp/cluster. + | + | Supported values: + | - "single" (single process) + | - "cluster" (run with vendor/bin/cluster and cluster sockets) + | + */ + 'server_mode' => env('APP_SERVER_MODE', static fn (): string => 'single'), 'debug' => env('APP_DEBUG', static fn (): bool => true), 'locale' => 'en', 'fallback_locale' => 'en', 'middlewares' => [ 'global' => [ \Phenix\Http\Middlewares\HandleCors::class, + \Phenix\Cache\RateLimit\Middlewares\RateLimiter::class, + \Phenix\Auth\Middlewares\TokenRateLimit::class, + ], + 'router' => [ + \Phenix\Http\Middlewares\ResponseHeaders::class, ], - 'router' => [], ], 'providers' => [ + \Phenix\Filesystem\FilesystemServiceProvider::class, \Phenix\Console\CommandsServiceProvider::class, \Phenix\Routing\RouteServiceProvider::class, \Phenix\Database\DatabaseServiceProvider::class, \Phenix\Redis\RedisServiceProvider::class, - \Phenix\Filesystem\FilesystemServiceProvider::class, + \Phenix\Auth\AuthServiceProvider::class, \Phenix\Tasks\TaskServiceProvider::class, \Phenix\Views\ViewServiceProvider::class, + \Phenix\Cache\CacheServiceProvider::class, \Phenix\Mail\MailServiceProvider::class, \Phenix\Crypto\CryptoServiceProvider::class, \Phenix\Queue\QueueServiceProvider::class, \Phenix\Events\EventServiceProvider::class, \Phenix\Translation\TranslationServiceProvider::class, + \Phenix\Scheduling\SchedulingServiceProvider::class, + \Phenix\Validation\ValidationServiceProvider::class, + ], + 'response' => [ + 'headers' => [ + \Phenix\Http\Headers\XDnsPrefetchControl::class, + \Phenix\Http\Headers\XFrameOptions::class, + \Phenix\Http\Headers\StrictTransportSecurity::class, + \Phenix\Http\Headers\XContentTypeOptions::class, + \Phenix\Http\Headers\ReferrerPolicy::class, + \Phenix\Http\Headers\CrossOriginResourcePolicy::class, + \Phenix\Http\Headers\CrossOriginOpenerPolicy::class, + ], ], -]; +]; \ No newline at end of file diff --git a/config/auth.php b/config/auth.php index 5667c14..6ea9fd3 100644 --- a/config/auth.php +++ b/config/auth.php @@ -3,6 +3,18 @@ declare(strict_types=1); return [ + 'users' => [ + 'model' => Phenix\Auth\User::class, + ], + 'tokens' => [ + 'model' => Phenix\Auth\PersonalAccessToken::class, + 'prefix' => '', + 'expiration' => 60 * 12, // in minutes + 'rate_limit' => [ + 'attempts' => 5, + 'window' => 300, // window in seconds + ], + ], 'otp' => [ 'expiration' => 10, // in minutes ], diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..fa507c9 --- /dev/null +++ b/config/cache.php @@ -0,0 +1,55 @@ + env('CACHE_STORE', static fn (): string => 'local'), + + 'stores' => [ + 'local' => [ + 'size_limit' => 1024, + 'gc_interval' => 5, + ], + + 'file' => [ + 'path' => base_path('storage/framework/cache'), + ], + + 'redis' => [ + 'connection' => env('CACHE_REDIS_CONNECTION', static fn (): string => 'default'), + ], + ], + + 'prefix' => env('CACHE_PREFIX', static fn (): string => 'phenix_cache_'), + + /* + |-------------------------------------------------------------------------- + | Default Cache TTL Minutes + |-------------------------------------------------------------------------- + | + | This option controls the default time-to-live (TTL) in minutes for cache + | items. It is used as the default expiration time for all cache stores + | unless a specific TTL is provided when setting a cache item. + */ + 'ttl' => env('CACHE_TTL', static fn (): int => 60), + + 'rate_limit' => [ + 'enabled' => env('RATE_LIMIT_ENABLED', static fn (): bool => true), + 'store' => env('RATE_LIMIT_STORE', static fn (): string => 'local'), + 'per_minute' => env('RATE_LIMIT_PER_MINUTE', static fn (): int => 60), + 'connection' => env('RATE_LIMIT_REDIS_CONNECTION', static fn (): string => 'default'), + ], +]; diff --git a/config/cors.php b/config/cors.php index 105b1ab..bf3b368 100644 --- a/config/cors.php +++ b/config/cors.php @@ -1,7 +1,9 @@ env('CORS_ORIGIN', static fn (): array => ['http://localhost', 'http://127.0.0.1']), + 'origins' => env('CORS_ORIGIN', static fn (): array => ['*']), 'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE'], 'max_age' => 8600, 'allowed_headers' => ['X-Request-Headers', 'Content-Type', 'Authorization', 'X-Requested-With'], diff --git a/config/database.php b/config/database.php index ad69ccf..10d3db7 100644 --- a/config/database.php +++ b/config/database.php @@ -3,13 +3,17 @@ declare(strict_types=1); return [ - 'default' => env('DB_CONNECTION', static fn (): string => 'mysql'), + 'default' => env('DB_CONNECTION', static fn () => 'mysql'), 'connections' => [ + 'sqlite' => [ + 'driver' => 'sqlite', + 'database' => env('DB_DATABASE', static fn () => base_path('database/database')), + ], 'mysql' => [ 'driver' => 'mysql', - 'host' => env('DB_HOST', static fn (): string => '127.0.0.1'), - 'port' => env('DB_PORT', static fn (): string => '3306'), + 'host' => env('DB_HOST', static fn () => '127.0.0.1'), + 'port' => env('DB_PORT', static fn () => '3306'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), @@ -20,8 +24,8 @@ ], 'postgresql' => [ 'driver' => 'postgresql', - 'host' => env('DB_HOST', static fn (): string => '127.0.0.1'), - 'port' => env('DB_PORT', static fn (): string => '5432'), + 'host' => env('DB_HOST', static fn () => '127.0.0.1'), + 'port' => env('DB_PORT', static fn () => '5432'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), @@ -36,12 +40,12 @@ 'redis' => [ 'connections' => [ 'default' => [ - 'scheme' => env('REDIS_SCHEME', static fn (): string => 'redis'), - 'host' => env('REDIS_HOST', static fn (): string => '127.0.0.1'), + 'scheme' => env('REDIS_SCHEME', static fn () => 'redis'), + 'host' => env('REDIS_HOST', static fn () => '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), - 'port' => env('REDIS_PORT', static fn (): string => '6379'), - 'database' => env('REDIS_DB', static fn (): int => 0), + 'port' => env('REDIS_PORT', static fn () => '6379'), + 'database' => env('REDIS_DB', static fn () => 0), ], ], ], diff --git a/config/mail.php b/config/mail.php index bdef847..6e77b62 100644 --- a/config/mail.php +++ b/config/mail.php @@ -1,5 +1,7 @@ env('MAIL_MAILER', static fn (): string => 'smtp'), @@ -27,4 +29,4 @@ 'address' => env('MAIL_FROM_ADDRESS', static fn (): string => 'hello@example.com'), 'name' => env('MAIL_FROM_NAME', static fn (): string => 'Example'), ], -]; +]; \ No newline at end of file diff --git a/config/queue.php b/config/queue.php index eaec4a4..25ab32b 100644 --- a/config/queue.php +++ b/config/queue.php @@ -1,5 +1,7 @@ env('QUEUE_DRIVER', static fn (): string => 'database'), diff --git a/config/services.php b/config/services.php index f382b6a..df85bee 100644 --- a/config/services.php +++ b/config/services.php @@ -1,5 +1,7 @@ [ 'key' => env('AWS_ACCESS_KEY_ID'), diff --git a/config/session.php b/config/session.php index 87ed685..67d2f8c 100644 --- a/config/session.php +++ b/config/session.php @@ -15,7 +15,7 @@ | */ - 'driver' => env('SESSION_DRIVER', static fn (): string => 'redis'), + 'driver' => env('SESSION_DRIVER', static fn (): string => 'local'), 'lifetime' => env('SESSION_LIFETIME', static fn (): int => 120), @@ -29,11 +29,11 @@ | connection in your database configuration options. */ - 'connection' => env('SESSION_CONNECTION', static fn (): string => 'default'), + 'connection' => env('SESSION_CONNECTION', static fn () => 'default'), 'cookie_name' => env( 'SESSION_COOKIE_NAME', - static fn (): string => Str::slug(env('APP_NAME', static fn (): string => 'phenix'), '_') . '_session' + static fn (): string => Str::slug(env('APP_NAME', static fn () => 'phenix'), '_') . '_session' ), 'path' => '/', From e2cf1ad3842c503bc46bf4a07c49872066dcbdaf Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 5 Jan 2026 17:49:19 -0500 Subject: [PATCH 080/133] chore: add *.sqlite* to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d7f2b9d..083c01a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ tests/coverage node_modules npm-debug.log package-lock.json -package.json \ No newline at end of file +package.json +*.sqlite* From ba5011bc866b587cb67bfa517697194d470728e3 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 5 Jan 2026 17:49:33 -0500 Subject: [PATCH 081/133] chore: remove empty .keep file from tests/Feature directory --- tests/Feature/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/Feature/.keep diff --git a/tests/Feature/.keep b/tests/Feature/.keep deleted file mode 100644 index e69de29..0000000 From d9ae14e51bf2f56c82dc855352daa6d40963c6a5 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 10 Feb 2026 07:58:21 -0500 Subject: [PATCH 082/133] chore: add SYS_PTRACE capability and seccomp security option to app service in docker-compose --- docker-compose.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 93eb9de..d4f38ea 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,10 @@ services: context: . dockerfile: docker/Dockerfile target: local + cap_add: + - SYS_PTRACE + security_opt: + - seccomp:unconfined volumes: - .:/var/www/html:rw - /var/www/html/vendor From 1371e2a02d57b5fb0f7069c4a89525b1a5d88016 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 10 Feb 2026 22:24:16 +0000 Subject: [PATCH 083/133] feat: remove pest --- .dockerignore | 1 - .github/copilot-instructions.md | 6 +- .github/workflows/run-tests.yml | 2 +- composer.json | 13 ++--- tests/Pest.php | 97 --------------------------------- tests/Util/Mock.php | 20 ------- tests/Util/Mockery.php | 69 ----------------------- 7 files changed, 7 insertions(+), 201 deletions(-) delete mode 100644 tests/Pest.php delete mode 100644 tests/Util/Mock.php delete mode 100644 tests/Util/Mockery.php diff --git a/.dockerignore b/.dockerignore index 4ff7ed4..050314d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -42,7 +42,6 @@ coverage/ *.pid.lock .phpunit.result.cache -.pest .php_cs.cache dist/ diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 350a36c..0f0ad3f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -25,11 +25,10 @@ XDEBUG_MODE=off php public/index.php # Direct server start (faster, no debuggin ### Testing ```bash -composer test # Pest tests (XDEBUG_MODE=off) +composer test # PHPUnit tests (XDEBUG_MODE=off) composer test:coverage # With coverage reports -composer test:parallel # Parallel execution ``` -- **Test Framework**: Pest PHP with custom HTTP client helpers +- **Test Framework**: PHPUnit with custom HTTP client helpers - **Test Structure**: `tests/Feature/` and `tests/Unit/` with shared `TestCase` - **HTTP Testing**: Uses Amp HTTP client with helper functions: `get()`, `post()`, etc. @@ -133,7 +132,6 @@ class MyController extends Controller - `config/app.php` - Service provider registration and app config - `vendor/phenixphp/framework/src/Queue/` - Queue implementation details - `vendor/phenixphp/framework/src/Tasks/QueuableTask.php` - Base task class -- `tests/Pest.php` - HTTP testing helpers and setup - `bootstrap/app.php` - Application bootstrap via `AppBuilder` ## Common Pitfalls diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 49cf7b9..659c183 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -44,7 +44,7 @@ jobs: - name: Execute tests run: | cp .env.example .env - vendor/bin/pest --coverage + vendor/bin/phpunit - name: Prepare paths for SonarQube analysis run: | diff --git a/composer.json b/composer.json index bbe927b..de47b5f 100644 --- a/composer.json +++ b/composer.json @@ -24,13 +24,10 @@ }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", + "fakerphp/faker": "^1.24", "friendsofphp/php-cs-fixer": "^3.11", "mockery/mockery": "^1.6", "nunomaduro/collision": "^6.3", - "pestphp/pest": "^1.22", - "pestphp/pest-plugin-faker": "^1.0", - "pestphp/pest-plugin-global-assertions": "^1.0", - "pestphp/pest-plugin-parallel": "^1.2", "phpstan/extension-installer": "^1.2", "phpstan/phpstan": "^1.9", "phpstan/phpstan-deprecation-rules": "^1.1", @@ -45,7 +42,6 @@ "allow-plugins": { "composer/package-versions-deprecated": true, "dealerdirect/phpcodesniffer-composer-installer": true, - "pestphp/pest-plugin": true, "phpstan/extension-installer": true } }, @@ -55,10 +51,9 @@ "post-root-package-install": [ "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" ], - "test": "XDEBUG_MODE=off vendor/bin/pest", - "test:debug": "vendor/bin/pest", - "test:coverage": "XDEBUG_MODE=coverage vendor/bin/pest --coverage", - "test:parallel": "vendor/bin/pest --parallel", + "test": "XDEBUG_MODE=off vendor/bin/phpunit", + "test:debug": "vendor/bin/phpunit", + "test:coverage": "XDEBUG_MODE=coverage vendor/bin/phpunit", "format": "vendor/bin/php-cs-fixer fix", "analyze": "vendor/bin/phpstan", "dev": [ diff --git a/tests/Pest.php b/tests/Pest.php deleted file mode 100644 index 22f4a36..0000000 --- a/tests/Pest.php +++ /dev/null @@ -1,97 +0,0 @@ -in('Unit'); -uses(Tests\TestCase::class)->in('Feature'); - -/* -|-------------------------------------------------------------------------- -| Expectations -|-------------------------------------------------------------------------- -| -| When you're writing tests, you often need to check that values meet certain conditions. The -| "expect()" function gives you access to a set of "expectations" methods that you can use -| to assert different things. Of course, you may extend the Expectation API at any time. -| -*/ - -expect()->extend('toBeOne', function () { - return $this->toBe(1); -}); - -/* -|-------------------------------------------------------------------------- -| Functions -|-------------------------------------------------------------------------- -| -| While Pest is very powerful out-of-the-box, you may have some testing code specific to your -| project that you don't want to repeat in every file. Here you can also expose helpers as -| global functions to help you to reduce the number of lines of code in your test files. -| -*/ - -function call( - HttpMethod $method, - string $path, - array $parameters = [], - array|string|null $body = null, - array $headers = [] -): TestResponse { - $request = new Request(URL::build($path, $parameters), $method->value); - - if (! empty($headers)) { - $request->setHeaders($headers); - } - - if (! empty($body)) { - $body = \is_array($body) ? json_encode($body) : $body; - - $request->setBody($body); - } - - $client = HttpClientBuilder::buildDefault(); - - return new TestResponse($client->request($request)); -} - -function get(string $path, array $parameters = [], array $headers = []): TestResponse -{ - return call(method: HttpMethod::GET, path: $path, parameters: $parameters, headers: $headers); -} - -function post(string $path, array|string|null $body, array $parameters = [], array $headers = []): TestResponse -{ - return call(HttpMethod::POST, $path, $parameters, $body, $headers); -} - -function put(string $path, array|string|null $body, array $parameters = [], array $headers = []): TestResponse -{ - return call(HttpMethod::PUT, $path, $parameters, $body, $headers); -} - -function patch(string $path, array|string|null $body, array $parameters = [], array $headers = []): TestResponse -{ - return call(HttpMethod::PATCH, $path, $parameters, $body, $headers); -} - -function delete(string $path, array $parameters = [], array $headers = []): TestResponse -{ - return call(method: HttpMethod::DELETE, path: $path, parameters: $parameters, headers: $headers); -} diff --git a/tests/Util/Mock.php b/tests/Util/Mock.php deleted file mode 100644 index 1c0c14a..0000000 --- a/tests/Util/Mock.php +++ /dev/null @@ -1,20 +0,0 @@ -|TObject $object - * - * @return Mockery - */ - public static function of(string|object $object): Mockery - { - return new Mockery($object); - } -} diff --git a/tests/Util/Mockery.php b/tests/Util/Mockery.php deleted file mode 100644 index a3b0770..0000000 --- a/tests/Util/Mockery.php +++ /dev/null @@ -1,69 +0,0 @@ -|TObject $object - */ - public function __construct(string|object $object) - { - /** @var TObject|MockInterface $mock */ - $mock = Mockery::mock($object); - - $this->mock = $mock; - } - - /** - * Define mock expectations. - * - * @return TObject|MockInterface - */ - public function expect(callable ...$methods) - { - foreach ($methods as $method => $expectation) { - /* @phpstan-ignore-next-line */ - $method = $this->mock - ->shouldReceive((string) $method) - ->atLeast() - ->once(); - - $method->andReturnUsing($expectation); - } - - return $this->mock; - } - - /** - * Proxies calls to the original mock object. - * - * @param array $arguments - */ - public function __call(string $method, array $arguments): mixed - { - /* @phpstan-ignore-next-line */ - return $this->mock->{$method}(...$arguments); - } -} From a86f14add8ab827fe51cfa4d44d392689ec574c6 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 10 Feb 2026 23:14:13 +0000 Subject: [PATCH 084/133] feat: register user --- app/Models/User.php | 38 +----------------- app/Models/UserOtp.php | 2 + config/database.php | 20 +++++----- tests/Feature/Auth/RegisterTest.php | 62 ++++++++++++++++------------- 4 files changed, 49 insertions(+), 73 deletions(-) diff --git a/app/Models/User.php b/app/Models/User.php index bc59c53..13eb918 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -7,46 +7,12 @@ use App\Constants\OneTimePasswordScope; use App\Mail\SendEmailVerificationOtp; use App\Mail\SendLoginOtp; -use App\Queries\UserQuery; -use Phenix\Database\Models\Attributes\Column; -use Phenix\Database\Models\Attributes\DateTime; -use Phenix\Database\Models\Attributes\Hidden; -use Phenix\Database\Models\Attributes\Id; -use Phenix\Database\Models\DatabaseModel; +use Phenix\Auth\User as Authenticable; use Phenix\Facades\Mail; use Phenix\Mail\Mailable; -use Phenix\Util\Date; -class User extends DatabaseModel +class User extends Authenticable { - #[Id] - public int $id; - - #[Column] - public string $name; - - #[Column] - public string $email; - - #[Hidden] - public string $password; - - #[DateTime(name: 'created_at', autoInit: true)] - public Date $createdAt; - - #[DateTime(name: 'updated_at')] - public Date|null $updatedAt = null; - - public static function table(): string - { - return 'users'; - } - - protected static function newQueryBuilder(): UserQuery - { - return new UserQuery(); - } - public function createOneTimePassword(OneTimePasswordScope $scope): UserOtp { $userOtp = UserOtp::make($scope); diff --git a/app/Models/UserOtp.php b/app/Models/UserOtp.php index 4d35eec..1644c6d 100644 --- a/app/Models/UserOtp.php +++ b/app/Models/UserOtp.php @@ -13,6 +13,7 @@ use Phenix\Database\Models\Attributes\Id; use Phenix\Database\Models\DatabaseModel; use Phenix\Util\Date; +use Phenix\Util\Str; class UserOtp extends DatabaseModel { @@ -60,6 +61,7 @@ public static function make(OneTimePasswordScope $scope): self $value = random_int(100000, 999999); $otp = new self(); + $otp->id = Str::uuid()->toString(); $otp->scope = $scope->value; $otp->code = hash('sha256', (string) $value); $otp->expiresAt = Date::now()->addMinutes(env('')); diff --git a/config/database.php b/config/database.php index 10d3db7..22be9b3 100644 --- a/config/database.php +++ b/config/database.php @@ -3,17 +3,17 @@ declare(strict_types=1); return [ - 'default' => env('DB_CONNECTION', static fn () => 'mysql'), + 'default' => env('DB_CONNECTION', static fn (): string => 'mysql'), 'connections' => [ 'sqlite' => [ 'driver' => 'sqlite', - 'database' => env('DB_DATABASE', static fn () => base_path('database/database')), + 'database' => env('DB_DATABASE', static fn (): string => base_path('database' . DIRECTORY_SEPARATOR . 'database.sqlite3')), ], 'mysql' => [ 'driver' => 'mysql', - 'host' => env('DB_HOST', static fn () => '127.0.0.1'), - 'port' => env('DB_PORT', static fn () => '3306'), + 'host' => env('DB_HOST', static fn (): string => '127.0.0.1'), + 'port' => env('DB_PORT', static fn (): string => '3306'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), @@ -24,8 +24,8 @@ ], 'postgresql' => [ 'driver' => 'postgresql', - 'host' => env('DB_HOST', static fn () => '127.0.0.1'), - 'port' => env('DB_PORT', static fn () => '5432'), + 'host' => env('DB_HOST', static fn (): string => '127.0.0.1'), + 'port' => env('DB_PORT', static fn (): string => '5432'), 'database' => env('DB_DATABASE'), 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD'), @@ -40,12 +40,12 @@ 'redis' => [ 'connections' => [ 'default' => [ - 'scheme' => env('REDIS_SCHEME', static fn () => 'redis'), - 'host' => env('REDIS_HOST', static fn () => '127.0.0.1'), + 'scheme' => env('REDIS_SCHEME', static fn (): string => 'redis'), + 'host' => env('REDIS_HOST', static fn (): string => '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), - 'port' => env('REDIS_PORT', static fn () => '6379'), - 'database' => env('REDIS_DB', static fn () => 0), + 'port' => env('REDIS_PORT', static fn (): string => '6379'), + 'database' => env('REDIS_DB', static fn (): int => 0), ], ], ], diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php index 772dc43..f7c4baa 100644 --- a/tests/Feature/Auth/RegisterTest.php +++ b/tests/Feature/Auth/RegisterTest.php @@ -2,35 +2,43 @@ declare(strict_types=1); +namespace Tests\Feature\Auth; + use App\Mail\SendEmailVerificationOtp; use Phenix\Facades\Mail; use Phenix\Testing\Concerns\RefreshDatabase; - -use function Pest\Faker\faker; - -uses(RefreshDatabase::class); - -it('registers a user', function (): void { - Mail::fake(); - - $data = [ - 'name' => faker()->name(), - 'email' => faker()->email(), - 'password' => 'P@ssw0rd', - 'password_confirmation' => 'P@ssw0rd', - ]; - - $response = post('/register', $data); - - $response->assertCreated() - ->assertJsonContains([ - 'name' => $data['name'], +use Phenix\Testing\Concerns\WithFaker; +use Tests\TestCase; + +class RegisterTest extends TestCase +{ + use WithFaker; + use RefreshDatabase; + + /** @test */ + public function it_registers_a_user(): void + { + Mail::fake(); + + $data = [ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->email(), + 'password' => 'P@ssw0rd', + 'password_confirmation' => 'P@ssw0rd', + ]; + + $response = $this->post('/register', $data); + + $response->assertCreated() + ->assertJsonContains([ + 'name' => $data['name'], + 'email' => $data['email'], + ], 'data'); + + $this->assertDatabaseHas('users', [ 'email' => $data['email'], - ], 'data'); - - $this->assertDatabaseHas('users', [ - 'email' => $data['email'], - ]); + ]); - Mail::expect(SendEmailVerificationOtp::class)->toBeSent(); -}); + Mail::expect(SendEmailVerificationOtp::class)->toBeSent(); + } +} From 81fe5982e191cdb090e0e53770f355650588862b Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 10 Feb 2026 23:14:29 +0000 Subject: [PATCH 085/133] refactor: rewrite test in PHPUnit --- tests/Feature/WelcomeTest.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/Feature/WelcomeTest.php b/tests/Feature/WelcomeTest.php index cadbae3..7e08af3 100644 --- a/tests/Feature/WelcomeTest.php +++ b/tests/Feature/WelcomeTest.php @@ -2,8 +2,17 @@ declare(strict_types=1); -it('responses successfully', function () { - get('/') - ->assertOk() - ->assertBodyContains('Hello, world!'); -}); +namespace Tests\Feature; + +use Tests\TestCase; + +class WelcomeTest extends TestCase +{ + /** @test */ + public function it_responses_successfully(): void + { + $this->get('/') + ->assertOk() + ->assertBodyContains('Hello, world!'); + } +} From e255309679d7a82dfac2345d3ff638fb202dfb52 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 10 Feb 2026 23:14:54 +0000 Subject: [PATCH 086/133] style: php cs --- config/app.php | 2 +- config/mail.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/app.php b/config/app.php index 0a3f2bd..616d6d6 100644 --- a/config/app.php +++ b/config/app.php @@ -92,4 +92,4 @@ \Phenix\Http\Headers\CrossOriginOpenerPolicy::class, ], ], -]; \ No newline at end of file +]; diff --git a/config/mail.php b/config/mail.php index 6e77b62..3a11d09 100644 --- a/config/mail.php +++ b/config/mail.php @@ -29,4 +29,4 @@ 'address' => env('MAIL_FROM_ADDRESS', static fn (): string => 'hello@example.com'), 'name' => env('MAIL_FROM_NAME', static fn (): string => 'Example'), ], -]; \ No newline at end of file +]; From 8538bb389a1720e7ef452ee30a6e97d07044102c Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 10 Feb 2026 23:15:29 +0000 Subject: [PATCH 087/133] feat: add pcntl and sockets extensions to Dockerfile --- docker/Dockerfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index a69a17a..fce4d40 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -5,7 +5,10 @@ USER root RUN apk add --no-cache \ curl \ git \ - unzip + unzip \ + linux-headers \ + && docker-php-ext-install pcntl sockets \ + && docker-php-ext-enable pcntl sockets COPY --from=composer:latest /usr/bin/composer /usr/bin/composer From e8f3eae7e5559eafbd49ab72a919920fe9c92235 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Thu, 12 Feb 2026 00:35:12 +0000 Subject: [PATCH 088/133] feat: update UserOtp creation method and enhance email verification test --- app/Models/User.php | 2 +- app/Models/UserOtp.php | 4 ++-- tests/Feature/Auth/RegisterTest.php | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/Models/User.php b/app/Models/User.php index 13eb918..09e580c 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -15,7 +15,7 @@ class User extends Authenticable { public function createOneTimePassword(OneTimePasswordScope $scope): UserOtp { - $userOtp = UserOtp::make($scope); + $userOtp = UserOtp::fromScope($scope); $userOtp->userId = $this->id; $userOtp->save(); diff --git a/app/Models/UserOtp.php b/app/Models/UserOtp.php index 1644c6d..53d6c42 100644 --- a/app/Models/UserOtp.php +++ b/app/Models/UserOtp.php @@ -56,7 +56,7 @@ protected static function newQueryBuilder(): UserOtpQuery return new UserOtpQuery(); } - public static function make(OneTimePasswordScope $scope): self + public static function fromScope(OneTimePasswordScope $scope): self { $value = random_int(100000, 999999); @@ -64,7 +64,7 @@ public static function make(OneTimePasswordScope $scope): self $otp->id = Str::uuid()->toString(); $otp->scope = $scope->value; $otp->code = hash('sha256', (string) $value); - $otp->expiresAt = Date::now()->addMinutes(env('')); + $otp->expiresAt = Date::now()->addMinutes(config('auth.otp.expiration', 10)); $otp->otp = $value; return $otp; diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php index f7c4baa..dfcf934 100644 --- a/tests/Feature/Auth/RegisterTest.php +++ b/tests/Feature/Auth/RegisterTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Auth; +use App\Constants\OneTimePasswordScope; use App\Mail\SendEmailVerificationOtp; use Phenix\Facades\Mail; use Phenix\Testing\Concerns\RefreshDatabase; @@ -39,6 +40,13 @@ public function it_registers_a_user(): void 'email' => $data['email'], ]); + $data = $response->getDecodedBody(); + + $this->assertDatabaseHas('user_one_time_passwords', [ + 'user_id' => $data['data']['id'], + 'scope' => OneTimePasswordScope::VERIFY_EMAIL->value, + ]); + Mail::expect(SendEmailVerificationOtp::class)->toBeSent(); } } From fc6d96700b41ea5331d00e2f3ddf952eec61fb60 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Thu, 12 Feb 2026 00:35:43 +0000 Subject: [PATCH 089/133] feat: update framework version to dev-feature/integration-v080 in composer.json --- composer.json | 2 +- composer.lock | 1883 +++++++++++++++++++++++-------------------------- 2 files changed, 892 insertions(+), 993 deletions(-) diff --git a/composer.json b/composer.json index de47b5f..62c95e3 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "dev-develop" + "phenixphp/framework": "dev-feature/integration-v080" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index 18ca3da..bd9c1d6 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": "906da3eaf71f2cab3278bedec76f5f31", + "content-hash": "8567e427ea7c0ba62ea818d9fad3a55a", "packages": [ { "name": "adbario/php-dot-notation", @@ -281,6 +281,108 @@ ], "time": "2024-04-19T03:38:06+00:00" }, + { + "name": "amphp/cluster", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/cluster.git", + "reference": "9098256a9260635a310364cd6debb03e60b4808d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/cluster/zipball/9098256a9260635a310364cd6debb03e60b4808d", + "reference": "9098256a9260635a310364cd6debb03e60b4808d", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/log": "^2", + "amphp/parallel": "^2.2", + "amphp/pipeline": "^1.1", + "amphp/process": "^2", + "amphp/serialization": "^1", + "amphp/socket": "^2", + "amphp/sync": "^2", + "ext-sockets": "*", + "league/climate": "^3", + "monolog/monolog": "^3|^2|^1.23", + "php": ">=8.1", + "psr/log": "^3|^2|^1", + "revolt/event-loop": "^1" + }, + "conflict": { + "amphp/file": "<3 || >=4" + }, + "require-dev": { + "amphp/file": "^3", + "amphp/http-server": "^3", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "ext-pcntl": "*", + "phpunit/phpunit": "^9", + "psalm/phar": "~5.26.1" + }, + "suggest": { + "amphp/file": "Required for logging to a file", + "ext-sockets": "Required for socket transfer on systems that do not support SO_REUSEPORT" + }, + "bin": [ + "bin/cluster" + ], + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Cluster\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Bob Weinand" + } + ], + "description": "Building multi-core network applications with PHP.", + "homepage": "https://github.com/amphp/cluster", + "keywords": [ + "amp", + "amphp", + "async", + "cluster", + "multi-core", + "multi-process", + "non-blocking", + "parallel", + "sockets", + "watcher" + ], + "support": { + "issues": "https://github.com/amphp/cluster/issues", + "source": "https://github.com/amphp/cluster/tree/v2.0.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-12-21T02:00:08+00:00" + }, { "name": "amphp/dns", "version": "v2.4.0", @@ -693,16 +795,16 @@ }, { "name": "amphp/http-server", - "version": "v3.4.3", + "version": "v3.4.4", "source": { "type": "git", "url": "https://github.com/amphp/http-server.git", - "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd" + "reference": "8dc32cc6a65c12a3543276305796b993c56b76ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-server/zipball/7aa962b0569f664af3ba23bc819f2a69884329cd", - "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd", + "url": "https://api.github.com/repos/amphp/http-server/zipball/8dc32cc6a65c12a3543276305796b993c56b76ef", + "reference": "8dc32cc6a65c12a3543276305796b993c56b76ef", "shasum": "" }, "require": { @@ -778,7 +880,7 @@ ], "support": { "issues": "https://github.com/amphp/http-server/issues", - "source": "https://github.com/amphp/http-server/tree/v3.4.3" + "source": "https://github.com/amphp/http-server/tree/v3.4.4" }, "funding": [ { @@ -786,7 +888,7 @@ "type": "github" } ], - "time": "2025-05-18T15:43:42+00:00" + "time": "2026-02-08T18:16:29+00:00" }, { "name": "amphp/http-server-form-parser", @@ -952,16 +1054,16 @@ }, { "name": "amphp/http-server-session", - "version": "v3.0.0", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/amphp/http-server-session.git", - "reference": "88ee2106cd79a21f225bb631f8686d509002c11b" + "reference": "1cac38d80dc339a4befae96451d92ea364787e83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-server-session/zipball/88ee2106cd79a21f225bb631f8686d509002c11b", - "reference": "88ee2106cd79a21f225bb631f8686d509002c11b", + "url": "https://api.github.com/repos/amphp/http-server-session/zipball/1cac38d80dc339a4befae96451d92ea364787e83", + "reference": "1cac38d80dc339a4befae96451d92ea364787e83", "shasum": "" }, "require": { @@ -971,7 +1073,7 @@ "amphp/http-server": "^3", "amphp/serialization": "^1", "amphp/sync": "^2", - "paragonie/constant_time_encoding": "^2.2", + "paragonie/constant_time_encoding": "^2 || ^3", "php": ">=8.1" }, "conflict": { @@ -1016,7 +1118,7 @@ "homepage": "https://amphp.org/http-server-session", "support": { "issues": "https://github.com/amphp/http-server-session/issues", - "source": "https://github.com/amphp/http-server-session/tree/v3.0.0" + "source": "https://github.com/amphp/http-server-session/tree/v3.0.1" }, "funding": [ { @@ -1024,7 +1126,7 @@ "type": "github" } ], - "time": "2023-08-20T17:32:14+00:00" + "time": "2026-01-12T20:16:56+00:00" }, { "name": "amphp/log", @@ -1172,16 +1274,16 @@ }, { "name": "amphp/parallel", - "version": "v2.3.2", + "version": "v2.3.3", "source": { "type": "git", "url": "https://github.com/amphp/parallel.git", - "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce" + "reference": "296b521137a54d3a02425b464e5aee4c93db2c60" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parallel/zipball/321b45ae771d9c33a068186b24117e3cd1c48dce", - "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce", + "url": "https://api.github.com/repos/amphp/parallel/zipball/296b521137a54d3a02425b464e5aee4c93db2c60", + "reference": "296b521137a54d3a02425b464e5aee4c93db2c60", "shasum": "" }, "require": { @@ -1244,7 +1346,7 @@ ], "support": { "issues": "https://github.com/amphp/parallel/issues", - "source": "https://github.com/amphp/parallel/tree/v2.3.2" + "source": "https://github.com/amphp/parallel/tree/v2.3.3" }, "funding": [ { @@ -1252,7 +1354,7 @@ "type": "github" } ], - "time": "2025-08-27T21:55:40+00:00" + "time": "2025-11-15T06:23:42+00:00" }, { "name": "amphp/parser", @@ -1802,16 +1904,16 @@ }, { "name": "amphp/sql-common", - "version": "v2.0.3", + "version": "v2.0.4", "source": { "type": "git", "url": "https://github.com/amphp/sql-common.git", - "reference": "0c926e0348c238c61bead25af5c2fa0d5afaed8d" + "reference": "735da17ef0a66e7139c9f7584af5c3f9827f83c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/sql-common/zipball/0c926e0348c238c61bead25af5c2fa0d5afaed8d", - "reference": "0c926e0348c238c61bead25af5c2fa0d5afaed8d", + "url": "https://api.github.com/repos/amphp/sql-common/zipball/735da17ef0a66e7139c9f7584af5c3f9827f83c0", + "reference": "735da17ef0a66e7139c9f7584af5c3f9827f83c0", "shasum": "" }, "require": { @@ -1846,7 +1948,7 @@ ], "support": { "issues": "https://github.com/amphp/sql-common/issues", - "source": "https://github.com/amphp/sql-common/tree/v2.0.3" + "source": "https://github.com/amphp/sql-common/tree/v2.0.4" }, "funding": [ { @@ -1854,7 +1956,7 @@ "type": "github" } ], - "time": "2025-06-07T15:35:29+00:00" + "time": "2025-12-11T20:05:29+00:00" }, { "name": "amphp/sync", @@ -1933,23 +2035,23 @@ }, { "name": "async-aws/core", - "version": "1.27.1", + "version": "1.28.0", "source": { "type": "git", "url": "https://github.com/async-aws/core.git", - "reference": "5b8e35c8df94990161e2c9750c9ba1683d0b48b8" + "reference": "0d5f4d650b74a8366bca1fb400b6cfb694c3b217" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/core/zipball/5b8e35c8df94990161e2c9750c9ba1683d0b48b8", - "reference": "5b8e35c8df94990161e2c9750c9ba1683d0b48b8", + "url": "https://api.github.com/repos/async-aws/core/zipball/0d5f4d650b74a8366bca1fb400b6cfb694c3b217", + "reference": "0d5f4d650b74a8366bca1fb400b6cfb694c3b217", "shasum": "" }, "require": { "ext-hash": "*", "ext-json": "*", "ext-simplexml": "*", - "php": "^7.2.5 || ^8.0", + "php": "^8.2", "psr/cache": "^1.0 || ^2.0 || ^3.0", "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/deprecation-contracts": "^2.1 || ^3.0", @@ -1961,10 +2063,15 @@ "async-aws/s3": "<1.1", "symfony/http-client": "5.2.0" }, + "require-dev": { + "phpunit/phpunit": "^11.5.42", + "symfony/error-handler": "^7.3.2 || ^8.0", + "symfony/phpunit-bridge": "^7.3.2 || ^8.0" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.27-dev" + "dev-master": "1.28-dev" } }, "autoload": { @@ -1985,7 +2092,7 @@ "sts" ], "support": { - "source": "https://github.com/async-aws/core/tree/1.27.1" + "source": "https://github.com/async-aws/core/tree/1.28.0" }, "funding": [ { @@ -1997,31 +2104,36 @@ "type": "github" } ], - "time": "2025-09-08T07:05:54+00:00" + "time": "2026-01-16T22:28:05+00:00" }, { "name": "async-aws/ses", - "version": "1.13.0", + "version": "1.14.0", "source": { "type": "git", "url": "https://github.com/async-aws/ses.git", - "reference": "e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42" + "reference": "c5b1d6c0c8ba32ea4f961b40b9e411aeca783302" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/ses/zipball/e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42", - "reference": "e11cdc16cfa3d7ae45266d62d886a1d7a71a1c42", + "url": "https://api.github.com/repos/async-aws/ses/zipball/c5b1d6c0c8ba32ea4f961b40b9e411aeca783302", + "reference": "c5b1d6c0c8ba32ea4f961b40b9e411aeca783302", "shasum": "" }, "require": { "async-aws/core": "^1.9", "ext-json": "*", - "php": "^7.2.5 || ^8.0" + "php": "^8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.42", + "symfony/error-handler": "^7.3.2 || ^8.0", + "symfony/phpunit-bridge": "^7.3.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.14-dev" } }, "autoload": { @@ -2042,7 +2154,7 @@ "ses" ], "support": { - "source": "https://github.com/async-aws/ses/tree/1.13.0" + "source": "https://github.com/async-aws/ses/tree/1.14.0" }, "funding": [ { @@ -2054,20 +2166,20 @@ "type": "github" } ], - "time": "2025-08-11T10:03:27+00:00" + "time": "2026-01-16T22:28:05+00:00" }, { "name": "cakephp/chronos", - "version": "3.2.0", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/cakephp/chronos.git", - "reference": "6c820947bc1372a250288ab164ec1b3bb7afab39" + "reference": "1e417fdd4a3c6602b6c4634cf54aa9b065127fa2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/chronos/zipball/6c820947bc1372a250288ab164ec1b3bb7afab39", - "reference": "6c820947bc1372a250288ab164ec1b3bb7afab39", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/1e417fdd4a3c6602b6c4634cf54aa9b065127fa2", + "reference": "1e417fdd4a3c6602b6c4634cf54aa9b065127fa2", "shasum": "" }, "require": { @@ -2079,7 +2191,7 @@ }, "require-dev": { "cakephp/cakephp-codesniffer": "^5.0", - "phpunit/phpunit": "^10.1.0 || ^11.1.3" + "phpunit/phpunit": "^10.5.58 || ^11.1.3" }, "type": "library", "autoload": { @@ -2113,20 +2225,20 @@ "issues": "https://github.com/cakephp/chronos/issues", "source": "https://github.com/cakephp/chronos" }, - "time": "2025-06-28T11:35:59+00:00" + "time": "2025-10-30T13:08:23+00:00" }, { "name": "cakephp/core", - "version": "5.2.9", + "version": "5.2.12", "source": { "type": "git", "url": "https://github.com/cakephp/core.git", - "reference": "231d67d9e192491e80f8e3f367822dbadcb6d15a" + "reference": "f18f37c04832831ca37f5300212b1adddcc54b86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/core/zipball/231d67d9e192491e80f8e3f367822dbadcb6d15a", - "reference": "231d67d9e192491e80f8e3f367822dbadcb6d15a", + "url": "https://api.github.com/repos/cakephp/core/zipball/f18f37c04832831ca37f5300212b1adddcc54b86", + "reference": "f18f37c04832831ca37f5300212b1adddcc54b86", "shasum": "" }, "require": { @@ -2180,20 +2292,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/core" }, - "time": "2025-08-30T05:23:22+00:00" + "time": "2025-11-14T14:52:55+00:00" }, { "name": "cakephp/database", - "version": "5.2.9", + "version": "5.2.12", "source": { "type": "git", "url": "https://github.com/cakephp/database.git", - "reference": "3027321fdd696cba09b1cad536f89e90f6c6693f" + "reference": "cf855540be5a0f522394827398c9552fe1656146" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/database/zipball/3027321fdd696cba09b1cad536f89e90f6c6693f", - "reference": "3027321fdd696cba09b1cad536f89e90f6c6693f", + "url": "https://api.github.com/repos/cakephp/database/zipball/cf855540be5a0f522394827398c9552fe1656146", + "reference": "cf855540be5a0f522394827398c9552fe1656146", "shasum": "" }, "require": { @@ -2247,20 +2359,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/database" }, - "time": "2025-10-15T09:58:33+00:00" + "time": "2025-11-16T20:33:48+00:00" }, { "name": "cakephp/datasource", - "version": "5.2.9", + "version": "5.2.12", "source": { "type": "git", "url": "https://github.com/cakephp/datasource.git", - "reference": "35cd45fdea18854e4f8fd7bdb5fa487d104a8efd" + "reference": "906a8b719b6dc241fa81a55be20c9adc51c31f74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/datasource/zipball/35cd45fdea18854e4f8fd7bdb5fa487d104a8efd", - "reference": "35cd45fdea18854e4f8fd7bdb5fa487d104a8efd", + "url": "https://api.github.com/repos/cakephp/datasource/zipball/906a8b719b6dc241fa81a55be20c9adc51c31f74", + "reference": "906a8b719b6dc241fa81a55be20c9adc51c31f74", "shasum": "" }, "require": { @@ -2314,20 +2426,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/datasource" }, - "time": "2025-09-04T00:13:11+00:00" + "time": "2025-11-14T14:52:55+00:00" }, { "name": "cakephp/utility", - "version": "5.2.9", + "version": "5.2.12", "source": { "type": "git", "url": "https://github.com/cakephp/utility.git", - "reference": "9d2bafa62f457084b7ce4737f2f71d2a40fc6812" + "reference": "df9bc4e420db3b4a02cafad896398bad48813e50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/utility/zipball/9d2bafa62f457084b7ce4737f2f71d2a40fc6812", - "reference": "9d2bafa62f457084b7ce4737f2f71d2a40fc6812", + "url": "https://api.github.com/repos/cakephp/utility/zipball/df9bc4e420db3b4a02cafad896398bad48813e50", + "reference": "df9bc4e420db3b4a02cafad896398bad48813e50", "shasum": "" }, "require": { @@ -2378,7 +2490,7 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/utility" }, - "time": "2025-09-06T07:02:20+00:00" + "time": "2025-11-14T14:52:55+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -2570,6 +2682,70 @@ ], "time": "2024-02-05T11:56:58+00:00" }, + { + "name": "dragonmantank/cron-expression", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/d61a8a9604ec1f8c3d150d09db6ce98b32675013", + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013", + "shasum": "" + }, + "require": { + "php": "^8.2|^8.3|^8.4|^8.5" + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.32|^2.1.31", + "phpunit/phpunit": "^8.5.48|^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "time": "2025-10-31T18:51:33+00:00" + }, { "name": "egulias/email-validator", "version": "4.0.4", @@ -2702,24 +2878,24 @@ }, { "name": "graham-campbell/result-type", - "version": "v1.1.3", + "version": "v1.1.4", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3" + "phpoption/phpoption": "^1.9.5" }, "require-dev": { - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" }, "type": "library", "autoload": { @@ -2748,7 +2924,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" }, "funding": [ { @@ -2760,7 +2936,7 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:45:45+00:00" + "time": "2025-12-27T19:43:20+00:00" }, { "name": "guzzlehttp/guzzle", @@ -3145,6 +3321,125 @@ }, "time": "2023-02-03T21:26:53+00:00" }, + { + "name": "kelunik/rate-limit", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/kelunik/rate-limit.git", + "reference": "473e8dd66b2f164d0ca7da039eb77574dffcf5b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/rate-limit/zipball/473e8dd66b2f164d0ca7da039eb77574dffcf5b3", + "reference": "473e8dd66b2f164d0ca7da039eb77574dffcf5b3", + "shasum": "" + }, + "require": { + "amphp/redis": "^2", + "php": ">=8.1" + }, + "require-dev": { + "amphp/amp": "^3", + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Kelunik\\RateLimit\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Rate Limiting for Amp.", + "keywords": [ + "amp", + "amphp", + "limit", + "rate-limit", + "redis" + ], + "support": { + "issues": "https://github.com/kelunik/rate-limit/issues", + "source": "https://github.com/kelunik/rate-limit/tree/v3.0.0" + }, + "time": "2023-09-04T17:56:06+00:00" + }, + { + "name": "league/climate", + "version": "3.10.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/climate.git", + "reference": "237f70e1032b16d32ff3f65dcda68706911e1c74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/climate/zipball/237f70e1032b16d32ff3f65dcda68706911e1c74", + "reference": "237f70e1032b16d32ff3f65dcda68706911e1c74", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "seld/cli-prompt": "^1.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6.12", + "mockery/mockery": "^1.6.12", + "phpunit/phpunit": "^9.5.10", + "squizlabs/php_codesniffer": "^3.10" + }, + "suggest": { + "ext-mbstring": "If ext-mbstring is not available you MUST install symfony/polyfill-mbstring" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\CLImate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joe Tannenbaum", + "email": "hey@joe.codes", + "homepage": "http://joe.codes/", + "role": "Developer" + }, + { + "name": "Craig Duncan", + "email": "git@duncanc.co.uk", + "homepage": "https://github.com/duncan3dc", + "role": "Developer" + } + ], + "description": "PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.", + "keywords": [ + "cli", + "colors", + "command", + "php", + "terminal" + ], + "support": { + "issues": "https://github.com/thephpleague/climate/issues", + "source": "https://github.com/thephpleague/climate/tree/3.10.0" + }, + "time": "2024-11-18T09:09:55+00:00" + }, { "name": "league/container", "version": "4.2.5", @@ -3229,33 +3524,38 @@ }, { "name": "league/uri", - "version": "7.5.1", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri.git", - "reference": "81fb5145d2644324614cc532b28efd0215bda430" + "reference": "4436c6ec8d458e4244448b069cc572d088230b76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", - "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76", + "reference": "4436c6ec8d458e4244448b069cc572d088230b76", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.5", - "php": "^8.1" + "league/uri-interfaces": "^7.8", + "php": "^8.1", + "psr/http-factory": "^1" }, "conflict": { "league/uri-schemes": "^1.0" }, "suggest": { "ext-bcmath": "to improve IPV4 host parsing", + "ext-dom": "to convert the URI into an HTML anchor tag", "ext-fileinfo": "to create Data URI from file contennts", "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", - "league/uri-components": "Needed to easily manipulate URI objects components", + "ext-uri": "to use the PHP native URI class", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-components": "to provide additional tools to manipulate URI objects components", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -3283,6 +3583,7 @@ "description": "URI manipulation library", "homepage": "https://uri.thephpleague.com", "keywords": [ + "URN", "data-uri", "file-uri", "ftp", @@ -3295,9 +3596,11 @@ "psr-7", "query-string", "querystring", + "rfc2141", "rfc3986", "rfc3987", "rfc6570", + "rfc8141", "uri", "uri-template", "url", @@ -3307,7 +3610,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.5.1" + "source": "https://github.com/thephpleague/uri/tree/7.8.0" }, "funding": [ { @@ -3315,24 +3618,24 @@ "type": "github" } ], - "time": "2024-12-08T08:40:02+00:00" + "time": "2026-01-14T17:24:56+00:00" }, { "name": "league/uri-components", - "version": "7.5.1", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-components.git", - "reference": "4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f" + "reference": "8b5ffcebcc0842b76eb80964795bd56a8333b2ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f", - "reference": "4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f", + "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/8b5ffcebcc0842b76eb80964795bd56a8333b2ba", + "reference": "8b5ffcebcc0842b76eb80964795bd56a8333b2ba", "shasum": "" }, "require": { - "league/uri": "^7.5", + "league/uri": "^7.8", "php": "^8.1" }, "suggest": { @@ -3341,8 +3644,10 @@ "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", "ext-mbstring": "to use the sorting algorithm of URLSearchParams", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -3389,7 +3694,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-components/tree/7.5.1" + "source": "https://github.com/thephpleague/uri-components/tree/7.8.0" }, "funding": [ { @@ -3397,26 +3702,25 @@ "type": "github" } ], - "time": "2024-12-08T08:40:02+00:00" + "time": "2026-01-14T17:24:56+00:00" }, { "name": "league/uri-interfaces", - "version": "7.5.0", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4", "shasum": "" }, "require": { "ext-filter": "*", "php": "^8.1", - "psr/http-factory": "^1", "psr/http-message": "^1.1 || ^2.0" }, "suggest": { @@ -3424,6 +3728,7 @@ "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -3448,7 +3753,7 @@ "homepage": "https://nyamsprod.com" } ], - "description": "Common interfaces and classes for URI representation and interaction", + "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI", "homepage": "https://uri.thephpleague.com", "keywords": [ "data-uri", @@ -3473,7 +3778,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0" }, "funding": [ { @@ -3481,20 +3786,20 @@ "type": "github" } ], - "time": "2024-12-08T08:18:47+00:00" + "time": "2026-01-15T06:54:53+00:00" }, { "name": "monolog/monolog", - "version": "3.9.0", + "version": "3.10.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", "shasum": "" }, "require": { @@ -3512,7 +3817,7 @@ "graylog2/gelf-php": "^1.4.2 || ^2.0", "guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/psr7": "^2.2", - "mongodb/mongodb": "^1.8", + "mongodb/mongodb": "^1.8 || ^2.0", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.8", "phpstan/phpstan": "^2", @@ -3572,7 +3877,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + "source": "https://github.com/Seldaek/monolog/tree/3.10.0" }, "funding": [ { @@ -3584,20 +3889,20 @@ "type": "tidelift" } ], - "time": "2025-03-24T10:02:05+00:00" + "time": "2026-01-02T08:56:05+00:00" }, { "name": "nesbot/carbon", - "version": "3.10.3", + "version": "3.11.1", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f" + "reference": "f438fcc98f92babee98381d399c65336f3a3827f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", - "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/f438fcc98f92babee98381d399c65336f3a3827f", + "reference": "f438fcc98f92babee98381d399c65336f3a3827f", "shasum": "" }, "require": { @@ -3605,9 +3910,9 @@ "ext-json": "*", "php": "^8.1", "psr/clock": "^1.0", - "symfony/clock": "^6.3.12 || ^7.0", + "symfony/clock": "^6.3.12 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0" }, "provide": { "psr/clock-implementation": "1.0" @@ -3621,7 +3926,7 @@ "phpstan/extension-installer": "^1.4.3", "phpstan/phpstan": "^2.1.22", "phpunit/phpunit": "^10.5.53", - "squizlabs/php_codesniffer": "^3.13.4" + "squizlabs/php_codesniffer": "^3.13.4 || ^4.0.0" }, "bin": [ "bin/carbon" @@ -3664,14 +3969,14 @@ } ], "description": "An API extension for DateTime that supports 281 different languages.", - "homepage": "https://carbon.nesbot.com", + "homepage": "https://carbonphp.github.io/carbon/", "keywords": [ "date", "datetime", "time" ], "support": { - "docs": "https://carbon.nesbot.com/docs", + "docs": "https://carbonphp.github.io/carbon/guide/getting-started/introduction.html", "issues": "https://github.com/CarbonPHP/carbon/issues", "source": "https://github.com/CarbonPHP/carbon" }, @@ -3689,7 +3994,7 @@ "type": "tidelift" } ], - "time": "2025-09-06T13:39:36+00:00" + "time": "2026-01-29T09:26:29+00:00" }, { "name": "nikic/fast-route", @@ -3743,24 +4048,26 @@ }, { "name": "paragonie/constant_time_encoding", - "version": "v2.8.2", + "version": "v3.1.3", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "e30811f7bc69e4b5b6d5783e712c06c8eabf0226" + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/e30811f7bc69e4b5b6d5783e712c06c8eabf0226", - "reference": "e30811f7bc69e4b5b6d5783e712c06c8eabf0226", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", "shasum": "" }, "require": { - "php": "^7|^8" + "php": "^8" }, "require-dev": { - "phpunit/phpunit": "^6|^7|^8|^9", - "vimeo/psalm": "^1|^2|^3|^4" + "infection/infection": "^0", + "nikic/php-fuzzer": "^0", + "phpunit/phpunit": "^9|^10|^11", + "vimeo/psalm": "^4|^5|^6" }, "type": "library", "autoload": { @@ -3806,25 +4113,26 @@ "issues": "https://github.com/paragonie/constant_time_encoding/issues", "source": "https://github.com/paragonie/constant_time_encoding" }, - "time": "2025-09-24T15:12:37+00:00" + "time": "2025-09-24T15:06:41+00:00" }, { "name": "phenixphp/framework", - "version": "dev-develop", + "version": "dev-feature/integration-v080", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "9a078e26ee528b136bb99d9aaa3d6eecb3592571" + "reference": "7c2cfdea19e8ee99388837f4e8cdbee1c096286c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/9a078e26ee528b136bb99d9aaa3d6eecb3592571", - "reference": "9a078e26ee528b136bb99d9aaa3d6eecb3592571", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/7c2cfdea19e8ee99388837f4e8cdbee1c096286c", + "reference": "7c2cfdea19e8ee99388837f4e8cdbee1c096286c", "shasum": "" }, "require": { "adbario/php-dot-notation": "^3.1", "amphp/cache": "^2.0", + "amphp/cluster": "^2.0", "amphp/file": "^v3.0.0", "amphp/http-client": "^v5.0.1", "amphp/http-server": "^v3.2.0", @@ -3837,12 +4145,16 @@ "amphp/postgres": "v2.0.0", "amphp/redis": "^2.0", "amphp/socket": "^2.1.0", + "dragonmantank/cron-expression": "^3.6", "egulias/email-validator": "^4.0", "ext-pcntl": "*", + "ext-sockets": "*", "fakerphp/faker": "^1.23", + "kelunik/rate-limit": "^3.0", "league/container": "^4.2", "nesbot/carbon": "^3.0", "phenixphp/http-cors": "^0.1.0", + "phenixphp/sqlite": "^0.1.1", "php": "^8.2", "ramsey/collection": "^2.0", "resend/resend-php": "^0.16.0", @@ -3894,9 +4206,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/develop" + "source": "https://github.com/phenixphp/framework/tree/feature/integration-v080" }, - "time": "2025-10-24T19:45:28+00:00" + "time": "2026-02-11T23:59:38+00:00" }, { "name": "phenixphp/http-cors", @@ -3937,55 +4249,116 @@ "time": "2024-05-01T02:55:36+00:00" }, { - "name": "phpoption/phpoption", - "version": "1.9.4", + "name": "phenixphp/sqlite", + "version": "0.1.1", "source": { "type": "git", - "url": "https://github.com/schmittjoh/php-option.git", - "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" + "url": "https://github.com/phenixphp/sqlite.git", + "reference": "a230208807aaae56a8707fd33fdd136d2a8cd2f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", - "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "url": "https://api.github.com/repos/phenixphp/sqlite/zipball/a230208807aaae56a8707fd33fdd136d2a8cd2f3", + "reference": "a230208807aaae56a8707fd33fdd136d2a8cd2f3", "shasum": "" }, "require": { - "php": "^7.2.5 || ^8.0" + "amphp/amp": "^3", + "amphp/parallel": "^2.3", + "amphp/parser": "^1.1", + "amphp/pipeline": "^1", + "amphp/sql": "^2", + "amphp/sql-common": "^2", + "ext-sqlite3": "*", + "php": "^8.2" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + "amphp/file": "^3", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "amphp/process": "^2", + "phpbench/phpbench": "^1.2.6", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^9", + "symfony/var-dumper": "^7.4" }, "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - }, - "branch-alias": { - "dev-master": "1.9-dev" - } - }, "autoload": { + "files": [ + "src/functions.php" + ], "psr-4": { - "PhpOption\\": "src/PhpOption/" + "Phenix\\Sqlite\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache-2.0" + "MIT" ], "authors": [ { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "https://github.com/schmittjoh" - }, - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" + "name": "Omar Barbosa", + "email": "contacto@omarbarbosa.com" + } + ], + "description": "Asynchronous SQLite 3 client for PHP based on Amp.", + "homepage": "https://github.com/phenixphp/sqlite", + "support": { + "issues": "https://github.com/phenixphp/sqlite/issues", + "source": "https://github.com/phenixphp/sqlite/tree/0.1.1" + }, + "time": "2026-02-01T20:48:38+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.5", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" } ], "description": "Option Type for PHP", @@ -3997,7 +4370,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" }, "funding": [ { @@ -4009,7 +4382,7 @@ "type": "tidelift" } ], - "time": "2025-08-21T11:53:16+00:00" + "time": "2025-12-27T19:41:33+00:00" }, { "name": "psr/cache", @@ -4651,16 +5024,16 @@ }, { "name": "revolt/event-loop", - "version": "v1.0.7", + "version": "v1.0.8", "source": { "type": "git", "url": "https://github.com/revoltphp/event-loop.git", - "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3" + "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3", - "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3", + "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/b6fc06dce8e9b523c9946138fa5e62181934f91c", + "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c", "shasum": "" }, "require": { @@ -4717,9 +5090,9 @@ ], "support": { "issues": "https://github.com/revoltphp/event-loop/issues", - "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7" + "source": "https://github.com/revoltphp/event-loop/tree/v1.0.8" }, - "time": "2025-01-25T19:27:39+00:00" + "time": "2025-08-27T21:33:23+00:00" }, { "name": "robmorgan/phinx", @@ -4807,27 +5180,82 @@ }, "time": "2023-12-05T13:24:00+00:00" }, + { + "name": "seld/cli-prompt", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/cli-prompt.git", + "reference": "b8dfcf02094b8c03b40322c229493bb2884423c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/b8dfcf02094b8c03b40322c229493bb2884423c5", + "reference": "b8dfcf02094b8c03b40322c229493bb2884423c5", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.63" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\CliPrompt\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", + "keywords": [ + "cli", + "console", + "hidden", + "input", + "prompt" + ], + "support": { + "issues": "https://github.com/Seldaek/cli-prompt/issues", + "source": "https://github.com/Seldaek/cli-prompt/tree/1.0.4" + }, + "time": "2020-12-15T21:32:01+00:00" + }, { "name": "symfony/amazon-mailer", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/amazon-mailer.git", - "reference": "7266d4285147c890f4f7f42dc875fe5a6df8006c" + "reference": "122c80099df1f415c091ce356442796406b61c7b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/7266d4285147c890f4f7f42dc875fe5a6df8006c", - "reference": "7266d4285147c890f4f7f42dc875fe5a6df8006c", + "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/122c80099df1f415c091ce356442796406b61c7b", + "reference": "122c80099df1f415c091ce356442796406b61c7b", "shasum": "" }, "require": { "async-aws/ses": "^1.8", "php": ">=8.2", - "symfony/mailer": "^7.2" + "symfony/mailer": "^7.2|^8.0" }, "require-dev": { - "symfony/http-client": "^6.4|^7.0" + "symfony/http-client": "^6.4|^7.0|^8.0" }, "type": "symfony-mailer-bridge", "autoload": { @@ -4855,7 +5283,7 @@ "description": "Symfony Amazon Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/amazon-mailer/tree/v7.3.0" + "source": "https://github.com/symfony/amazon-mailer/tree/v7.4.0" }, "funding": [ { @@ -4866,25 +5294,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-26T16:10:57+00:00" + "time": "2025-08-04T07:05:15+00:00" }, { "name": "symfony/clock", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110", + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110", "shasum": "" }, "require": { @@ -4929,7 +5361,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.3.0" + "source": "https://github.com/symfony/clock/tree/v7.4.0" }, "funding": [ { @@ -4940,31 +5372,35 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/config", - "version": "v7.3.4", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "8a09223170046d2cfda3d2e11af01df2c641e961" + "reference": "4275b53b8ab0cf37f48bf273dc2285c8178efdfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/8a09223170046d2cfda3d2e11af01df2c641e961", - "reference": "8a09223170046d2cfda3d2e11af01df2c641e961", + "url": "https://api.github.com/repos/symfony/config/zipball/4275b53b8ab0cf37f48bf273dc2285c8178efdfb", + "reference": "4275b53b8ab0cf37f48bf273dc2285c8178efdfb", "shasum": "" }, "require": { "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^7.1", + "symfony/filesystem": "^7.1|^8.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -4972,11 +5408,11 @@ "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5004,7 +5440,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.3.4" + "source": "https://github.com/symfony/config/tree/v7.4.4" }, "funding": [ { @@ -5024,20 +5460,20 @@ "type": "tidelift" } ], - "time": "2025-09-22T12:46:16+00:00" + "time": "2026-01-13T11:36:38+00:00" }, { "name": "symfony/console", - "version": "v6.4.26", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f" + "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f", - "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f", + "url": "https://api.github.com/repos/symfony/console/zipball/0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", + "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", "shasum": "" }, "require": { @@ -5102,7 +5538,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.26" + "source": "https://github.com/symfony/console/tree/v6.4.32" }, "funding": [ { @@ -5122,7 +5558,7 @@ "type": "tidelift" } ], - "time": "2025-09-26T12:13:46+00:00" + "time": "2026-01-13T08:45:59+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5193,16 +5629,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v7.3.3", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" + "reference": "dc2c0eba1af673e736bb851d747d266108aea746" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dc2c0eba1af673e736bb851d747d266108aea746", + "reference": "dc2c0eba1af673e736bb851d747d266108aea746", "shasum": "" }, "require": { @@ -5219,13 +5655,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5253,7 +5690,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.4" }, "funding": [ { @@ -5273,7 +5710,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2026-01-05T11:45:34+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5353,16 +5790,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.3.2", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" + "reference": "d551b38811096d0be9c4691d406991b47c0c630a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a", + "reference": "d551b38811096d0be9c4691d406991b47c0c630a", "shasum": "" }, "require": { @@ -5371,7 +5808,7 @@ "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^6.4|^7.0" + "symfony/process": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5399,7 +5836,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.2" + "source": "https://github.com/symfony/filesystem/tree/v7.4.0" }, "funding": [ { @@ -5419,20 +5856,20 @@ "type": "tidelift" } ], - "time": "2025-07-07T08:17:47+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/http-client", - "version": "v7.3.4", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62" + "reference": "84bb634857a893cc146cceb467e31b3f02c5fe9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62", + "url": "https://api.github.com/repos/symfony/http-client/zipball/84bb634857a893cc146cceb467e31b3f02c5fe9f", + "reference": "84bb634857a893cc146cceb467e31b3f02c5fe9f", "shasum": "" }, "require": { @@ -5463,12 +5900,13 @@ "php-http/httplug": "^1.0|^2.0", "psr/http-client": "^1.0", "symfony/amphp-http-client-meta": "^1.0|^2.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5499,7 +5937,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.4" + "source": "https://github.com/symfony/http-client/tree/v7.4.5" }, "funding": [ { @@ -5519,7 +5957,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2026-01-27T16:16:02+00:00" }, { "name": "symfony/http-client-contracts", @@ -5601,16 +6039,16 @@ }, { "name": "symfony/mailer", - "version": "v7.3.4", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "ab97ef2f7acf0216955f5845484235113047a31d" + "reference": "7b750074c40c694ceb34cb926d6dffee231c5cd6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/ab97ef2f7acf0216955f5845484235113047a31d", - "reference": "ab97ef2f7acf0216955f5845484235113047a31d", + "url": "https://api.github.com/repos/symfony/mailer/zipball/7b750074c40c694ceb34cb926d6dffee231c5cd6", + "reference": "7b750074c40c694ceb34cb926d6dffee231c5cd6", "shasum": "" }, "require": { @@ -5618,8 +6056,8 @@ "php": ">=8.2", "psr/event-dispatcher": "^1", "psr/log": "^1|^2|^3", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/mime": "^7.2", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/mime": "^7.2|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -5630,10 +6068,10 @@ "symfony/twig-bridge": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/twig-bridge": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5661,7 +6099,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.4" + "source": "https://github.com/symfony/mailer/tree/v7.4.4" }, "funding": [ { @@ -5681,43 +6119,44 @@ "type": "tidelift" } ], - "time": "2025-09-17T05:51:54+00:00" + "time": "2026-01-08T08:25:11+00:00" }, { "name": "symfony/mime", - "version": "v7.3.4", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35" + "reference": "b18c7e6e9eee1e19958138df10412f3c4c316148" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/b1b828f69cbaf887fa835a091869e55df91d0e35", - "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35", + "url": "https://api.github.com/repos/symfony/mime/zipball/b18c7e6e9eee1e19958138df10412f3c4c316148", + "reference": "b18c7e6e9eee1e19958138df10412f3c4c316148", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, "conflict": { "egulias/email-validator": "~3.0.0", - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", + "phpdocumentor/reflection-docblock": "<5.2|>=6", + "phpdocumentor/type-resolver": "<1.5.1", "symfony/mailer": "<6.4", "symfony/serializer": "<6.4.3|>7.0,<7.0.3" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3" + "phpdocumentor/reflection-docblock": "^5.2", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0" }, "type": "library", "autoload": { @@ -5749,7 +6188,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.4" + "source": "https://github.com/symfony/mime/tree/v7.4.5" }, "funding": [ { @@ -5769,7 +6208,7 @@ "type": "tidelift" } ], - "time": "2025-09-16T08:38:17+00:00" + "time": "2026-01-27T08:59:58+00:00" }, { "name": "symfony/polyfill-ctype", @@ -6442,29 +6881,29 @@ }, { "name": "symfony/resend-mailer", - "version": "v7.3.3", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/resend-mailer.git", - "reference": "dffa55453571e3a6c161f1c12ee402ca19cb4dd1" + "reference": "3c1761d758bf6373c4c8a32ab6eb530dc761536f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/resend-mailer/zipball/dffa55453571e3a6c161f1c12ee402ca19cb4dd1", - "reference": "dffa55453571e3a6c161f1c12ee402ca19cb4dd1", + "url": "https://api.github.com/repos/symfony/resend-mailer/zipball/3c1761d758bf6373c4c8a32ab6eb530dc761536f", + "reference": "3c1761d758bf6373c4c8a32ab6eb530dc761536f", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/mailer": "^7.2" + "php": ">=8.2", + "symfony/mailer": "^7.2|^8.0" }, "conflict": { "symfony/http-foundation": "<7.1" }, "require-dev": { - "symfony/http-client": "^6.4|^7.0", - "symfony/http-foundation": "^7.1", - "symfony/webhook": "^6.4|^7.0" + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^7.1|^8.0", + "symfony/webhook": "^6.4|^7.0|^8.0" }, "type": "symfony-mailer-bridge", "autoload": { @@ -6492,7 +6931,7 @@ "description": "Symfony Resend Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/resend-mailer/tree/v7.3.3" + "source": "https://github.com/symfony/resend-mailer/tree/v7.4.0" }, "funding": [ { @@ -6512,20 +6951,20 @@ "type": "tidelift" } ], - "time": "2025-08-05T11:38:12+00:00" + "time": "2025-08-12T10:41:57+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -6579,7 +7018,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -6590,31 +7029,36 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "symfony/string", - "version": "v7.3.4", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f96476035142921000338bad71e5247fbc138872" + "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", - "reference": "f96476035142921000338bad71e5247fbc138872", + "url": "https://api.github.com/repos/symfony/string/zipball/1c4b10461bf2ec27537b5f36105337262f5f5d6f", + "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-grapheme": "~1.33", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, @@ -6622,11 +7066,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6665,7 +7109,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.4" + "source": "https://github.com/symfony/string/tree/v7.4.4" }, "funding": [ { @@ -6685,27 +7129,27 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:36:48+00:00" + "time": "2026-01-12T10:54:30+00:00" }, { "name": "symfony/translation", - "version": "v7.3.4", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "ec25870502d0c7072d086e8ffba1420c85965174" + "reference": "bfde13711f53f549e73b06d27b35a55207528877" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/ec25870502d0c7072d086e8ffba1420c85965174", - "reference": "ec25870502d0c7072d086e8ffba1420c85965174", + "url": "https://api.github.com/repos/symfony/translation/zipball/bfde13711f53f549e73b06d27b35a55207528877", + "reference": "bfde13711f53f549e73b06d27b35a55207528877", "shasum": "" }, "require": { "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5|^3.0" + "symfony/translation-contracts": "^2.5.3|^3.3" }, "conflict": { "nikic/php-parser": "<5.0", @@ -6724,17 +7168,17 @@ "require-dev": { "nikic/php-parser": "^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6765,7 +7209,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.4" + "source": "https://github.com/symfony/translation/tree/v7.4.4" }, "funding": [ { @@ -6785,20 +7229,20 @@ "type": "tidelift" } ], - "time": "2025-09-07T11:39:36+00:00" + "time": "2026-01-13T10:40:19+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" + "reference": "65a8bc82080447fae78373aa10f8d13b38338977" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977", "shasum": "" }, "require": { @@ -6847,7 +7291,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" }, "funding": [ { @@ -6858,25 +7302,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-27T08:32:26+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/uid", - "version": "v7.3.1", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb" + "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/a69f69f3159b852651a6bf45a9fdd149520525bb", - "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb", + "url": "https://api.github.com/repos/symfony/uid/zipball/7719ce8aba76be93dfe249192f1fbfa52c588e36", + "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36", "shasum": "" }, "require": { @@ -6884,7 +7332,7 @@ "symfony/polyfill-uuid": "^1.15" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6921,7 +7369,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.3.1" + "source": "https://github.com/symfony/uid/tree/v7.4.4" }, "funding": [ { @@ -6932,25 +7380,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2026-01-03T23:30:35+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.3.4", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb" + "reference": "0e4769b46a0c3c62390d124635ce59f66874b282" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb", - "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0e4769b46a0c3c62390d124635ce59f66874b282", + "reference": "0e4769b46a0c3c62390d124635ce59f66874b282", "shasum": "" }, "require": { @@ -6962,10 +7414,10 @@ "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/uid": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", "twig/twig": "^3.12" }, "bin": [ @@ -7004,7 +7456,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.4" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.4" }, "funding": [ { @@ -7024,30 +7476,30 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2026-01-01T22:13:48+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.6.2", + "version": "v5.6.3", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af" + "reference": "955e7815d677a3eaa7075231212f2110983adecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af", - "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.3", + "graham-campbell/result-type": "^1.1.4", "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3", - "symfony/polyfill-ctype": "^1.24", - "symfony/polyfill-mbstring": "^1.24", - "symfony/polyfill-php80": "^1.24" + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", @@ -7096,7 +7548,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" }, "funding": [ { @@ -7108,7 +7560,7 @@ "type": "tidelift" } ], - "time": "2025-04-30T23:37:27+00:00" + "time": "2025-12-27T19:49:13+00:00" } ], "packages-dev": [ @@ -7169,98 +7621,6 @@ ], "time": "2022-12-18T17:47:31+00:00" }, - { - "name": "brianium/paratest", - "version": "v6.11.1", - "source": { - "type": "git", - "url": "https://github.com/paratestphp/paratest.git", - "reference": "78e297a969049ca7cc370e80ff5e102921ef39a3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/78e297a969049ca7cc370e80ff5e102921ef39a3", - "reference": "78e297a969049ca7cc370e80ff5e102921ef39a3", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-simplexml": "*", - "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0", - "jean85/pretty-package-versions": "^2.0.5", - "php": "^7.3 || ^8.0", - "phpunit/php-code-coverage": "^9.2.25", - "phpunit/php-file-iterator": "^3.0.6", - "phpunit/php-timer": "^5.0.3", - "phpunit/phpunit": "^9.6.4", - "sebastian/environment": "^5.1.5", - "symfony/console": "^5.4.28 || ^6.3.4 || ^7.0.0", - "symfony/process": "^5.4.28 || ^6.3.4 || ^7.0.0" - }, - "require-dev": { - "doctrine/coding-standard": "^12.0.0", - "ext-pcov": "*", - "ext-posix": "*", - "infection/infection": "^0.27.6", - "squizlabs/php_codesniffer": "^3.7.2", - "symfony/filesystem": "^5.4.25 || ^6.3.1 || ^7.0.0", - "vimeo/psalm": "^5.7.7" - }, - "bin": [ - "bin/paratest", - "bin/paratest.bat", - "bin/paratest_for_phpstorm" - ], - "type": "library", - "autoload": { - "psr-4": { - "ParaTest\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Brian Scaturro", - "email": "scaturrob@gmail.com", - "role": "Developer" - }, - { - "name": "Filippo Tessarotto", - "email": "zoeslam@gmail.com", - "role": "Developer" - } - ], - "description": "Parallel testing for PHP", - "homepage": "https://github.com/paratestphp/paratest", - "keywords": [ - "concurrent", - "parallel", - "phpunit", - "testing" - ], - "support": { - "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v6.11.1" - }, - "funding": [ - { - "url": "https://github.com/sponsors/Slamdunk", - "type": "github" - }, - { - "url": "https://paypal.me/filippotessarotto", - "type": "paypal" - } - ], - "time": "2024-03-13T06:54:29+00:00" - }, { "name": "clue/ndjson-react", "version": "v1.3.0", @@ -7798,16 +8158,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.89.1", + "version": "v3.94.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "f34967da2866ace090a2b447de1f357356474573" + "reference": "883b20fb38c7866de9844ab6d0a205c423bde2d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/f34967da2866ace090a2b447de1f357356474573", - "reference": "f34967da2866ace090a2b447de1f357356474573", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/883b20fb38c7866de9844ab6d0a205c423bde2d4", + "reference": "883b20fb38c7866de9844ab6d0a205c423bde2d4", "shasum": "" }, "require": { @@ -7824,31 +8184,32 @@ "react/event-loop": "^1.5", "react/socket": "^1.16", "react/stream": "^1.4", - "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", - "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0", - "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0", - "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0", - "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0", - "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0", + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0", + "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.33", "symfony/polyfill-php80": "^1.33", "symfony/polyfill-php81": "^1.33", "symfony/polyfill-php84": "^1.33", - "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2", - "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0" + "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0", + "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0" }, "require-dev": { - "facile-it/paraunit": "^1.3.1 || ^2.7", - "infection/infection": "^0.31.0", - "justinrainbow/json-schema": "^6.5", - "keradus/cli-executor": "^2.2", + "facile-it/paraunit": "^1.3.1 || ^2.7.1", + "infection/infection": "^0.32.3", + "justinrainbow/json-schema": "^6.6.4", + "keradus/cli-executor": "^2.3", "mikey179/vfsstream": "^1.6.12", - "php-coveralls/php-coveralls": "^2.8", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", - "phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34", - "symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2", - "symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2" + "php-coveralls/php-coveralls": "^2.9.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.7", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.7", + "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.51", + "symfony/polyfill-php85": "^1.33", + "symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.4", + "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.1" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -7863,7 +8224,7 @@ "PhpCsFixer\\": "src/" }, "exclude-from-classmap": [ - "src/Fixer/Internal/*" + "src/**/Internal/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -7889,7 +8250,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.89.1" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.0" }, "funding": [ { @@ -7897,7 +8258,7 @@ "type": "github" } ], - "time": "2025-10-24T12:05:10+00:00" + "time": "2026-02-11T16:44:33+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -7950,66 +8311,6 @@ }, "time": "2025-04-30T06:54:44+00:00" }, - { - "name": "jean85/pretty-package-versions", - "version": "2.1.1", - "source": { - "type": "git", - "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a", - "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2.1.0", - "php": "^7.4|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^7.5|^8.5|^9.6", - "rector/rector": "^2.0", - "vimeo/psalm": "^4.3 || ^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Jean85\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alessandro Lai", - "email": "alessandro.lai85@gmail.com" - } - ], - "description": "A library to get pretty versions strings of installed dependencies", - "keywords": [ - "composer", - "package", - "release", - "versions" - ], - "support": { - "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1" - }, - "time": "2025-03-19T14:43:43+00:00" - }, { "name": "mockery/mockery", "version": "1.6.12", @@ -8155,16 +8456,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.2", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { @@ -8207,9 +8508,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-10-21T19:32:17+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "nunomaduro/collision", @@ -8299,412 +8600,6 @@ ], "time": "2023-01-03T12:54:54+00:00" }, - { - "name": "pestphp/pest", - "version": "v1.23.1", - "source": { - "type": "git", - "url": "https://github.com/pestphp/pest.git", - "reference": "5c56ad8772b89611c72a07e23f6e30aa29dc677a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/5c56ad8772b89611c72a07e23f6e30aa29dc677a", - "reference": "5c56ad8772b89611c72a07e23f6e30aa29dc677a", - "shasum": "" - }, - "require": { - "nunomaduro/collision": "^5.11.0|^6.4.0", - "pestphp/pest-plugin": "^1.1.0", - "php": "^7.3 || ^8.0", - "phpunit/phpunit": "^9.6.10" - }, - "require-dev": { - "illuminate/console": "^8.83.27", - "illuminate/support": "^8.83.27", - "laravel/dusk": "^6.25.2", - "pestphp/pest-dev-tools": "^1.0.0", - "pestphp/pest-plugin-parallel": "^1.2.1" - }, - "bin": [ - "bin/pest" - ], - "type": "library", - "extra": { - "pest": { - "plugins": [ - "Pest\\Plugins\\Coverage", - "Pest\\Plugins\\Init", - "Pest\\Plugins\\Version", - "Pest\\Plugins\\Environment" - ] - }, - "laravel": { - "providers": [ - "Pest\\Laravel\\PestServiceProvider" - ] - }, - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "files": [ - "src/Functions.php", - "src/Pest.php" - ], - "psr-4": { - "Pest\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "An elegant PHP Testing Framework.", - "keywords": [ - "framework", - "pest", - "php", - "test", - "testing", - "unit" - ], - "support": { - "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v1.23.1" - }, - "funding": [ - { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - } - ], - "time": "2023-07-12T19:42:47+00:00" - }, - { - "name": "pestphp/pest-plugin", - "version": "v1.1.0", - "source": { - "type": "git", - "url": "https://github.com/pestphp/pest-plugin.git", - "reference": "606c5f79c6a339b49838ffbee0151ca519efe378" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/606c5f79c6a339b49838ffbee0151ca519efe378", - "reference": "606c5f79c6a339b49838ffbee0151ca519efe378", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1.0 || ^2.0.0", - "php": "^7.3 || ^8.0" - }, - "conflict": { - "pestphp/pest": "<1.0" - }, - "require-dev": { - "composer/composer": "^2.4.2", - "pestphp/pest": "^1.22.1", - "pestphp/pest-dev-tools": "^1.0.0" - }, - "type": "composer-plugin", - "extra": { - "class": "Pest\\Plugin\\Manager", - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Pest\\Plugin\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "The Pest plugin manager", - "keywords": [ - "framework", - "manager", - "pest", - "php", - "plugin", - "test", - "testing", - "unit" - ], - "support": { - "source": "https://github.com/pestphp/pest-plugin/tree/v1.1.0" - }, - "funding": [ - { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - }, - { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" - } - ], - "time": "2022-09-18T13:18:17+00:00" - }, - { - "name": "pestphp/pest-plugin-faker", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/pestphp/pest-plugin-faker.git", - "reference": "9d93419f1f47ffd856ee544317b2f9144a129044" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-faker/zipball/9d93419f1f47ffd856ee544317b2f9144a129044", - "reference": "9d93419f1f47ffd856ee544317b2f9144a129044", - "shasum": "" - }, - "require": { - "fakerphp/faker": "^1.9.1", - "pestphp/pest": "^1.0", - "php": "^7.3 || ^8.0" - }, - "require-dev": { - "pestphp/pest-dev-tools": "dev-master" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "files": [ - "src/Faker.php" - ], - "psr-4": { - "Pest\\Faker\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "The Pest Faker Plugin", - "keywords": [ - "faker", - "framework", - "pest", - "php", - "plugin", - "test", - "testing", - "unit" - ], - "support": { - "source": "https://github.com/pestphp/pest-plugin-faker/tree/v1.0.0" - }, - "funding": [ - { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - }, - { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" - } - ], - "time": "2021-01-03T15:42:35+00:00" - }, - { - "name": "pestphp/pest-plugin-global-assertions", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/pestphp/pest-plugin-global-assertions.git", - "reference": "66eb17338393b84a5086ad01ef4f9ce972e177b3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-global-assertions/zipball/66eb17338393b84a5086ad01ef4f9ce972e177b3", - "reference": "66eb17338393b84a5086ad01ef4f9ce972e177b3", - "shasum": "" - }, - "require": { - "pestphp/pest": "^1.0", - "pestphp/pest-plugin": "^1.0", - "php": "^7.3 || ^8.0" - }, - "conflict": { - "pestphp/pest": "<1.0" - }, - "require-dev": { - "pestphp/pest-dev-tools": "dev-master" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "files": [ - "src/compiled.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A plugin to add global assertions to Pest", - "keywords": [ - "assertions", - "framework", - "global", - "pest", - "php", - "test", - "testing", - "unit" - ], - "support": { - "issues": "https://github.com/pestphp/pest-plugin-global-assertions/issues", - "source": "https://github.com/pestphp/pest-plugin-global-assertions/tree/v1.0.0" - }, - "funding": [ - { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - }, - { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" - } - ], - "time": "2021-01-03T15:35:12+00:00" - }, - { - "name": "pestphp/pest-plugin-parallel", - "version": "v1.2.1", - "source": { - "type": "git", - "url": "https://github.com/pestphp/pest-plugin-parallel.git", - "reference": "842592eba2439ba6477f6d6c7ee4a4e7bccdcd10" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-parallel/zipball/842592eba2439ba6477f6d6c7ee4a4e7bccdcd10", - "reference": "842592eba2439ba6477f6d6c7ee4a4e7bccdcd10", - "shasum": "" - }, - "require": { - "brianium/paratest": "^6.8.1", - "pestphp/pest-plugin": "^1.1.0", - "php": "^7.3 || ^8.0" - }, - "conflict": { - "laravel/framework": "<8.55", - "nunomaduro/collision": "<5.8", - "pestphp/pest": "<1.16" - }, - "require-dev": { - "pestphp/pest": "^1.22.3", - "pestphp/pest-dev-tools": "^1.0.0" - }, - "type": "library", - "extra": { - "pest": { - "plugins": [ - "Pest\\Parallel\\Plugin" - ] - } - }, - "autoload": { - "files": [ - "src/Autoload.php", - "build/RunnerWorker.php", - "build/BaseRunner.php" - ], - "psr-4": { - "Pest\\Parallel\\": "src/" - }, - "exclude-from-classmap": [ - "ParaTest\\Runners\\PHPUnit\\Worker\\RunnerWorker", - "ParaTest\\Runners\\PHPUnit\\BaseRunner" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "The Pest Parallel Plugin", - "keywords": [ - "framework", - "parallel", - "pest", - "php", - "plugin", - "test", - "testing", - "unit" - ], - "support": { - "source": "https://github.com/pestphp/pest-plugin-parallel/tree/v1.2.1" - }, - "funding": [ - { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", - "type": "custom" - }, - { - "url": "https://github.com/lukeraymonddowning", - "type": "github" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - }, - { - "url": "https://github.com/octoper", - "type": "github" - }, - { - "url": "https://github.com/olivernybroe", - "type": "github" - }, - { - "url": "https://github.com/owenvoke", - "type": "github" - }, - { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" - } - ], - "time": "2023-02-03T13:01:17+00:00" - }, { "name": "phar-io/manifest", "version": "2.0.4", @@ -9344,16 +9239,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.29", + "version": "9.6.34", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3" + "reference": "b36f02317466907a230d3aa1d34467041271ef4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9ecfec57835a5581bc888ea7e13b51eb55ab9dd3", - "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b36f02317466907a230d3aa1d34467041271ef4a", + "reference": "b36f02317466907a230d3aa1d34467041271ef4a", "shasum": "" }, "require": { @@ -9375,7 +9270,7 @@ "phpunit/php-timer": "^5.0.3", "sebastian/cli-parser": "^1.0.2", "sebastian/code-unit": "^1.0.8", - "sebastian/comparator": "^4.0.9", + "sebastian/comparator": "^4.0.10", "sebastian/diff": "^4.0.6", "sebastian/environment": "^5.1.5", "sebastian/exporter": "^4.0.8", @@ -9427,7 +9322,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.29" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.34" }, "funding": [ { @@ -9451,7 +9346,7 @@ "type": "tidelift" } ], - "time": "2025-09-24T06:29:11+00:00" + "time": "2026-01-27T05:45:00+00:00" }, { "name": "react/cache", @@ -9527,16 +9422,16 @@ }, { "name": "react/child-process", - "version": "v0.6.6", + "version": "v0.6.7", "source": { "type": "git", "url": "https://github.com/reactphp/child-process.git", - "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159" + "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159", - "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/970f0e71945556422ee4570ccbabaedc3cf04ad3", + "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3", "shasum": "" }, "require": { @@ -9590,7 +9485,7 @@ ], "support": { "issues": "https://github.com/reactphp/child-process/issues", - "source": "https://github.com/reactphp/child-process/tree/v0.6.6" + "source": "https://github.com/reactphp/child-process/tree/v0.6.7" }, "funding": [ { @@ -9598,20 +9493,20 @@ "type": "open_collective" } ], - "time": "2025-01-01T16:37:48+00:00" + "time": "2025-12-23T15:25:20+00:00" }, { "name": "react/dns", - "version": "v1.13.0", + "version": "v1.14.0", "source": { "type": "git", "url": "https://github.com/reactphp/dns.git", - "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", - "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3", + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3", "shasum": "" }, "require": { @@ -9666,7 +9561,7 @@ ], "support": { "issues": "https://github.com/reactphp/dns/issues", - "source": "https://github.com/reactphp/dns/tree/v1.13.0" + "source": "https://github.com/reactphp/dns/tree/v1.14.0" }, "funding": [ { @@ -9674,20 +9569,20 @@ "type": "open_collective" } ], - "time": "2024-06-13T14:18:03+00:00" + "time": "2025-11-18T19:34:28+00:00" }, { "name": "react/event-loop", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/reactphp/event-loop.git", - "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", - "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a", + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a", "shasum": "" }, "require": { @@ -9738,7 +9633,7 @@ ], "support": { "issues": "https://github.com/reactphp/event-loop/issues", - "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + "source": "https://github.com/reactphp/event-loop/tree/v1.6.0" }, "funding": [ { @@ -9746,7 +9641,7 @@ "type": "open_collective" } ], - "time": "2023-11-13T13:48:05+00:00" + "time": "2025-11-17T20:46:25+00:00" }, { "name": "react/promise", @@ -9823,16 +9718,16 @@ }, { "name": "react/socket", - "version": "v1.16.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/reactphp/socket.git", - "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1" + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", - "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08", + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08", "shasum": "" }, "require": { @@ -9891,7 +9786,7 @@ ], "support": { "issues": "https://github.com/reactphp/socket/issues", - "source": "https://github.com/reactphp/socket/tree/v1.16.0" + "source": "https://github.com/reactphp/socket/tree/v1.17.0" }, "funding": [ { @@ -9899,7 +9794,7 @@ "type": "open_collective" } ], - "time": "2024-07-26T10:38:09+00:00" + "time": "2025-11-19T20:47:34+00:00" }, { "name": "react/stream", @@ -10148,16 +10043,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.9", + "version": "4.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5" + "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5", - "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e4df00b9b3571187db2831ae9aada2c6efbd715d", + "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d", "shasum": "" }, "require": { @@ -10210,7 +10105,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.10" }, "funding": [ { @@ -10230,7 +10125,7 @@ "type": "tidelift" } ], - "time": "2025-08-10T06:51:50+00:00" + "time": "2026-01-24T09:22:56+00:00" }, { "name": "sebastian/complexity", @@ -11052,23 +10947,23 @@ }, { "name": "symfony/finder", - "version": "v7.3.2", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" + "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", + "url": "https://api.github.com/repos/symfony/finder/zipball/ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", + "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0" + "symfony/filesystem": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -11096,7 +10991,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.2" + "source": "https://github.com/symfony/finder/tree/v7.4.5" }, "funding": [ { @@ -11116,20 +11011,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2026-01-26T15:07:59+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.3.3", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d" + "reference": "b38026df55197f9e39a44f3215788edf83187b80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d", - "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", + "reference": "b38026df55197f9e39a44f3215788edf83187b80", "shasum": "" }, "require": { @@ -11167,7 +11062,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.3.3" + "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" }, "funding": [ { @@ -11187,7 +11082,7 @@ "type": "tidelift" } ], - "time": "2025-08-05T10:16:07+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/polyfill-php81", @@ -11351,16 +11246,16 @@ }, { "name": "symfony/process", - "version": "v7.3.4", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b" + "reference": "608476f4604102976d687c483ac63a79ba18cc97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b", - "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b", + "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", + "reference": "608476f4604102976d687c483ac63a79ba18cc97", "shasum": "" }, "require": { @@ -11392,7 +11287,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.4" + "source": "https://github.com/symfony/process/tree/v7.4.5" }, "funding": [ { @@ -11412,20 +11307,20 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2026-01-26T15:07:59+00:00" }, { "name": "symfony/stopwatch", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" + "reference": "8a24af0a2e8a872fb745047180649b8418303084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", - "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/8a24af0a2e8a872fb745047180649b8418303084", + "reference": "8a24af0a2e8a872fb745047180649b8418303084", "shasum": "" }, "require": { @@ -11458,7 +11353,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.3.0" + "source": "https://github.com/symfony/stopwatch/tree/v7.4.0" }, "funding": [ { @@ -11469,25 +11364,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-24T10:49:57+00:00" + "time": "2025-08-04T07:05:15+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { @@ -11516,7 +11415,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" }, "funding": [ { @@ -11524,7 +11423,7 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2025-11-17T20:03:58+00:00" } ], "aliases": [], @@ -11539,5 +11438,5 @@ "ext-pcntl": "*" }, "platform-dev": {}, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } From 1de439ca8ee1f6dcaae16031f30847b48d432e86 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 2 Mar 2026 22:18:10 +0000 Subject: [PATCH 090/133] feat: email verification using otp --- .../Auth/VerifyEmailController.php | 72 ++++ app/Models/User.php | 5 + routes/api.php | 7 +- tests/Feature/Auth/VerifyEmailTest.php | 382 ++++++++++++++++++ 4 files changed, 465 insertions(+), 1 deletion(-) create mode 100644 app/Http/Controllers/Auth/VerifyEmailController.php create mode 100644 tests/Feature/Auth/VerifyEmailTest.php diff --git a/app/Http/Controllers/Auth/VerifyEmailController.php b/app/Http/Controllers/Auth/VerifyEmailController.php new file mode 100644 index 0000000..db551ac --- /dev/null +++ b/app/Http/Controllers/Auth/VerifyEmailController.php @@ -0,0 +1,72 @@ +setRules([ + 'email' => Email::required()->validations( + new DNSCheckValidation(), + new NoRFCWarningsValidation() + )->max(100) + ->exists('users', 'email', function ($query) use ($request): void { + $query->whereEqual('email', $request->body('email')) + ->whereNull('email_verified_at'); + }), + 'otp' => Numeric::required()->digits(6), + ]); + + if ($validator->fails()) { + return response()->json([ + 'errors' => $validator->failing(), + ], HttpStatus::UNPROCESSABLE_ENTITY); + } + + /** @var User $user */ + $user = User::query()->whereEqual('email', $request->body('email'))->first(); + + /** @var UserOtp $otp */ + $otp = UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::VERIFY_EMAIL->value) + ->whereEqual('code', hash('sha256', (string) $request->body('otp'))) + ->whereNull('used_at') + ->whereGreaterThanOrEqual('expires_at', Date::now()->toDateTimeString()) + ->first(); + + if (! $otp) { + return response()->json([ + 'message' => 'The provided OTP is invalid.', + ], HttpStatus::NOT_FOUND); + } + + $otp->usedAt = Date::now(); + $otp->save(); + + $user->emailVerifiedAt = Date::now(); + $user->save(); + + return response()->json([ + 'message' => 'Email verified successfully.', + ], HttpStatus::OK); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 09e580c..dfa03f2 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -8,11 +8,16 @@ use App\Mail\SendEmailVerificationOtp; use App\Mail\SendLoginOtp; use Phenix\Auth\User as Authenticable; +use Phenix\Database\Models\Attributes\DateTime; use Phenix\Facades\Mail; use Phenix\Mail\Mailable; +use Phenix\Util\Date; class User extends Authenticable { + #[DateTime(name: 'email_verified_at')] + public Date|null $emailVerifiedAt = null; + public function createOneTimePassword(OneTimePasswordScope $scope): UserOtp { $userOtp = UserOtp::fromScope($scope); diff --git a/routes/api.php b/routes/api.php index e2b082b..a034b7c 100644 --- a/routes/api.php +++ b/routes/api.php @@ -3,6 +3,7 @@ declare(strict_types=1); use App\Http\Controllers\Auth\RegisterController; +use App\Http\Controllers\Auth\VerifyEmailController; use App\Http\Controllers\WelcomeController; use App\Http\Middleware\RedirectIfAuthenticated; use Phenix\Facades\Route; @@ -11,5 +12,9 @@ Route::get('/', [WelcomeController::class, 'index']); Route::middleware(RedirectIfAuthenticated::class)->group(function (Router $router): void { - $router->post('register', [RegisterController::class, 'store']); + $router->post('register', [RegisterController::class, 'store']) + ->name('register'); + + $router->post('verify-email', [VerifyEmailController::class, 'verify']) + ->name('verification.verify'); }); diff --git a/tests/Feature/Auth/VerifyEmailTest.php b/tests/Feature/Auth/VerifyEmailTest.php new file mode 100644 index 0000000..eb44192 --- /dev/null +++ b/tests/Feature/Auth/VerifyEmailTest.php @@ -0,0 +1,382 @@ + $this->faker()->name(), + 'email' => 'test@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => $otp->otp, + ]); + + $response->assertOk() + ->assertJsonPath('data.message', 'Email verified successfully.'); + + $this->assertDatabaseHas('users', [ + 'email' => $user->email, + 'email_verified_at' => Date::now(), + ]); + + $this->assertDatabaseHas('user_one_time_passwords', [ + 'user_id' => $user->id, + 'scope' => OneTimePasswordScope::VERIFY_EMAIL->value, + 'used_at' => Date::now(), + ]); + } + + /** @test */ + public function it_does_not_verify_email_because_email_is_already_verified(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'verified@gmail.com', + 'password' => Crypto::encryptString('password'), + 'email_verified_at' => Date::now(), + ]); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => '123456', + ]); + + $response->assertUnprocessableEntity() + ->assertJsonPath('data.errors.email.0', 'The selected email is invalid.'); + } + + /** @test */ + public function it_responds_not_found_for_non_existing_otp(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'nonexist@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => '123456', + ]); + + $response->assertNotFound() + ->assertJsonPath('data.message', 'The provided OTP is invalid.'); + } + + /** @test */ + public function it_responds_not_found_when_otp_has_different_scope(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'scope@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + // Create OTP with LOGIN scope instead of VERIFY_EMAIL + $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => $otp->otp, + ]); + + $response->assertNotFound() + ->assertJsonPath('data.message', 'The provided OTP is invalid.'); + + $this->assertDatabaseHas('users', [ + 'email' => $user->email, + 'email_verified_at' => null, + ]); + } + + /** @test */ + public function it_responds_not_found_when_otp_belongs_to_different_user(): void + { + $userA = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'usera@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $userB = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'userb@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + // Create OTP for user A + $otp = $userA->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + + // Try to use user A's OTP with user B's email + $response = $this->post('/verify-email', [ + 'email' => $userB->email, + 'otp' => $otp->otp, + ]); + + $response->assertNotFound() + ->assertJsonPath('data.message', 'The provided OTP is invalid.'); + + // Neither user should be verified + $this->assertDatabaseHas('users', [ + 'email' => $userA->email, + 'email_verified_at' => null, + ]); + + $this->assertDatabaseHas('users', [ + 'email' => $userB->email, + 'email_verified_at' => null, + ]); + } + + /** @test */ + public function it_responds_not_found_when_otp_is_already_used(): void + { + Date::setTestNow(Date::now()); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'used@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + + // Mark the OTP as already used + $otp->usedAt = Date::now(); + $otp->save(); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => $otp->otp, + ]); + + $response->assertNotFound() + ->assertJsonPath('data.message', 'The provided OTP is invalid.'); + + // User should not be verified + $this->assertDatabaseHas('users', [ + 'email' => $user->email, + 'email_verified_at' => null, + ]); + } + + /** @test */ + public function it_responds_not_found_when_otp_is_expired(): void + { + Date::setTestNow(Date::now()); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'expired@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + + // Advance time by 11 minutes (default expiration is 10 minutes) + Date::setTestNow(Date::now()->addMinutes(11)); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => $otp->otp, + ]); + + $response->assertNotFound() + ->assertJsonPath('data.message', 'The provided OTP is invalid.'); + + // User should not be verified + $this->assertDatabaseHas('users', [ + 'email' => $user->email, + 'email_verified_at' => null, + ]); + } + + /** @test */ + public function it_verifies_email_when_otp_is_one_second_before_expiration(): void + { + $startTime = Date::now(); + Date::setTestNow($startTime); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'boundary@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + + // Advance time to 1 second before expiration (default is 10 minutes) + Date::setTestNow($startTime->addMinutes(10)->subSecond()); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => $otp->otp, + ]); + + $response->assertOk() + ->assertJsonPath('data.message', 'Email verified successfully.'); + + // User should be verified + $this->assertDatabaseHas('users', [ + 'email' => $user->email, + 'email_verified_at' => Date::now(), + ]); + } + + /** @test */ + public function it_verifies_email_with_older_otp_when_multiple_valid_otps_exist(): void + { + Date::setTestNow(Date::now()); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'multiple@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + // Create two OTPs for the same user and scope + $otp1 = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + Date::setTestNow(Date::now()->addMinute()); + $otp2 = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + + // Try to verify with the older OTP (both are valid) + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => $otp1->otp, + ]); + + $response->assertOk() + ->assertJsonPath('data.message', 'Email verified successfully.'); + + // User should be verified + $this->assertDatabaseHas('users', [ + 'email' => $user->email, + 'email_verified_at' => Date::now(), + ]); + } + + /** @test */ + public function it_responds_with_validation_error_when_otp_has_less_than_6_digits(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'digits5@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => '12345', // Only 5 digits + ]); + + $response->assertUnprocessableEntity() + ->assertJsonPath('data.errors.otp.0', 'The otp must be 6 digits.'); + } + + /** @test */ + public function it_responds_with_validation_error_when_otp_has_more_than_6_digits(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'digits7@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => '1234567', // 7 digits + ]); + + $response->assertUnprocessableEntity() + ->assertJsonPath('data.errors.otp.0', 'The otp must be 6 digits.'); + } + + /** @test */ + public function it_responds_with_validation_error_when_otp_is_not_numeric(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'nonnumeric@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => '12345a', // Contains letter + ]); + + $response->assertUnprocessableEntity() + ->assertJsonPath('data.errors.otp.0', 'The otp must be a number.'); + } + + /** @test */ + public function it_responds_with_validation_error_when_otp_is_missing(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'nootp@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + ]); + + $response->assertUnprocessableEntity() + ->assertJsonPath('data.errors.otp.0', 'The otp field is required.'); + } + + /** @test */ + public function it_responds_with_validation_error_when_email_is_empty_string(): void + { + $response = $this->post('/verify-email', [ + 'email' => '', + 'otp' => '123456', + ]); + + $response->assertUnprocessableEntity() + ->assertJsonPath('data.errors.email.0', 'The email field is required.'); + } + + /** @test */ + public function it_responds_with_validation_error_when_otp_is_empty_string(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => 'emptyotp@gmail.com', + 'password' => Crypto::encryptString('password'), + ]); + + $response = $this->post('/verify-email', [ + 'email' => $user->email, + 'otp' => '', + ]); + + $response->assertUnprocessableEntity() + ->assertJsonPath('data.errors.otp.0', 'The otp field is required.'); + } +} From 2b27fe549fd7d257a1501f9e246d4352e6d1d57d Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Mon, 2 Mar 2026 22:52:26 +0000 Subject: [PATCH 091/133] feat: use faker for dynamic email generation in VerifyEmailTest --- tests/Feature/Auth/VerifyEmailTest.php | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/Feature/Auth/VerifyEmailTest.php b/tests/Feature/Auth/VerifyEmailTest.php index eb44192..865ab5e 100644 --- a/tests/Feature/Auth/VerifyEmailTest.php +++ b/tests/Feature/Auth/VerifyEmailTest.php @@ -24,7 +24,7 @@ public function it_verifies_email(): void $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'test@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -55,7 +55,7 @@ public function it_does_not_verify_email_because_email_is_already_verified(): vo { $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'verified@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), 'email_verified_at' => Date::now(), ]); @@ -74,7 +74,7 @@ public function it_responds_not_found_for_non_existing_otp(): void { $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'nonexist@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -92,7 +92,7 @@ public function it_responds_not_found_when_otp_has_different_scope(): void { $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'scope@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -118,13 +118,13 @@ public function it_responds_not_found_when_otp_belongs_to_different_user(): void { $userA = User::create([ 'name' => $this->faker()->name(), - 'email' => 'usera@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); $userB = User::create([ 'name' => $this->faker()->name(), - 'email' => 'userb@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -159,7 +159,7 @@ public function it_responds_not_found_when_otp_is_already_used(): void $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'used@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -191,7 +191,7 @@ public function it_responds_not_found_when_otp_is_expired(): void $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'expired@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -223,7 +223,7 @@ public function it_verifies_email_when_otp_is_one_second_before_expiration(): vo $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'boundary@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -254,7 +254,7 @@ public function it_verifies_email_with_older_otp_when_multiple_valid_otps_exist( $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'multiple@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -284,7 +284,7 @@ public function it_responds_with_validation_error_when_otp_has_less_than_6_digit { $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'digits5@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -302,7 +302,7 @@ public function it_responds_with_validation_error_when_otp_has_more_than_6_digit { $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'digits7@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -320,7 +320,7 @@ public function it_responds_with_validation_error_when_otp_is_not_numeric(): voi { $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'nonnumeric@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -338,7 +338,7 @@ public function it_responds_with_validation_error_when_otp_is_missing(): void { $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'nootp@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); @@ -367,7 +367,7 @@ public function it_responds_with_validation_error_when_otp_is_empty_string(): vo { $user = User::create([ 'name' => $this->faker()->name(), - 'email' => 'emptyotp@gmail.com', + 'email' => $this->faker()->freeEmail(), 'password' => Crypto::encryptString('password'), ]); From 35111bd1be875bda71b67078c872d564fbee7e18 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 11 Mar 2026 21:23:26 +0000 Subject: [PATCH 092/133] feat: sync config files with framework --- config/cache.php | 2 +- config/mail.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/config/cache.php b/config/cache.php index fa507c9..c0c5238 100644 --- a/config/cache.php +++ b/config/cache.php @@ -12,7 +12,7 @@ | using this caching library. This connection is used when another is | not explicitly specified when executing a given caching function. | - | Supported: "local", "redis" + | Supported: "local", "file", "redis" | */ diff --git a/config/mail.php b/config/mail.php index 3a11d09..462f244 100644 --- a/config/mail.php +++ b/config/mail.php @@ -23,6 +23,10 @@ 'resend' => [ 'transport' => 'resend', ], + + 'log' => [ + 'transport' => 'log', + ], ], 'from' => [ From 6841c758f39c4626fe44a221087be9d0d4b81ff1 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 11 Mar 2026 21:23:40 +0000 Subject: [PATCH 093/133] feat: add scheduled task to delete unused UserOtp records --- schedule/schedules.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 schedule/schedules.php diff --git a/schedule/schedules.php b/schedule/schedules.php new file mode 100644 index 0000000..6ac6751 --- /dev/null +++ b/schedule/schedules.php @@ -0,0 +1,14 @@ +whereNull('used_at') + ->whereLessThan('expires_at', Date::now()->toDateTimeString()) + ->delete(); +})->everyMinute(); \ No newline at end of file From f0aba6f6fe6a1ab91037f277d98591cb7287a0f5 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 13 Mar 2026 12:15:56 -0500 Subject: [PATCH 094/133] feat: implement ResendOtpController and corresponding tests for email verification OTP --- .../Controllers/Auth/ResendOtpController.php | 62 +++++++++ routes/api.php | 22 ++- tests/Feature/Auth/ResendOtpTest.php | 128 ++++++++++++++++++ 3 files changed, 205 insertions(+), 7 deletions(-) create mode 100644 app/Http/Controllers/Auth/ResendOtpController.php create mode 100644 tests/Feature/Auth/ResendOtpTest.php diff --git a/app/Http/Controllers/Auth/ResendOtpController.php b/app/Http/Controllers/Auth/ResendOtpController.php new file mode 100644 index 0000000..a89659f --- /dev/null +++ b/app/Http/Controllers/Auth/ResendOtpController.php @@ -0,0 +1,62 @@ +setRules([ + 'email' => Email::required()->validations( + new DNSCheckValidation(), + new NoRFCWarningsValidation() + )->max(100) + ->exists('users', 'email', function ($query): void { + $query->whereNull('email_verified_at'); + }), + ]); + + if ($validator->fails()) { + return response()->json([ + 'errors' => $validator->failing(), + ], HttpStatus::UNPROCESSABLE_ENTITY); + } + + /** @var User $user */ + $user = User::query()->whereEqual('email', $request->body('email'))->first(); + + $otpCount = UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::VERIFY_EMAIL->value) + ->whereGreaterThanOrEqual('created_at', Date::now()->subHour()->toDateTimeString()) + ->count(); + + if ($otpCount >= 5) { + return response()->json([ + 'message' => 'You have exceeded the maximum number of OTP requests. Please try again later.', + ], HttpStatus::TOO_MANY_REQUESTS); + } + + $user->sendOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + + return response()->json([ + 'message' => 'OTP has been resent successfully.', + ], HttpStatus::OK); + } +} diff --git a/routes/api.php b/routes/api.php index a034b7c..eeb053b 100644 --- a/routes/api.php +++ b/routes/api.php @@ -3,18 +3,26 @@ declare(strict_types=1); use App\Http\Controllers\Auth\RegisterController; +use App\Http\Controllers\Auth\ResendOtpController; use App\Http\Controllers\Auth\VerifyEmailController; use App\Http\Controllers\WelcomeController; -use App\Http\Middleware\RedirectIfAuthenticated; +use App\Http\Middleware\Guest; +use Phenix\Cache\RateLimit\Middlewares\RateLimiter; use Phenix\Facades\Route; use Phenix\Routing\Route as Router; Route::get('/', [WelcomeController::class, 'index']); -Route::middleware(RedirectIfAuthenticated::class)->group(function (Router $router): void { - $router->post('register', [RegisterController::class, 'store']) - ->name('register'); +Route::middleware(Guest::class) + ->group(function (Router $router): void { + $router->post('register', [RegisterController::class, 'store']) + ->name('register'); - $router->post('verify-email', [VerifyEmailController::class, 'verify']) - ->name('verification.verify'); -}); + $router->post('verify-email', [VerifyEmailController::class, 'verify']) + ->name('verification.verify') + ->middleware(RateLimiter::perMinute(6)); + + $router->post('resend-verification-otp', [ResendOtpController::class, 'resend']) + ->name('verification.resend') + ->middleware(RateLimiter::perMinute(2)); + }); diff --git a/tests/Feature/Auth/ResendOtpTest.php b/tests/Feature/Auth/ResendOtpTest.php new file mode 100644 index 0000000..844066e --- /dev/null +++ b/tests/Feature/Auth/ResendOtpTest.php @@ -0,0 +1,128 @@ + $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Crypto::encryptString('password'), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + + $response = $this->post('/resend-verification-otp', [ + 'email' => $user->email, + ]); + + $response->assertOk() + ->assertJsonPath('message', 'OTP has been resent successfully.'); + + $this->assertDatabaseHas('user_one_time_passwords', [ + 'id' => $otp->id, + 'user_id' => $user->id, + 'scope' => OneTimePasswordScope::VERIFY_EMAIL->value, + 'used_at' => null, + ]); + + $this->assertEquals( + 2, + UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::VERIFY_EMAIL->value) + ->count() + ); + + Mail::expect(SendEmailVerificationOtp::class)->toBeSentTimes(1); + } + + /** @test */ + public function it_does_not_resend_otp_when_email_is_already_verified(): void + { + Mail::fake(); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Crypto::encryptString('password'), + 'email_verified_at' => Date::now(), + ]); + + $response = $this->post('/resend-verification-otp', [ + 'email' => $user->email, + ]); + + $response->assertUnprocessableEntity() + ->assertJsonPath('errors.email.0', 'The selected email is invalid.'); + + Mail::expect(SendEmailVerificationOtp::class)->toNotBeSent(); + } + + /** @test */ + public function it_responds_unauthorized_when_authorization_token_is_present(): void + { + Mail::fake(); + + $response = $this->post( + '/resend-verification-otp', + ['email' => $this->faker()->freeEmail()], + [], + ['Authorization' => 'Bearer any-token'] + ); + + $response->assertUnauthorized() + ->assertJsonPath('message', 'Unauthorized'); + + Mail::expect(SendEmailVerificationOtp::class)->toNotBeSent(); + } + + /** @test */ + public function it_responds_too_many_requests_when_exceed_otp_limit(): void + { + Date::setTestNow(Date::now()); + Mail::fake(); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Crypto::encryptString('password'), + ]); + + for ($i = 0; $i < 5; $i++) { + $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + } + + $response = $this->post('/resend-verification-otp', [ + 'email' => $user->email, + ]); + + $response->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) + ->assertJsonPath('message', 'You have exceeded the maximum number of OTP requests. Please try again later.'); + + Mail::expect(SendEmailVerificationOtp::class)->toNotBeSent(); + } +} From e958748aef4e8e7e3b317e52c618e000a03cb36d Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 14 Mar 2026 03:21:06 +0000 Subject: [PATCH 095/133] tests(refactor): remove non required tests --- tests/Feature/Auth/VerifyEmailTest.php | 216 +------------------------ 1 file changed, 6 insertions(+), 210 deletions(-) diff --git a/tests/Feature/Auth/VerifyEmailTest.php b/tests/Feature/Auth/VerifyEmailTest.php index 865ab5e..b35ec58 100644 --- a/tests/Feature/Auth/VerifyEmailTest.php +++ b/tests/Feature/Auth/VerifyEmailTest.php @@ -36,7 +36,7 @@ public function it_verifies_email(): void ]); $response->assertOk() - ->assertJsonPath('data.message', 'Email verified successfully.'); + ->assertJsonPath('message', 'Email verified successfully.'); $this->assertDatabaseHas('users', [ 'email' => $user->email, @@ -66,7 +66,7 @@ public function it_does_not_verify_email_because_email_is_already_verified(): vo ]); $response->assertUnprocessableEntity() - ->assertJsonPath('data.errors.email.0', 'The selected email is invalid.'); + ->assertJsonPath('errors.email.0', 'The selected email is invalid.'); } /** @test */ @@ -84,7 +84,7 @@ public function it_responds_not_found_for_non_existing_otp(): void ]); $response->assertNotFound() - ->assertJsonPath('data.message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', 'The provided OTP is invalid.'); } /** @test */ @@ -105,7 +105,7 @@ public function it_responds_not_found_when_otp_has_different_scope(): void ]); $response->assertNotFound() - ->assertJsonPath('data.message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', 'The provided OTP is invalid.'); $this->assertDatabaseHas('users', [ 'email' => $user->email, @@ -113,45 +113,6 @@ public function it_responds_not_found_when_otp_has_different_scope(): void ]); } - /** @test */ - public function it_responds_not_found_when_otp_belongs_to_different_user(): void - { - $userA = User::create([ - 'name' => $this->faker()->name(), - 'email' => $this->faker()->freeEmail(), - 'password' => Crypto::encryptString('password'), - ]); - - $userB = User::create([ - 'name' => $this->faker()->name(), - 'email' => $this->faker()->freeEmail(), - 'password' => Crypto::encryptString('password'), - ]); - - // Create OTP for user A - $otp = $userA->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); - - // Try to use user A's OTP with user B's email - $response = $this->post('/verify-email', [ - 'email' => $userB->email, - 'otp' => $otp->otp, - ]); - - $response->assertNotFound() - ->assertJsonPath('data.message', 'The provided OTP is invalid.'); - - // Neither user should be verified - $this->assertDatabaseHas('users', [ - 'email' => $userA->email, - 'email_verified_at' => null, - ]); - - $this->assertDatabaseHas('users', [ - 'email' => $userB->email, - 'email_verified_at' => null, - ]); - } - /** @test */ public function it_responds_not_found_when_otp_is_already_used(): void { @@ -175,7 +136,7 @@ public function it_responds_not_found_when_otp_is_already_used(): void ]); $response->assertNotFound() - ->assertJsonPath('data.message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', 'The provided OTP is invalid.'); // User should not be verified $this->assertDatabaseHas('users', [ @@ -206,7 +167,7 @@ public function it_responds_not_found_when_otp_is_expired(): void ]); $response->assertNotFound() - ->assertJsonPath('data.message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', 'The provided OTP is invalid.'); // User should not be verified $this->assertDatabaseHas('users', [ @@ -214,169 +175,4 @@ public function it_responds_not_found_when_otp_is_expired(): void 'email_verified_at' => null, ]); } - - /** @test */ - public function it_verifies_email_when_otp_is_one_second_before_expiration(): void - { - $startTime = Date::now(); - Date::setTestNow($startTime); - - $user = User::create([ - 'name' => $this->faker()->name(), - 'email' => $this->faker()->freeEmail(), - 'password' => Crypto::encryptString('password'), - ]); - - $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); - - // Advance time to 1 second before expiration (default is 10 minutes) - Date::setTestNow($startTime->addMinutes(10)->subSecond()); - - $response = $this->post('/verify-email', [ - 'email' => $user->email, - 'otp' => $otp->otp, - ]); - - $response->assertOk() - ->assertJsonPath('data.message', 'Email verified successfully.'); - - // User should be verified - $this->assertDatabaseHas('users', [ - 'email' => $user->email, - 'email_verified_at' => Date::now(), - ]); - } - - /** @test */ - public function it_verifies_email_with_older_otp_when_multiple_valid_otps_exist(): void - { - Date::setTestNow(Date::now()); - - $user = User::create([ - 'name' => $this->faker()->name(), - 'email' => $this->faker()->freeEmail(), - 'password' => Crypto::encryptString('password'), - ]); - - // Create two OTPs for the same user and scope - $otp1 = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); - Date::setTestNow(Date::now()->addMinute()); - $otp2 = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); - - // Try to verify with the older OTP (both are valid) - $response = $this->post('/verify-email', [ - 'email' => $user->email, - 'otp' => $otp1->otp, - ]); - - $response->assertOk() - ->assertJsonPath('data.message', 'Email verified successfully.'); - - // User should be verified - $this->assertDatabaseHas('users', [ - 'email' => $user->email, - 'email_verified_at' => Date::now(), - ]); - } - - /** @test */ - public function it_responds_with_validation_error_when_otp_has_less_than_6_digits(): void - { - $user = User::create([ - 'name' => $this->faker()->name(), - 'email' => $this->faker()->freeEmail(), - 'password' => Crypto::encryptString('password'), - ]); - - $response = $this->post('/verify-email', [ - 'email' => $user->email, - 'otp' => '12345', // Only 5 digits - ]); - - $response->assertUnprocessableEntity() - ->assertJsonPath('data.errors.otp.0', 'The otp must be 6 digits.'); - } - - /** @test */ - public function it_responds_with_validation_error_when_otp_has_more_than_6_digits(): void - { - $user = User::create([ - 'name' => $this->faker()->name(), - 'email' => $this->faker()->freeEmail(), - 'password' => Crypto::encryptString('password'), - ]); - - $response = $this->post('/verify-email', [ - 'email' => $user->email, - 'otp' => '1234567', // 7 digits - ]); - - $response->assertUnprocessableEntity() - ->assertJsonPath('data.errors.otp.0', 'The otp must be 6 digits.'); - } - - /** @test */ - public function it_responds_with_validation_error_when_otp_is_not_numeric(): void - { - $user = User::create([ - 'name' => $this->faker()->name(), - 'email' => $this->faker()->freeEmail(), - 'password' => Crypto::encryptString('password'), - ]); - - $response = $this->post('/verify-email', [ - 'email' => $user->email, - 'otp' => '12345a', // Contains letter - ]); - - $response->assertUnprocessableEntity() - ->assertJsonPath('data.errors.otp.0', 'The otp must be a number.'); - } - - /** @test */ - public function it_responds_with_validation_error_when_otp_is_missing(): void - { - $user = User::create([ - 'name' => $this->faker()->name(), - 'email' => $this->faker()->freeEmail(), - 'password' => Crypto::encryptString('password'), - ]); - - $response = $this->post('/verify-email', [ - 'email' => $user->email, - ]); - - $response->assertUnprocessableEntity() - ->assertJsonPath('data.errors.otp.0', 'The otp field is required.'); - } - - /** @test */ - public function it_responds_with_validation_error_when_email_is_empty_string(): void - { - $response = $this->post('/verify-email', [ - 'email' => '', - 'otp' => '123456', - ]); - - $response->assertUnprocessableEntity() - ->assertJsonPath('data.errors.email.0', 'The email field is required.'); - } - - /** @test */ - public function it_responds_with_validation_error_when_otp_is_empty_string(): void - { - $user = User::create([ - 'name' => $this->faker()->name(), - 'email' => $this->faker()->freeEmail(), - 'password' => Crypto::encryptString('password'), - ]); - - $response = $this->post('/verify-email', [ - 'email' => $user->email, - 'otp' => '', - ]); - - $response->assertUnprocessableEntity() - ->assertJsonPath('data.errors.otp.0', 'The otp field is required.'); - } } From f450548d2a02c47c03991c8e6024d7becf59235d Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 14 Mar 2026 03:22:34 +0000 Subject: [PATCH 096/133] tests(refactor): remove data key wrapper --- tests/Feature/Auth/RegisterTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php index dfcf934..02991ad 100644 --- a/tests/Feature/Auth/RegisterTest.php +++ b/tests/Feature/Auth/RegisterTest.php @@ -34,7 +34,7 @@ public function it_registers_a_user(): void ->assertJsonContains([ 'name' => $data['name'], 'email' => $data['email'], - ], 'data'); + ]); $this->assertDatabaseHas('users', [ 'email' => $data['email'], @@ -43,7 +43,7 @@ public function it_registers_a_user(): void $data = $response->getDecodedBody(); $this->assertDatabaseHas('user_one_time_passwords', [ - 'user_id' => $data['data']['id'], + 'user_id' => $data['id'], 'scope' => OneTimePasswordScope::VERIFY_EMAIL->value, ]); From 3e38b3e9aef66b6450074db0b86141be772e2914 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 14 Mar 2026 03:22:58 +0000 Subject: [PATCH 097/133] chore: remove non required docblocks --- app/Http/Controllers/Auth/VerifyEmailController.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/Http/Controllers/Auth/VerifyEmailController.php b/app/Http/Controllers/Auth/VerifyEmailController.php index db551ac..9901132 100644 --- a/app/Http/Controllers/Auth/VerifyEmailController.php +++ b/app/Http/Controllers/Auth/VerifyEmailController.php @@ -41,10 +41,8 @@ public function verify(Request $request): Response ], HttpStatus::UNPROCESSABLE_ENTITY); } - /** @var User $user */ $user = User::query()->whereEqual('email', $request->body('email'))->first(); - /** @var UserOtp $otp */ $otp = UserOtp::query() ->whereEqual('user_id', $user->id) ->whereEqual('scope', OneTimePasswordScope::VERIFY_EMAIL->value) From 9b61218366ee18a797bbb2ada3bed9ec7a030ad8 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 20 Mar 2026 13:00:45 +0000 Subject: [PATCH 098/133] feat: login and logout flows --- app/Http/Controllers/Auth/LoginController.php | 131 ++++++++ composer.json | 2 +- composer.lock | 281 +++++++++--------- config/auth.php | 4 +- ...00_create_personal_access_tokens_table.php | 31 ++ routes/api.php | 20 +- tests/Feature/Auth/LoginAuthorizationTest.php | 204 +++++++++++++ tests/Feature/Auth/LoginTest.php | 191 ++++++++++++ tests/Feature/Auth/LogoutTest.php | 56 ++++ 9 files changed, 775 insertions(+), 145 deletions(-) create mode 100644 app/Http/Controllers/Auth/LoginController.php create mode 100644 database/migrations/20251128110000_create_personal_access_tokens_table.php create mode 100644 tests/Feature/Auth/LoginAuthorizationTest.php create mode 100644 tests/Feature/Auth/LoginTest.php create mode 100644 tests/Feature/Auth/LogoutTest.php diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php new file mode 100644 index 0000000..32b8f03 --- /dev/null +++ b/app/Http/Controllers/Auth/LoginController.php @@ -0,0 +1,131 @@ +setRules([ + 'email' => Email::required()->validations( + new DNSCheckValidation(), + new NoRFCWarningsValidation() + )->max(100) + ->exists('users', 'email', function ($query): void { + $query->whereNotNull('email_verified_at'); + }), + 'password' => Password::required(), + ]); + + if ($validator->fails()) { + return response()->json([ + 'errors' => $validator->failing(), + ], HttpStatus::UNPROCESSABLE_ENTITY); + } + + $user = User::query()->whereEqual('email', $request->body('email'))->first(); + + if (! Hash::verify($user->password, (string) $request->body('password'))) { + return response()->json([ + 'message' => 'Invalid credentials.', + ], HttpStatus::UNAUTHORIZED); + } + + $otpCount = UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::LOGIN->value) + ->whereGreaterThanOrEqual('created_at', Date::now()->subHour()->toDateTimeString()) + ->count(); + + if ($otpCount >= 5) { + return response()->json([ + 'message' => 'You have exceeded the maximum number of OTP requests. Please try again later.', + ], HttpStatus::TOO_MANY_REQUESTS); + } + + $user->sendOneTimePassword(OneTimePasswordScope::LOGIN); + + return response()->json([ + 'message' => 'A verification code has been sent to your email address.', + ]); + } + + public function authorize(Request $request): Response + { + $validator = new Validator($request); + $validator->setRules([ + 'email' => Email::required()->validations( + new DNSCheckValidation(), + new NoRFCWarningsValidation() + )->max(100) + ->exists('users', 'email', function ($query): void { + $query->whereNotNull('email_verified_at'); + }), + 'otp' => Numeric::required()->digits(6), + ]); + + if ($validator->fails()) { + return response()->json([ + 'errors' => $validator->failing(), + ], HttpStatus::UNPROCESSABLE_ENTITY); + } + + $user = User::query()->whereEqual('email', $request->body('email'))->first(); + + $otp = UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::LOGIN->value) + ->whereEqual('code', hash('sha256', (string) $request->body('otp'))) + ->whereNull('used_at') + ->whereGreaterThanOrEqual('expires_at', Date::now()->toDateTimeString()) + ->first(); + + if (! $otp) { + return response()->json([ + 'message' => 'The provided OTP is invalid.', + ], HttpStatus::NOT_FOUND); + } + + $otp->usedAt = Date::now(); + $otp->save(); + + $token = $user->createToken('auth_token'); + + return response()->json([ + 'access_token' => $token->toString(), + 'expires_at' => $token->expiresAt()->toDateTimeString(), + 'token_type' => 'Bearer', + ]); + } + + public function logout(Request $request): Response + { + /** @var User|null $user */ + $user = $request->user(); + + $user?->currentAccessToken()?->delete(); + + return response()->json([ + 'message' => 'Logged out successfully.', + ], HttpStatus::OK); + } +} diff --git a/composer.json b/composer.json index 62c95e3..de47b5f 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "dev-feature/integration-v080" + "phenixphp/framework": "dev-develop" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index bd9c1d6..279b649 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": "8567e427ea7c0ba62ea818d9fad3a55a", + "content-hash": "20497fa3a14fe489f84dfbe0efd733fa", "packages": [ { "name": "adbario/php-dot-notation", @@ -1204,16 +1204,16 @@ }, { "name": "amphp/mysql", - "version": "v3.0.0", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/amphp/mysql.git", - "reference": "0eb9d1df67c206c043b1a1c6ad7ba1bc2aa836bf" + "reference": "bef63fda61eefca601be54aa1d983a6a31b4a50f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/mysql/zipball/0eb9d1df67c206c043b1a1c6ad7ba1bc2aa836bf", - "reference": "0eb9d1df67c206c043b1a1c6ad7ba1bc2aa836bf", + "url": "https://api.github.com/repos/amphp/mysql/zipball/bef63fda61eefca601be54aa1d983a6a31b4a50f", + "reference": "bef63fda61eefca601be54aa1d983a6a31b4a50f", "shasum": "" }, "require": { @@ -1262,7 +1262,7 @@ "description": "Asynchronous MySQL client for PHP based on Amp.", "support": { "issues": "https://github.com/amphp/mysql/issues", - "source": "https://github.com/amphp/mysql/tree/v3.0.0" + "source": "https://github.com/amphp/mysql/tree/v3.0.1" }, "funding": [ { @@ -1270,7 +1270,7 @@ "type": "github" } ], - "time": "2024-03-10T17:33:58+00:00" + "time": "2025-11-08T22:59:09+00:00" }, { "name": "amphp/parallel", @@ -1627,16 +1627,16 @@ }, { "name": "amphp/redis", - "version": "v2.0.3", + "version": "v2.0.4", "source": { "type": "git", "url": "https://github.com/amphp/redis.git", - "reference": "1572c2fec2849d272570919e998f9a3c1a5b1703" + "reference": "964bcf6c2574645058371925a3668240a622bdab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/redis/zipball/1572c2fec2849d272570919e998f9a3c1a5b1703", - "reference": "1572c2fec2849d272570919e998f9a3c1a5b1703", + "url": "https://api.github.com/repos/amphp/redis/zipball/964bcf6c2574645058371925a3668240a622bdab", + "reference": "964bcf6c2574645058371925a3668240a622bdab", "shasum": "" }, "require": { @@ -1696,7 +1696,7 @@ ], "support": { "issues": "https://github.com/amphp/redis/issues", - "source": "https://github.com/amphp/redis/tree/v2.0.3" + "source": "https://github.com/amphp/redis/tree/v2.0.4" }, "funding": [ { @@ -1704,7 +1704,7 @@ "type": "github" } ], - "time": "2025-01-15T04:14:11+00:00" + "time": "2026-03-03T20:52:26+00:00" }, { "name": "amphp/serialization", @@ -1850,16 +1850,16 @@ }, { "name": "amphp/sql", - "version": "v2.0.1", + "version": "v2.1.1", "source": { "type": "git", "url": "https://github.com/amphp/sql.git", - "reference": "2a7962dba23bf017bbdd3c3a0af0eb212481627b" + "reference": "258bafe5ecf8a0491d86681f2a2af1dee2933a69" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/sql/zipball/2a7962dba23bf017bbdd3c3a0af0eb212481627b", - "reference": "2a7962dba23bf017bbdd3c3a0af0eb212481627b", + "url": "https://api.github.com/repos/amphp/sql/zipball/258bafe5ecf8a0491d86681f2a2af1dee2933a69", + "reference": "258bafe5ecf8a0491d86681f2a2af1dee2933a69", "shasum": "" }, "require": { @@ -1869,7 +1869,7 @@ "require-dev": { "amphp/php-cs-fixer-config": "^2", "phpunit/phpunit": "^9", - "psalm/phar": "5.23" + "psalm/phar": "6.15.1" }, "type": "library", "autoload": { @@ -1892,7 +1892,7 @@ ], "support": { "issues": "https://github.com/amphp/sql/issues", - "source": "https://github.com/amphp/sql/tree/v2.0.1" + "source": "https://github.com/amphp/sql/tree/v2.1.1" }, "funding": [ { @@ -1900,7 +1900,7 @@ "type": "github" } ], - "time": "2024-11-23T16:16:34+00:00" + "time": "2026-02-25T04:44:15+00:00" }, { "name": "amphp/sql-common", @@ -2035,21 +2035,20 @@ }, { "name": "async-aws/core", - "version": "1.28.0", + "version": "1.28.1", "source": { "type": "git", "url": "https://github.com/async-aws/core.git", - "reference": "0d5f4d650b74a8366bca1fb400b6cfb694c3b217" + "reference": "e8b02ac30b17afaf1352cbd352dceb789d792d39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/core/zipball/0d5f4d650b74a8366bca1fb400b6cfb694c3b217", - "reference": "0d5f4d650b74a8366bca1fb400b6cfb694c3b217", + "url": "https://api.github.com/repos/async-aws/core/zipball/e8b02ac30b17afaf1352cbd352dceb789d792d39", + "reference": "e8b02ac30b17afaf1352cbd352dceb789d792d39", "shasum": "" }, "require": { "ext-hash": "*", - "ext-json": "*", "ext-simplexml": "*", "php": "^8.2", "psr/cache": "^1.0 || ^2.0 || ^3.0", @@ -2092,7 +2091,7 @@ "sts" ], "support": { - "source": "https://github.com/async-aws/core/tree/1.28.0" + "source": "https://github.com/async-aws/core/tree/1.28.1" }, "funding": [ { @@ -2104,25 +2103,24 @@ "type": "github" } ], - "time": "2026-01-16T22:28:05+00:00" + "time": "2026-02-16T10:24:54+00:00" }, { "name": "async-aws/ses", - "version": "1.14.0", + "version": "1.14.1", "source": { "type": "git", "url": "https://github.com/async-aws/ses.git", - "reference": "c5b1d6c0c8ba32ea4f961b40b9e411aeca783302" + "reference": "8ba4c7f5bbb4d1055f3ebedcf0ea1b8b79393e5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/async-aws/ses/zipball/c5b1d6c0c8ba32ea4f961b40b9e411aeca783302", - "reference": "c5b1d6c0c8ba32ea4f961b40b9e411aeca783302", + "url": "https://api.github.com/repos/async-aws/ses/zipball/8ba4c7f5bbb4d1055f3ebedcf0ea1b8b79393e5b", + "reference": "8ba4c7f5bbb4d1055f3ebedcf0ea1b8b79393e5b", "shasum": "" }, "require": { "async-aws/core": "^1.9", - "ext-json": "*", "php": "^8.2" }, "require-dev": { @@ -2154,7 +2152,7 @@ "ses" ], "support": { - "source": "https://github.com/async-aws/ses/tree/1.14.0" + "source": "https://github.com/async-aws/ses/tree/1.14.1" }, "funding": [ { @@ -2166,7 +2164,7 @@ "type": "github" } ], - "time": "2026-01-16T22:28:05+00:00" + "time": "2026-02-16T10:24:54+00:00" }, { "name": "cakephp/chronos", @@ -3149,16 +3147,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.8.0", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "21dc724a0583619cd1652f673303492272778051" + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", - "reference": "21dc724a0583619cd1652f673303492272778051", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884", + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884", "shasum": "" }, "require": { @@ -3174,6 +3172,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", + "jshttp/mime-db": "1.54.0.1", "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { @@ -3245,7 +3244,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.8.0" + "source": "https://github.com/guzzle/psr7/tree/2.9.0" }, "funding": [ { @@ -3261,7 +3260,7 @@ "type": "tidelift" } ], - "time": "2025-08-23T21:21:41+00:00" + "time": "2026-03-10T16:41:02+00:00" }, { "name": "kelunik/certificate", @@ -3893,16 +3892,16 @@ }, { "name": "nesbot/carbon", - "version": "3.11.1", + "version": "3.11.3", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "f438fcc98f92babee98381d399c65336f3a3827f" + "reference": "6a7e652845bb018c668220c2a545aded8594fbbf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/f438fcc98f92babee98381d399c65336f3a3827f", - "reference": "f438fcc98f92babee98381d399c65336f3a3827f", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/6a7e652845bb018c668220c2a545aded8594fbbf", + "reference": "6a7e652845bb018c668220c2a545aded8594fbbf", "shasum": "" }, "require": { @@ -3994,7 +3993,7 @@ "type": "tidelift" } ], - "time": "2026-01-29T09:26:29+00:00" + "time": "2026-03-11T17:23:39+00:00" }, { "name": "nikic/fast-route", @@ -4117,16 +4116,16 @@ }, { "name": "phenixphp/framework", - "version": "dev-feature/integration-v080", + "version": "dev-develop", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "7c2cfdea19e8ee99388837f4e8cdbee1c096286c" + "reference": "80c4a6657f78f5173b05aa01afafdaa72e69c5a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/7c2cfdea19e8ee99388837f4e8cdbee1c096286c", - "reference": "7c2cfdea19e8ee99388837f4e8cdbee1c096286c", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/80c4a6657f78f5173b05aa01afafdaa72e69c5a9", + "reference": "80c4a6657f78f5173b05aa01afafdaa72e69c5a9", "shasum": "" }, "require": { @@ -4206,9 +4205,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/feature/integration-v080" + "source": "https://github.com/phenixphp/framework/tree/develop" }, - "time": "2026-02-11T23:59:38+00:00" + "time": "2026-03-13T00:17:20+00:00" }, { "name": "phenixphp/http-cors", @@ -4250,16 +4249,16 @@ }, { "name": "phenixphp/sqlite", - "version": "0.1.1", + "version": "0.1.2", "source": { "type": "git", "url": "https://github.com/phenixphp/sqlite.git", - "reference": "a230208807aaae56a8707fd33fdd136d2a8cd2f3" + "reference": "6a70e92387fefefbb93f9f1c1284f169c36dd4c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/sqlite/zipball/a230208807aaae56a8707fd33fdd136d2a8cd2f3", - "reference": "a230208807aaae56a8707fd33fdd136d2a8cd2f3", + "url": "https://api.github.com/repos/phenixphp/sqlite/zipball/6a70e92387fefefbb93f9f1c1284f169c36dd4c9", + "reference": "6a70e92387fefefbb93f9f1c1284f169c36dd4c9", "shasum": "" }, "require": { @@ -4305,9 +4304,9 @@ "homepage": "https://github.com/phenixphp/sqlite", "support": { "issues": "https://github.com/phenixphp/sqlite/issues", - "source": "https://github.com/phenixphp/sqlite/tree/0.1.1" + "source": "https://github.com/phenixphp/sqlite/tree/0.1.2" }, - "time": "2026-02-01T20:48:38+00:00" + "time": "2026-03-02T15:28:29+00:00" }, { "name": "phpoption/phpoption", @@ -5237,16 +5236,16 @@ }, { "name": "symfony/amazon-mailer", - "version": "v7.4.0", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/amazon-mailer.git", - "reference": "122c80099df1f415c091ce356442796406b61c7b" + "reference": "6fedfa970a1b5b2c93fd32c598df7db7d03070b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/122c80099df1f415c091ce356442796406b61c7b", - "reference": "122c80099df1f415c091ce356442796406b61c7b", + "url": "https://api.github.com/repos/symfony/amazon-mailer/zipball/6fedfa970a1b5b2c93fd32c598df7db7d03070b4", + "reference": "6fedfa970a1b5b2c93fd32c598df7db7d03070b4", "shasum": "" }, "require": { @@ -5283,7 +5282,7 @@ "description": "Symfony Amazon Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/amazon-mailer/tree/v7.4.0" + "source": "https://github.com/symfony/amazon-mailer/tree/v7.4.6" }, "funding": [ { @@ -5303,7 +5302,7 @@ "type": "tidelift" } ], - "time": "2025-08-04T07:05:15+00:00" + "time": "2026-02-11T15:05:50+00:00" }, { "name": "symfony/clock", @@ -5385,16 +5384,16 @@ }, { "name": "symfony/config", - "version": "v7.4.4", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "4275b53b8ab0cf37f48bf273dc2285c8178efdfb" + "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/4275b53b8ab0cf37f48bf273dc2285c8178efdfb", - "reference": "4275b53b8ab0cf37f48bf273dc2285c8178efdfb", + "url": "https://api.github.com/repos/symfony/config/zipball/6c17162555bfb58957a55bb0e43e00035b6ae3d5", + "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5", "shasum": "" }, "require": { @@ -5440,7 +5439,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.4.4" + "source": "https://github.com/symfony/config/tree/v7.4.7" }, "funding": [ { @@ -5460,20 +5459,20 @@ "type": "tidelift" } ], - "time": "2026-01-13T11:36:38+00:00" + "time": "2026-03-06T10:41:14+00:00" }, { "name": "symfony/console", - "version": "v6.4.32", + "version": "v6.4.35", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3" + "reference": "49257c96304c508223815ee965c251e7c79e614e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", - "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", + "url": "https://api.github.com/repos/symfony/console/zipball/49257c96304c508223815ee965c251e7c79e614e", + "reference": "49257c96304c508223815ee965c251e7c79e614e", "shasum": "" }, "require": { @@ -5538,7 +5537,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.32" + "source": "https://github.com/symfony/console/tree/v6.4.35" }, "funding": [ { @@ -5558,7 +5557,7 @@ "type": "tidelift" } ], - "time": "2026-01-13T08:45:59+00:00" + "time": "2026-03-06T13:31:08+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5790,16 +5789,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.4.0", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "d551b38811096d0be9c4691d406991b47c0c630a" + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a", - "reference": "d551b38811096d0be9c4691d406991b47c0c630a", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e", + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e", "shasum": "" }, "require": { @@ -5836,7 +5835,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.4.0" + "source": "https://github.com/symfony/filesystem/tree/v7.4.6" }, "funding": [ { @@ -5856,20 +5855,20 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2026-02-25T16:50:00+00:00" }, { "name": "symfony/http-client", - "version": "v7.4.5", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "84bb634857a893cc146cceb467e31b3f02c5fe9f" + "reference": "1010624285470eb60e88ed10035102c75b4ea6af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/84bb634857a893cc146cceb467e31b3f02c5fe9f", - "reference": "84bb634857a893cc146cceb467e31b3f02c5fe9f", + "url": "https://api.github.com/repos/symfony/http-client/zipball/1010624285470eb60e88ed10035102c75b4ea6af", + "reference": "1010624285470eb60e88ed10035102c75b4ea6af", "shasum": "" }, "require": { @@ -5937,7 +5936,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.4.5" + "source": "https://github.com/symfony/http-client/tree/v7.4.7" }, "funding": [ { @@ -5957,7 +5956,7 @@ "type": "tidelift" } ], - "time": "2026-01-27T16:16:02+00:00" + "time": "2026-03-05T11:16:58+00:00" }, { "name": "symfony/http-client-contracts", @@ -6039,16 +6038,16 @@ }, { "name": "symfony/mailer", - "version": "v7.4.4", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "7b750074c40c694ceb34cb926d6dffee231c5cd6" + "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/7b750074c40c694ceb34cb926d6dffee231c5cd6", - "reference": "7b750074c40c694ceb34cb926d6dffee231c5cd6", + "url": "https://api.github.com/repos/symfony/mailer/zipball/b02726f39a20bc65e30364f5c750c4ddbf1f58e9", + "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9", "shasum": "" }, "require": { @@ -6099,7 +6098,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.4.4" + "source": "https://github.com/symfony/mailer/tree/v7.4.6" }, "funding": [ { @@ -6119,20 +6118,20 @@ "type": "tidelift" } ], - "time": "2026-01-08T08:25:11+00:00" + "time": "2026-02-25T16:50:00+00:00" }, { "name": "symfony/mime", - "version": "v7.4.5", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "b18c7e6e9eee1e19958138df10412f3c4c316148" + "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/b18c7e6e9eee1e19958138df10412f3c4c316148", - "reference": "b18c7e6e9eee1e19958138df10412f3c4c316148", + "url": "https://api.github.com/repos/symfony/mime/zipball/da5ab4fde3f6c88ab06e96185b9922f48b677cd1", + "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1", "shasum": "" }, "require": { @@ -6143,7 +6142,7 @@ }, "conflict": { "egulias/email-validator": "~3.0.0", - "phpdocumentor/reflection-docblock": "<5.2|>=6", + "phpdocumentor/reflection-docblock": "<5.2|>=7", "phpdocumentor/type-resolver": "<1.5.1", "symfony/mailer": "<6.4", "symfony/serializer": "<6.4.3|>7.0,<7.0.3" @@ -6151,7 +6150,7 @@ "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^5.2", + "phpdocumentor/reflection-docblock": "^5.2|^6.0", "symfony/dependency-injection": "^6.4|^7.0|^8.0", "symfony/process": "^6.4|^7.0|^8.0", "symfony/property-access": "^6.4|^7.0|^8.0", @@ -6188,7 +6187,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.4.5" + "source": "https://github.com/symfony/mime/tree/v7.4.7" }, "funding": [ { @@ -6208,7 +6207,7 @@ "type": "tidelift" } ], - "time": "2026-01-27T08:59:58+00:00" + "time": "2026-03-05T15:24:09+00:00" }, { "name": "symfony/polyfill-ctype", @@ -6881,16 +6880,16 @@ }, { "name": "symfony/resend-mailer", - "version": "v7.4.0", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/resend-mailer.git", - "reference": "3c1761d758bf6373c4c8a32ab6eb530dc761536f" + "reference": "eb7f4d83128eef12fcceccf33e5b4b89f2e2474f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/resend-mailer/zipball/3c1761d758bf6373c4c8a32ab6eb530dc761536f", - "reference": "3c1761d758bf6373c4c8a32ab6eb530dc761536f", + "url": "https://api.github.com/repos/symfony/resend-mailer/zipball/eb7f4d83128eef12fcceccf33e5b4b89f2e2474f", + "reference": "eb7f4d83128eef12fcceccf33e5b4b89f2e2474f", "shasum": "" }, "require": { @@ -6931,7 +6930,7 @@ "description": "Symfony Resend Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/resend-mailer/tree/v7.4.0" + "source": "https://github.com/symfony/resend-mailer/tree/v7.4.6" }, "funding": [ { @@ -6951,7 +6950,7 @@ "type": "tidelift" } ], - "time": "2025-08-12T10:41:57+00:00" + "time": "2026-02-09T14:10:20+00:00" }, { "name": "symfony/service-contracts", @@ -7042,16 +7041,16 @@ }, { "name": "symfony/string", - "version": "v7.4.4", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f" + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/1c4b10461bf2ec27537b5f36105337262f5f5d6f", - "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f", + "url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b", "shasum": "" }, "require": { @@ -7109,7 +7108,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.4.4" + "source": "https://github.com/symfony/string/tree/v7.4.6" }, "funding": [ { @@ -7129,20 +7128,20 @@ "type": "tidelift" } ], - "time": "2026-01-12T10:54:30+00:00" + "time": "2026-02-09T09:33:46+00:00" }, { "name": "symfony/translation", - "version": "v7.4.4", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "bfde13711f53f549e73b06d27b35a55207528877" + "reference": "1888cf064399868af3784b9e043240f1d89d25ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/bfde13711f53f549e73b06d27b35a55207528877", - "reference": "bfde13711f53f549e73b06d27b35a55207528877", + "url": "https://api.github.com/repos/symfony/translation/zipball/1888cf064399868af3784b9e043240f1d89d25ce", + "reference": "1888cf064399868af3784b9e043240f1d89d25ce", "shasum": "" }, "require": { @@ -7209,7 +7208,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.4.4" + "source": "https://github.com/symfony/translation/tree/v7.4.6" }, "funding": [ { @@ -7229,7 +7228,7 @@ "type": "tidelift" } ], - "time": "2026-01-13T10:40:19+00:00" + "time": "2026-02-17T07:53:42+00:00" }, { "name": "symfony/translation-contracts", @@ -7393,16 +7392,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.4.4", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "0e4769b46a0c3c62390d124635ce59f66874b282" + "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0e4769b46a0c3c62390d124635ce59f66874b282", - "reference": "0e4769b46a0c3c62390d124635ce59f66874b282", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/045321c440ac18347b136c63d2e9bf28a2dc0291", + "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291", "shasum": "" }, "require": { @@ -7456,7 +7455,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.4.4" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.6" }, "funding": [ { @@ -7476,7 +7475,7 @@ "type": "tidelift" } ], - "time": "2026-01-01T22:13:48+00:00" + "time": "2026-02-15T10:53:20+00:00" }, { "name": "vlucas/phpdotenv", @@ -8158,16 +8157,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.94.0", + "version": "v3.94.2", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "883b20fb38c7866de9844ab6d0a205c423bde2d4" + "reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/883b20fb38c7866de9844ab6d0a205c423bde2d4", - "reference": "883b20fb38c7866de9844ab6d0a205c423bde2d4", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7787ceff91365ba7d623ec410b8f429cdebb4f63", + "reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63", "shasum": "" }, "require": { @@ -8250,7 +8249,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.2" }, "funding": [ { @@ -8258,7 +8257,7 @@ "type": "github" } ], - "time": "2026-02-11T16:44:33+00:00" + "time": "2026-02-20T16:13:53+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -8768,11 +8767,11 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.32", + "version": "1.12.33", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8", - "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/37982d6fc7cbb746dda7773530cda557cdf119e1", + "reference": "37982d6fc7cbb746dda7773530cda557cdf119e1", "shasum": "" }, "require": { @@ -8817,7 +8816,7 @@ "type": "github" } ], - "time": "2025-09-30T10:16:31+00:00" + "time": "2026-02-28T20:30:03+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -10947,16 +10946,16 @@ }, { "name": "symfony/finder", - "version": "v7.4.5", + "version": "v7.4.6", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb" + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", - "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", + "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", "shasum": "" }, "require": { @@ -10991,7 +10990,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.5" + "source": "https://github.com/symfony/finder/tree/v7.4.6" }, "funding": [ { @@ -11011,7 +11010,7 @@ "type": "tidelift" } ], - "time": "2026-01-26T15:07:59+00:00" + "time": "2026-01-29T09:40:50+00:00" }, { "name": "symfony/options-resolver", diff --git a/config/auth.php b/config/auth.php index 6ea9fd3..b12347d 100644 --- a/config/auth.php +++ b/config/auth.php @@ -2,9 +2,11 @@ declare(strict_types=1); +use App\Models\User; + return [ 'users' => [ - 'model' => Phenix\Auth\User::class, + 'model' => User::class, ], 'tokens' => [ 'model' => Phenix\Auth\PersonalAccessToken::class, diff --git a/database/migrations/20251128110000_create_personal_access_tokens_table.php b/database/migrations/20251128110000_create_personal_access_tokens_table.php new file mode 100644 index 0000000..54600d8 --- /dev/null +++ b/database/migrations/20251128110000_create_personal_access_tokens_table.php @@ -0,0 +1,31 @@ +table('personal_access_tokens', ['id' => false, 'primary_key' => 'id']); + + $table->uuid('id'); + $table->string('tokenable_type', 100); + $table->unsignedInteger('tokenable_id'); + $table->string('name', 100); + $table->string('token', 255)->unique(); + $table->text('abilities')->nullable(); + $table->dateTime('last_used_at')->nullable(); + $table->dateTime('expires_at'); + $table->timestamps(); + $table->addIndex(['tokenable_type', 'tokenable_id'], ['name' => 'idx_tokenable']); + $table->addIndex(['expires_at'], ['name' => 'idx_expires_at']); + $table->create(); + } + + public function down(): void + { + $this->table('personal_access_tokens')->drop(); + } +} diff --git a/routes/api.php b/routes/api.php index eeb053b..1367e34 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,11 +2,13 @@ declare(strict_types=1); +use App\Http\Controllers\Auth\LoginController; use App\Http\Controllers\Auth\RegisterController; use App\Http\Controllers\Auth\ResendOtpController; use App\Http\Controllers\Auth\VerifyEmailController; use App\Http\Controllers\WelcomeController; use App\Http\Middleware\Guest; +use Phenix\Auth\Middlewares\Authenticated; use Phenix\Cache\RateLimit\Middlewares\RateLimiter; use Phenix\Facades\Route; use Phenix\Routing\Route as Router; @@ -20,9 +22,23 @@ $router->post('verify-email', [VerifyEmailController::class, 'verify']) ->name('verification.verify') - ->middleware(RateLimiter::perMinute(6)); + ->middleware(RateLimiter::perMinute(6, 'auth:verify-email')); $router->post('resend-verification-otp', [ResendOtpController::class, 'resend']) ->name('verification.resend') - ->middleware(RateLimiter::perMinute(2)); + ->middleware(RateLimiter::perMinute(2, 'auth:resend-verification-otp')); + + $router->post('login', [LoginController::class, 'login']) + ->name('login') + ->middleware(RateLimiter::perMinute(5, 'auth:login')); + + $router->post('login/authorize', [LoginController::class, 'authorize']) + ->name('login.authorize') + ->middleware(RateLimiter::perMinute(5, 'auth:login-authorize')); + }); + +Route::middleware(Authenticated::class) + ->group(function (Router $router): void { + $router->post('logout', [LoginController::class, 'logout']) + ->name('logout'); }); diff --git a/tests/Feature/Auth/LoginAuthorizationTest.php b/tests/Feature/Auth/LoginAuthorizationTest.php new file mode 100644 index 0000000..5bff347 --- /dev/null +++ b/tests/Feature/Auth/LoginAuthorizationTest.php @@ -0,0 +1,204 @@ + $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); + + $response = $this->post('/login/authorize', [ + 'email' => $user->email, + 'otp' => $otp->otp, + ]); + + $response->assertOk() + ->assertJsonPath('token_type', 'Bearer'); + + $data = $response->getDecodedBody(); + + $this->assertNotEmpty($data['access_token'] ?? null); + $this->assertNotEmpty($data['expires_at'] ?? null); + + $this->assertDatabaseHas('user_one_time_passwords', [ + 'id' => $otp->id, + 'used_at' => Date::now(), + ]); + + $this->assertDatabaseHas('personal_access_tokens', [ + 'tokenable_id' => $user->id, + 'name' => 'auth_token', + 'token' => hash('sha256', $data['access_token']), + ]); + } + + /** @test */ + public function it_responds_not_found_for_non_existing_otp(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $response = $this->post('/login/authorize', [ + 'email' => $user->email, + 'otp' => '123456', + ]); + + $response->assertNotFound() + ->assertJsonPath('message', 'The provided OTP is invalid.'); + } + + /** @test */ + public function it_responds_not_found_when_otp_has_different_scope(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + + $response = $this->post('/login/authorize', [ + 'email' => $user->email, + 'otp' => $otp->otp, + ]); + + $response->assertNotFound() + ->assertJsonPath('message', 'The provided OTP is invalid.'); + } + + /** @test */ + public function it_responds_not_found_when_otp_is_already_used(): void + { + Date::setTestNow(Date::now()); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); + $otp->usedAt = Date::now(); + $otp->save(); + + $response = $this->post('/login/authorize', [ + 'email' => $user->email, + 'otp' => $otp->otp, + ]); + + $response->assertNotFound() + ->assertJsonPath('message', 'The provided OTP is invalid.'); + } + + /** @test */ + public function it_responds_not_found_when_otp_is_expired(): void + { + Date::setTestNow(Date::now()); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); + + Date::setTestNow(Date::now()->addMinutes(11)); + + $response = $this->post('/login/authorize', [ + 'email' => $user->email, + 'otp' => $otp->otp, + ]); + + $response->assertNotFound() + ->assertJsonPath('message', 'The provided OTP is invalid.'); + } + + /** @test */ + public function it_rate_limits_login_authorization_attempts_per_client(): void + { + Cache::clear(); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + for ($i = 0; $i < 5; $i++) { + $this->post('/login/authorize', [ + 'email' => $user->email, + 'otp' => '123456', + ])->assertNotFound(); + } + + $this->post('/login/authorize', [ + 'email' => $user->email, + 'otp' => '123456', + ])->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) + ->assertJsonPath('message', 'Rate limit exceeded. Please try again later.'); + } + + /** @test */ + public function it_uses_independent_rate_limit_buckets_for_login_and_login_authorization(): void + { + Cache::clear(); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); + + for ($i = 0; $i < 5; $i++) { + $this->post('/login', [ + 'email' => $user->email, + 'password' => 'WrongPass99', + ])->assertUnauthorized(); + } + + $this->post('/login/authorize', [ + 'email' => $user->email, + 'otp' => $otp->otp, + ])->assertOk() + ->assertJsonPath('token_type', 'Bearer'); + } +} diff --git a/tests/Feature/Auth/LoginTest.php b/tests/Feature/Auth/LoginTest.php new file mode 100644 index 0000000..535ed9d --- /dev/null +++ b/tests/Feature/Auth/LoginTest.php @@ -0,0 +1,191 @@ + $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $response = $this->post('/login', [ + 'email' => $user->email, + 'password' => 'P@ssw0rd12', + ]); + + $response->assertOk() + ->assertJsonPath('message', 'A verification code has been sent to your email address.'); + + $this->assertDatabaseHas('user_one_time_passwords', [ + 'user_id' => $user->id, + 'scope' => OneTimePasswordScope::LOGIN->value, + ]); + + Mail::expect(SendLoginOtp::class)->toBeSentTimes(1); + } + + /** @test */ + public function it_rejects_wrong_password(): void + { + Mail::fake(); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $response = $this->post('/login', [ + 'email' => $user->email, + 'password' => 'WrongPass99', + ]); + + $response->assertUnauthorized() + ->assertJsonPath('message', 'Invalid credentials.'); + + $this->assertSame( + 0, + UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::LOGIN->value) + ->count() + ); + + Mail::expect(SendLoginOtp::class)->toNotBeSent(); + } + + /** @test */ + public function it_rejects_unverified_email(): void + { + Mail::fake(); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + ]); + + $response = $this->post('/login', [ + 'email' => $user->email, + 'password' => 'P@ssw0rd12', + ]); + + $response->assertUnprocessableEntity() + ->assertJsonPath('errors.email.0', 'The selected email is invalid.'); + + Mail::expect(SendLoginOtp::class)->toNotBeSent(); + } + + /** @test */ + public function it_responds_too_many_requests_when_login_otp_limit_is_exceeded(): void + { + Date::setTestNow(Date::now()); + Mail::fake(); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + for ($i = 0; $i < 5; $i++) { + $user->createOneTimePassword(OneTimePasswordScope::LOGIN); + } + + $response = $this->post('/login', [ + 'email' => $user->email, + 'password' => 'P@ssw0rd12', + ]); + + $response->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) + ->assertJsonPath('message', 'You have exceeded the maximum number of OTP requests. Please try again later.'); + + $this->assertSame( + 5, + UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::LOGIN->value) + ->count() + ); + + Mail::expect(SendLoginOtp::class)->toNotBeSent(); + } + + /** @test */ + public function it_responds_unauthorized_when_authorization_token_is_present(): void + { + Mail::fake(); + + $response = $this->post( + '/login', + [ + 'email' => $this->faker()->freeEmail(), + 'password' => 'P@ssw0rd12', + ], + [], + ['Authorization' => 'Bearer any-token'] + ); + + $response->assertUnauthorized() + ->assertJsonPath('message', 'Unauthorized'); + + Mail::expect(SendLoginOtp::class)->toNotBeSent(); + } + + /** @test */ + public function it_rate_limits_login_attempts_per_client(): void + { + Cache::clear(); + Mail::fake(); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + for ($i = 0; $i < 5; $i++) { + $this->post('/login', [ + 'email' => $user->email, + 'password' => 'WrongPass99', + ])->assertUnauthorized(); + } + + $this->post('/login', [ + 'email' => $user->email, + 'password' => 'WrongPass99', + ])->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) + ->assertJsonPath('message', 'Rate limit exceeded. Please try again later.'); + + Mail::expect(SendLoginOtp::class)->toNotBeSent(); + } +} diff --git a/tests/Feature/Auth/LogoutTest.php b/tests/Feature/Auth/LogoutTest.php new file mode 100644 index 0000000..4f0bf58 --- /dev/null +++ b/tests/Feature/Auth/LogoutTest.php @@ -0,0 +1,56 @@ + $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $currentToken = $user->createToken('current-token'); + $otherToken = $user->createToken('other-token'); + + $response = $this->post( + path: '/logout', + headers: ['Authorization' => 'Bearer ' . $currentToken->toString()] + ); + + $response->assertOk() + ->assertJsonPath('message', 'Logged out successfully.'); + + $this->assertDatabaseMissing('personal_access_tokens', [ + 'id' => $currentToken->id(), + ]); + + $this->assertDatabaseHas('personal_access_tokens', [ + 'id' => $otherToken->id(), + ]); + } + + /** @test */ + public function it_responds_unauthorized_when_logging_out_without_a_token(): void + { + $this->post('/logout') + ->assertUnauthorized() + ->assertJsonPath('message', 'Unauthorized'); + } +} From fb1970c9da50dd0d1b74f6032f4589ec6f84fe3b Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 20 Mar 2026 14:36:57 +0000 Subject: [PATCH 099/133] feat: implement translations --- app/Http/Controllers/Auth/LoginController.php | 10 ++--- .../Controllers/Auth/ResendOtpController.php | 4 +- .../Auth/VerifyEmailController.php | 4 +- lang/en/auth.php | 38 +++++++++++++++++++ tests/Feature/Auth/LoginAuthorizationTest.php | 10 ++--- tests/Feature/Auth/LoginTest.php | 12 +++--- tests/Feature/Auth/LogoutTest.php | 4 +- tests/Feature/Auth/ResendOtpTest.php | 8 ++-- tests/Feature/Auth/VerifyEmailTest.php | 12 +++--- 9 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 lang/en/auth.php diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 32b8f03..e0ce71e 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -46,7 +46,7 @@ public function login(Request $request): Response if (! Hash::verify($user->password, (string) $request->body('password'))) { return response()->json([ - 'message' => 'Invalid credentials.', + 'message' => trans('auth.login.invalid_credentials'), ], HttpStatus::UNAUTHORIZED); } @@ -58,14 +58,14 @@ public function login(Request $request): Response if ($otpCount >= 5) { return response()->json([ - 'message' => 'You have exceeded the maximum number of OTP requests. Please try again later.', + 'message' => trans('auth.otp.limit_exceeded'), ], HttpStatus::TOO_MANY_REQUESTS); } $user->sendOneTimePassword(OneTimePasswordScope::LOGIN); return response()->json([ - 'message' => 'A verification code has been sent to your email address.', + 'message' => trans('auth.otp.login.sent'), ]); } @@ -101,7 +101,7 @@ public function authorize(Request $request): Response if (! $otp) { return response()->json([ - 'message' => 'The provided OTP is invalid.', + 'message' => trans('auth.otp.invalid'), ], HttpStatus::NOT_FOUND); } @@ -125,7 +125,7 @@ public function logout(Request $request): Response $user?->currentAccessToken()?->delete(); return response()->json([ - 'message' => 'Logged out successfully.', + 'message' => trans('auth.logout.success'), ], HttpStatus::OK); } } diff --git a/app/Http/Controllers/Auth/ResendOtpController.php b/app/Http/Controllers/Auth/ResendOtpController.php index a89659f..745923f 100644 --- a/app/Http/Controllers/Auth/ResendOtpController.php +++ b/app/Http/Controllers/Auth/ResendOtpController.php @@ -49,14 +49,14 @@ public function resend(Request $request): Response if ($otpCount >= 5) { return response()->json([ - 'message' => 'You have exceeded the maximum number of OTP requests. Please try again later.', + 'message' => trans('auth.otp.limit_exceeded'), ], HttpStatus::TOO_MANY_REQUESTS); } $user->sendOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); return response()->json([ - 'message' => 'OTP has been resent successfully.', + 'message' => trans('auth.otp.email_verification.resent'), ], HttpStatus::OK); } } diff --git a/app/Http/Controllers/Auth/VerifyEmailController.php b/app/Http/Controllers/Auth/VerifyEmailController.php index 9901132..e367846 100644 --- a/app/Http/Controllers/Auth/VerifyEmailController.php +++ b/app/Http/Controllers/Auth/VerifyEmailController.php @@ -53,7 +53,7 @@ public function verify(Request $request): Response if (! $otp) { return response()->json([ - 'message' => 'The provided OTP is invalid.', + 'message' => trans('auth.otp.invalid'), ], HttpStatus::NOT_FOUND); } @@ -64,7 +64,7 @@ public function verify(Request $request): Response $user->save(); return response()->json([ - 'message' => 'Email verified successfully.', + 'message' => trans('auth.email_verification.verified'), ], HttpStatus::OK); } } diff --git a/lang/en/auth.php b/lang/en/auth.php new file mode 100644 index 0000000..8cd4d1b --- /dev/null +++ b/lang/en/auth.php @@ -0,0 +1,38 @@ + 'Unauthorized', + 'login' => [ + 'invalid_credentials' => 'Invalid credentials.', + ], + 'logout' => [ + 'success' => 'Logged out successfully.', + ], + 'email_verification' => [ + 'verified' => 'Email verified successfully.', + ], + 'otp' => [ + 'invalid' => 'The provided OTP is invalid.', + 'limit_exceeded' => 'You have exceeded the maximum number of OTP requests. Please try again later.', + 'label' => 'Verification code', + 'expiry' => 'This code expires in :minutes minutes.', + 'login' => [ + 'subject' => 'Your login verification code', + 'title' => 'Login verification code', + 'message' => 'Use the following verification code to complete your sign in.', + 'sent' => 'A verification code has been sent to your email address.', + ], + 'email_verification' => [ + 'subject' => 'Verify your email address', + 'title' => 'Email verification code', + 'message' => 'Use the following verification code to verify your email address.', + 'resent' => 'OTP has been resent successfully.', + ], + ], + 'rate_limit' => [ + 'error' => 'Too Many Requests', + 'exceeded' => 'Rate limit exceeded. Please try again later.', + ], +]; diff --git a/tests/Feature/Auth/LoginAuthorizationTest.php b/tests/Feature/Auth/LoginAuthorizationTest.php index 5bff347..0e621a1 100644 --- a/tests/Feature/Auth/LoginAuthorizationTest.php +++ b/tests/Feature/Auth/LoginAuthorizationTest.php @@ -74,7 +74,7 @@ public function it_responds_not_found_for_non_existing_otp(): void ]); $response->assertNotFound() - ->assertJsonPath('message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', trans('auth.otp.invalid')); } /** @test */ @@ -95,7 +95,7 @@ public function it_responds_not_found_when_otp_has_different_scope(): void ]); $response->assertNotFound() - ->assertJsonPath('message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', trans('auth.otp.invalid')); } /** @test */ @@ -120,7 +120,7 @@ public function it_responds_not_found_when_otp_is_already_used(): void ]); $response->assertNotFound() - ->assertJsonPath('message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', trans('auth.otp.invalid')); } /** @test */ @@ -145,7 +145,7 @@ public function it_responds_not_found_when_otp_is_expired(): void ]); $response->assertNotFound() - ->assertJsonPath('message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', trans('auth.otp.invalid')); } /** @test */ @@ -171,7 +171,7 @@ public function it_rate_limits_login_authorization_attempts_per_client(): void 'email' => $user->email, 'otp' => '123456', ])->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) - ->assertJsonPath('message', 'Rate limit exceeded. Please try again later.'); + ->assertJsonPath('message', trans('auth.rate_limit.exceeded')); } /** @test */ diff --git a/tests/Feature/Auth/LoginTest.php b/tests/Feature/Auth/LoginTest.php index 535ed9d..613c04f 100644 --- a/tests/Feature/Auth/LoginTest.php +++ b/tests/Feature/Auth/LoginTest.php @@ -40,7 +40,7 @@ public function it_sends_a_login_otp_for_valid_verified_credentials(): void ]); $response->assertOk() - ->assertJsonPath('message', 'A verification code has been sent to your email address.'); + ->assertJsonPath('message', trans('auth.otp.login.sent')); $this->assertDatabaseHas('user_one_time_passwords', [ 'user_id' => $user->id, @@ -68,7 +68,7 @@ public function it_rejects_wrong_password(): void ]); $response->assertUnauthorized() - ->assertJsonPath('message', 'Invalid credentials.'); + ->assertJsonPath('message', trans('auth.login.invalid_credentials')); $this->assertSame( 0, @@ -98,7 +98,7 @@ public function it_rejects_unverified_email(): void ]); $response->assertUnprocessableEntity() - ->assertJsonPath('errors.email.0', 'The selected email is invalid.'); + ->assertJsonPath('errors.email.0', trans('validation.exists', ['field' => 'email'])); Mail::expect(SendLoginOtp::class)->toNotBeSent(); } @@ -126,7 +126,7 @@ public function it_responds_too_many_requests_when_login_otp_limit_is_exceeded() ]); $response->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) - ->assertJsonPath('message', 'You have exceeded the maximum number of OTP requests. Please try again later.'); + ->assertJsonPath('message', trans('auth.otp.limit_exceeded')); $this->assertSame( 5, @@ -155,7 +155,7 @@ public function it_responds_unauthorized_when_authorization_token_is_present(): ); $response->assertUnauthorized() - ->assertJsonPath('message', 'Unauthorized'); + ->assertJsonPath('message', trans('auth.unauthorized')); Mail::expect(SendLoginOtp::class)->toNotBeSent(); } @@ -184,7 +184,7 @@ public function it_rate_limits_login_attempts_per_client(): void 'email' => $user->email, 'password' => 'WrongPass99', ])->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) - ->assertJsonPath('message', 'Rate limit exceeded. Please try again later.'); + ->assertJsonPath('message', trans('auth.rate_limit.exceeded')); Mail::expect(SendLoginOtp::class)->toNotBeSent(); } diff --git a/tests/Feature/Auth/LogoutTest.php b/tests/Feature/Auth/LogoutTest.php index 4f0bf58..21c89fd 100644 --- a/tests/Feature/Auth/LogoutTest.php +++ b/tests/Feature/Auth/LogoutTest.php @@ -35,7 +35,7 @@ public function it_logs_out_and_revokes_only_the_current_token(): void ); $response->assertOk() - ->assertJsonPath('message', 'Logged out successfully.'); + ->assertJsonPath('message', trans('auth.logout.success')); $this->assertDatabaseMissing('personal_access_tokens', [ 'id' => $currentToken->id(), @@ -51,6 +51,6 @@ public function it_responds_unauthorized_when_logging_out_without_a_token(): voi { $this->post('/logout') ->assertUnauthorized() - ->assertJsonPath('message', 'Unauthorized'); + ->assertJsonPath('message', trans('auth.unauthorized')); } } diff --git a/tests/Feature/Auth/ResendOtpTest.php b/tests/Feature/Auth/ResendOtpTest.php index 844066e..70e53a4 100644 --- a/tests/Feature/Auth/ResendOtpTest.php +++ b/tests/Feature/Auth/ResendOtpTest.php @@ -40,7 +40,7 @@ public function it_resend_otp_for_unverified_email(): void ]); $response->assertOk() - ->assertJsonPath('message', 'OTP has been resent successfully.'); + ->assertJsonPath('message', trans('auth.otp.email_verification.resent')); $this->assertDatabaseHas('user_one_time_passwords', [ 'id' => $otp->id, @@ -77,7 +77,7 @@ public function it_does_not_resend_otp_when_email_is_already_verified(): void ]); $response->assertUnprocessableEntity() - ->assertJsonPath('errors.email.0', 'The selected email is invalid.'); + ->assertJsonPath('errors.email.0', trans('validation.exists', ['field' => 'email'])); Mail::expect(SendEmailVerificationOtp::class)->toNotBeSent(); } @@ -95,7 +95,7 @@ public function it_responds_unauthorized_when_authorization_token_is_present(): ); $response->assertUnauthorized() - ->assertJsonPath('message', 'Unauthorized'); + ->assertJsonPath('message', trans('auth.unauthorized')); Mail::expect(SendEmailVerificationOtp::class)->toNotBeSent(); } @@ -121,7 +121,7 @@ public function it_responds_too_many_requests_when_exceed_otp_limit(): void ]); $response->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) - ->assertJsonPath('message', 'You have exceeded the maximum number of OTP requests. Please try again later.'); + ->assertJsonPath('message', trans('auth.otp.limit_exceeded')); Mail::expect(SendEmailVerificationOtp::class)->toNotBeSent(); } diff --git a/tests/Feature/Auth/VerifyEmailTest.php b/tests/Feature/Auth/VerifyEmailTest.php index b35ec58..8b27f90 100644 --- a/tests/Feature/Auth/VerifyEmailTest.php +++ b/tests/Feature/Auth/VerifyEmailTest.php @@ -36,7 +36,7 @@ public function it_verifies_email(): void ]); $response->assertOk() - ->assertJsonPath('message', 'Email verified successfully.'); + ->assertJsonPath('message', trans('auth.email_verification.verified')); $this->assertDatabaseHas('users', [ 'email' => $user->email, @@ -66,7 +66,7 @@ public function it_does_not_verify_email_because_email_is_already_verified(): vo ]); $response->assertUnprocessableEntity() - ->assertJsonPath('errors.email.0', 'The selected email is invalid.'); + ->assertJsonPath('errors.email.0', trans('validation.exists', ['field' => 'email'])); } /** @test */ @@ -84,7 +84,7 @@ public function it_responds_not_found_for_non_existing_otp(): void ]); $response->assertNotFound() - ->assertJsonPath('message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', trans('auth.otp.invalid')); } /** @test */ @@ -105,7 +105,7 @@ public function it_responds_not_found_when_otp_has_different_scope(): void ]); $response->assertNotFound() - ->assertJsonPath('message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', trans('auth.otp.invalid')); $this->assertDatabaseHas('users', [ 'email' => $user->email, @@ -136,7 +136,7 @@ public function it_responds_not_found_when_otp_is_already_used(): void ]); $response->assertNotFound() - ->assertJsonPath('message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', trans('auth.otp.invalid')); // User should not be verified $this->assertDatabaseHas('users', [ @@ -167,7 +167,7 @@ public function it_responds_not_found_when_otp_is_expired(): void ]); $response->assertNotFound() - ->assertJsonPath('message', 'The provided OTP is invalid.'); + ->assertJsonPath('message', trans('auth.otp.invalid')); // User should not be verified $this->assertDatabaseHas('users', [ From 4d559c7383a84189e0080ffaf425c8826b62bf81 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 20 Mar 2026 15:25:21 +0000 Subject: [PATCH 100/133] feat: reponds 401 if token is present in guest routes --- app/Http/Middleware/Guest.php | 50 +++++++++++++++++++ .../Middleware/RedirectIfAuthenticated.php | 18 ------- tests/Feature/Auth/ResendOtpTest.php | 7 ++- 3 files changed, 53 insertions(+), 22 deletions(-) create mode 100644 app/Http/Middleware/Guest.php delete mode 100644 app/Http/Middleware/RedirectIfAuthenticated.php diff --git a/app/Http/Middleware/Guest.php b/app/Http/Middleware/Guest.php new file mode 100644 index 0000000..4838c0b --- /dev/null +++ b/app/Http/Middleware/Guest.php @@ -0,0 +1,50 @@ +extractToken($request->getHeader('Authorization')); + + if ($token === null) { + return $next->handleRequest($request); + } + + return $this->unauthorized(); + } + + protected function hasBearerToken(string|null $authorizationHeader): bool + { + return $authorizationHeader !== null + && trim($authorizationHeader) !== '' + && str_starts_with($authorizationHeader, 'Bearer '); + } + + protected function extractToken(string|null $authorizationHeader): string|null + { + if (!$this->hasBearerToken($authorizationHeader)) { + return null; + } + + $parts = explode(' ', $authorizationHeader, 2); + + return isset($parts[1]) ? trim($parts[1]) : null; + } + + protected function unauthorized(): Response + { + return response()->json([ + 'message' => trans('auth.unauthorized'), + ], HttpStatus::UNAUTHORIZED)->send(); + } +} diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php deleted file mode 100644 index 0725db9..0000000 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ /dev/null @@ -1,18 +0,0 @@ -handleRequest($request); - } -} diff --git a/tests/Feature/Auth/ResendOtpTest.php b/tests/Feature/Auth/ResendOtpTest.php index 70e53a4..bd2cc80 100644 --- a/tests/Feature/Auth/ResendOtpTest.php +++ b/tests/Feature/Auth/ResendOtpTest.php @@ -88,10 +88,9 @@ public function it_responds_unauthorized_when_authorization_token_is_present(): Mail::fake(); $response = $this->post( - '/resend-verification-otp', - ['email' => $this->faker()->freeEmail()], - [], - ['Authorization' => 'Bearer any-token'] + path: '/resend-verification-otp', + body: ['email' => $this->faker()->freeEmail()], + headers: ['Authorization' => 'Bearer any-token'] ); $response->assertUnauthorized() From da550e4eeaf0a0a897f82a64bc51b2a7056a70cf Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 20 Mar 2026 15:31:09 +0000 Subject: [PATCH 101/133] refactor: rename class --- ...dOtpController.php => ResendVerificationOtpController.php} | 2 +- routes/api.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename app/Http/Controllers/Auth/{ResendOtpController.php => ResendVerificationOtpController.php} (97%) diff --git a/app/Http/Controllers/Auth/ResendOtpController.php b/app/Http/Controllers/Auth/ResendVerificationOtpController.php similarity index 97% rename from app/Http/Controllers/Auth/ResendOtpController.php rename to app/Http/Controllers/Auth/ResendVerificationOtpController.php index 745923f..184d0d9 100644 --- a/app/Http/Controllers/Auth/ResendOtpController.php +++ b/app/Http/Controllers/Auth/ResendVerificationOtpController.php @@ -17,7 +17,7 @@ use Phenix\Validation\Types\Email; use Phenix\Validation\Validator; -class ResendOtpController extends Controller +class ResendVerificationOtpController extends Controller { public function resend(Request $request): Response { diff --git a/routes/api.php b/routes/api.php index 1367e34..305a336 100644 --- a/routes/api.php +++ b/routes/api.php @@ -4,7 +4,7 @@ use App\Http\Controllers\Auth\LoginController; use App\Http\Controllers\Auth\RegisterController; -use App\Http\Controllers\Auth\ResendOtpController; +use App\Http\Controllers\Auth\ResendVerificationOtpController; use App\Http\Controllers\Auth\VerifyEmailController; use App\Http\Controllers\WelcomeController; use App\Http\Middleware\Guest; @@ -24,7 +24,7 @@ ->name('verification.verify') ->middleware(RateLimiter::perMinute(6, 'auth:verify-email')); - $router->post('resend-verification-otp', [ResendOtpController::class, 'resend']) + $router->post('resend-verification-otp', [ResendVerificationOtpController::class, 'resend']) ->name('verification.resend') ->middleware(RateLimiter::perMinute(2, 'auth:resend-verification-otp')); From 88ab73730be44cb256d48bcf14c7ae646d51185f Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Fri, 20 Mar 2026 20:24:29 +0000 Subject: [PATCH 102/133] refactor: fix import statement for Router class --- routes/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/api.php b/routes/api.php index 305a336..e9cf3a1 100644 --- a/routes/api.php +++ b/routes/api.php @@ -11,7 +11,7 @@ use Phenix\Auth\Middlewares\Authenticated; use Phenix\Cache\RateLimit\Middlewares\RateLimiter; use Phenix\Facades\Route; -use Phenix\Routing\Route as Router; +use Phenix\Routing\Router; Route::get('/', [WelcomeController::class, 'index']); From 0e07ce9b552f4bd686375bede92e07b70e67002e Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 24 Mar 2026 22:48:51 +0000 Subject: [PATCH 103/133] feat: implement forgot and reset password functionality with OTP --- .../Auth/ForgotPasswordController.php | 59 ++++++ .../Auth/ResetPasswordController.php | 82 ++++++++ app/Mail/SendResetPasswordOtp.php | 26 +++ app/Models/User.php | 2 + lang/en/auth.php | 17 ++ routes/api.php | 10 + tests/Feature/Auth/ForgotPasswordTest.php | 130 ++++++++++++ tests/Feature/Auth/ResetPasswordTest.php | 199 ++++++++++++++++++ 8 files changed, 525 insertions(+) create mode 100644 app/Http/Controllers/Auth/ForgotPasswordController.php create mode 100644 app/Http/Controllers/Auth/ResetPasswordController.php create mode 100644 app/Mail/SendResetPasswordOtp.php create mode 100644 tests/Feature/Auth/ForgotPasswordTest.php create mode 100644 tests/Feature/Auth/ResetPasswordTest.php diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php new file mode 100644 index 0000000..b56856f --- /dev/null +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -0,0 +1,59 @@ +setRules([ + 'email' => Email::required()->validations( + new DNSCheckValidation(), + new NoRFCWarningsValidation() + )->max(100), + ]); + + if ($validator->fails()) { + return response()->json([ + 'errors' => $validator->failing(), + ], HttpStatus::UNPROCESSABLE_ENTITY); + } + + $user = User::query() + ->whereEqual('email', $request->body('email')) + ->whereNotNull('email_verified_at') + ->first(); + + if ($user !== null) { + $otpCount = UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::RESET_PASSWORD->value) + ->whereGreaterThanOrEqual('created_at', Date::now()->subHour()->toDateTimeString()) + ->count(); + + if ($otpCount < 5) { + $user->sendOneTimePassword(OneTimePasswordScope::RESET_PASSWORD); + } + } + + return response()->json([ + 'message' => trans('auth.password_reset.sent'), + ], HttpStatus::OK); + } +} diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php new file mode 100644 index 0000000..983de2b --- /dev/null +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -0,0 +1,82 @@ +setRules([ + 'email' => Email::required()->validations( + new DNSCheckValidation(), + new NoRFCWarningsValidation() + )->max(100), + 'otp' => Numeric::required()->digits(6), + 'password' => Password::required()->secure(static fn (): bool => App::isProduction())->confirmed(), + ]); + + if ($validator->fails()) { + return response()->json([ + 'errors' => $validator->failing(), + ], HttpStatus::UNPROCESSABLE_ENTITY); + } + + /** @var User|null $user */ + $user = User::query() + ->whereEqual('email', $request->body('email')) + ->whereNotNull('email_verified_at') + ->first(); + + if ($user === null) { + return response()->json([ + 'message' => trans('auth.otp.invalid'), + ], HttpStatus::NOT_FOUND); + } + + $otp = UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::RESET_PASSWORD->value) + ->whereEqual('code', hash('sha256', (string) $request->body('otp'))) + ->whereNull('used_at') + ->whereGreaterThanOrEqual('expires_at', Date::now()->toDateTimeString()) + ->first(); + + if (! $otp) { + return response()->json([ + 'message' => trans('auth.otp.invalid'), + ], HttpStatus::NOT_FOUND); + } + + $otp->usedAt = Date::now(); + $otp->save(); + + $user->password = Hash::make($request->body('password')); + $user->save(); + + $user->tokens()->delete(); + + return response()->json([ + 'message' => trans('auth.password_reset.reset'), + ], HttpStatus::OK); + } +} diff --git a/app/Mail/SendResetPasswordOtp.php b/app/Mail/SendResetPasswordOtp.php new file mode 100644 index 0000000..1bb54e8 --- /dev/null +++ b/app/Mail/SendResetPasswordOtp.php @@ -0,0 +1,26 @@ +view('emails.otp', [ + 'title' => trans('auth.otp.reset_password.title'), + 'message' => trans('auth.otp.reset_password.message'), + 'otp' => $this->userOtp->otp, + ]) + ->subject(trans('auth.otp.reset_password.subject')); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index dfa03f2..4fb53ed 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -7,6 +7,7 @@ use App\Constants\OneTimePasswordScope; use App\Mail\SendEmailVerificationOtp; use App\Mail\SendLoginOtp; +use App\Mail\SendResetPasswordOtp; use Phenix\Auth\User as Authenticable; use Phenix\Database\Models\Attributes\DateTime; use Phenix\Facades\Mail; @@ -41,6 +42,7 @@ protected function resolveMailable(OneTimePasswordScope $scope, UserOtp $userOtp return match ($scope) { OneTimePasswordScope::VERIFY_EMAIL => new SendEmailVerificationOtp($userOtp), OneTimePasswordScope::LOGIN => new SendLoginOtp($userOtp), + OneTimePasswordScope::RESET_PASSWORD => new SendResetPasswordOtp($userOtp), }; } } diff --git a/lang/en/auth.php b/lang/en/auth.php index 8cd4d1b..70003bb 100644 --- a/lang/en/auth.php +++ b/lang/en/auth.php @@ -24,6 +24,11 @@ 'message' => 'Use the following verification code to complete your sign in.', 'sent' => 'A verification code has been sent to your email address.', ], + 'reset_password' => [ + 'subject' => 'Your password reset code', + 'title' => 'Password reset code', + 'message' => 'Use the following verification code to reset your password.', + ], 'email_verification' => [ 'subject' => 'Verify your email address', 'title' => 'Email verification code', @@ -31,6 +36,18 @@ 'resent' => 'OTP has been resent successfully.', ], ], + 'password_reset' => [ + 'sent' => 'If your email address exists in our records, a password reset code has been sent.', + 'reset' => 'Password has been reset successfully.', + ], + 'security' => [ + 'warning' => 'For your security:', + 'never_share' => 'Never share this code with anyone. Our team will never ask you for your verification code.', + 'ignore_if_not_requested' => 'If you didn\'t request this verification, please ignore this email.', + ], + 'footer' => [ + 'copyright' => ':year :appName. All rights reserved.', + ], 'rate_limit' => [ 'error' => 'Too Many Requests', 'exceeded' => 'Rate limit exceeded. Please try again later.', diff --git a/routes/api.php b/routes/api.php index e9cf3a1..1a0c35d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,9 +2,11 @@ declare(strict_types=1); +use App\Http\Controllers\Auth\ForgotPasswordController; use App\Http\Controllers\Auth\LoginController; use App\Http\Controllers\Auth\RegisterController; use App\Http\Controllers\Auth\ResendVerificationOtpController; +use App\Http\Controllers\Auth\ResetPasswordController; use App\Http\Controllers\Auth\VerifyEmailController; use App\Http\Controllers\WelcomeController; use App\Http\Middleware\Guest; @@ -28,6 +30,14 @@ ->name('verification.resend') ->middleware(RateLimiter::perMinute(2, 'auth:resend-verification-otp')); + $router->post('forgot-password', [ForgotPasswordController::class, 'store']) + ->name('password.email') + ->middleware(RateLimiter::perMinute(2, 'auth:forgot-password')); + + $router->post('reset-password', [ResetPasswordController::class, 'store']) + ->name('password.store') + ->middleware(RateLimiter::perMinute(5, 'auth:reset-password')); + $router->post('login', [LoginController::class, 'login']) ->name('login') ->middleware(RateLimiter::perMinute(5, 'auth:login')); diff --git a/tests/Feature/Auth/ForgotPasswordTest.php b/tests/Feature/Auth/ForgotPasswordTest.php new file mode 100644 index 0000000..c9d7da1 --- /dev/null +++ b/tests/Feature/Auth/ForgotPasswordTest.php @@ -0,0 +1,130 @@ + $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $this->post('/forgot-password', [ + 'email' => $user->email, + ])->assertOk() + ->assertJsonPath('message', trans('auth.password_reset.sent')); + + $this->assertDatabaseHas('user_one_time_passwords', [ + 'user_id' => $user->id, + 'scope' => OneTimePasswordScope::RESET_PASSWORD->value, + ]); + + Mail::expect(SendResetPasswordOtp::class)->toBeSentTimes(1); + } + + /** @test */ + public function it_returns_a_generic_response_for_non_existing_emails(): void + { + Mail::fake(); + + $this->post('/forgot-password', [ + 'email' => $this->faker()->freeEmail(), + ])->assertOk() + ->assertJsonPath('message', trans('auth.password_reset.sent')); + + $this->assertSame( + 0, + UserOtp::query() + ->whereEqual('scope', OneTimePasswordScope::RESET_PASSWORD->value) + ->count() + ); + + Mail::expect(SendResetPasswordOtp::class)->toNotBeSent(); + } + + /** @test */ + public function it_returns_a_generic_response_for_unverified_users(): void + { + Mail::fake(); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + ]); + + $this->post('/forgot-password', [ + 'email' => $user->email, + ])->assertOk() + ->assertJsonPath('message', trans('auth.password_reset.sent')); + + $this->assertSame( + 0, + UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::RESET_PASSWORD->value) + ->count() + ); + + Mail::expect(SendResetPasswordOtp::class)->toNotBeSent(); + } + + /** @test */ + public function it_returns_a_generic_response_when_the_reset_otp_limit_is_exceeded(): void + { + Date::setTestNow(Date::now()); + Mail::fake(); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + for ($i = 0; $i < 5; $i++) { + $user->createOneTimePassword(OneTimePasswordScope::RESET_PASSWORD); + } + + $this->post('/forgot-password', [ + 'email' => $user->email, + ])->assertOk() + ->assertJsonPath('message', trans('auth.password_reset.sent')); + + $this->assertSame( + 5, + UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::RESET_PASSWORD->value) + ->count() + ); + + Mail::expect(SendResetPasswordOtp::class)->toNotBeSent(); + } +} diff --git a/tests/Feature/Auth/ResetPasswordTest.php b/tests/Feature/Auth/ResetPasswordTest.php new file mode 100644 index 0000000..bd6ba51 --- /dev/null +++ b/tests/Feature/Auth/ResetPasswordTest.php @@ -0,0 +1,199 @@ + $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('OldP@ssw0rd1'), + 'email_verified_at' => Date::now(), + ]); + + $firstToken = $user->createToken('first-token'); + $secondToken = $user->createToken('second-token'); + $otp = $user->createOneTimePassword(OneTimePasswordScope::RESET_PASSWORD); + + $this->post('/reset-password', [ + 'email' => $user->email, + 'otp' => $otp->otp, + 'password' => 'N3wP@ssw0rd1', + 'password_confirmation' => 'N3wP@ssw0rd1', + ])->assertOk() + ->assertJsonPath('message', trans('auth.password_reset.reset')); + + $updatedUser = User::find($user->id); + + $this->assertNotNull($updatedUser); + $this->assertTrue(Hash::verify($updatedUser->password, 'N3wP@ssw0rd1')); + + $this->assertDatabaseHas('user_one_time_passwords', [ + 'id' => $otp->id, + 'used_at' => Date::now(), + ]); + + $this->assertDatabaseMissing('personal_access_tokens', [ + 'id' => $firstToken->id(), + ]); + + $this->assertDatabaseMissing('personal_access_tokens', [ + 'id' => $secondToken->id(), + ]); + } + + /** @test */ + public function it_responds_not_found_for_non_existing_otp(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('OldP@ssw0rd1'), + 'email_verified_at' => Date::now(), + ]); + + $token = $user->createToken('active-token'); + + $this->post('/reset-password', [ + 'email' => $user->email, + 'otp' => '123456', + 'password' => 'N3wP@ssw0rd1', + 'password_confirmation' => 'N3wP@ssw0rd1', + ])->assertNotFound() + ->assertJsonPath('message', trans('auth.otp.invalid')); + + $updatedUser = User::find($user->id); + + $this->assertNotNull($updatedUser); + $this->assertTrue(Hash::verify($updatedUser->password, 'OldP@ssw0rd1')); + + $this->assertDatabaseHas('personal_access_tokens', [ + 'id' => $token->id(), + ]); + } + + /** @test */ + public function it_responds_not_found_when_otp_has_different_scope(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('OldP@ssw0rd1'), + 'email_verified_at' => Date::now(), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); + + $this->post('/reset-password', [ + 'email' => $user->email, + 'otp' => $otp->otp, + 'password' => 'N3wP@ssw0rd1', + 'password_confirmation' => 'N3wP@ssw0rd1', + ])->assertNotFound() + ->assertJsonPath('message', trans('auth.otp.invalid')); + } + + /** @test */ + public function it_responds_not_found_when_otp_is_already_used(): void + { + Date::setTestNow(Date::now()); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('OldP@ssw0rd1'), + 'email_verified_at' => Date::now(), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::RESET_PASSWORD); + $otp->usedAt = Date::now(); + $otp->save(); + + $this->post('/reset-password', [ + 'email' => $user->email, + 'otp' => $otp->otp, + 'password' => 'N3wP@ssw0rd1', + 'password_confirmation' => 'N3wP@ssw0rd1', + ])->assertNotFound() + ->assertJsonPath('message', trans('auth.otp.invalid')); + } + + /** @test */ + public function it_responds_not_found_when_otp_is_expired(): void + { + Date::setTestNow(Date::now()); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('OldP@ssw0rd1'), + 'email_verified_at' => Date::now(), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::RESET_PASSWORD); + + Date::setTestNow(Date::now()->addMinutes(11)); + + $this->post('/reset-password', [ + 'email' => $user->email, + 'otp' => $otp->otp, + 'password' => 'N3wP@ssw0rd1', + 'password_confirmation' => 'N3wP@ssw0rd1', + ])->assertNotFound() + ->assertJsonPath('message', trans('auth.otp.invalid')); + } + + /** @test */ + public function it_responds_not_found_when_email_is_not_verified(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('OldP@ssw0rd1'), + ]); + + $this->post('/reset-password', [ + 'email' => $user->email, + 'otp' => '123456', + 'password' => 'N3wP@ssw0rd1', + 'password_confirmation' => 'N3wP@ssw0rd1', + ])->assertNotFound() + ->assertJsonPath('message', trans('auth.otp.invalid')); + } + + /** @test */ + public function it_validates_password_payload_for_reset_password(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('OldP@ssw0rd1'), + 'email_verified_at' => Date::now(), + ]); + + $this->post('/reset-password', [ + 'email' => $user->email, + 'otp' => '123456', + 'password' => 'N3wP@ssw0rd1', + 'password_confirmation' => 'DifferentValue1', + ])->assertUnprocessableEntity(); + } +} From f5eb2035d4d348019a9d9971bcca3566bd03acc6 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 24 Mar 2026 22:48:59 +0000 Subject: [PATCH 104/133] refactor: remove unauthorized response tests for login and resend OTP --- tests/Feature/Auth/LoginTest.php | 21 --------------------- tests/Feature/Auth/ResendOtpTest.php | 17 ----------------- 2 files changed, 38 deletions(-) diff --git a/tests/Feature/Auth/LoginTest.php b/tests/Feature/Auth/LoginTest.php index 613c04f..af1ffe6 100644 --- a/tests/Feature/Auth/LoginTest.php +++ b/tests/Feature/Auth/LoginTest.php @@ -139,27 +139,6 @@ public function it_responds_too_many_requests_when_login_otp_limit_is_exceeded() Mail::expect(SendLoginOtp::class)->toNotBeSent(); } - /** @test */ - public function it_responds_unauthorized_when_authorization_token_is_present(): void - { - Mail::fake(); - - $response = $this->post( - '/login', - [ - 'email' => $this->faker()->freeEmail(), - 'password' => 'P@ssw0rd12', - ], - [], - ['Authorization' => 'Bearer any-token'] - ); - - $response->assertUnauthorized() - ->assertJsonPath('message', trans('auth.unauthorized')); - - Mail::expect(SendLoginOtp::class)->toNotBeSent(); - } - /** @test */ public function it_rate_limits_login_attempts_per_client(): void { diff --git a/tests/Feature/Auth/ResendOtpTest.php b/tests/Feature/Auth/ResendOtpTest.php index bd2cc80..b445ee9 100644 --- a/tests/Feature/Auth/ResendOtpTest.php +++ b/tests/Feature/Auth/ResendOtpTest.php @@ -82,23 +82,6 @@ public function it_does_not_resend_otp_when_email_is_already_verified(): void Mail::expect(SendEmailVerificationOtp::class)->toNotBeSent(); } - /** @test */ - public function it_responds_unauthorized_when_authorization_token_is_present(): void - { - Mail::fake(); - - $response = $this->post( - path: '/resend-verification-otp', - body: ['email' => $this->faker()->freeEmail()], - headers: ['Authorization' => 'Bearer any-token'] - ); - - $response->assertUnauthorized() - ->assertJsonPath('message', trans('auth.unauthorized')); - - Mail::expect(SendEmailVerificationOtp::class)->toNotBeSent(); - } - /** @test */ public function it_responds_too_many_requests_when_exceed_otp_limit(): void { From 8186ee75c7ed5510bd81485001ec328a2ae31a2f Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 24 Mar 2026 22:49:16 +0000 Subject: [PATCH 105/133] chore: remove invalid file --- app/lang/en/auth.php | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 app/lang/en/auth.php diff --git a/app/lang/en/auth.php b/app/lang/en/auth.php deleted file mode 100644 index b90644c..0000000 --- a/app/lang/en/auth.php +++ /dev/null @@ -1,35 +0,0 @@ - [ - 'email_verification' => [ - 'title' => 'Verify Your Email Address', - 'subject' => 'Verify Your Email Address', - 'message' => 'Please use the following One-Time Password (OTP) to verify your email address:', - ], - 'login' => [ - 'title' => 'Login Verification Code', - 'subject' => 'Login Verification Code', - 'message' => 'Please use the following One-Time Password (OTP) to log in to your account:', - ], - 'label' => 'Your one-time password code', - 'expiry' => 'Valid for :minutes minutes', - 'sent' => 'A verification code has been sent to your email address.', - 'verified' => 'Your verification code has been confirmed successfully.', - 'expired' => 'The verification code has expired. Please request a new one.', - 'invalid' => 'The verification code is invalid.', - 'already_used' => 'This verification code has already been used.', - ], - - 'security' => [ - 'warning' => '⚠️ For your security:', - 'never_share' => 'Never share this code with anyone. Our team will never ask you for your verification code.', - 'ignore_if_not_requested' => 'If you didn\'t request this verification, please ignore this email.', - ], - - 'footer' => [ - 'copyright' => ':year :appName. All rights reserved.', - ], -]; From 92475cf46cb8a9a5945298d8aedba96e28a058bd Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 24 Mar 2026 22:49:51 +0000 Subject: [PATCH 106/133] style: php cs --- app/Http/Middleware/Guest.php | 4 ++-- tests/Feature/Auth/ForgotPasswordTest.php | 2 -- tests/Feature/Auth/ResetPasswordTest.php | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/Http/Middleware/Guest.php b/app/Http/Middleware/Guest.php index 4838c0b..252287d 100644 --- a/app/Http/Middleware/Guest.php +++ b/app/Http/Middleware/Guest.php @@ -32,10 +32,10 @@ protected function hasBearerToken(string|null $authorizationHeader): bool protected function extractToken(string|null $authorizationHeader): string|null { - if (!$this->hasBearerToken($authorizationHeader)) { + if (! $this->hasBearerToken($authorizationHeader)) { return null; } - + $parts = explode(' ', $authorizationHeader, 2); return isset($parts[1]) ? trim($parts[1]) : null; diff --git a/tests/Feature/Auth/ForgotPasswordTest.php b/tests/Feature/Auth/ForgotPasswordTest.php index c9d7da1..a6ce528 100644 --- a/tests/Feature/Auth/ForgotPasswordTest.php +++ b/tests/Feature/Auth/ForgotPasswordTest.php @@ -8,10 +8,8 @@ use App\Mail\SendResetPasswordOtp; use App\Models\User; use App\Models\UserOtp; -use Phenix\Facades\Cache; use Phenix\Facades\Hash; use Phenix\Facades\Mail; -use Phenix\Http\Constants\HttpStatus; use Phenix\Testing\Concerns\RefreshDatabase; use Phenix\Testing\Concerns\WithFaker; use Phenix\Util\Date; diff --git a/tests/Feature/Auth/ResetPasswordTest.php b/tests/Feature/Auth/ResetPasswordTest.php index bd6ba51..72050e0 100644 --- a/tests/Feature/Auth/ResetPasswordTest.php +++ b/tests/Feature/Auth/ResetPasswordTest.php @@ -40,7 +40,7 @@ public function it_resets_password_marks_otp_as_used_and_revokes_all_tokens(): v 'password_confirmation' => 'N3wP@ssw0rd1', ])->assertOk() ->assertJsonPath('message', trans('auth.password_reset.reset')); - + $updatedUser = User::find($user->id); $this->assertNotNull($updatedUser); From 963eb6b3a0925f2cce626a6f761600e4afb84527 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 24 Mar 2026 23:50:27 +0000 Subject: [PATCH 107/133] chore: update dependencies --- composer.lock | 74 +++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/composer.lock b/composer.lock index 279b649..df720a7 100644 --- a/composer.lock +++ b/composer.lock @@ -2168,16 +2168,16 @@ }, { "name": "cakephp/chronos", - "version": "3.3.1", + "version": "3.3.3", "source": { "type": "git", "url": "https://github.com/cakephp/chronos.git", - "reference": "1e417fdd4a3c6602b6c4634cf54aa9b065127fa2" + "reference": "960e7ecd5709fc186309b0733a18beecb37fd37e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/chronos/zipball/1e417fdd4a3c6602b6c4634cf54aa9b065127fa2", - "reference": "1e417fdd4a3c6602b6c4634cf54aa9b065127fa2", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/960e7ecd5709fc186309b0733a18beecb37fd37e", + "reference": "960e7ecd5709fc186309b0733a18beecb37fd37e", "shasum": "" }, "require": { @@ -2189,7 +2189,7 @@ }, "require-dev": { "cakephp/cakephp-codesniffer": "^5.0", - "phpunit/phpunit": "^10.5.58 || ^11.1.3" + "phpunit/phpunit": "^10.5.58 || ^11.5.3 || ^12.1.3" }, "type": "library", "autoload": { @@ -2223,7 +2223,7 @@ "issues": "https://github.com/cakephp/chronos/issues", "source": "https://github.com/cakephp/chronos" }, - "time": "2025-10-30T13:08:23+00:00" + "time": "2026-03-14T17:03:37+00:00" }, { "name": "cakephp/core", @@ -3375,16 +3375,16 @@ }, { "name": "league/climate", - "version": "3.10.0", + "version": "3.10.1", "source": { "type": "git", "url": "https://github.com/thephpleague/climate.git", - "reference": "237f70e1032b16d32ff3f65dcda68706911e1c74" + "reference": "f2d78fbc504740bcd0209e40a4586c886567ddc9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/climate/zipball/237f70e1032b16d32ff3f65dcda68706911e1c74", - "reference": "237f70e1032b16d32ff3f65dcda68706911e1c74", + "url": "https://api.github.com/repos/thephpleague/climate/zipball/f2d78fbc504740bcd0209e40a4586c886567ddc9", + "reference": "f2d78fbc504740bcd0209e40a4586c886567ddc9", "shasum": "" }, "require": { @@ -3395,7 +3395,7 @@ "require-dev": { "mikey179/vfsstream": "^1.6.12", "mockery/mockery": "^1.6.12", - "phpunit/phpunit": "^9.5.10", + "phpunit/phpunit": "^9.6.21", "squizlabs/php_codesniffer": "^3.10" }, "suggest": { @@ -3435,9 +3435,9 @@ ], "support": { "issues": "https://github.com/thephpleague/climate/issues", - "source": "https://github.com/thephpleague/climate/tree/3.10.0" + "source": "https://github.com/thephpleague/climate/tree/3.10.1" }, - "time": "2024-11-18T09:09:55+00:00" + "time": "2026-03-19T19:32:55+00:00" }, { "name": "league/container", @@ -3523,20 +3523,20 @@ }, { "name": "league/uri", - "version": "7.8.0", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/thephpleague/uri.git", - "reference": "4436c6ec8d458e4244448b069cc572d088230b76" + "reference": "08cf38e3924d4f56238125547b5720496fac8fd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76", - "reference": "4436c6ec8d458e4244448b069cc572d088230b76", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/08cf38e3924d4f56238125547b5720496fac8fd4", + "reference": "08cf38e3924d4f56238125547b5720496fac8fd4", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.8", + "league/uri-interfaces": "^7.8.1", "php": "^8.1", "psr/http-factory": "^1" }, @@ -3609,7 +3609,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.8.0" + "source": "https://github.com/thephpleague/uri/tree/7.8.1" }, "funding": [ { @@ -3617,24 +3617,24 @@ "type": "github" } ], - "time": "2026-01-14T17:24:56+00:00" + "time": "2026-03-15T20:22:25+00:00" }, { "name": "league/uri-components", - "version": "7.8.0", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-components.git", - "reference": "8b5ffcebcc0842b76eb80964795bd56a8333b2ba" + "reference": "848ff9db2f0be06229d6034b7c2e33d41b4fd675" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/8b5ffcebcc0842b76eb80964795bd56a8333b2ba", - "reference": "8b5ffcebcc0842b76eb80964795bd56a8333b2ba", + "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/848ff9db2f0be06229d6034b7c2e33d41b4fd675", + "reference": "848ff9db2f0be06229d6034b7c2e33d41b4fd675", "shasum": "" }, "require": { - "league/uri": "^7.8", + "league/uri": "^7.8.1", "php": "^8.1" }, "suggest": { @@ -3693,7 +3693,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-components/tree/7.8.0" + "source": "https://github.com/thephpleague/uri-components/tree/7.8.1" }, "funding": [ { @@ -3701,20 +3701,20 @@ "type": "github" } ], - "time": "2026-01-14T17:24:56+00:00" + "time": "2026-03-15T20:22:25+00:00" }, { "name": "league/uri-interfaces", - "version": "7.8.0", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4" + "reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4", - "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/85d5c77c5d6d3af6c54db4a78246364908f3c928", + "reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928", "shasum": "" }, "require": { @@ -3777,7 +3777,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.1" }, "funding": [ { @@ -3785,7 +3785,7 @@ "type": "github" } ], - "time": "2026-01-15T06:54:53+00:00" + "time": "2026-03-08T20:05:35+00:00" }, { "name": "monolog/monolog", @@ -4120,12 +4120,12 @@ "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "80c4a6657f78f5173b05aa01afafdaa72e69c5a9" + "reference": "4aa5081b1d04621f9e84cd832a62a40c20b90633" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/80c4a6657f78f5173b05aa01afafdaa72e69c5a9", - "reference": "80c4a6657f78f5173b05aa01afafdaa72e69c5a9", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/4aa5081b1d04621f9e84cd832a62a40c20b90633", + "reference": "4aa5081b1d04621f9e84cd832a62a40c20b90633", "shasum": "" }, "require": { @@ -4207,7 +4207,7 @@ "issues": "https://github.com/phenixphp/framework/issues", "source": "https://github.com/phenixphp/framework/tree/develop" }, - "time": "2026-03-13T00:17:20+00:00" + "time": "2026-03-24T23:34:14+00:00" }, { "name": "phenixphp/http-cors", From d8326d3d642d5788545445a10c49a3a9429e5402 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 25 Mar 2026 12:08:21 +0000 Subject: [PATCH 108/133] feat: implement token management functionality with listing, refreshing, and revoking tokens --- app/Http/Controllers/Auth/TokenController.php | 65 +++++++++++ lang/en/auth.php | 3 + routes/api.php | 10 ++ schedule/schedules.php | 7 ++ tests/Feature/Auth/TokenManagementTest.php | 110 ++++++++++++++++++ tests/Feature/Auth/TokenRefreshTest.php | 90 ++++++++++++++ 6 files changed, 285 insertions(+) create mode 100644 app/Http/Controllers/Auth/TokenController.php create mode 100644 tests/Feature/Auth/TokenManagementTest.php create mode 100644 tests/Feature/Auth/TokenRefreshTest.php diff --git a/app/Http/Controllers/Auth/TokenController.php b/app/Http/Controllers/Auth/TokenController.php new file mode 100644 index 0000000..f61b6e7 --- /dev/null +++ b/app/Http/Controllers/Auth/TokenController.php @@ -0,0 +1,65 @@ +user(); + + $tokens = $user->tokens() + ->whereGreaterThan('expires_at', Date::now()->toDateTimeString()) + ->get(); + + return response()->json($tokens); + } + + public function refresh(Request $request): Response + { + /** @var User $user */ + $user = $request->user(); + + $token = $user->refreshToken('auth_token'); + + return response()->json([ + 'access_token' => $token->toString(), + 'expires_at' => $token->expiresAt()->toDateTimeString(), + 'token_type' => 'Bearer', + ]); + } + + public function destroy(Request $request): Response + { + /** @var User $user */ + $user = $request->user(); + + /** @var PersonalAccessToken|null $token */ + $token = PersonalAccessToken::query() + ->whereEqual('id', $request->route('id')) + ->whereEqual('tokenable_type', User::class) + ->whereEqual('tokenable_id', $user->id) + ->first(); + + if (! $token) { + return response()->json([ + 'message' => trans('auth.token.not_found'), + ], HttpStatus::NOT_FOUND); + } + + $token->delete(); + + return response()->json([], HttpStatus::OK); + } +} diff --git a/lang/en/auth.php b/lang/en/auth.php index 70003bb..e2f66ff 100644 --- a/lang/en/auth.php +++ b/lang/en/auth.php @@ -52,4 +52,7 @@ 'error' => 'Too Many Requests', 'exceeded' => 'Rate limit exceeded. Please try again later.', ], + 'token' => [ + 'not_found' => 'Token not found.', + ], ]; diff --git a/routes/api.php b/routes/api.php index 1a0c35d..8f95cef 100644 --- a/routes/api.php +++ b/routes/api.php @@ -5,6 +5,7 @@ use App\Http\Controllers\Auth\ForgotPasswordController; use App\Http\Controllers\Auth\LoginController; use App\Http\Controllers\Auth\RegisterController; +use App\Http\Controllers\Auth\TokenController; use App\Http\Controllers\Auth\ResendVerificationOtpController; use App\Http\Controllers\Auth\ResetPasswordController; use App\Http\Controllers\Auth\VerifyEmailController; @@ -51,4 +52,13 @@ ->group(function (Router $router): void { $router->post('logout', [LoginController::class, 'logout']) ->name('logout'); + + $router->get('tokens', [TokenController::class, 'index']) + ->name('tokens.index'); + + $router->post('token/refresh', [TokenController::class, 'refresh']) + ->name('token.refresh'); + + $router->delete('tokens/{id}', [TokenController::class, 'destroy']) + ->name('tokens.destroy'); }); diff --git a/schedule/schedules.php b/schedule/schedules.php index 6ac6751..a652654 100644 --- a/schedule/schedules.php +++ b/schedule/schedules.php @@ -3,6 +3,7 @@ declare(strict_types=1); use App\Models\UserOtp; +use Phenix\Auth\PersonalAccessToken; use Phenix\Facades\Schedule; use Phenix\Util\Date; @@ -11,4 +12,10 @@ ->whereNull('used_at') ->whereLessThan('expires_at', Date::now()->toDateTimeString()) ->delete(); +})->everyMinute(); + +Schedule::timer(function (): void { + PersonalAccessToken::query() + ->whereLessThanOrEqual('expires_at', Date::now()->toDateTimeString()) + ->delete(); })->everyMinute(); \ No newline at end of file diff --git a/tests/Feature/Auth/TokenManagementTest.php b/tests/Feature/Auth/TokenManagementTest.php new file mode 100644 index 0000000..02e1d82 --- /dev/null +++ b/tests/Feature/Auth/TokenManagementTest.php @@ -0,0 +1,110 @@ + $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $tokenA = $user->createToken('token-a'); + $tokenB = $user->createToken('token-b'); + + $expiredToken = $user->createToken('token-expired', ['*'], Date::now()->subMinute()); + + $response = $this->get( + path: '/tokens', + headers: ['Authorization' => 'Bearer ' . $tokenA->toString()] + ); + + $response->assertOk(); + + $data = $response->getDecodedBody(); + + $this->assertCount(2, $data); + + $ids = array_column($data, 'id'); + $this->assertContains($tokenA->id(), $ids); + $this->assertContains($tokenB->id(), $ids); + $this->assertNotContains($expiredToken->id(), $ids); + } + + /** @test */ + public function it_revokes_a_specific_token_by_id(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $tokenA = $user->createToken('token-a'); + $tokenB = $user->createToken('token-b'); + + $response = $this->delete( + path: '/tokens/' . $tokenA->id(), + headers: ['Authorization' => 'Bearer ' . $tokenB->toString()] + ); + + $response->assertOk(); + + $this->assertDatabaseMissing('personal_access_tokens', [ + 'id' => $tokenA->id(), + ]); + + $this->assertDatabaseHas('personal_access_tokens', [ + 'id' => $tokenB->id(), + ]); + } + + /** @test */ + public function it_responds_not_found_when_revoking_another_users_token(): void + { + $userA = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $userB = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $tokenA = $userA->createToken('token-a'); + $tokenB = $userB->createToken('token-b'); + + $response = $this->delete( + path: '/tokens/' . $tokenB->id(), + headers: ['Authorization' => 'Bearer ' . $tokenA->toString()] + ); + + $response->assertNotFound() + ->assertJsonPath('message', trans('auth.token.not_found')); + } +} diff --git a/tests/Feature/Auth/TokenRefreshTest.php b/tests/Feature/Auth/TokenRefreshTest.php new file mode 100644 index 0000000..1992635 --- /dev/null +++ b/tests/Feature/Auth/TokenRefreshTest.php @@ -0,0 +1,90 @@ + $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $oldToken = $user->createToken('auth_token'); + + $response = $this->post( + path: '/token/refresh', + headers: ['Authorization' => 'Bearer ' . $oldToken->toString()] + ); + + $response->assertOk() + ->assertJsonPath('token_type', 'Bearer'); + + $data = $response->getDecodedBody(); + + $this->assertNotEmpty($data['access_token'] ?? null); + $this->assertNotEmpty($data['expires_at'] ?? null); + $this->assertNotSame($oldToken->toString(), $data['access_token']); + + $this->assertDatabaseHas('personal_access_tokens', [ + 'token' => hash('sha256', $data['access_token']), + ]); + + $this->assertDatabaseHas('personal_access_tokens', [ + 'id' => $oldToken->id(), + 'expires_at' => Date::now()->toDateTimeString(), + ]); + } + + /** @test */ + public function it_cannot_use_old_token_after_refresh(): void + { + Date::setTestNow(Date::now()); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $oldToken = $user->createToken('auth_token'); + + $this->post( + path: '/token/refresh', + headers: ['Authorization' => 'Bearer ' . $oldToken->toString()] + )->assertOk(); + + Date::setTestNow(Date::now()->addSecond()); + + $this->post( + path: '/logout', + headers: ['Authorization' => 'Bearer ' . $oldToken->toString()] + )->assertUnauthorized(); + } + + /** @test */ + public function it_responds_unauthorized_without_token(): void + { + $this->post('/token/refresh') + ->assertUnauthorized(); + } +} From 68a113a69fd6fb93d5e3305add7e58c932704349 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 25 Mar 2026 12:09:07 +0000 Subject: [PATCH 109/133] feat: add cancel registration functionality with validation and tests --- .../Controllers/Auth/RegisterController.php | 32 ++++++++ lang/en/auth.php | 3 + routes/api.php | 3 + tests/Feature/Auth/CancelRegistrationTest.php | 81 +++++++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 tests/Feature/Auth/CancelRegistrationTest.php diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 96a228c..32e257d 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -49,4 +49,36 @@ public function store(Request $request): Response return response()->json($user, HttpStatus::CREATED); } + + public function cancel(Request $request): Response + { + $validator = new Validator($request); + $validator->setRules([ + 'email' => Email::required()->validations( + new DNSCheckValidation(), + new NoRFCWarningsValidation() + )->max(100) + ->exists('users', 'email', function ($query): void { + $query->whereNull('email_verified_at'); + }), + ]); + + if ($validator->fails()) { + return response()->json([ + 'errors' => $validator->failing(), + ], HttpStatus::UNPROCESSABLE_ENTITY); + } + + /** @var User $user */ + $user = User::query() + ->whereEqual('email', $request->body('email')) + ->whereNull('email_verified_at') + ->first(); + + $user->delete(); + + return response()->json([ + 'message' => trans('auth.registration.cancelled'), + ], HttpStatus::OK); + } } diff --git a/lang/en/auth.php b/lang/en/auth.php index e2f66ff..336521e 100644 --- a/lang/en/auth.php +++ b/lang/en/auth.php @@ -55,4 +55,7 @@ 'token' => [ 'not_found' => 'Token not found.', ], + 'registration' => [ + 'cancelled' => 'Registration cancelled.', + ], ]; diff --git a/routes/api.php b/routes/api.php index 8f95cef..89b8c22 100644 --- a/routes/api.php +++ b/routes/api.php @@ -46,6 +46,9 @@ $router->post('login/authorize', [LoginController::class, 'authorize']) ->name('login.authorize') ->middleware(RateLimiter::perMinute(5, 'auth:login-authorize')); + + $router->post('register/cancel', [RegisterController::class, 'cancel']) + ->name('register.cancel'); }); Route::middleware(Authenticated::class) diff --git a/tests/Feature/Auth/CancelRegistrationTest.php b/tests/Feature/Auth/CancelRegistrationTest.php new file mode 100644 index 0000000..4529972 --- /dev/null +++ b/tests/Feature/Auth/CancelRegistrationTest.php @@ -0,0 +1,81 @@ + $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); + + $response = $this->post('/register/cancel', ['email' => $user->email]); + + $response->assertOk() + ->assertJsonPath('message', trans('auth.registration.cancelled')); + + $this->assertDatabaseMissing('users', ['id' => $user->id]); + $this->assertDatabaseMissing('user_one_time_passwords', ['id' => $otp->id]); + } + + /** @test */ + public function it_responds_unprocessable_when_email_does_not_exist(): void + { + $response = $this->post('/register/cancel', ['email' => 'nonexistent@example.com']); + + $response->assertUnprocessableEntity(); + } + + /** @test */ + public function it_responds_unprocessable_when_email_is_already_verified(): void + { + User::create([ + 'name' => $this->faker()->name(), + 'email' => 'verified@example.com', + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $response = $this->post('/register/cancel', ['email' => 'verified@example.com']); + + $response->assertUnprocessableEntity(); + } + + /** @test */ + public function it_rejects_authenticated_users_via_guest_middleware(): void + { + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $token = $user->createToken('auth_token'); + + $this->post( + path: '/register/cancel', + body: ['email' => $user->email], + headers: ['Authorization' => 'Bearer ' . $token->toString()] + )->assertUnauthorized(); + } +} From f6b5e0589ecd7f9559b0df3cc0dd72d48e30f898 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 25 Mar 2026 12:10:46 +0000 Subject: [PATCH 110/133] style: php cs --- routes/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/api.php b/routes/api.php index 89b8c22..491bc3a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -5,9 +5,9 @@ use App\Http\Controllers\Auth\ForgotPasswordController; use App\Http\Controllers\Auth\LoginController; use App\Http\Controllers\Auth\RegisterController; -use App\Http\Controllers\Auth\TokenController; use App\Http\Controllers\Auth\ResendVerificationOtpController; use App\Http\Controllers\Auth\ResetPasswordController; +use App\Http\Controllers\Auth\TokenController; use App\Http\Controllers\Auth\VerifyEmailController; use App\Http\Controllers\WelcomeController; use App\Http\Middleware\Guest; From 6db96535337c601fe2cfe910107f3604704eb8c9 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 25 Mar 2026 12:39:02 +0000 Subject: [PATCH 111/133] tests(refactor): use route global helper --- tests/Feature/Auth/CancelRegistrationTest.php | 8 ++++---- tests/Feature/Auth/ForgotPasswordTest.php | 8 ++++---- tests/Feature/Auth/LoginAuthorizationTest.php | 18 +++++++++--------- tests/Feature/Auth/LoginTest.php | 12 ++++++------ tests/Feature/Auth/LogoutTest.php | 4 ++-- tests/Feature/Auth/RegisterTest.php | 2 +- tests/Feature/Auth/ResendOtpTest.php | 6 +++--- tests/Feature/Auth/ResetPasswordTest.php | 14 +++++++------- tests/Feature/Auth/TokenManagementTest.php | 6 +++--- tests/Feature/Auth/TokenRefreshTest.php | 8 ++++---- tests/Feature/Auth/VerifyEmailTest.php | 12 ++++++------ 11 files changed, 49 insertions(+), 49 deletions(-) diff --git a/tests/Feature/Auth/CancelRegistrationTest.php b/tests/Feature/Auth/CancelRegistrationTest.php index 4529972..8a0f789 100644 --- a/tests/Feature/Auth/CancelRegistrationTest.php +++ b/tests/Feature/Auth/CancelRegistrationTest.php @@ -28,7 +28,7 @@ public function it_cancels_a_pending_unverified_registration(): void $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); - $response = $this->post('/register/cancel', ['email' => $user->email]); + $response = $this->post(route('register.cancel'), ['email' => $user->email]); $response->assertOk() ->assertJsonPath('message', trans('auth.registration.cancelled')); @@ -40,7 +40,7 @@ public function it_cancels_a_pending_unverified_registration(): void /** @test */ public function it_responds_unprocessable_when_email_does_not_exist(): void { - $response = $this->post('/register/cancel', ['email' => 'nonexistent@example.com']); + $response = $this->post(route('register.cancel'), ['email' => 'nonexistent@example.com']); $response->assertUnprocessableEntity(); } @@ -55,7 +55,7 @@ public function it_responds_unprocessable_when_email_is_already_verified(): void 'email_verified_at' => Date::now(), ]); - $response = $this->post('/register/cancel', ['email' => 'verified@example.com']); + $response = $this->post(route('register.cancel'), ['email' => 'verified@example.com']); $response->assertUnprocessableEntity(); } @@ -73,7 +73,7 @@ public function it_rejects_authenticated_users_via_guest_middleware(): void $token = $user->createToken('auth_token'); $this->post( - path: '/register/cancel', + path: route('register.cancel'), body: ['email' => $user->email], headers: ['Authorization' => 'Bearer ' . $token->toString()] )->assertUnauthorized(); diff --git a/tests/Feature/Auth/ForgotPasswordTest.php b/tests/Feature/Auth/ForgotPasswordTest.php index a6ce528..d1377e0 100644 --- a/tests/Feature/Auth/ForgotPasswordTest.php +++ b/tests/Feature/Auth/ForgotPasswordTest.php @@ -33,7 +33,7 @@ public function it_sends_a_reset_password_otp_for_verified_users(): void 'email_verified_at' => Date::now(), ]); - $this->post('/forgot-password', [ + $this->post(route('password.email'), [ 'email' => $user->email, ])->assertOk() ->assertJsonPath('message', trans('auth.password_reset.sent')); @@ -51,7 +51,7 @@ public function it_returns_a_generic_response_for_non_existing_emails(): void { Mail::fake(); - $this->post('/forgot-password', [ + $this->post(route('password.email'), [ 'email' => $this->faker()->freeEmail(), ])->assertOk() ->assertJsonPath('message', trans('auth.password_reset.sent')); @@ -77,7 +77,7 @@ public function it_returns_a_generic_response_for_unverified_users(): void 'password' => Hash::make('P@ssw0rd12'), ]); - $this->post('/forgot-password', [ + $this->post(route('password.email'), [ 'email' => $user->email, ])->assertOk() ->assertJsonPath('message', trans('auth.password_reset.sent')); @@ -110,7 +110,7 @@ public function it_returns_a_generic_response_when_the_reset_otp_limit_is_exceed $user->createOneTimePassword(OneTimePasswordScope::RESET_PASSWORD); } - $this->post('/forgot-password', [ + $this->post(route('password.email'), [ 'email' => $user->email, ])->assertOk() ->assertJsonPath('message', trans('auth.password_reset.sent')); diff --git a/tests/Feature/Auth/LoginAuthorizationTest.php b/tests/Feature/Auth/LoginAuthorizationTest.php index 0e621a1..95bee6a 100644 --- a/tests/Feature/Auth/LoginAuthorizationTest.php +++ b/tests/Feature/Auth/LoginAuthorizationTest.php @@ -33,7 +33,7 @@ public function it_authorizes_login_and_returns_a_bearer_token(): void $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); - $response = $this->post('/login/authorize', [ + $response = $this->post(route('login.authorize'), [ 'email' => $user->email, 'otp' => $otp->otp, ]); @@ -68,7 +68,7 @@ public function it_responds_not_found_for_non_existing_otp(): void 'email_verified_at' => Date::now(), ]); - $response = $this->post('/login/authorize', [ + $response = $this->post(route('login.authorize'), [ 'email' => $user->email, 'otp' => '123456', ]); @@ -89,7 +89,7 @@ public function it_responds_not_found_when_otp_has_different_scope(): void $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); - $response = $this->post('/login/authorize', [ + $response = $this->post(route('login.authorize'), [ 'email' => $user->email, 'otp' => $otp->otp, ]); @@ -114,7 +114,7 @@ public function it_responds_not_found_when_otp_is_already_used(): void $otp->usedAt = Date::now(); $otp->save(); - $response = $this->post('/login/authorize', [ + $response = $this->post(route('login.authorize'), [ 'email' => $user->email, 'otp' => $otp->otp, ]); @@ -139,7 +139,7 @@ public function it_responds_not_found_when_otp_is_expired(): void Date::setTestNow(Date::now()->addMinutes(11)); - $response = $this->post('/login/authorize', [ + $response = $this->post(route('login.authorize'), [ 'email' => $user->email, 'otp' => $otp->otp, ]); @@ -161,13 +161,13 @@ public function it_rate_limits_login_authorization_attempts_per_client(): void ]); for ($i = 0; $i < 5; $i++) { - $this->post('/login/authorize', [ + $this->post(route('login.authorize'), [ 'email' => $user->email, 'otp' => '123456', ])->assertNotFound(); } - $this->post('/login/authorize', [ + $this->post(route('login.authorize'), [ 'email' => $user->email, 'otp' => '123456', ])->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) @@ -189,13 +189,13 @@ public function it_uses_independent_rate_limit_buckets_for_login_and_login_autho $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); for ($i = 0; $i < 5; $i++) { - $this->post('/login', [ + $this->post(route('login'), [ 'email' => $user->email, 'password' => 'WrongPass99', ])->assertUnauthorized(); } - $this->post('/login/authorize', [ + $this->post(route('login.authorize'), [ 'email' => $user->email, 'otp' => $otp->otp, ])->assertOk() diff --git a/tests/Feature/Auth/LoginTest.php b/tests/Feature/Auth/LoginTest.php index af1ffe6..369f683 100644 --- a/tests/Feature/Auth/LoginTest.php +++ b/tests/Feature/Auth/LoginTest.php @@ -34,7 +34,7 @@ public function it_sends_a_login_otp_for_valid_verified_credentials(): void 'email_verified_at' => Date::now(), ]); - $response = $this->post('/login', [ + $response = $this->post(route('login'), [ 'email' => $user->email, 'password' => 'P@ssw0rd12', ]); @@ -62,7 +62,7 @@ public function it_rejects_wrong_password(): void 'email_verified_at' => Date::now(), ]); - $response = $this->post('/login', [ + $response = $this->post(route('login'), [ 'email' => $user->email, 'password' => 'WrongPass99', ]); @@ -92,7 +92,7 @@ public function it_rejects_unverified_email(): void 'password' => Hash::make('P@ssw0rd12'), ]); - $response = $this->post('/login', [ + $response = $this->post(route('login'), [ 'email' => $user->email, 'password' => 'P@ssw0rd12', ]); @@ -120,7 +120,7 @@ public function it_responds_too_many_requests_when_login_otp_limit_is_exceeded() $user->createOneTimePassword(OneTimePasswordScope::LOGIN); } - $response = $this->post('/login', [ + $response = $this->post(route('login'), [ 'email' => $user->email, 'password' => 'P@ssw0rd12', ]); @@ -153,13 +153,13 @@ public function it_rate_limits_login_attempts_per_client(): void ]); for ($i = 0; $i < 5; $i++) { - $this->post('/login', [ + $this->post(route('login'), [ 'email' => $user->email, 'password' => 'WrongPass99', ])->assertUnauthorized(); } - $this->post('/login', [ + $this->post(route('login'), [ 'email' => $user->email, 'password' => 'WrongPass99', ])->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) diff --git a/tests/Feature/Auth/LogoutTest.php b/tests/Feature/Auth/LogoutTest.php index 21c89fd..e576647 100644 --- a/tests/Feature/Auth/LogoutTest.php +++ b/tests/Feature/Auth/LogoutTest.php @@ -30,7 +30,7 @@ public function it_logs_out_and_revokes_only_the_current_token(): void $otherToken = $user->createToken('other-token'); $response = $this->post( - path: '/logout', + path: route('logout'), headers: ['Authorization' => 'Bearer ' . $currentToken->toString()] ); @@ -49,7 +49,7 @@ public function it_logs_out_and_revokes_only_the_current_token(): void /** @test */ public function it_responds_unauthorized_when_logging_out_without_a_token(): void { - $this->post('/logout') + $this->post(route('logout')) ->assertUnauthorized() ->assertJsonPath('message', trans('auth.unauthorized')); } diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php index 02991ad..c20a876 100644 --- a/tests/Feature/Auth/RegisterTest.php +++ b/tests/Feature/Auth/RegisterTest.php @@ -28,7 +28,7 @@ public function it_registers_a_user(): void 'password_confirmation' => 'P@ssw0rd', ]; - $response = $this->post('/register', $data); + $response = $this->post(route('register'), $data); $response->assertCreated() ->assertJsonContains([ diff --git a/tests/Feature/Auth/ResendOtpTest.php b/tests/Feature/Auth/ResendOtpTest.php index b445ee9..3eab626 100644 --- a/tests/Feature/Auth/ResendOtpTest.php +++ b/tests/Feature/Auth/ResendOtpTest.php @@ -35,7 +35,7 @@ public function it_resend_otp_for_unverified_email(): void $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); - $response = $this->post('/resend-verification-otp', [ + $response = $this->post(route('verification.resend'), [ 'email' => $user->email, ]); @@ -72,7 +72,7 @@ public function it_does_not_resend_otp_when_email_is_already_verified(): void 'email_verified_at' => Date::now(), ]); - $response = $this->post('/resend-verification-otp', [ + $response = $this->post(route('verification.resend'), [ 'email' => $user->email, ]); @@ -98,7 +98,7 @@ public function it_responds_too_many_requests_when_exceed_otp_limit(): void $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); } - $response = $this->post('/resend-verification-otp', [ + $response = $this->post(route('verification.resend'), [ 'email' => $user->email, ]); diff --git a/tests/Feature/Auth/ResetPasswordTest.php b/tests/Feature/Auth/ResetPasswordTest.php index 72050e0..3913a59 100644 --- a/tests/Feature/Auth/ResetPasswordTest.php +++ b/tests/Feature/Auth/ResetPasswordTest.php @@ -33,7 +33,7 @@ public function it_resets_password_marks_otp_as_used_and_revokes_all_tokens(): v $secondToken = $user->createToken('second-token'); $otp = $user->createOneTimePassword(OneTimePasswordScope::RESET_PASSWORD); - $this->post('/reset-password', [ + $this->post(route('password.store'), [ 'email' => $user->email, 'otp' => $otp->otp, 'password' => 'N3wP@ssw0rd1', @@ -72,7 +72,7 @@ public function it_responds_not_found_for_non_existing_otp(): void $token = $user->createToken('active-token'); - $this->post('/reset-password', [ + $this->post(route('password.store'), [ 'email' => $user->email, 'otp' => '123456', 'password' => 'N3wP@ssw0rd1', @@ -102,7 +102,7 @@ public function it_responds_not_found_when_otp_has_different_scope(): void $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); - $this->post('/reset-password', [ + $this->post(route('password.store'), [ 'email' => $user->email, 'otp' => $otp->otp, 'password' => 'N3wP@ssw0rd1', @@ -127,7 +127,7 @@ public function it_responds_not_found_when_otp_is_already_used(): void $otp->usedAt = Date::now(); $otp->save(); - $this->post('/reset-password', [ + $this->post(route('password.store'), [ 'email' => $user->email, 'otp' => $otp->otp, 'password' => 'N3wP@ssw0rd1', @@ -152,7 +152,7 @@ public function it_responds_not_found_when_otp_is_expired(): void Date::setTestNow(Date::now()->addMinutes(11)); - $this->post('/reset-password', [ + $this->post(route('password.store'), [ 'email' => $user->email, 'otp' => $otp->otp, 'password' => 'N3wP@ssw0rd1', @@ -170,7 +170,7 @@ public function it_responds_not_found_when_email_is_not_verified(): void 'password' => Hash::make('OldP@ssw0rd1'), ]); - $this->post('/reset-password', [ + $this->post(route('password.store'), [ 'email' => $user->email, 'otp' => '123456', 'password' => 'N3wP@ssw0rd1', @@ -189,7 +189,7 @@ public function it_validates_password_payload_for_reset_password(): void 'email_verified_at' => Date::now(), ]); - $this->post('/reset-password', [ + $this->post(route('password.store'), [ 'email' => $user->email, 'otp' => '123456', 'password' => 'N3wP@ssw0rd1', diff --git a/tests/Feature/Auth/TokenManagementTest.php b/tests/Feature/Auth/TokenManagementTest.php index 02e1d82..404e6f4 100644 --- a/tests/Feature/Auth/TokenManagementTest.php +++ b/tests/Feature/Auth/TokenManagementTest.php @@ -34,7 +34,7 @@ public function it_lists_active_tokens_for_authenticated_user(): void $expiredToken = $user->createToken('token-expired', ['*'], Date::now()->subMinute()); $response = $this->get( - path: '/tokens', + path: route('tokens.index'), headers: ['Authorization' => 'Bearer ' . $tokenA->toString()] ); @@ -64,7 +64,7 @@ public function it_revokes_a_specific_token_by_id(): void $tokenB = $user->createToken('token-b'); $response = $this->delete( - path: '/tokens/' . $tokenA->id(), + path: route('tokens.destroy', ['id' => $tokenA->id()]), headers: ['Authorization' => 'Bearer ' . $tokenB->toString()] ); @@ -100,7 +100,7 @@ public function it_responds_not_found_when_revoking_another_users_token(): void $tokenB = $userB->createToken('token-b'); $response = $this->delete( - path: '/tokens/' . $tokenB->id(), + path: route('tokens.destroy', ['id' => $tokenB->id()]), headers: ['Authorization' => 'Bearer ' . $tokenA->toString()] ); diff --git a/tests/Feature/Auth/TokenRefreshTest.php b/tests/Feature/Auth/TokenRefreshTest.php index 1992635..0a0d558 100644 --- a/tests/Feature/Auth/TokenRefreshTest.php +++ b/tests/Feature/Auth/TokenRefreshTest.php @@ -31,7 +31,7 @@ public function it_refreshes_current_token_and_expires_the_previous_one(): void $oldToken = $user->createToken('auth_token'); $response = $this->post( - path: '/token/refresh', + path: route('token.refresh'), headers: ['Authorization' => 'Bearer ' . $oldToken->toString()] ); @@ -69,14 +69,14 @@ public function it_cannot_use_old_token_after_refresh(): void $oldToken = $user->createToken('auth_token'); $this->post( - path: '/token/refresh', + path: route('token.refresh'), headers: ['Authorization' => 'Bearer ' . $oldToken->toString()] )->assertOk(); Date::setTestNow(Date::now()->addSecond()); $this->post( - path: '/logout', + path: route('logout'), headers: ['Authorization' => 'Bearer ' . $oldToken->toString()] )->assertUnauthorized(); } @@ -84,7 +84,7 @@ public function it_cannot_use_old_token_after_refresh(): void /** @test */ public function it_responds_unauthorized_without_token(): void { - $this->post('/token/refresh') + $this->post(route('token.refresh')) ->assertUnauthorized(); } } diff --git a/tests/Feature/Auth/VerifyEmailTest.php b/tests/Feature/Auth/VerifyEmailTest.php index 8b27f90..9de3f8e 100644 --- a/tests/Feature/Auth/VerifyEmailTest.php +++ b/tests/Feature/Auth/VerifyEmailTest.php @@ -30,7 +30,7 @@ public function it_verifies_email(): void $otp = $user->createOneTimePassword(OneTimePasswordScope::VERIFY_EMAIL); - $response = $this->post('/verify-email', [ + $response = $this->post(route('verification.verify'), [ 'email' => $user->email, 'otp' => $otp->otp, ]); @@ -60,7 +60,7 @@ public function it_does_not_verify_email_because_email_is_already_verified(): vo 'email_verified_at' => Date::now(), ]); - $response = $this->post('/verify-email', [ + $response = $this->post(route('verification.verify'), [ 'email' => $user->email, 'otp' => '123456', ]); @@ -78,7 +78,7 @@ public function it_responds_not_found_for_non_existing_otp(): void 'password' => Crypto::encryptString('password'), ]); - $response = $this->post('/verify-email', [ + $response = $this->post(route('verification.verify'), [ 'email' => $user->email, 'otp' => '123456', ]); @@ -99,7 +99,7 @@ public function it_responds_not_found_when_otp_has_different_scope(): void // Create OTP with LOGIN scope instead of VERIFY_EMAIL $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); - $response = $this->post('/verify-email', [ + $response = $this->post(route('verification.verify'), [ 'email' => $user->email, 'otp' => $otp->otp, ]); @@ -130,7 +130,7 @@ public function it_responds_not_found_when_otp_is_already_used(): void $otp->usedAt = Date::now(); $otp->save(); - $response = $this->post('/verify-email', [ + $response = $this->post(route('verification.verify'), [ 'email' => $user->email, 'otp' => $otp->otp, ]); @@ -161,7 +161,7 @@ public function it_responds_not_found_when_otp_is_expired(): void // Advance time by 11 minutes (default expiration is 10 minutes) Date::setTestNow(Date::now()->addMinutes(11)); - $response = $this->post('/verify-email', [ + $response = $this->post(route('verification.verify'), [ 'email' => $user->email, 'otp' => $otp->otp, ]); From 684c72ce180ad8c3b2f6e69657b47db64e79d962 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 25 Mar 2026 17:18:55 +0000 Subject: [PATCH 112/133] feat: remove Guest middleware and update related routes and tests --- app/Http/Middleware/Guest.php | 50 ------------------- composer.lock | 8 +-- routes/api.php | 2 +- tests/Feature/Auth/LoginAuthorizationTest.php | 27 ++++++++++ 4 files changed, 32 insertions(+), 55 deletions(-) delete mode 100644 app/Http/Middleware/Guest.php diff --git a/app/Http/Middleware/Guest.php b/app/Http/Middleware/Guest.php deleted file mode 100644 index 252287d..0000000 --- a/app/Http/Middleware/Guest.php +++ /dev/null @@ -1,50 +0,0 @@ -extractToken($request->getHeader('Authorization')); - - if ($token === null) { - return $next->handleRequest($request); - } - - return $this->unauthorized(); - } - - protected function hasBearerToken(string|null $authorizationHeader): bool - { - return $authorizationHeader !== null - && trim($authorizationHeader) !== '' - && str_starts_with($authorizationHeader, 'Bearer '); - } - - protected function extractToken(string|null $authorizationHeader): string|null - { - if (! $this->hasBearerToken($authorizationHeader)) { - return null; - } - - $parts = explode(' ', $authorizationHeader, 2); - - return isset($parts[1]) ? trim($parts[1]) : null; - } - - protected function unauthorized(): Response - { - return response()->json([ - 'message' => trans('auth.unauthorized'), - ], HttpStatus::UNAUTHORIZED)->send(); - } -} diff --git a/composer.lock b/composer.lock index df720a7..56f0fb1 100644 --- a/composer.lock +++ b/composer.lock @@ -4120,12 +4120,12 @@ "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "4aa5081b1d04621f9e84cd832a62a40c20b90633" + "reference": "a697243e6859a56d4b631587eb3e1d97d20bf925" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/4aa5081b1d04621f9e84cd832a62a40c20b90633", - "reference": "4aa5081b1d04621f9e84cd832a62a40c20b90633", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/a697243e6859a56d4b631587eb3e1d97d20bf925", + "reference": "a697243e6859a56d4b631587eb3e1d97d20bf925", "shasum": "" }, "require": { @@ -4207,7 +4207,7 @@ "issues": "https://github.com/phenixphp/framework/issues", "source": "https://github.com/phenixphp/framework/tree/develop" }, - "time": "2026-03-24T23:34:14+00:00" + "time": "2026-03-25T17:14:49+00:00" }, { "name": "phenixphp/http-cors", diff --git a/routes/api.php b/routes/api.php index 491bc3a..0a0ec3f 100644 --- a/routes/api.php +++ b/routes/api.php @@ -10,8 +10,8 @@ use App\Http\Controllers\Auth\TokenController; use App\Http\Controllers\Auth\VerifyEmailController; use App\Http\Controllers\WelcomeController; -use App\Http\Middleware\Guest; use Phenix\Auth\Middlewares\Authenticated; +use Phenix\Auth\Middlewares\Guest; use Phenix\Cache\RateLimit\Middlewares\RateLimiter; use Phenix\Facades\Route; use Phenix\Routing\Router; diff --git a/tests/Feature/Auth/LoginAuthorizationTest.php b/tests/Feature/Auth/LoginAuthorizationTest.php index 95bee6a..899b43d 100644 --- a/tests/Feature/Auth/LoginAuthorizationTest.php +++ b/tests/Feature/Auth/LoginAuthorizationTest.php @@ -201,4 +201,31 @@ public function it_uses_independent_rate_limit_buckets_for_login_and_login_autho ])->assertOk() ->assertJsonPath('token_type', 'Bearer'); } + + /** @test */ + public function it_allows_login_authorization_to_continue_when_bearer_token_is_invalid(): void + { + Date::setTestNow(Date::now()); + + $user = User::create([ + 'name' => $this->faker()->name(), + 'email' => $this->faker()->freeEmail(), + 'password' => Hash::make('P@ssw0rd12'), + 'email_verified_at' => Date::now(), + ]); + + $otp = $user->createOneTimePassword(OneTimePasswordScope::LOGIN); + + $response = $this->post( + path: route('login.authorize'), + body: [ + 'email' => $user->email, + 'otp' => $otp->otp, + ], + headers: ['Authorization' => 'Bearer invalid-token'] + ); + + $response->assertOk() + ->assertJsonPath('token_type', 'Bearer'); + } } From 9b1ad8df5f45adf3a1e9e14ea9babe458ffbf575 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 25 Mar 2026 18:10:36 +0000 Subject: [PATCH 113/133] chore: update phenixphp/framework version to stable release --- composer.json | 2 +- composer.lock | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index de47b5f..88c551e 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": "^8.2", "ext-pcntl": "*", - "phenixphp/framework": "dev-develop" + "phenixphp/framework": "^0.8.1" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index 56f0fb1..d030c61 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": "20497fa3a14fe489f84dfbe0efd733fa", + "content-hash": "758623e13cd9e5af7f7fd40b62f38532", "packages": [ { "name": "adbario/php-dot-notation", @@ -4116,16 +4116,16 @@ }, { "name": "phenixphp/framework", - "version": "dev-develop", + "version": "0.8.1", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "a697243e6859a56d4b631587eb3e1d97d20bf925" + "reference": "6fabb4f7b6220458acbc20e4c5b8251f1cf3e52c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/a697243e6859a56d4b631587eb3e1d97d20bf925", - "reference": "a697243e6859a56d4b631587eb3e1d97d20bf925", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/6fabb4f7b6220458acbc20e4c5b8251f1cf3e52c", + "reference": "6fabb4f7b6220458acbc20e4c5b8251f1cf3e52c", "shasum": "" }, "require": { @@ -4205,9 +4205,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/develop" + "source": "https://github.com/phenixphp/framework/tree/0.8.1" }, - "time": "2026-03-25T17:14:49+00:00" + "time": "2026-03-25T17:55:15+00:00" }, { "name": "phenixphp/http-cors", @@ -11427,9 +11427,7 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": { - "phenixphp/framework": 20 - }, + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { From 062634fcb7900eb0e4207bc0bcfa319ed7b26ee5 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 25 Mar 2026 20:29:35 +0000 Subject: [PATCH 114/133] feat: update composer.json to include additional extensions and improve analyze script --- composer.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 88c551e..9ae8e54 100644 --- a/composer.json +++ b/composer.json @@ -20,6 +20,8 @@ "require": { "php": "^8.2", "ext-pcntl": "*", + "ext-sockets": "*", + "ext-sqlite3": "*", "phenixphp/framework": "^0.8.1" }, "require-dev": { @@ -51,11 +53,14 @@ "post-root-package-install": [ "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" ], + "post-create-project-cmd": [ + "@php phenix key:generate" + ], "test": "XDEBUG_MODE=off vendor/bin/phpunit", "test:debug": "vendor/bin/phpunit", "test:coverage": "XDEBUG_MODE=coverage vendor/bin/phpunit", "format": "vendor/bin/php-cs-fixer fix", - "analyze": "vendor/bin/phpstan", + "analyze": "vendor/bin/phpstan --memory-limit=1G", "dev": [ "Composer\\Config::disableProcessTimeout", "@php server" From 3241049aa6e13d13f9cd989d4743e1f6d2f310e9 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 25 Mar 2026 21:06:55 +0000 Subject: [PATCH 115/133] style: add phpstan ignore comment for mailable resolution --- app/Models/User.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Models/User.php b/app/Models/User.php index 4fb53ed..fca3401 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -39,6 +39,7 @@ public function sendOneTimePassword(OneTimePasswordScope $scope): void protected function resolveMailable(OneTimePasswordScope $scope, UserOtp $userOtp): Mailable { + /** @phpstan-ignore-next-line */ return match ($scope) { OneTimePasswordScope::VERIFY_EMAIL => new SendEmailVerificationOtp($userOtp), OneTimePasswordScope::LOGIN => new SendLoginOtp($userOtp), From ea4cf8001ef25a2ecc20e30f3f80f259540d4e73 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Thu, 26 Mar 2026 00:16:18 +0000 Subject: [PATCH 116/133] chore: update phenixphp/framework version to ^0.8.2 --- composer.json | 2 +- composer.lock | 28 +++++++++++++++------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index 9ae8e54..6053499 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "ext-pcntl": "*", "ext-sockets": "*", "ext-sqlite3": "*", - "phenixphp/framework": "^0.8.1" + "phenixphp/framework": "^0.8.2" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index d030c61..f5c5bdf 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": "758623e13cd9e5af7f7fd40b62f38532", + "content-hash": "f46b6c2623e79847035c117236469660", "packages": [ { "name": "adbario/php-dot-notation", @@ -2168,16 +2168,16 @@ }, { "name": "cakephp/chronos", - "version": "3.3.3", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/cakephp/chronos.git", - "reference": "960e7ecd5709fc186309b0733a18beecb37fd37e" + "reference": "608bbc32c59f74a0ea3358c20436c8dd94536e7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/chronos/zipball/960e7ecd5709fc186309b0733a18beecb37fd37e", - "reference": "960e7ecd5709fc186309b0733a18beecb37fd37e", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/608bbc32c59f74a0ea3358c20436c8dd94536e7c", + "reference": "608bbc32c59f74a0ea3358c20436c8dd94536e7c", "shasum": "" }, "require": { @@ -2223,7 +2223,7 @@ "issues": "https://github.com/cakephp/chronos/issues", "source": "https://github.com/cakephp/chronos" }, - "time": "2026-03-14T17:03:37+00:00" + "time": "2026-03-25T23:05:15+00:00" }, { "name": "cakephp/core", @@ -4116,16 +4116,16 @@ }, { "name": "phenixphp/framework", - "version": "0.8.1", + "version": "0.8.2", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "6fabb4f7b6220458acbc20e4c5b8251f1cf3e52c" + "reference": "d4b53687660c10696d55d511afd7619e3a111f8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/6fabb4f7b6220458acbc20e4c5b8251f1cf3e52c", - "reference": "6fabb4f7b6220458acbc20e4c5b8251f1cf3e52c", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/d4b53687660c10696d55d511afd7619e3a111f8b", + "reference": "d4b53687660c10696d55d511afd7619e3a111f8b", "shasum": "" }, "require": { @@ -4205,9 +4205,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/0.8.1" + "source": "https://github.com/phenixphp/framework/tree/0.8.2" }, - "time": "2026-03-25T17:55:15+00:00" + "time": "2026-03-25T23:58:17+00:00" }, { "name": "phenixphp/http-cors", @@ -11432,7 +11432,9 @@ "prefer-lowest": false, "platform": { "php": "^8.2", - "ext-pcntl": "*" + "ext-pcntl": "*", + "ext-sockets": "*", + "ext-sqlite3": "*" }, "platform-dev": {}, "plugin-api-version": "2.9.0" From 3d9ce7a697dffe1a8269f80c0edf2e5fbb40e35f Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Thu, 26 Mar 2026 00:33:09 +0000 Subject: [PATCH 117/133] ci: add key generation step before executing tests --- .github/workflows/run-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 659c183..dc6ac52 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -44,6 +44,7 @@ jobs: - name: Execute tests run: | cp .env.example .env + php phenix key:generate vendor/bin/phpunit - name: Prepare paths for SonarQube analysis From 85094ad38c9bbd45f84a97aebc70a58b8fce0e3c Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Thu, 26 Mar 2026 13:44:13 +0000 Subject: [PATCH 118/133] ci: update environment configuration for Redis and MySQL services in CI workflow --- .env.example | 8 ++++++-- .github/workflows/run-tests.yml | 26 +++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index 63f1619..fcf8faa 100644 --- a/.env.example +++ b/.env.example @@ -14,15 +14,19 @@ DB_PASSWORD= LOG_CHANNEL=stream -QUEUE_DRIVER=parallel +CACHE_STORE=redis +RATE_LIMIT_STORE="${CACHE_STORE}" + +QUEUE_DRIVER=redis CORS_ORIGIN= REDIS_HOST=127.0.0.1 REDIS_PORT=6379 +REDIS_USERNAME= REDIS_PASSWORD=null -SESSION_DRIVER=local +SESSION_DRIVER=redis MAIL_MAILER=smtp MAIL_HOST=127.0.0.1 diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index dc6ac52..77bf06c 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -9,6 +9,30 @@ on: jobs: test: runs-on: ubuntu-latest + services: + mysql: + image: mysql:8.0 + env: + MYSQL_DATABASE: phenix_testing + MYSQL_USER: phenix + MYSQL_PASSWORD: secret + MYSQL_ROOT_PASSWORD: secret + ports: + - 3306:3306 + options: >- + --health-cmd="mysqladmin ping -h 127.0.0.1 -uphenix -psecret --silent" + --health-interval=10s + --health-timeout=5s + --health-retries=10 + redis: + image: redis:7-alpine + ports: + - 6379:6379 + options: >- + --health-cmd="redis-cli ping" + --health-interval=10s + --health-timeout=5s + --health-retries=10 steps: - name: Checkout code @@ -20,7 +44,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: 8.2 - extensions: json, mbstring, pcntl, intl, fileinfo + extensions: json, mbstring, pcntl, intl, fileinfo, sockets, mysqli, sqlite3 coverage: xdebug - name: Setup problem matchers From d505cccf5cc5673f74826734f5b2b6d01af401ce Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Thu, 26 Mar 2026 15:35:15 +0000 Subject: [PATCH 119/133] ci: update database username to 'root' and adjust MySQL service configuration in CI workflow --- .env.example | 2 +- .github/workflows/run-tests.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index fcf8faa..3bae0a3 100644 --- a/.env.example +++ b/.env.example @@ -9,7 +9,7 @@ DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=phenix -DB_USERNAME=phenix +DB_USERNAME=root DB_PASSWORD= LOG_CHANNEL=stream diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 77bf06c..77d7b3f 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -16,11 +16,11 @@ jobs: MYSQL_DATABASE: phenix_testing MYSQL_USER: phenix MYSQL_PASSWORD: secret - MYSQL_ROOT_PASSWORD: secret + MYSQL_ALLOW_EMPTY_PASSWORD: "yes" ports: - 3306:3306 options: >- - --health-cmd="mysqladmin ping -h 127.0.0.1 -uphenix -psecret --silent" + --health-cmd="mysqladmin ping -h 127.0.0.1 -uroot --silent" --health-interval=10s --health-timeout=5s --health-retries=10 @@ -68,7 +68,7 @@ jobs: - name: Execute tests run: | cp .env.example .env - php phenix key:generate + php phenix key:generate .env --force vendor/bin/phpunit - name: Prepare paths for SonarQube analysis From a80616cac410cb8ffde243b335f8f07c94f1d26a Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Thu, 26 Mar 2026 16:03:00 +0000 Subject: [PATCH 120/133] ci: update database password and configuration for MySQL service in CI workflow --- .env.example | 2 +- .github/workflows/run-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 3bae0a3..0c299ad 100644 --- a/.env.example +++ b/.env.example @@ -10,7 +10,7 @@ DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=phenix DB_USERNAME=root -DB_PASSWORD= +DB_PASSWORD=secret LOG_CHANNEL=stream diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 77d7b3f..ff7b400 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -13,7 +13,7 @@ jobs: mysql: image: mysql:8.0 env: - MYSQL_DATABASE: phenix_testing + MYSQL_DATABASE: phenix MYSQL_USER: phenix MYSQL_PASSWORD: secret MYSQL_ALLOW_EMPTY_PASSWORD: "yes" From b9306ab25cf7eca09b301795567f1af37e3c8eef Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Thu, 26 Mar 2026 16:08:57 +0000 Subject: [PATCH 121/133] ci: update environment file handling for PHPStan and PHPUnit execution --- .github/workflows/run-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index ff7b400..b653ee8 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -62,13 +62,13 @@ jobs: - name: Analyze code statically with PHPStan run: | - cp .env.example .env + cp .env.example .env.testing vendor/bin/phpstan --xdebug - name: Execute tests run: | - cp .env.example .env - php phenix key:generate .env --force + cp .env.example .env.testing + php phenix key:generate --force vendor/bin/phpunit - name: Prepare paths for SonarQube analysis From 508bc9b0bdd7a97c2319d832ce176c7e8576f045 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Thu, 26 Mar 2026 16:32:17 +0000 Subject: [PATCH 122/133] ci: update MySQL service configuration and test execution command in CI workflow --- .github/workflows/run-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index b653ee8..d6fef92 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -16,11 +16,11 @@ jobs: MYSQL_DATABASE: phenix MYSQL_USER: phenix MYSQL_PASSWORD: secret - MYSQL_ALLOW_EMPTY_PASSWORD: "yes" + MYSQL_ROOT_PASSWORD: secret ports: - 3306:3306 options: >- - --health-cmd="mysqladmin ping -h 127.0.0.1 -uroot --silent" + --health-cmd="mysqladmin ping -h 127.0.0.1 -uroot -psecret --silent" --health-interval=10s --health-timeout=5s --health-retries=10 @@ -68,7 +68,7 @@ jobs: - name: Execute tests run: | cp .env.example .env.testing - php phenix key:generate --force + php phenix key:generate .env.testing --force vendor/bin/phpunit - name: Prepare paths for SonarQube analysis From 4223aadcc40f4f68bf8488e2a5695167b75b0c1e Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Tue, 31 Mar 2026 18:56:24 +0000 Subject: [PATCH 123/133] feat: update phenixphp/framework version to ^0.8.3 in composer.json --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 6053499..08e3009 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "ext-pcntl": "*", "ext-sockets": "*", "ext-sqlite3": "*", - "phenixphp/framework": "^0.8.2" + "phenixphp/framework": "^0.8.3" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index f5c5bdf..656f72f 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": "f46b6c2623e79847035c117236469660", + "content-hash": "102d0a66003d31e813f956d74b4c3ce9", "packages": [ { "name": "adbario/php-dot-notation", @@ -4116,16 +4116,16 @@ }, { "name": "phenixphp/framework", - "version": "0.8.2", + "version": "0.8.3", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "d4b53687660c10696d55d511afd7619e3a111f8b" + "reference": "922a9222f32f46c439af449eff15b0dcf0a0ba0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/d4b53687660c10696d55d511afd7619e3a111f8b", - "reference": "d4b53687660c10696d55d511afd7619e3a111f8b", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/922a9222f32f46c439af449eff15b0dcf0a0ba0a", + "reference": "922a9222f32f46c439af449eff15b0dcf0a0ba0a", "shasum": "" }, "require": { @@ -4205,9 +4205,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/0.8.2" + "source": "https://github.com/phenixphp/framework/tree/0.8.3" }, - "time": "2026-03-25T23:58:17+00:00" + "time": "2026-03-31T17:34:03+00:00" }, { "name": "phenixphp/http-cors", From 7fcbd5aeecdd8780b33f0d12bc9559c240963e7a Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 1 Apr 2026 04:10:03 +0000 Subject: [PATCH 124/133] feat: update phenixphp/framework version to ^0.8.4 in composer.json --- composer.json | 2 +- composer.lock | 204 +++++++++++++++++++++++++------------------------- 2 files changed, 103 insertions(+), 103 deletions(-) diff --git a/composer.json b/composer.json index 08e3009..4fac1fa 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "ext-pcntl": "*", "ext-sockets": "*", "ext-sqlite3": "*", - "phenixphp/framework": "^0.8.3" + "phenixphp/framework": "^0.8.4" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index 656f72f..fec80cc 100644 --- a/composer.lock +++ b/composer.lock @@ -4116,16 +4116,16 @@ }, { "name": "phenixphp/framework", - "version": "0.8.3", + "version": "0.8.4", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "922a9222f32f46c439af449eff15b0dcf0a0ba0a" + "reference": "9eb5921ec28967164094f3ccd8f1ab466e57f1f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/922a9222f32f46c439af449eff15b0dcf0a0ba0a", - "reference": "922a9222f32f46c439af449eff15b0dcf0a0ba0a", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/9eb5921ec28967164094f3ccd8f1ab466e57f1f1", + "reference": "9eb5921ec28967164094f3ccd8f1ab466e57f1f1", "shasum": "" }, "require": { @@ -4205,9 +4205,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/0.8.3" + "source": "https://github.com/phenixphp/framework/tree/0.8.4" }, - "time": "2026-03-31T17:34:03+00:00" + "time": "2026-03-31T21:57:13+00:00" }, { "name": "phenixphp/http-cors", @@ -5306,16 +5306,16 @@ }, { "name": "symfony/clock", - "version": "v7.4.0", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "9169f24776edde469914c1e7a1442a50f7a4e110" + "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110", - "reference": "9169f24776edde469914c1e7a1442a50f7a4e110", + "url": "https://api.github.com/repos/symfony/clock/zipball/674fa3b98e21531dd040e613479f5f6fa8f32111", + "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111", "shasum": "" }, "require": { @@ -5360,7 +5360,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.4.0" + "source": "https://github.com/symfony/clock/tree/v7.4.8" }, "funding": [ { @@ -5380,20 +5380,20 @@ "type": "tidelift" } ], - "time": "2025-11-12T15:39:26+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/config", - "version": "v7.4.7", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5" + "reference": "2d19dde43fa2ff720b9a40763ace7226594f503b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/6c17162555bfb58957a55bb0e43e00035b6ae3d5", - "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5", + "url": "https://api.github.com/repos/symfony/config/zipball/2d19dde43fa2ff720b9a40763ace7226594f503b", + "reference": "2d19dde43fa2ff720b9a40763ace7226594f503b", "shasum": "" }, "require": { @@ -5439,7 +5439,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.4.7" + "source": "https://github.com/symfony/config/tree/v7.4.8" }, "funding": [ { @@ -5459,20 +5459,20 @@ "type": "tidelift" } ], - "time": "2026-03-06T10:41:14+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/console", - "version": "v6.4.35", + "version": "v6.4.36", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "49257c96304c508223815ee965c251e7c79e614e" + "reference": "9f481cfb580db8bcecc9b2d4c63f3e13df022ad5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/49257c96304c508223815ee965c251e7c79e614e", - "reference": "49257c96304c508223815ee965c251e7c79e614e", + "url": "https://api.github.com/repos/symfony/console/zipball/9f481cfb580db8bcecc9b2d4c63f3e13df022ad5", + "reference": "9f481cfb580db8bcecc9b2d4c63f3e13df022ad5", "shasum": "" }, "require": { @@ -5537,7 +5537,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.35" + "source": "https://github.com/symfony/console/tree/v6.4.36" }, "funding": [ { @@ -5557,7 +5557,7 @@ "type": "tidelift" } ], - "time": "2026-03-06T13:31:08+00:00" + "time": "2026-03-27T15:30:51+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5628,16 +5628,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "dc2c0eba1af673e736bb851d747d266108aea746" + "reference": "f57b899fa736fd71121168ef268f23c206083f0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dc2c0eba1af673e736bb851d747d266108aea746", - "reference": "dc2c0eba1af673e736bb851d747d266108aea746", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f57b899fa736fd71121168ef268f23c206083f0a", + "reference": "f57b899fa736fd71121168ef268f23c206083f0a", "shasum": "" }, "require": { @@ -5689,7 +5689,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.4" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.8" }, "funding": [ { @@ -5709,7 +5709,7 @@ "type": "tidelift" } ], - "time": "2026-01-05T11:45:34+00:00" + "time": "2026-03-30T13:54:39+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5789,16 +5789,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.4.6", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e" + "reference": "58b9790d12f9670b7f53a1c1738febd3108970a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e", - "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/58b9790d12f9670b7f53a1c1738febd3108970a5", + "reference": "58b9790d12f9670b7f53a1c1738febd3108970a5", "shasum": "" }, "require": { @@ -5835,7 +5835,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.4.6" + "source": "https://github.com/symfony/filesystem/tree/v7.4.8" }, "funding": [ { @@ -5855,20 +5855,20 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/http-client", - "version": "v7.4.7", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "1010624285470eb60e88ed10035102c75b4ea6af" + "reference": "01933e626c3de76bea1e22641e205e78f6a34342" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/1010624285470eb60e88ed10035102c75b4ea6af", - "reference": "1010624285470eb60e88ed10035102c75b4ea6af", + "url": "https://api.github.com/repos/symfony/http-client/zipball/01933e626c3de76bea1e22641e205e78f6a34342", + "reference": "01933e626c3de76bea1e22641e205e78f6a34342", "shasum": "" }, "require": { @@ -5936,7 +5936,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.4.7" + "source": "https://github.com/symfony/http-client/tree/v7.4.8" }, "funding": [ { @@ -5956,7 +5956,7 @@ "type": "tidelift" } ], - "time": "2026-03-05T11:16:58+00:00" + "time": "2026-03-30T12:55:43+00:00" }, { "name": "symfony/http-client-contracts", @@ -6038,16 +6038,16 @@ }, { "name": "symfony/mailer", - "version": "v7.4.6", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9" + "reference": "f6ea532250b476bfc1b56699b388a1bdbf168f62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/b02726f39a20bc65e30364f5c750c4ddbf1f58e9", - "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9", + "url": "https://api.github.com/repos/symfony/mailer/zipball/f6ea532250b476bfc1b56699b388a1bdbf168f62", + "reference": "f6ea532250b476bfc1b56699b388a1bdbf168f62", "shasum": "" }, "require": { @@ -6098,7 +6098,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.4.6" + "source": "https://github.com/symfony/mailer/tree/v7.4.8" }, "funding": [ { @@ -6118,20 +6118,20 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/mime", - "version": "v7.4.7", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1" + "reference": "6df02f99998081032da3407a8d6c4e1dcb5d4379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/da5ab4fde3f6c88ab06e96185b9922f48b677cd1", - "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1", + "url": "https://api.github.com/repos/symfony/mime/zipball/6df02f99998081032da3407a8d6c4e1dcb5d4379", + "reference": "6df02f99998081032da3407a8d6c4e1dcb5d4379", "shasum": "" }, "require": { @@ -6187,7 +6187,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.4.7" + "source": "https://github.com/symfony/mime/tree/v7.4.8" }, "funding": [ { @@ -6207,7 +6207,7 @@ "type": "tidelift" } ], - "time": "2026-03-05T15:24:09+00:00" + "time": "2026-03-30T14:11:46+00:00" }, { "name": "symfony/polyfill-ctype", @@ -7041,16 +7041,16 @@ }, { "name": "symfony/string", - "version": "v7.4.6", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "9f209231affa85aa930a5e46e6eb03381424b30b" + "reference": "114ac57257d75df748eda23dd003878080b8e688" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b", - "reference": "9f209231affa85aa930a5e46e6eb03381424b30b", + "url": "https://api.github.com/repos/symfony/string/zipball/114ac57257d75df748eda23dd003878080b8e688", + "reference": "114ac57257d75df748eda23dd003878080b8e688", "shasum": "" }, "require": { @@ -7108,7 +7108,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.4.6" + "source": "https://github.com/symfony/string/tree/v7.4.8" }, "funding": [ { @@ -7128,20 +7128,20 @@ "type": "tidelift" } ], - "time": "2026-02-09T09:33:46+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/translation", - "version": "v7.4.6", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "1888cf064399868af3784b9e043240f1d89d25ce" + "reference": "33600f8489485425bfcddd0d983391038d3422e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/1888cf064399868af3784b9e043240f1d89d25ce", - "reference": "1888cf064399868af3784b9e043240f1d89d25ce", + "url": "https://api.github.com/repos/symfony/translation/zipball/33600f8489485425bfcddd0d983391038d3422e7", + "reference": "33600f8489485425bfcddd0d983391038d3422e7", "shasum": "" }, "require": { @@ -7208,7 +7208,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.4.6" + "source": "https://github.com/symfony/translation/tree/v7.4.8" }, "funding": [ { @@ -7228,7 +7228,7 @@ "type": "tidelift" } ], - "time": "2026-02-17T07:53:42+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/translation-contracts", @@ -7314,16 +7314,16 @@ }, { "name": "symfony/uid", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36" + "reference": "6883ebdf7bf6a12b37519dbc0df62b0222401b56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/7719ce8aba76be93dfe249192f1fbfa52c588e36", - "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36", + "url": "https://api.github.com/repos/symfony/uid/zipball/6883ebdf7bf6a12b37519dbc0df62b0222401b56", + "reference": "6883ebdf7bf6a12b37519dbc0df62b0222401b56", "shasum": "" }, "require": { @@ -7368,7 +7368,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.4.4" + "source": "https://github.com/symfony/uid/tree/v7.4.8" }, "funding": [ { @@ -7388,20 +7388,20 @@ "type": "tidelift" } ], - "time": "2026-01-03T23:30:35+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.4.6", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291" + "reference": "9510c3966f749a1d1ff0059e1eabef6cc621e7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/045321c440ac18347b136c63d2e9bf28a2dc0291", - "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9510c3966f749a1d1ff0059e1eabef6cc621e7fd", + "reference": "9510c3966f749a1d1ff0059e1eabef6cc621e7fd", "shasum": "" }, "require": { @@ -7455,7 +7455,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.4.6" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.8" }, "funding": [ { @@ -7475,7 +7475,7 @@ "type": "tidelift" } ], - "time": "2026-02-15T10:53:20+00:00" + "time": "2026-03-30T13:44:50+00:00" }, { "name": "vlucas/phpdotenv", @@ -10946,16 +10946,16 @@ }, { "name": "symfony/finder", - "version": "v7.4.6", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" + "reference": "e0be088d22278583a82da281886e8c3592fbf149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", - "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "url": "https://api.github.com/repos/symfony/finder/zipball/e0be088d22278583a82da281886e8c3592fbf149", + "reference": "e0be088d22278583a82da281886e8c3592fbf149", "shasum": "" }, "require": { @@ -10990,7 +10990,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.6" + "source": "https://github.com/symfony/finder/tree/v7.4.8" }, "funding": [ { @@ -11010,20 +11010,20 @@ "type": "tidelift" } ], - "time": "2026-01-29T09:40:50+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.4.0", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "b38026df55197f9e39a44f3215788edf83187b80" + "reference": "2888fcdc4dc2fd5f7c7397be78631e8af12e02b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", - "reference": "b38026df55197f9e39a44f3215788edf83187b80", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/2888fcdc4dc2fd5f7c7397be78631e8af12e02b4", + "reference": "2888fcdc4dc2fd5f7c7397be78631e8af12e02b4", "shasum": "" }, "require": { @@ -11061,7 +11061,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" + "source": "https://github.com/symfony/options-resolver/tree/v7.4.8" }, "funding": [ { @@ -11081,7 +11081,7 @@ "type": "tidelift" } ], - "time": "2025-11-12T15:39:26+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/polyfill-php81", @@ -11245,16 +11245,16 @@ }, { "name": "symfony/process", - "version": "v7.4.5", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "608476f4604102976d687c483ac63a79ba18cc97" + "reference": "60f19cd3badc8de688421e21e4305eba50f8089a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", - "reference": "608476f4604102976d687c483ac63a79ba18cc97", + "url": "https://api.github.com/repos/symfony/process/zipball/60f19cd3badc8de688421e21e4305eba50f8089a", + "reference": "60f19cd3badc8de688421e21e4305eba50f8089a", "shasum": "" }, "require": { @@ -11286,7 +11286,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.4.5" + "source": "https://github.com/symfony/process/tree/v7.4.8" }, "funding": [ { @@ -11306,20 +11306,20 @@ "type": "tidelift" } ], - "time": "2026-01-26T15:07:59+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/stopwatch", - "version": "v7.4.0", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "8a24af0a2e8a872fb745047180649b8418303084" + "reference": "70a852d72fec4d51efb1f48dcd968efcaf5ccb89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/8a24af0a2e8a872fb745047180649b8418303084", - "reference": "8a24af0a2e8a872fb745047180649b8418303084", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/70a852d72fec4d51efb1f48dcd968efcaf5ccb89", + "reference": "70a852d72fec4d51efb1f48dcd968efcaf5ccb89", "shasum": "" }, "require": { @@ -11352,7 +11352,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.4.0" + "source": "https://github.com/symfony/stopwatch/tree/v7.4.8" }, "funding": [ { @@ -11372,7 +11372,7 @@ "type": "tidelift" } ], - "time": "2025-08-04T07:05:15+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "theseer/tokenizer", From 4525077f655978ef9d4751afee790009e15b36d3 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 1 Apr 2026 07:20:03 -0500 Subject: [PATCH 125/133] feat: change LOG_CHANNEL from stream to file in .env.example --- .env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 0c299ad..39051f9 100644 --- a/.env.example +++ b/.env.example @@ -12,7 +12,7 @@ DB_DATABASE=phenix DB_USERNAME=root DB_PASSWORD=secret -LOG_CHANNEL=stream +LOG_CHANNEL=file CACHE_STORE=redis RATE_LIMIT_STORE="${CACHE_STORE}" From cd843f35b3168b8d48819877349868b6df9da4bd Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 1 Apr 2026 19:40:55 +0000 Subject: [PATCH 126/133] feat: update phenixphp/framework version to ^0.8.5 in composer.json --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 4fac1fa..5b785ab 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "ext-pcntl": "*", "ext-sockets": "*", "ext-sqlite3": "*", - "phenixphp/framework": "^0.8.4" + "phenixphp/framework": "^0.8.5" }, "require-dev": { "amphp/phpunit-util": "^v3.0.0", diff --git a/composer.lock b/composer.lock index fec80cc..da24d80 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": "102d0a66003d31e813f956d74b4c3ce9", + "content-hash": "d9718ea6bd56cb81771975fdd73b5836", "packages": [ { "name": "adbario/php-dot-notation", @@ -4116,16 +4116,16 @@ }, { "name": "phenixphp/framework", - "version": "0.8.4", + "version": "0.8.5", "source": { "type": "git", "url": "https://github.com/phenixphp/framework.git", - "reference": "9eb5921ec28967164094f3ccd8f1ab466e57f1f1" + "reference": "64b4d155ddc119f1291e65d33b01b2b6ff235d96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phenixphp/framework/zipball/9eb5921ec28967164094f3ccd8f1ab466e57f1f1", - "reference": "9eb5921ec28967164094f3ccd8f1ab466e57f1f1", + "url": "https://api.github.com/repos/phenixphp/framework/zipball/64b4d155ddc119f1291e65d33b01b2b6ff235d96", + "reference": "64b4d155ddc119f1291e65d33b01b2b6ff235d96", "shasum": "" }, "require": { @@ -4205,9 +4205,9 @@ "description": "Phenix framework based on Amphp", "support": { "issues": "https://github.com/phenixphp/framework/issues", - "source": "https://github.com/phenixphp/framework/tree/0.8.4" + "source": "https://github.com/phenixphp/framework/tree/0.8.5" }, - "time": "2026-03-31T21:57:13+00:00" + "time": "2026-04-01T15:17:50+00:00" }, { "name": "phenixphp/http-cors", From 957946ed223bf6751181a882f2eb7230366c24b9 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 1 Apr 2026 14:52:43 -0500 Subject: [PATCH 127/133] ci: update PHPStan command and change SonarQube action in CI workflow --- .github/workflows/run-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index d6fef92..7912f33 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -63,7 +63,7 @@ jobs: - name: Analyze code statically with PHPStan run: | cp .env.example .env.testing - vendor/bin/phpstan --xdebug + XDEBUG_MODE=off vendor/bin/phpstan --xdebug - name: Execute tests run: | @@ -77,7 +77,7 @@ jobs: sed -i "s|$GITHUB_WORKSPACE|/github/workspace|g" build/report.junit.xml - name: Run SonarQube analysis - uses: sonarsource/sonarcloud-github-action@master + uses: sonarsource/sonarqube-scan-action@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 62d20132c091a8f6b644b53ac067621486191485 Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Wed, 1 Apr 2026 16:20:51 -0500 Subject: [PATCH 128/133] refactor: enhance OTP handling in login and reset password processes for reduce return sentences --- app/Http/Controllers/Auth/LoginController.php | 37 ++++++++++--------- .../Auth/ResetPasswordController.php | 24 ++++++------ 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index e0ce71e..9b6f228 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -43,30 +43,31 @@ public function login(Request $request): Response } $user = User::query()->whereEqual('email', $request->body('email'))->first(); + $response = response()->json([ + 'message' => trans('auth.otp.login.sent'), + ]); if (! Hash::verify($user->password, (string) $request->body('password'))) { - return response()->json([ + $response = response()->json([ 'message' => trans('auth.login.invalid_credentials'), ], HttpStatus::UNAUTHORIZED); + } else { + $otpCount = UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::LOGIN->value) + ->whereGreaterThanOrEqual('created_at', Date::now()->subHour()->toDateTimeString()) + ->count(); + + if ($otpCount >= 5) { + $response = response()->json([ + 'message' => trans('auth.otp.limit_exceeded'), + ], HttpStatus::TOO_MANY_REQUESTS); + } else { + $user->sendOneTimePassword(OneTimePasswordScope::LOGIN); + } } - $otpCount = UserOtp::query() - ->whereEqual('user_id', $user->id) - ->whereEqual('scope', OneTimePasswordScope::LOGIN->value) - ->whereGreaterThanOrEqual('created_at', Date::now()->subHour()->toDateTimeString()) - ->count(); - - if ($otpCount >= 5) { - return response()->json([ - 'message' => trans('auth.otp.limit_exceeded'), - ], HttpStatus::TOO_MANY_REQUESTS); - } - - $user->sendOneTimePassword(OneTimePasswordScope::LOGIN); - - return response()->json([ - 'message' => trans('auth.otp.login.sent'), - ]); + return $response; } public function authorize(Request $request): Response diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index 983de2b..2dcff8b 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -47,21 +47,19 @@ public function store(Request $request): Response ->whereNotNull('email_verified_at') ->first(); - if ($user === null) { - return response()->json([ - 'message' => trans('auth.otp.invalid'), - ], HttpStatus::NOT_FOUND); - } + $otp = null; - $otp = UserOtp::query() - ->whereEqual('user_id', $user->id) - ->whereEqual('scope', OneTimePasswordScope::RESET_PASSWORD->value) - ->whereEqual('code', hash('sha256', (string) $request->body('otp'))) - ->whereNull('used_at') - ->whereGreaterThanOrEqual('expires_at', Date::now()->toDateTimeString()) - ->first(); + if ($user !== null) { + $otp = UserOtp::query() + ->whereEqual('user_id', $user->id) + ->whereEqual('scope', OneTimePasswordScope::RESET_PASSWORD->value) + ->whereEqual('code', hash('sha256', (string) $request->body('otp'))) + ->whereNull('used_at') + ->whereGreaterThanOrEqual('expires_at', Date::now()->toDateTimeString()) + ->first(); + } - if (! $otp) { + if ($user === null || $otp === null) { return response()->json([ 'message' => trans('auth.otp.invalid'), ], HttpStatus::NOT_FOUND); From 5b48b9c054e4a94d95791811922f94bf904c9c75 Mon Sep 17 00:00:00 2001 From: leonardo2006jaimes-ux Date: Fri, 3 Apr 2026 10:40:33 -0500 Subject: [PATCH 129/133] refacttor: rename mailables --- app/Mail/{SendLoginOtp.php => LoginOtp.php} | 2 +- ...SendResetPasswordOtp.php => ResetPasswordOtp.php} | 2 +- ...dEmailVerificationOtp.php => VerificationOtp.php} | 2 +- app/Models/User.php | 12 ++++++------ tests/Feature/Auth/ForgotPasswordTest.php | 10 +++++----- tests/Feature/Auth/LoginTest.php | 12 ++++++------ tests/Feature/Auth/ResendOtpTest.php | 8 ++++---- 7 files changed, 24 insertions(+), 24 deletions(-) rename app/Mail/{SendLoginOtp.php => LoginOtp.php} (93%) rename app/Mail/{SendResetPasswordOtp.php => ResetPasswordOtp.php} (92%) rename app/Mail/{SendEmailVerificationOtp.php => VerificationOtp.php} (92%) diff --git a/app/Mail/SendLoginOtp.php b/app/Mail/LoginOtp.php similarity index 93% rename from app/Mail/SendLoginOtp.php rename to app/Mail/LoginOtp.php index 863a1a1..dbafade 100644 --- a/app/Mail/SendLoginOtp.php +++ b/app/Mail/LoginOtp.php @@ -7,7 +7,7 @@ use App\Models\UserOtp; use Phenix\Mail\Mailable; -class SendLoginOtp extends Mailable +class LoginOtp extends Mailable { public function __construct( protected UserOtp $userOtp, diff --git a/app/Mail/SendResetPasswordOtp.php b/app/Mail/ResetPasswordOtp.php similarity index 92% rename from app/Mail/SendResetPasswordOtp.php rename to app/Mail/ResetPasswordOtp.php index 1bb54e8..0c651a3 100644 --- a/app/Mail/SendResetPasswordOtp.php +++ b/app/Mail/ResetPasswordOtp.php @@ -7,7 +7,7 @@ use App\Models\UserOtp; use Phenix\Mail\Mailable; -class SendResetPasswordOtp extends Mailable +class ResetPasswordOtp extends Mailable { public function __construct( protected UserOtp $userOtp, diff --git a/app/Mail/SendEmailVerificationOtp.php b/app/Mail/VerificationOtp.php similarity index 92% rename from app/Mail/SendEmailVerificationOtp.php rename to app/Mail/VerificationOtp.php index 818e516..45cee54 100644 --- a/app/Mail/SendEmailVerificationOtp.php +++ b/app/Mail/VerificationOtp.php @@ -7,7 +7,7 @@ use App\Models\UserOtp; use Phenix\Mail\Mailable; -class SendEmailVerificationOtp extends Mailable +class VerificationOtp extends Mailable { public function __construct( protected UserOtp $userOtp, diff --git a/app/Models/User.php b/app/Models/User.php index fca3401..00a47f3 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -5,9 +5,9 @@ namespace App\Models; use App\Constants\OneTimePasswordScope; -use App\Mail\SendEmailVerificationOtp; -use App\Mail\SendLoginOtp; -use App\Mail\SendResetPasswordOtp; +use App\Mail\VerificationOtp; +use App\Mail\LoginOtp; +use App\Mail\ResetPasswordOtp; use Phenix\Auth\User as Authenticable; use Phenix\Database\Models\Attributes\DateTime; use Phenix\Facades\Mail; @@ -41,9 +41,9 @@ protected function resolveMailable(OneTimePasswordScope $scope, UserOtp $userOtp { /** @phpstan-ignore-next-line */ return match ($scope) { - OneTimePasswordScope::VERIFY_EMAIL => new SendEmailVerificationOtp($userOtp), - OneTimePasswordScope::LOGIN => new SendLoginOtp($userOtp), - OneTimePasswordScope::RESET_PASSWORD => new SendResetPasswordOtp($userOtp), + OneTimePasswordScope::VERIFY_EMAIL => new VerificationOtp($userOtp), + OneTimePasswordScope::LOGIN => new LoginOtp($userOtp), + OneTimePasswordScope::RESET_PASSWORD => new ResetPasswordOtp($userOtp), }; } } diff --git a/tests/Feature/Auth/ForgotPasswordTest.php b/tests/Feature/Auth/ForgotPasswordTest.php index d1377e0..b295ed8 100644 --- a/tests/Feature/Auth/ForgotPasswordTest.php +++ b/tests/Feature/Auth/ForgotPasswordTest.php @@ -5,7 +5,7 @@ namespace Tests\Feature\Auth; use App\Constants\OneTimePasswordScope; -use App\Mail\SendResetPasswordOtp; +use App\Mail\ResetPasswordOtp; use App\Models\User; use App\Models\UserOtp; use Phenix\Facades\Hash; @@ -43,7 +43,7 @@ public function it_sends_a_reset_password_otp_for_verified_users(): void 'scope' => OneTimePasswordScope::RESET_PASSWORD->value, ]); - Mail::expect(SendResetPasswordOtp::class)->toBeSentTimes(1); + Mail::expect(ResetPasswordOtp::class)->toBeSentTimes(1); } /** @test */ @@ -63,7 +63,7 @@ public function it_returns_a_generic_response_for_non_existing_emails(): void ->count() ); - Mail::expect(SendResetPasswordOtp::class)->toNotBeSent(); + Mail::expect(ResetPasswordOtp::class)->toNotBeSent(); } /** @test */ @@ -90,7 +90,7 @@ public function it_returns_a_generic_response_for_unverified_users(): void ->count() ); - Mail::expect(SendResetPasswordOtp::class)->toNotBeSent(); + Mail::expect(ResetPasswordOtp::class)->toNotBeSent(); } /** @test */ @@ -123,6 +123,6 @@ public function it_returns_a_generic_response_when_the_reset_otp_limit_is_exceed ->count() ); - Mail::expect(SendResetPasswordOtp::class)->toNotBeSent(); + Mail::expect(ResetPasswordOtp::class)->toNotBeSent(); } } diff --git a/tests/Feature/Auth/LoginTest.php b/tests/Feature/Auth/LoginTest.php index 369f683..2c23bcb 100644 --- a/tests/Feature/Auth/LoginTest.php +++ b/tests/Feature/Auth/LoginTest.php @@ -5,7 +5,7 @@ namespace Tests\Feature\Auth; use App\Constants\OneTimePasswordScope; -use App\Mail\SendLoginOtp; +use App\Mail\LoginOtp; use App\Models\User; use App\Models\UserOtp; use Phenix\Facades\Cache; @@ -47,7 +47,7 @@ public function it_sends_a_login_otp_for_valid_verified_credentials(): void 'scope' => OneTimePasswordScope::LOGIN->value, ]); - Mail::expect(SendLoginOtp::class)->toBeSentTimes(1); + Mail::expect(LoginOtp::class)->toBeSentTimes(1); } /** @test */ @@ -78,7 +78,7 @@ public function it_rejects_wrong_password(): void ->count() ); - Mail::expect(SendLoginOtp::class)->toNotBeSent(); + Mail::expect(LoginOtp::class)->toNotBeSent(); } /** @test */ @@ -100,7 +100,7 @@ public function it_rejects_unverified_email(): void $response->assertUnprocessableEntity() ->assertJsonPath('errors.email.0', trans('validation.exists', ['field' => 'email'])); - Mail::expect(SendLoginOtp::class)->toNotBeSent(); + Mail::expect(LoginOtp::class)->toNotBeSent(); } /** @test */ @@ -136,7 +136,7 @@ public function it_responds_too_many_requests_when_login_otp_limit_is_exceeded() ->count() ); - Mail::expect(SendLoginOtp::class)->toNotBeSent(); + Mail::expect(LoginOtp::class)->toNotBeSent(); } /** @test */ @@ -165,6 +165,6 @@ public function it_rate_limits_login_attempts_per_client(): void ])->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) ->assertJsonPath('message', trans('auth.rate_limit.exceeded')); - Mail::expect(SendLoginOtp::class)->toNotBeSent(); + Mail::expect(LoginOtp::class)->toNotBeSent(); } } diff --git a/tests/Feature/Auth/ResendOtpTest.php b/tests/Feature/Auth/ResendOtpTest.php index 3eab626..c030f2d 100644 --- a/tests/Feature/Auth/ResendOtpTest.php +++ b/tests/Feature/Auth/ResendOtpTest.php @@ -5,7 +5,7 @@ namespace Tests\Feature\Auth; use App\Constants\OneTimePasswordScope; -use App\Mail\SendEmailVerificationOtp; +use App\Mail\VerificationOtp; use App\Models\User; use App\Models\UserOtp; use Phenix\Facades\Crypto; @@ -57,7 +57,7 @@ public function it_resend_otp_for_unverified_email(): void ->count() ); - Mail::expect(SendEmailVerificationOtp::class)->toBeSentTimes(1); + Mail::expect(VerificationOtp::class)->toBeSentTimes(1); } /** @test */ @@ -79,7 +79,7 @@ public function it_does_not_resend_otp_when_email_is_already_verified(): void $response->assertUnprocessableEntity() ->assertJsonPath('errors.email.0', trans('validation.exists', ['field' => 'email'])); - Mail::expect(SendEmailVerificationOtp::class)->toNotBeSent(); + Mail::expect(VerificationOtp::class)->toNotBeSent(); } /** @test */ @@ -105,6 +105,6 @@ public function it_responds_too_many_requests_when_exceed_otp_limit(): void $response->assertStatusCode(HttpStatus::TOO_MANY_REQUESTS) ->assertJsonPath('message', trans('auth.otp.limit_exceeded')); - Mail::expect(SendEmailVerificationOtp::class)->toNotBeSent(); + Mail::expect(VerificationOtp::class)->toNotBeSent(); } } From 4f876fa749c5746af7203d24f31bde4a33a495d5 Mon Sep 17 00:00:00 2001 From: leonardo2006jaimes-ux Date: Fri, 3 Apr 2026 10:40:44 -0500 Subject: [PATCH 130/133] refacttor: rename mailables --- tests/Feature/Auth/RegisterTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php index c20a876..41513e4 100644 --- a/tests/Feature/Auth/RegisterTest.php +++ b/tests/Feature/Auth/RegisterTest.php @@ -5,7 +5,7 @@ namespace Tests\Feature\Auth; use App\Constants\OneTimePasswordScope; -use App\Mail\SendEmailVerificationOtp; +use App\Mail\VerificationOtp; use Phenix\Facades\Mail; use Phenix\Testing\Concerns\RefreshDatabase; use Phenix\Testing\Concerns\WithFaker; @@ -47,6 +47,6 @@ public function it_registers_a_user(): void 'scope' => OneTimePasswordScope::VERIFY_EMAIL->value, ]); - Mail::expect(SendEmailVerificationOtp::class)->toBeSent(); + Mail::expect(VerificationOtp::class)->toBeSent(); } } From 35d6418deff7bd0b9c917d489432faf40bc2a868 Mon Sep 17 00:00:00 2001 From: leonardo2006jaimes-ux Date: Fri, 3 Apr 2026 10:42:06 -0500 Subject: [PATCH 131/133] refactor: remove docblock --- app/Http/Controllers/Auth/RegisterController.php | 1 - app/Http/Controllers/Auth/ResendVerificationOtpController.php | 1 - app/Http/Controllers/Auth/ResetPasswordController.php | 1 - app/Http/Controllers/Auth/TokenController.php | 3 +-- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 32e257d..eaba13a 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -69,7 +69,6 @@ public function cancel(Request $request): Response ], HttpStatus::UNPROCESSABLE_ENTITY); } - /** @var User $user */ $user = User::query() ->whereEqual('email', $request->body('email')) ->whereNull('email_verified_at') diff --git a/app/Http/Controllers/Auth/ResendVerificationOtpController.php b/app/Http/Controllers/Auth/ResendVerificationOtpController.php index 184d0d9..c10d3e8 100644 --- a/app/Http/Controllers/Auth/ResendVerificationOtpController.php +++ b/app/Http/Controllers/Auth/ResendVerificationOtpController.php @@ -38,7 +38,6 @@ public function resend(Request $request): Response ], HttpStatus::UNPROCESSABLE_ENTITY); } - /** @var User $user */ $user = User::query()->whereEqual('email', $request->body('email'))->first(); $otpCount = UserOtp::query() diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index 2dcff8b..54da489 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -41,7 +41,6 @@ public function store(Request $request): Response ], HttpStatus::UNPROCESSABLE_ENTITY); } - /** @var User|null $user */ $user = User::query() ->whereEqual('email', $request->body('email')) ->whereNotNull('email_verified_at') diff --git a/app/Http/Controllers/Auth/TokenController.php b/app/Http/Controllers/Auth/TokenController.php index f61b6e7..2a1e819 100644 --- a/app/Http/Controllers/Auth/TokenController.php +++ b/app/Http/Controllers/Auth/TokenController.php @@ -44,8 +44,7 @@ public function destroy(Request $request): Response { /** @var User $user */ $user = $request->user(); - - /** @var PersonalAccessToken|null $token */ + $token = PersonalAccessToken::query() ->whereEqual('id', $request->route('id')) ->whereEqual('tokenable_type', User::class) From 018925eb837d053cf7d75ee984bda5bfbb088518 Mon Sep 17 00:00:00 2001 From: leonardo2006jaimes-ux Date: Fri, 3 Apr 2026 10:46:05 -0500 Subject: [PATCH 132/133] refactor: split routes --- routes/api.php | 59 +-------------------------------------------- routes/auth.php | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 58 deletions(-) create mode 100644 routes/auth.php diff --git a/routes/api.php b/routes/api.php index 0a0ec3f..97d5c3a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,66 +2,9 @@ declare(strict_types=1); -use App\Http\Controllers\Auth\ForgotPasswordController; -use App\Http\Controllers\Auth\LoginController; -use App\Http\Controllers\Auth\RegisterController; -use App\Http\Controllers\Auth\ResendVerificationOtpController; -use App\Http\Controllers\Auth\ResetPasswordController; -use App\Http\Controllers\Auth\TokenController; -use App\Http\Controllers\Auth\VerifyEmailController; use App\Http\Controllers\WelcomeController; -use Phenix\Auth\Middlewares\Authenticated; -use Phenix\Auth\Middlewares\Guest; -use Phenix\Cache\RateLimit\Middlewares\RateLimiter; use Phenix\Facades\Route; -use Phenix\Routing\Router; Route::get('/', [WelcomeController::class, 'index']); -Route::middleware(Guest::class) - ->group(function (Router $router): void { - $router->post('register', [RegisterController::class, 'store']) - ->name('register'); - - $router->post('verify-email', [VerifyEmailController::class, 'verify']) - ->name('verification.verify') - ->middleware(RateLimiter::perMinute(6, 'auth:verify-email')); - - $router->post('resend-verification-otp', [ResendVerificationOtpController::class, 'resend']) - ->name('verification.resend') - ->middleware(RateLimiter::perMinute(2, 'auth:resend-verification-otp')); - - $router->post('forgot-password', [ForgotPasswordController::class, 'store']) - ->name('password.email') - ->middleware(RateLimiter::perMinute(2, 'auth:forgot-password')); - - $router->post('reset-password', [ResetPasswordController::class, 'store']) - ->name('password.store') - ->middleware(RateLimiter::perMinute(5, 'auth:reset-password')); - - $router->post('login', [LoginController::class, 'login']) - ->name('login') - ->middleware(RateLimiter::perMinute(5, 'auth:login')); - - $router->post('login/authorize', [LoginController::class, 'authorize']) - ->name('login.authorize') - ->middleware(RateLimiter::perMinute(5, 'auth:login-authorize')); - - $router->post('register/cancel', [RegisterController::class, 'cancel']) - ->name('register.cancel'); - }); - -Route::middleware(Authenticated::class) - ->group(function (Router $router): void { - $router->post('logout', [LoginController::class, 'logout']) - ->name('logout'); - - $router->get('tokens', [TokenController::class, 'index']) - ->name('tokens.index'); - - $router->post('token/refresh', [TokenController::class, 'refresh']) - ->name('token.refresh'); - - $router->delete('tokens/{id}', [TokenController::class, 'destroy']) - ->name('tokens.destroy'); - }); +require __DIR__ . '/auth.php'; diff --git a/routes/auth.php b/routes/auth.php new file mode 100644 index 0000000..1010d7f --- /dev/null +++ b/routes/auth.php @@ -0,0 +1,64 @@ +group(function (Router $router): void { + $router->post('register', [RegisterController::class, 'store']) + ->name('register'); + + $router->post('verify-email', [VerifyEmailController::class, 'verify']) + ->name('verification.verify') + ->middleware(RateLimiter::perMinute(6, 'auth:verify-email')); + + $router->post('resend-verification-otp', [ResendVerificationOtpController::class, 'resend']) + ->name('verification.resend') + ->middleware(RateLimiter::perMinute(2, 'auth:resend-verification-otp')); + + $router->post('forgot-password', [ForgotPasswordController::class, 'store']) + ->name('password.email') + ->middleware(RateLimiter::perMinute(2, 'auth:forgot-password')); + + $router->post('reset-password', [ResetPasswordController::class, 'store']) + ->name('password.store') + ->middleware(RateLimiter::perMinute(5, 'auth:reset-password')); + + $router->post('login', [LoginController::class, 'login']) + ->name('login') + ->middleware(RateLimiter::perMinute(5, 'auth:login')); + + $router->post('login/authorize', [LoginController::class, 'authorize']) + ->name('login.authorize') + ->middleware(RateLimiter::perMinute(5, 'auth:login-authorize')); + + $router->post('register/cancel', [RegisterController::class, 'cancel']) + ->name('register.cancel'); + }); + +Route::middleware(Authenticated::class) + ->group(function (Router $router): void { + $router->post('logout', [LoginController::class, 'logout']) + ->name('logout'); + + $router->get('tokens', [TokenController::class, 'index']) + ->name('tokens.index'); + + $router->post('token/refresh', [TokenController::class, 'refresh']) + ->name('token.refresh'); + + $router->delete('tokens/{id}', [TokenController::class, 'destroy']) + ->name('tokens.destroy'); + }); From 5c6e7b9d60e3e418c4617843468da68e36eb0f9e Mon Sep 17 00:00:00 2001 From: Omar Barbosa Date: Sat, 4 Apr 2026 15:58:19 -0500 Subject: [PATCH 133/133] style: php cs --- app/Http/Controllers/Auth/TokenController.php | 2 +- app/Models/User.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Auth/TokenController.php b/app/Http/Controllers/Auth/TokenController.php index 2a1e819..cfd9c16 100644 --- a/app/Http/Controllers/Auth/TokenController.php +++ b/app/Http/Controllers/Auth/TokenController.php @@ -44,7 +44,7 @@ public function destroy(Request $request): Response { /** @var User $user */ $user = $request->user(); - + $token = PersonalAccessToken::query() ->whereEqual('id', $request->route('id')) ->whereEqual('tokenable_type', User::class) diff --git a/app/Models/User.php b/app/Models/User.php index 00a47f3..a0b5712 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -5,9 +5,9 @@ namespace App\Models; use App\Constants\OneTimePasswordScope; -use App\Mail\VerificationOtp; use App\Mail\LoginOtp; use App\Mail\ResetPasswordOtp; +use App\Mail\VerificationOtp; use Phenix\Auth\User as Authenticable; use Phenix\Database\Models\Attributes\DateTime; use Phenix\Facades\Mail;