diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
index a545c1b3..943c0957 100644
--- a/.github/workflows/php.yml
+++ b/.github/workflows/php.yml
@@ -17,6 +17,7 @@ jobs:
- "8.1"
- "8.2"
- "8.3"
+ - "8.4"
dependencies:
- "lowest"
- "highest"
diff --git a/composer.json b/composer.json
index 0baa4051..e5c9c52f 100644
--- a/composer.json
+++ b/composer.json
@@ -8,7 +8,7 @@
],
"bin": ["bin/svc"],
"require": {
- "php": "~8.1.0||~8.2.0||~8.3.0",
+ "php": "~8.1.0||~8.2.0||~8.3.0||~8.4.0",
"ext-json": "*",
"laminas/laminas-stdlib": "^3.18",
"nikic/php-parser": "^4.15",
diff --git a/composer.lock b/composer.lock
index 1bce5fca..d97f6e3f 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": "33ac8c8057e26605bdd59f9d6162b506",
+ "content-hash": "fef25ea90a323b619f8947668fa74553",
"packages": [
{
"name": "hassankhan/config",
@@ -70,30 +70,30 @@
},
{
"name": "laminas/laminas-stdlib",
- "version": "3.19.0",
+ "version": "3.20.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-stdlib.git",
- "reference": "6a192dd0882b514e45506f533b833b623b78fff3"
+ "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/6a192dd0882b514e45506f533b833b623b78fff3",
- "reference": "6a192dd0882b514e45506f533b833b623b78fff3",
+ "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/8974a1213be42c3e2f70b2c27b17f910291ab2f4",
+ "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4",
"shasum": ""
},
"require": {
- "php": "~8.1.0 || ~8.2.0 || ~8.3.0"
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
},
"conflict": {
"zendframework/zend-stdlib": "*"
},
"require-dev": {
- "laminas/laminas-coding-standard": "^2.5",
- "phpbench/phpbench": "^1.2.15",
- "phpunit/phpunit": "^10.5.8",
- "psalm/plugin-phpunit": "^0.18.4",
- "vimeo/psalm": "^5.20.0"
+ "laminas/laminas-coding-standard": "^3.0",
+ "phpbench/phpbench": "^1.3.1",
+ "phpunit/phpunit": "^10.5.38",
+ "psalm/plugin-phpunit": "^0.19.0",
+ "vimeo/psalm": "^5.26.1"
},
"type": "library",
"autoload": {
@@ -125,20 +125,20 @@
"type": "community_bridge"
}
],
- "time": "2024-01-19T12:39:49+00:00"
+ "time": "2024-10-29T13:46:07+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v4.19.1",
+ "version": "v4.19.4",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b"
+ "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b",
- "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2",
+ "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2",
"shasum": ""
},
"require": {
@@ -147,7 +147,7 @@
},
"require-dev": {
"ircmaxell/php-yacc": "^0.0.7",
- "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
+ "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
},
"bin": [
"bin/php-parse"
@@ -179,9 +179,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4"
},
- "time": "2024-03-17T08:10:35+00:00"
+ "time": "2024-09-29T15:01:53+00:00"
},
{
"name": "phpstan/phpdoc-parser",
@@ -287,27 +287,27 @@
},
{
"name": "sabre/uri",
- "version": "2.3.3",
+ "version": "2.3.4",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/uri.git",
- "reference": "7e0e7dfd0b7e14346a27eabd66e843a6e7f1812b"
+ "reference": "b76524c22de90d80ca73143680a8e77b1266c291"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sabre-io/uri/zipball/7e0e7dfd0b7e14346a27eabd66e843a6e7f1812b",
- "reference": "7e0e7dfd0b7e14346a27eabd66e843a6e7f1812b",
+ "url": "https://api.github.com/repos/sabre-io/uri/zipball/b76524c22de90d80ca73143680a8e77b1266c291",
+ "reference": "b76524c22de90d80ca73143680a8e77b1266c291",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.17",
- "phpstan/extension-installer": "^1.3",
- "phpstan/phpstan": "^1.10",
- "phpstan/phpstan-phpunit": "^1.3",
- "phpstan/phpstan-strict-rules": "^1.5",
+ "friendsofphp/php-cs-fixer": "^3.63",
+ "phpstan/extension-installer": "^1.4",
+ "phpstan/phpstan": "^1.12",
+ "phpstan/phpstan-phpunit": "^1.4",
+ "phpstan/phpstan-strict-rules": "^1.6",
"phpunit/phpunit": "^9.6"
},
"type": "library",
@@ -343,20 +343,20 @@
"issues": "https://github.com/sabre-io/uri/issues",
"source": "https://github.com/fruux/sabre-uri"
},
- "time": "2023-06-09T06:54:04+00:00"
+ "time": "2024-08-27T12:18:16+00:00"
},
{
"name": "sabre/xml",
- "version": "2.2.6",
+ "version": "2.2.11",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/xml.git",
- "reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b"
+ "reference": "01a7927842abf3e10df3d9c2d9b0cc9d813a3fcc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sabre-io/xml/zipball/9cde7cdab1e50893cc83b037b40cd47bfde42a2b",
- "reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b",
+ "url": "https://api.github.com/repos/sabre-io/xml/zipball/01a7927842abf3e10df3d9c2d9b0cc9d813a3fcc",
+ "reference": "01a7927842abf3e10df3d9c2d9b0cc9d813a3fcc",
"shasum": ""
},
"require": {
@@ -368,9 +368,9 @@
"sabre/uri": ">=1.0,<3.0.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "~2.17.1",
+ "friendsofphp/php-cs-fixer": "~2.17.1||3.63.2",
"phpstan/phpstan": "^0.12",
- "phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6"
},
"type": "library",
"autoload": {
@@ -412,20 +412,20 @@
"issues": "https://github.com/sabre-io/xml/issues",
"source": "https://github.com/fruux/sabre-xml"
},
- "time": "2023-06-28T12:56:05+00:00"
+ "time": "2024-09-06T07:37:46+00:00"
},
{
"name": "symfony/console",
- "version": "v6.4.3",
+ "version": "v6.4.15",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "2aaf83b4de5b9d43b93e4aec6f2f8b676f7c567e"
+ "reference": "f1fc6f47283e27336e7cebb9e8946c8de7bff9bd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/2aaf83b4de5b9d43b93e4aec6f2f8b676f7c567e",
- "reference": "2aaf83b4de5b9d43b93e4aec6f2f8b676f7c567e",
+ "url": "https://api.github.com/repos/symfony/console/zipball/f1fc6f47283e27336e7cebb9e8946c8de7bff9bd",
+ "reference": "f1fc6f47283e27336e7cebb9e8946c8de7bff9bd",
"shasum": ""
},
"require": {
@@ -490,7 +490,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v6.4.3"
+ "source": "https://github.com/symfony/console/tree/v6.4.15"
},
"funding": [
{
@@ -506,20 +506,20 @@
"type": "tidelift"
}
],
- "time": "2024-01-23T14:51:35+00:00"
+ "time": "2024-11-06T14:19:14+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.4.0",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
- "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"shasum": ""
},
"require": {
@@ -528,7 +528,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "3.4-dev"
+ "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -557,7 +557,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -573,24 +573,24 @@
"type": "tidelift"
}
],
- "time": "2023-05-23T14:45:45+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.29.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
- "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
@@ -636,7 +636,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
},
"funding": [
{
@@ -652,24 +652,24 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.29.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f"
+ "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f",
- "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
+ "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
@@ -714,7 +714,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0"
},
"funding": [
{
@@ -730,24 +730,24 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.29.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
+ "reference": "3833d7255cc303546435cb650316bff708a1c75c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
- "reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
+ "reference": "3833d7255cc303546435cb650316bff708a1c75c",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
@@ -795,7 +795,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
},
"funding": [
{
@@ -811,24 +811,24 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.29.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
+ "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
- "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
+ "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"provide": {
"ext-mbstring": "*"
@@ -875,7 +875,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
},
"funding": [
{
@@ -891,25 +891,26 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v3.4.1",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0"
+ "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0",
- "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
+ "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
"shasum": ""
},
"require": {
"php": ">=8.1",
- "psr/container": "^1.1|^2.0"
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
@@ -917,7 +918,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "3.4-dev"
+ "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -957,7 +958,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.4.1"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -973,24 +974,24 @@
"type": "tidelift"
}
],
- "time": "2023-12-26T14:02:43+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/string",
- "version": "v6.4.3",
+ "version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "7a14736fb179876575464e4658fce0c304e8c15b"
+ "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/7a14736fb179876575464e4658fce0c304e8c15b",
- "reference": "7a14736fb179876575464e4658fce0c304e8c15b",
+ "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82",
+ "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82",
"shasum": ""
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-grapheme": "~1.0",
"symfony/polyfill-intl-normalizer": "~1.0",
@@ -1000,11 +1001,12 @@
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/error-handler": "^5.4|^6.0|^7.0",
- "symfony/http-client": "^5.4|^6.0|^7.0",
- "symfony/intl": "^6.2|^7.0",
+ "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": "^5.4|^6.0|^7.0"
+ "symfony/var-exporter": "^6.4|^7.0"
},
"type": "library",
"autoload": {
@@ -1043,7 +1045,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v6.4.3"
+ "source": "https://github.com/symfony/string/tree/v7.2.0"
},
"funding": [
{
@@ -1059,20 +1061,20 @@
"type": "tidelift"
}
],
- "time": "2024-01-25T09:26:29+00:00"
+ "time": "2024-11-13T13:31:26+00:00"
},
{
"name": "symfony/yaml",
- "version": "v6.4.3",
+ "version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "d75715985f0f94f978e3a8fa42533e10db921b90"
+ "reference": "e99b4e94d124b29ee4cf3140e1b537d2dad8cec9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/d75715985f0f94f978e3a8fa42533e10db921b90",
- "reference": "d75715985f0f94f978e3a8fa42533e10db921b90",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/e99b4e94d124b29ee4cf3140e1b537d2dad8cec9",
+ "reference": "e99b4e94d124b29ee4cf3140e1b537d2dad8cec9",
"shasum": ""
},
"require": {
@@ -1115,7 +1117,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/yaml/tree/v6.4.3"
+ "source": "https://github.com/symfony/yaml/tree/v6.4.13"
},
"funding": [
{
@@ -1131,7 +1133,7 @@
"type": "tidelift"
}
],
- "time": "2024-01-23T14:51:35+00:00"
+ "time": "2024-09-25T14:18:03+00:00"
},
{
"name": "tomzx/finder",
@@ -1329,16 +1331,16 @@
"packages-dev": [
{
"name": "myclabs/deep-copy",
- "version": "1.11.1",
+ "version": "1.12.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
+ "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
- "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
+ "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"shasum": ""
},
"require": {
@@ -1346,11 +1348,12 @@
},
"conflict": {
"doctrine/collections": "<1.6.8",
- "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+ "doctrine/common": "<2.13.3 || >=3 <3.2.2"
},
"require-dev": {
"doctrine/collections": "^1.6.8",
"doctrine/common": "^2.13.3 || ^3.2.2",
+ "phpspec/prophecy": "^1.10",
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
},
"type": "library",
@@ -1376,7 +1379,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
},
"funding": [
{
@@ -1384,7 +1387,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-08T13:26:56+00:00"
+ "time": "2024-11-08T17:47:46+00:00"
},
{
"name": "phar-io/manifest",
@@ -1506,32 +1509,32 @@
},
{
"name": "phpunit/php-code-coverage",
- "version": "10.1.14",
+ "version": "10.1.16",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b"
+ "reference": "7e308268858ed6baedc8704a304727d20bc07c77"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
- "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77",
+ "reference": "7e308268858ed6baedc8704a304727d20bc07c77",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
- "nikic/php-parser": "^4.18 || ^5.0",
+ "nikic/php-parser": "^4.19.1 || ^5.1.0",
"php": ">=8.1",
- "phpunit/php-file-iterator": "^4.0",
- "phpunit/php-text-template": "^3.0",
- "sebastian/code-unit-reverse-lookup": "^3.0",
- "sebastian/complexity": "^3.0",
- "sebastian/environment": "^6.0",
- "sebastian/lines-of-code": "^2.0",
- "sebastian/version": "^4.0",
- "theseer/tokenizer": "^1.2.0"
+ "phpunit/php-file-iterator": "^4.1.0",
+ "phpunit/php-text-template": "^3.0.1",
+ "sebastian/code-unit-reverse-lookup": "^3.0.0",
+ "sebastian/complexity": "^3.2.0",
+ "sebastian/environment": "^6.1.0",
+ "sebastian/lines-of-code": "^2.0.2",
+ "sebastian/version": "^4.0.1",
+ "theseer/tokenizer": "^1.2.3"
},
"require-dev": {
"phpunit/phpunit": "^10.1"
@@ -1543,7 +1546,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "10.1-dev"
+ "dev-main": "10.1.x-dev"
}
},
"autoload": {
@@ -1572,7 +1575,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16"
},
"funding": [
{
@@ -1580,7 +1583,7 @@
"type": "github"
}
],
- "time": "2024-03-12T15:33:41+00:00"
+ "time": "2024-08-22T04:31:57+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -1827,16 +1830,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "10.5.19",
+ "version": "10.5.38",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "c726f0de022368f6ed103e452a765d3304a996a4"
+ "reference": "a86773b9e887a67bc53efa9da9ad6e3f2498c132"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c726f0de022368f6ed103e452a765d3304a996a4",
- "reference": "c726f0de022368f6ed103e452a765d3304a996a4",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a86773b9e887a67bc53efa9da9ad6e3f2498c132",
+ "reference": "a86773b9e887a67bc53efa9da9ad6e3f2498c132",
"shasum": ""
},
"require": {
@@ -1846,26 +1849,26 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.10.1",
- "phar-io/manifest": "^2.0.3",
- "phar-io/version": "^3.0.2",
+ "myclabs/deep-copy": "^1.12.0",
+ "phar-io/manifest": "^2.0.4",
+ "phar-io/version": "^3.2.1",
"php": ">=8.1",
- "phpunit/php-code-coverage": "^10.1.5",
- "phpunit/php-file-iterator": "^4.0",
- "phpunit/php-invoker": "^4.0",
- "phpunit/php-text-template": "^3.0",
- "phpunit/php-timer": "^6.0",
- "sebastian/cli-parser": "^2.0",
- "sebastian/code-unit": "^2.0",
- "sebastian/comparator": "^5.0",
- "sebastian/diff": "^5.0",
- "sebastian/environment": "^6.0",
- "sebastian/exporter": "^5.1",
- "sebastian/global-state": "^6.0.1",
- "sebastian/object-enumerator": "^5.0",
- "sebastian/recursion-context": "^5.0",
- "sebastian/type": "^4.0",
- "sebastian/version": "^4.0"
+ "phpunit/php-code-coverage": "^10.1.16",
+ "phpunit/php-file-iterator": "^4.1.0",
+ "phpunit/php-invoker": "^4.0.0",
+ "phpunit/php-text-template": "^3.0.1",
+ "phpunit/php-timer": "^6.0.0",
+ "sebastian/cli-parser": "^2.0.1",
+ "sebastian/code-unit": "^2.0.0",
+ "sebastian/comparator": "^5.0.3",
+ "sebastian/diff": "^5.1.1",
+ "sebastian/environment": "^6.1.0",
+ "sebastian/exporter": "^5.1.2",
+ "sebastian/global-state": "^6.0.2",
+ "sebastian/object-enumerator": "^5.0.0",
+ "sebastian/recursion-context": "^5.0.0",
+ "sebastian/type": "^4.0.0",
+ "sebastian/version": "^4.0.1"
},
"suggest": {
"ext-soap": "To be able to generate mocks based on WSDL files"
@@ -1908,7 +1911,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.19"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.38"
},
"funding": [
{
@@ -1924,7 +1927,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-17T14:06:18+00:00"
+ "time": "2024-10-28T13:06:21+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -2096,16 +2099,16 @@
},
{
"name": "sebastian/comparator",
- "version": "5.0.1",
+ "version": "5.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "2db5010a484d53ebf536087a70b4a5423c102372"
+ "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372",
- "reference": "2db5010a484d53ebf536087a70b4a5423c102372",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
+ "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
"shasum": ""
},
"require": {
@@ -2116,7 +2119,7 @@
"sebastian/exporter": "^5.0"
},
"require-dev": {
- "phpunit/phpunit": "^10.3"
+ "phpunit/phpunit": "^10.5"
},
"type": "library",
"extra": {
@@ -2161,7 +2164,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
- "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1"
+ "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3"
},
"funding": [
{
@@ -2169,7 +2172,7 @@
"type": "github"
}
],
- "time": "2023-08-14T13:18:12+00:00"
+ "time": "2024-10-18T14:56:07+00:00"
},
{
"name": "sebastian/complexity",
@@ -2965,15 +2968,15 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": "~8.1.0||~8.2.0||~8.3.0",
+ "php": "~8.1.0||~8.2.0||~8.3.0||~8.4.0",
"ext-json": "*"
},
"platform-dev": {
"ext-dom": "*"
},
- "plugin-api-version": "2.2.0"
+ "plugin-api-version": "2.6.0"
}
diff --git a/dev/tests/Unit/Console/Command/CompareSourceCommandApiClassesTest.php b/dev/tests/Unit/Console/Command/CompareSourceCommandApiClassesTest.php
index 82d4ed6c..32dadfe9 100644
--- a/dev/tests/Unit/Console/Command/CompareSourceCommandApiClassesTest.php
+++ b/dev/tests/Unit/Console/Command/CompareSourceCommandApiClassesTest.php
@@ -59,10 +59,10 @@ public static function changesDataProvider()
$pathToFixtures . '/new-method/source-code-before',
$pathToFixtures . '/new-method/source-code-after',
[
- 'Class (PATCH)',
+ 'Class (MINOR)',
'Test\Vcs\TestClass::testMethod | [public] Method has been added. | V015'
],
- 'Patch change is detected.'
+ 'Minor change is detected.'
],
'api-class-removed-class' => [
$pathToFixtures . '/removed-class/source-code-before',
diff --git a/dev/tests/Unit/bootstrap.php b/dev/tests/Unit/bootstrap.php
index 0481b696..e5c95dd5 100644
--- a/dev/tests/Unit/bootstrap.php
+++ b/dev/tests/Unit/bootstrap.php
@@ -37,7 +37,6 @@ function ($errNo, $errStr, $errFile, $errLine) {
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
- E_STRICT => 'Strict',
E_RECOVERABLE_ERROR => 'Recoverable Error',
E_DEPRECATED => 'Deprecated',
E_USER_DEPRECATED => 'User Deprecated',
diff --git a/src/Analyzer/SystemXml/Analyzer.php b/src/Analyzer/SystemXml/Analyzer.php
index 5fe050a3..d1b2206c 100644
--- a/src/Analyzer/SystemXml/Analyzer.php
+++ b/src/Analyzer/SystemXml/Analyzer.php
@@ -25,6 +25,8 @@
use Magento\SemanticVersionChecker\Registry\XmlRegistry;
use PHPSemVerChecker\Registry\Registry;
use PHPSemVerChecker\Report\Report;
+use Magento\SemanticVersionChecker\Operation\SystemXml\DuplicateFieldAdded;
+use RecursiveDirectoryIterator;
/**
* Analyzes system.xml files:
@@ -92,14 +94,152 @@ public function analyze($registryBefore, $registryAfter)
$beforeFile = $registryBefore->mapping[XmlRegistry::NODES_KEY][$moduleName];
$this->reportRemovedNodes($beforeFile, $removedNodes);
}
+
if ($addedNodes) {
$afterFile = $registryAfter->mapping[XmlRegistry::NODES_KEY][$moduleName];
- $this->reportAddedNodes($afterFile, $addedNodes);
+ if (strpos($afterFile, '_files') !== false) {
+ $this->reportAddedNodes($afterFile, $addedNodes);
+ } else {
+ $baseDir = $this->getBaseDir($afterFile);
+ foreach ($addedNodes as $nodeId => $node) {
+ $newNodeData = $this->getNodeData($node);
+ $nodePath = $newNodeData['path'];
+
+ // Extract section, group, and fieldId with error handling
+ $extractedData = $this->extractSectionGroupField($nodePath);
+ if ($extractedData === null) {
+ // Skip the node if its path is invalid
+ continue;
+ }
+
+ // Extract section, group, and fieldId
+ list($sectionId, $groupId, $fieldId) = $extractedData;
+
+ // Call function to check if this field is duplicated in other system.xml files
+ $isDuplicated = $this->isDuplicatedFieldInXml(
+ $baseDir,
+ $sectionId,
+ $groupId,
+ $fieldId,
+ $afterFile
+ );
+
+ foreach ($isDuplicated as $isDuplicatedItem) {
+ if ($isDuplicatedItem['status'] === 'duplicate') {
+ $this->reportDuplicateNodes($afterFile, [$nodeId => $node]);
+ } else {
+ $this->reportAddedNodes($afterFile, [$nodeId => $node]);
+ }
+ }
+ }
+ }
}
}
return $this->report;
}
+ /**
+ * Get Magento Base directory from the path
+ *
+ * @param string $filePath
+ * @return string|null
+ */
+ private function getBaseDir(string $filePath): ?string
+ {
+ $currentDir = dirname($filePath);
+ while ($currentDir !== '/' && $currentDir !== false) {
+ // Check if current directory contains files unique to Magento root
+ if (file_exists($currentDir . '/SECURITY.md')) {
+ return $currentDir; // Found the Magento base directory
+ }
+ $currentDir = dirname($currentDir);
+ }
+ return null;
+ }
+
+ /**
+ * Search for system.xml files in both app/code and vendor directories, excluding the provided file.
+ *
+ * @param string $magentoBaseDir The base directory of Magento.
+ * @param string|null $excludeFile The file to exclude from the search.
+ * @return array An array of paths to system.xml files, excluding the specified file.
+ */
+ private function getSystemXmlFiles(string $magentoBaseDir, ?string $excludeFile = null): array
+ {
+ $systemXmlFiles = [];
+ $directoryToSearch = [
+ $magentoBaseDir . '/app/code'
+ ];
+
+ // Check if 'vendor' directory exists, and only add it if it does
+ if (is_dir($magentoBaseDir . '/vendor')) {
+ $directoriesToSearch[] = $magentoBaseDir . '/vendor';
+ }
+ foreach ($directoryToSearch as $directory) {
+ $iterator = new \RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
+ foreach ($iterator as $file) {
+ if ($file->getfileName() === 'system.xml') {
+ $filePath = $file->getRealPath();
+ if ($filePath !== $excludeFile) {
+ $systemXmlFiles[] = $file->getRealPath();
+ }
+ }
+ }
+ }
+ return $systemXmlFiles;
+ }
+
+ /**
+ * Method to extract section, group and field from the Node
+ *
+ * @param string $nodePath
+ * @return array|null
+ */
+ private function extractSectionGroupField(string $nodePath): ?array
+ {
+ $parts = explode('/', $nodePath);
+
+ if (count($parts) < 3) {
+ // Invalid path if there are fewer than 3 parts
+ return null;
+ }
+
+ $sectionId = $parts[0];
+ $groupId = $parts[1];
+ $fieldId = $parts[2];
+
+ return [$sectionId, $groupId, $fieldId];
+ }
+
+ /**
+ * Method to get Node Data using reflection class
+ *
+ * @param object|string $node
+ * @return array
+ * @throws \ReflectionException
+ */
+ private function getNodeData(object|string $node): array
+ {
+ $data = [];
+
+ // Use reflection to get accessible properties
+ $reflection = new \ReflectionClass($node);
+ foreach ($reflection->getMethods() as $method) {
+ // Skip 'getId' and 'getParent' methods for comparison
+ if ($method->getName() === 'getId' || $method->getName() === 'getParent') {
+ continue;
+ }
+
+ // Dynamically call the getter methods
+ if (strpos($method->getName(), 'get') === 0) {
+ $propertyName = lcfirst(str_replace('get', '', $method->getName()));
+ $data[$propertyName] = $method->invoke($node);
+ }
+ }
+
+ return $data;
+ }
+
/**
* Extracts the node from $registry as an associative array.
*
@@ -164,13 +304,32 @@ private function reportAddedNodes(string $file, array $nodes)
}
}
+ /**
+ * Creates reports for $nodes considering that they have been duplicated.
+ *
+ * @param string $file
+ * @param NodeInterface[] $nodes
+ * @return void
+ */
+ private function reportDuplicateNodes(string $file, array $nodes): void
+ {
+ foreach ($nodes as $node) {
+ switch (true) {
+ case $node instanceof Field:
+ $this->report->add('system', new DuplicateFieldAdded($file, $node->getPath()));
+ break;
+ }
+ }
+ }
+
/**
* Creates reports for $modules considering that system.xml has been removed from them.
*
* @param array $modules
* @param XmlRegistry $registryBefore
+ * @return void
*/
- private function reportRemovedFiles(array $modules, XmlRegistry $registryBefore)
+ private function reportRemovedFiles(array $modules, XmlRegistry $registryBefore): void
{
foreach ($modules as $module) {
$beforeFile = $registryBefore->mapping[XmlRegistry::NODES_KEY][$module];
@@ -183,8 +342,9 @@ private function reportRemovedFiles(array $modules, XmlRegistry $registryBefore)
*
* @param string $file
* @param NodeInterface[] $nodes
+ * @return void
*/
- private function reportRemovedNodes(string $file, array $nodes)
+ private function reportRemovedNodes(string $file, array $nodes): void
{
foreach ($nodes as $node) {
switch (true) {
@@ -202,4 +362,56 @@ private function reportRemovedNodes(string $file, array $nodes)
}
}
}
+
+ /**
+ * @param string|null $baseDir
+ * @param string $sectionId
+ * @param string $groupId
+ * @param string|null $fieldId
+ * @param string $afterFile
+ * @return array
+ */
+ private function isDuplicatedFieldInXml(
+ ?string $baseDir,
+ string $sectionId,
+ string $groupId,
+ ?string $fieldId,
+ string $afterFile
+ ): array {
+ $hasDuplicate = false;
+
+ $result = [
+ 'status' => 'minor',
+ 'field' => $fieldId
+ ];
+
+ if ($baseDir) {
+ $systemXmlFiles = $this->getSystemXmlFiles($baseDir, $afterFile);
+
+ foreach ($systemXmlFiles as $systemXmlFile) {
+ $xmlContent = file_get_contents($systemXmlFile);
+ try {
+ $xml = new \SimpleXMLElement($xmlContent);
+ } catch (\Exception $e) {
+ continue; // Skip this file if there's a parsing error
+ }
+ // Find nodes with the given field ID
+ // XPath to search for within a specific section and group
+ $fields = $xml->xpath("//section[@id='$sectionId']/group[@id='$groupId']/field[@id='$fieldId']");
+ if (!empty($fields)) {
+ $hasDuplicate = true; // Set the duplicate flag to true if a match is found
+ break; // Since we found a duplicate, we don't need to check further for this field
+ }
+ }
+ if ($hasDuplicate) {
+ return [
+ [
+ 'status' => 'duplicate',
+ 'field' => $fieldId
+ ]
+ ];
+ }
+ }
+ return [$result];
+ }
}
diff --git a/src/Operation/SystemXml/DuplicateFieldAdded.php b/src/Operation/SystemXml/DuplicateFieldAdded.php
new file mode 100644
index 00000000..8424574e
--- /dev/null
+++ b/src/Operation/SystemXml/DuplicateFieldAdded.php
@@ -0,0 +1,34 @@
+field node is added.
+ */
+class DuplicateFieldAdded extends AbstractOperation
+{
+ /**
+ * @var string
+ */
+ protected $code = 'M302';
+
+ /**
+ * @var int
+ */
+ protected $level = Level::PATCH;
+
+ /**
+ * @var string
+ */
+ protected $reason = 'A field-node was duplicated';
+}
diff --git a/src/ReportBuilder.php b/src/ReportBuilder.php
index d9e391af..e39d8682 100644
--- a/src/ReportBuilder.php
+++ b/src/ReportBuilder.php
@@ -126,7 +126,7 @@ protected function makeVersionReport()
// Customize severity level of some @api changes
LevelMapping::setOverrides(
[
- 'V015' => Level::PATCH, // Add public method
+ 'V015' => Level::MINOR, // Add public method
'V016' => Level::PATCH, // Add protected method
'V019' => Level::MINOR, // Add public property
'V020' => Level::MINOR, // Add protected property