diff --git a/composer.lock b/composer.lock index e6540e66..67b4e975 100644 --- a/composer.lock +++ b/composer.lock @@ -227,16 +227,16 @@ }, { "name": "symfony/config", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "d0a82d965296083fe463d655a3644cbe49cbaa80" + "reference": "50e0e1314a3b2609d32b6a5a0d0fb5342494c4ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/d0a82d965296083fe463d655a3644cbe49cbaa80", - "reference": "d0a82d965296083fe463d655a3644cbe49cbaa80", + "url": "https://api.github.com/repos/symfony/config/zipball/50e0e1314a3b2609d32b6a5a0d0fb5342494c4ab", + "reference": "50e0e1314a3b2609d32b6a5a0d0fb5342494c4ab", "shasum": "" }, "require": { @@ -282,10 +282,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Config Component", + "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/v5.2.1" + "source": "https://github.com/symfony/config/tree/v5.2.2" }, "funding": [ { @@ -301,20 +301,20 @@ "type": "tidelift" } ], - "time": "2020-12-09T18:54:12+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/console", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "47c02526c532fb381374dab26df05e7313978976" + "reference": "d62ec79478b55036f65e2602e282822b8eaaff0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/47c02526c532fb381374dab26df05e7313978976", - "reference": "47c02526c532fb381374dab26df05e7313978976", + "url": "https://api.github.com/repos/symfony/console/zipball/d62ec79478b55036f65e2602e282822b8eaaff0a", + "reference": "d62ec79478b55036f65e2602e282822b8eaaff0a", "shasum": "" }, "require": { @@ -373,7 +373,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Console Component", + "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "keywords": [ "cli", @@ -382,7 +382,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.2.1" + "source": "https://github.com/symfony/console/tree/v5.2.2" }, "funding": [ { @@ -398,20 +398,20 @@ "type": "tidelift" } ], - "time": "2020-12-18T08:03:05+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "7f8a9e9eff0581a33e20f6c5d41096fe22832d25" + "reference": "62f72187be689540385dce6c68a5d4c16f034139" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7f8a9e9eff0581a33e20f6c5d41096fe22832d25", - "reference": "7f8a9e9eff0581a33e20f6c5d41096fe22832d25", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/62f72187be689540385dce6c68a5d4c16f034139", + "reference": "62f72187be689540385dce6c68a5d4c16f034139", "shasum": "" }, "require": { @@ -466,10 +466,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DependencyInjection Component", + "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.2.1" + "source": "https://github.com/symfony/dependency-injection/tree/v5.2.2" }, "funding": [ { @@ -485,7 +485,7 @@ "type": "tidelift" } ], - "time": "2020-12-18T08:03:05+00:00" + "time": "2021-01-27T12:56:27+00:00" }, { "name": "symfony/deprecation-contracts", @@ -556,16 +556,16 @@ }, { "name": "symfony/error-handler", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "59b190ce16ddf32771a22087b60f6dafd3407147" + "reference": "4fd4a377f7b7ec7c3f3b40346a1411e0a83f9d40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/59b190ce16ddf32771a22087b60f6dafd3407147", - "reference": "59b190ce16ddf32771a22087b60f6dafd3407147", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/4fd4a377f7b7ec7c3f3b40346a1411e0a83f9d40", + "reference": "4fd4a377f7b7ec7c3f3b40346a1411e0a83f9d40", "shasum": "" }, "require": { @@ -602,10 +602,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony ErrorHandler Component", + "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.2.1" + "source": "https://github.com/symfony/error-handler/tree/v5.2.2" }, "funding": [ { @@ -621,20 +621,20 @@ "type": "tidelift" } ], - "time": "2020-12-09T18:54:12+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "1c93f7a1dff592c252574c79a8635a8a80856042" + "reference": "4f9760f8074978ad82e2ce854dff79a71fe45367" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1c93f7a1dff592c252574c79a8635a8a80856042", - "reference": "1c93f7a1dff592c252574c79a8635a8a80856042", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4f9760f8074978ad82e2ce854dff79a71fe45367", + "reference": "4f9760f8074978ad82e2ce854dff79a71fe45367", "shasum": "" }, "require": { @@ -687,10 +687,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "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/v5.2.1" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.2.2" }, "funding": [ { @@ -706,7 +706,7 @@ "type": "tidelift" } ], - "time": "2020-12-18T08:03:05+00:00" + "time": "2021-01-27T10:36:42+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -789,16 +789,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d" + "reference": "262d033b57c73e8b59cd6e68a45c528318b15038" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/fa8f8cab6b65e2d99a118e082935344c5ba8c60d", - "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/262d033b57c73e8b59cd6e68a45c528318b15038", + "reference": "262d033b57c73e8b59cd6e68a45c528318b15038", "shasum": "" }, "require": { @@ -828,10 +828,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Filesystem Component", + "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.2.1" + "source": "https://github.com/symfony/filesystem/tree/v5.2.2" }, "funding": [ { @@ -847,7 +847,7 @@ "type": "tidelift" } ], - "time": "2020-11-30T17:05:38+00:00" + "time": "2021-01-27T10:01:46+00:00" }, { "name": "symfony/http-client-contracts", @@ -930,16 +930,16 @@ }, { "name": "symfony/http-foundation", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "a1f6218b29897ab52acba58cfa905b83625bef8d" + "reference": "16dfa5acf8103f0394d447f8eea3ea49f9e50855" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a1f6218b29897ab52acba58cfa905b83625bef8d", - "reference": "a1f6218b29897ab52acba58cfa905b83625bef8d", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/16dfa5acf8103f0394d447f8eea3ea49f9e50855", + "reference": "16dfa5acf8103f0394d447f8eea3ea49f9e50855", "shasum": "" }, "require": { @@ -980,10 +980,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpFoundation Component", + "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.2.1" + "source": "https://github.com/symfony/http-foundation/tree/v5.2.2" }, "funding": [ { @@ -999,20 +999,20 @@ "type": "tidelift" } ], - "time": "2020-12-18T10:00:10+00:00" + "time": "2021-01-27T11:19:04+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "1feb619286d819180f7b8bc0dc44f516d9c62647" + "reference": "831b51e9370ece0febd0950dd819c63f996721c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/1feb619286d819180f7b8bc0dc44f516d9c62647", - "reference": "1feb619286d819180f7b8bc0dc44f516d9c62647", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/831b51e9370ece0febd0950dd819c63f996721c7", + "reference": "831b51e9370ece0febd0950dd819c63f996721c7", "shasum": "" }, "require": { @@ -1041,7 +1041,7 @@ "symfony/translation": "<5.0", "symfony/twig-bridge": "<5.0", "symfony/validator": "<5.0", - "twig/twig": "<2.4" + "twig/twig": "<2.13" }, "provide": { "psr/log-implementation": "1.0" @@ -1061,7 +1061,7 @@ "symfony/stopwatch": "^4.4|^5.0", "symfony/translation": "^4.4|^5.0", "symfony/translation-contracts": "^1.1|^2", - "twig/twig": "^2.4|^3.0" + "twig/twig": "^2.13|^3.0.4" }, "suggest": { "symfony/browser-kit": "", @@ -1092,10 +1092,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpKernel Component", + "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.2.1" + "source": "https://github.com/symfony/http-kernel/tree/v5.2.2" }, "funding": [ { @@ -1111,20 +1111,20 @@ "type": "tidelift" } ], - "time": "2020-12-18T13:49:39+00:00" + "time": "2021-01-27T14:45:46+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.20.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41" + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41", - "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", "shasum": "" }, "require": { @@ -1136,7 +1136,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1174,7 +1174,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.0" }, "funding": [ { @@ -1190,20 +1190,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.20.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c" + "reference": "267a9adeb8ecb8071040a740930e077cdfb987af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", - "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/267a9adeb8ecb8071040a740930e077cdfb987af", + "reference": "267a9adeb8ecb8071040a740930e077cdfb987af", "shasum": "" }, "require": { @@ -1215,7 +1215,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1255,7 +1255,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.0" }, "funding": [ { @@ -1271,20 +1271,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.20.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "727d1096295d807c309fb01a851577302394c897" + "reference": "6e971c891537eb617a00bb07a43d182a6915faba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/727d1096295d807c309fb01a851577302394c897", - "reference": "727d1096295d807c309fb01a851577302394c897", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/6e971c891537eb617a00bb07a43d182a6915faba", + "reference": "6e971c891537eb617a00bb07a43d182a6915faba", "shasum": "" }, "require": { @@ -1296,7 +1296,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1339,7 +1339,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.0" }, "funding": [ { @@ -1355,20 +1355,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-07T17:09:11+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.20.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "39d483bdf39be819deabf04ec872eb0b2410b531" + "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531", - "reference": "39d483bdf39be819deabf04ec872eb0b2410b531", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", + "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", "shasum": "" }, "require": { @@ -1380,7 +1380,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1419,7 +1419,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.0" }, "funding": [ { @@ -1435,20 +1435,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.20.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed" + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/8ff431c517be11c78c48a39a66d37431e26a6bed", - "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", "shasum": "" }, "require": { @@ -1457,7 +1457,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1498,7 +1498,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.0" }, "funding": [ { @@ -1514,20 +1514,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.20.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de" + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/e70aa8b064c5b72d3df2abd5ab1e90464ad009de", - "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", "shasum": "" }, "require": { @@ -1536,7 +1536,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1581,7 +1581,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.0" }, "funding": [ { @@ -1597,20 +1597,20 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/process", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "bd8815b8b6705298beaa384f04fabd459c10bedd" + "reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/bd8815b8b6705298beaa384f04fabd459c10bedd", - "reference": "bd8815b8b6705298beaa384f04fabd459c10bedd", + "url": "https://api.github.com/repos/symfony/process/zipball/313a38f09c77fbcdc1d223e57d368cea76a2fd2f", + "reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f", "shasum": "" }, "require": { @@ -1640,10 +1640,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Process Component", + "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.2.1" + "source": "https://github.com/symfony/process/tree/v5.2.2" }, "funding": [ { @@ -1659,7 +1659,7 @@ "type": "tidelift" } ], - "time": "2020-12-08T17:03:37+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/service-contracts", @@ -1742,16 +1742,16 @@ }, { "name": "symfony/string", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed" + "reference": "c95468897f408dd0aca2ff582074423dd0455122" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed", - "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed", + "url": "https://api.github.com/repos/symfony/string/zipball/c95468897f408dd0aca2ff582074423dd0455122", + "reference": "c95468897f408dd0aca2ff582074423dd0455122", "shasum": "" }, "require": { @@ -1794,7 +1794,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony String component", + "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": [ "grapheme", @@ -1805,7 +1805,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.2.1" + "source": "https://github.com/symfony/string/tree/v5.2.2" }, "funding": [ { @@ -1821,20 +1821,20 @@ "type": "tidelift" } ], - "time": "2020-12-05T07:33:16+00:00" + "time": "2021-01-25T15:14:59+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "13e7e882eaa55863faa7c4ad7c60f12f1a8b5089" + "reference": "72ca213014a92223a5d18651ce79ef441c12b694" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/13e7e882eaa55863faa7c4ad7c60f12f1a8b5089", - "reference": "13e7e882eaa55863faa7c4ad7c60f12f1a8b5089", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/72ca213014a92223a5d18651ce79ef441c12b694", + "reference": "72ca213014a92223a5d18651ce79ef441c12b694", "shasum": "" }, "require": { @@ -1850,7 +1850,7 @@ "ext-iconv": "*", "symfony/console": "^4.4|^5.0", "symfony/process": "^4.4|^5.0", - "twig/twig": "^2.4|^3.0" + "twig/twig": "^2.13|^3.0.4" }, "suggest": { "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", @@ -1886,14 +1886,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony mechanism for exploring and dumping PHP variables", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", "homepage": "https://symfony.com", "keywords": [ "debug", "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.2.1" + "source": "https://github.com/symfony/var-dumper/tree/v5.2.2" }, "funding": [ { @@ -1909,7 +1909,7 @@ "type": "tidelift" } ], - "time": "2020-12-16T17:02:19+00:00" + "time": "2021-01-27T10:15:41+00:00" } ], "packages-dev": [ @@ -1985,16 +1985,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.2.8", + "version": "1.2.9", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "8a7ecad675253e4654ea05505233285377405215" + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215", - "reference": "8a7ecad675253e4654ea05505233285377405215", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", "shasum": "" }, "require": { @@ -2003,14 +2003,15 @@ "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "phpstan/phpstan": "^0.12.55", "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -2040,7 +2041,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.8" + "source": "https://github.com/composer/ca-bundle/tree/1.2.9" }, "funding": [ { @@ -2056,7 +2057,7 @@ "type": "tidelift" } ], - "time": "2020-08-23T12:54:47+00:00" + "time": "2021-01-12T12:10:35+00:00" }, { "name": "composer/package-versions-deprecated", @@ -2521,16 +2522,16 @@ }, { "name": "doctrine/common", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/common.git", - "reference": "9f3e3f3cc5399604c0325d5ffa92609d694d950d" + "reference": "2afde5a9844126bc311cd5f548b5475e75f800d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/9f3e3f3cc5399604c0325d5ffa92609d694d950d", - "reference": "9f3e3f3cc5399604c0325d5ffa92609d694d950d", + "url": "https://api.github.com/repos/doctrine/common/zipball/2afde5a9844126bc311cd5f548b5475e75f800d3", + "reference": "2afde5a9844126bc311cd5f548b5475e75f800d3", "shasum": "" }, "require": { @@ -2590,7 +2591,7 @@ ], "support": { "issues": "https://github.com/doctrine/common/issues", - "source": "https://github.com/doctrine/common/tree/3.1.0" + "source": "https://github.com/doctrine/common/tree/3.1.1" }, "funding": [ { @@ -2606,7 +2607,7 @@ "type": "tidelift" } ], - "time": "2020-12-03T21:02:31+00:00" + "time": "2021-01-20T19:58:05+00:00" }, { "name": "doctrine/dbal", @@ -3235,16 +3236,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v2.17.3", + "version": "v2.18.2", "source": { "type": "git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "bd32f5dd72cdfc7b53f54077f980e144bfa2f595" + "reference": "18f8c9d184ba777380794a389fabc179896ba913" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/bd32f5dd72cdfc7b53f54077f980e144bfa2f595", - "reference": "bd32f5dd72cdfc7b53f54077f980e144bfa2f595", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/18f8c9d184ba777380794a389fabc179896ba913", + "reference": "18f8c9d184ba777380794a389fabc179896ba913", "shasum": "" }, "require": { @@ -3266,7 +3267,6 @@ "symfony/stopwatch": "^3.0 || ^4.0 || ^5.0" }, "require-dev": { - "johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0", "justinrainbow/json-schema": "^5.0", "keradus/cli-executor": "^1.4", "mikey179/vfsstream": "^1.6", @@ -3275,11 +3275,11 @@ "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", "phpspec/prophecy-phpunit": "^1.1 || ^2.0", - "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.13 || ^9.4.4 <9.5", + "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.13 || ^9.5", "phpunitgoodpractices/polyfill": "^1.5", "phpunitgoodpractices/traits": "^1.9.1", "sanmai/phpunit-legacy-adapter": "^6.4 || ^8.2.1", - "symfony/phpunit-bridge": "^5.1", + "symfony/phpunit-bridge": "^5.2.1", "symfony/yaml": "^3.0 || ^4.0 || ^5.0" }, "suggest": { @@ -3327,7 +3327,7 @@ "description": "A tool to automatically fix PHP code style", "support": { "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", - "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.17.3" + "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.2" }, "funding": [ { @@ -3335,7 +3335,7 @@ "type": "github" } ], - "time": "2020-12-24T11:14:44+00:00" + "time": "2021-01-26T00:22:21+00:00" }, { "name": "jangregor/phpstan-prophecy", @@ -4106,16 +4106,16 @@ }, { "name": "phpstan/phpstan", - "version": "0.12.64", + "version": "0.12.71", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "23eb1cb7ae125f45f1d0e48051bcf67a9a9b08aa" + "reference": "d508fa3b0ecc5fc91ac70c6c7ac2862f968ba2b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/23eb1cb7ae125f45f1d0e48051bcf67a9a9b08aa", - "reference": "23eb1cb7ae125f45f1d0e48051bcf67a9a9b08aa", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d508fa3b0ecc5fc91ac70c6c7ac2862f968ba2b5", + "reference": "d508fa3b0ecc5fc91ac70c6c7ac2862f968ba2b5", "shasum": "" }, "require": { @@ -4146,7 +4146,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.64" + "source": "https://github.com/phpstan/phpstan/tree/0.12.71" }, "funding": [ { @@ -4162,20 +4162,20 @@ "type": "tidelift" } ], - "time": "2020-12-21T11:59:02+00:00" + "time": "2021-02-01T18:24:00+00:00" }, { "name": "phpstan/phpstan-beberlei-assert", - "version": "0.12.4", + "version": "0.12.6", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-beberlei-assert.git", - "reference": "c714b071e856200e60ba586a942bdd590c60da4b" + "reference": "daf1176ee507b7dcd01276fabf20a0a308c94124" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-beberlei-assert/zipball/c714b071e856200e60ba586a942bdd590c60da4b", - "reference": "c714b071e856200e60ba586a942bdd590c60da4b", + "url": "https://api.github.com/repos/phpstan/phpstan-beberlei-assert/zipball/daf1176ee507b7dcd01276fabf20a0a308c94124", + "reference": "daf1176ee507b7dcd01276fabf20a0a308c94124", "shasum": "" }, "require": { @@ -4183,7 +4183,7 @@ "phpstan/phpstan": "^0.12.40" }, "require-dev": { - "beberlei/assert": "^2.9.5", + "beberlei/assert": "^3.3.0", "phing/phing": "^2.16.3", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/phpstan-phpunit": "^0.12.16", @@ -4213,22 +4213,22 @@ "description": "PHPStan beberlei/assert extension", "support": { "issues": "https://github.com/phpstan/phpstan-beberlei-assert/issues", - "source": "https://github.com/phpstan/phpstan-beberlei-assert/tree/0.12.4" + "source": "https://github.com/phpstan/phpstan-beberlei-assert/tree/0.12.6" }, - "time": "2020-12-12T16:05:56+00:00" + "time": "2021-01-25T12:31:38+00:00" }, { "name": "phpstan/phpstan-doctrine", - "version": "0.12.26", + "version": "0.12.30", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-doctrine.git", - "reference": "716ea5f101636cd6cf36bb7298a4fe8b62c6606d" + "reference": "c4b910638ef416ad336aca596b4551a2db10b5f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/716ea5f101636cd6cf36bb7298a4fe8b62c6606d", - "reference": "716ea5f101636cd6cf36bb7298a4fe8b62c6606d", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/c4b910638ef416ad336aca596b4551a2db10b5f7", + "reference": "c4b910638ef416ad336aca596b4551a2db10b5f7", "shasum": "" }, "require": { @@ -4246,6 +4246,7 @@ "doctrine/annotations": "^1.11.0", "doctrine/collections": "^1.0", "doctrine/common": "^2.7 || ^3.0", + "doctrine/dbal": "^2.11.0", "doctrine/mongodb-odm": "^1.3 || ^2.1", "doctrine/orm": "^2.5", "doctrine/persistence": "^1.1 || ^2.0", @@ -4280,9 +4281,9 @@ "description": "Doctrine extensions for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-doctrine/issues", - "source": "https://github.com/phpstan/phpstan-doctrine/tree/0.12.26" + "source": "https://github.com/phpstan/phpstan-doctrine/tree/0.12.30" }, - "time": "2020-12-13T11:58:47+00:00" + "time": "2021-01-18T13:00:10+00:00" }, { "name": "phpstan/phpstan-phpunit", @@ -4721,16 +4722,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.0", + "version": "9.5.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "8e16c225d57c3d6808014df6b1dd7598d0a5bbbe" + "reference": "f661659747f2f87f9e72095bb207bceb0f151cb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8e16c225d57c3d6808014df6b1dd7598d0a5bbbe", - "reference": "8e16c225d57c3d6808014df6b1dd7598d0a5bbbe", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f661659747f2f87f9e72095bb207bceb0f151cb4", + "reference": "f661659747f2f87f9e72095bb207bceb0f151cb4", "shasum": "" }, "require": { @@ -4808,7 +4809,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.0" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.2" }, "funding": [ { @@ -4820,7 +4821,7 @@ "type": "github" } ], - "time": "2020-12-04T05:05:53+00:00" + "time": "2021-02-02T14:45:58+00:00" }, { "name": "psr/cache", @@ -5837,16 +5838,16 @@ }, { "name": "swoole/ide-helper", - "version": "4.5.10", + "version": "4.6.2", "source": { "type": "git", "url": "https://github.com/swoole/ide-helper.git", - "reference": "11d77b630ec63e426326439bea0c4b0460fb3a00" + "reference": "62d923e3406d4d9c5a4749d810d11e2beb201abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swoole/ide-helper/zipball/11d77b630ec63e426326439bea0c4b0460fb3a00", - "reference": "11d77b630ec63e426326439bea0c4b0460fb3a00", + "url": "https://api.github.com/repos/swoole/ide-helper/zipball/62d923e3406d4d9c5a4749d810d11e2beb201abe", + "reference": "62d923e3406d4d9c5a4749d810d11e2beb201abe", "shasum": "" }, "require-dev": { @@ -5869,22 +5870,22 @@ "description": "IDE help files for Swoole.", "support": { "issues": "https://github.com/swoole/ide-helper/issues", - "source": "https://github.com/swoole/ide-helper/tree/4.5.10" + "source": "https://github.com/swoole/ide-helper/tree/4.6.2" }, - "time": "2020-12-27T05:03:52+00:00" + "time": "2021-01-26T00:17:29+00:00" }, { "name": "symfony/amqp-messenger", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/amqp-messenger.git", - "reference": "a7f681b022f9cfb88febc12face05b12a47232c1" + "reference": "cf309a35ed08caa77886ee6a352b8491c7681424" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/amqp-messenger/zipball/a7f681b022f9cfb88febc12face05b12a47232c1", - "reference": "a7f681b022f9cfb88febc12face05b12a47232c1", + "url": "https://api.github.com/repos/symfony/amqp-messenger/zipball/cf309a35ed08caa77886ee6a352b8491c7681424", + "reference": "cf309a35ed08caa77886ee6a352b8491c7681424", "shasum": "" }, "require": { @@ -5924,7 +5925,7 @@ "description": "Symfony AMQP extension Messenger Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/amqp-messenger/tree/v5.2.1" + "source": "https://github.com/symfony/amqp-messenger/tree/v5.2.2" }, "funding": [ { @@ -5940,20 +5941,20 @@ "type": "tidelift" } ], - "time": "2020-12-15T11:52:46+00:00" + "time": "2021-01-27T11:19:04+00:00" }, { "name": "symfony/cache", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "5e61d63b1ef4fb4852994038267ad45e12f3ec52" + "reference": "d6aed6c1bbf6f59e521f46437475a0ff4878d388" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/5e61d63b1ef4fb4852994038267ad45e12f3ec52", - "reference": "5e61d63b1ef4fb4852994038267ad45e12f3ec52", + "url": "https://api.github.com/repos/symfony/cache/zipball/d6aed6c1bbf6f59e521f46437475a0ff4878d388", + "reference": "d6aed6c1bbf6f59e521f46437475a0ff4878d388", "shasum": "" }, "require": { @@ -6012,14 +6013,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Cache component with PSR-6, PSR-16, and tags", + "description": "Provides an extended PSR-6, PSR-16 (and tags) implementation", "homepage": "https://symfony.com", "keywords": [ "caching", "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v5.2.1" + "source": "https://github.com/symfony/cache/tree/v5.2.2" }, "funding": [ { @@ -6035,7 +6036,7 @@ "type": "tidelift" } ], - "time": "2020-12-10T19:16:15+00:00" + "time": "2021-01-27T11:24:50+00:00" }, { "name": "symfony/cache-contracts", @@ -6118,16 +6119,16 @@ }, { "name": "symfony/debug-bundle", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/debug-bundle.git", - "reference": "c79722fc3d430810d7a764fbc84fe212e532e004" + "reference": "ec21bd26d24dab02ac40e4bec362b3f4032486e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/c79722fc3d430810d7a764fbc84fe212e532e004", - "reference": "c79722fc3d430810d7a764fbc84fe212e532e004", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/ec21bd26d24dab02ac40e4bec362b3f4032486e8", + "reference": "ec21bd26d24dab02ac40e4bec362b3f4032486e8", "shasum": "" }, "require": { @@ -6173,10 +6174,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DebugBundle", + "description": "Provides a tight integration of the Symfony Debug component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug-bundle/tree/v5.2.1" + "source": "https://github.com/symfony/debug-bundle/tree/v5.2.2" }, "funding": [ { @@ -6192,7 +6193,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:08:07+00:00" + "time": "2021-01-10T16:30:10+00:00" }, { "name": "symfony/debug-pack", @@ -6242,16 +6243,16 @@ }, { "name": "symfony/doctrine-messenger", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-messenger.git", - "reference": "8ad222fc5abce88f2b7c9cb91aa53b9f445a5889" + "reference": "e00cd690e49f08b41472e18b0d420c9874d2c707" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/8ad222fc5abce88f2b7c9cb91aa53b9f445a5889", - "reference": "8ad222fc5abce88f2b7c9cb91aa53b9f445a5889", + "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/e00cd690e49f08b41472e18b0d420c9874d2c707", + "reference": "e00cd690e49f08b41472e18b0d420c9874d2c707", "shasum": "" }, "require": { @@ -6295,7 +6296,7 @@ "description": "Symfony Doctrine Messenger Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-messenger/tree/v5.2.1" + "source": "https://github.com/symfony/doctrine-messenger/tree/v5.2.2" }, "funding": [ { @@ -6311,20 +6312,20 @@ "type": "tidelift" } ], - "time": "2020-12-10T19:16:15+00:00" + "time": "2021-01-27T11:19:04+00:00" }, { "name": "symfony/finder", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba" + "reference": "196f45723b5e618bf0e23b97e96d11652696ea9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0b9231a5922fd7287ba5b411893c0ecd2733e5ba", - "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba", + "url": "https://api.github.com/repos/symfony/finder/zipball/196f45723b5e618bf0e23b97e96d11652696ea9e", + "reference": "196f45723b5e618bf0e23b97e96d11652696ea9e", "shasum": "" }, "require": { @@ -6353,10 +6354,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Finder Component", + "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.2.1" + "source": "https://github.com/symfony/finder/tree/v5.2.2" }, "funding": [ { @@ -6372,20 +6373,20 @@ "type": "tidelift" } ], - "time": "2020-12-08T17:02:38+00:00" + "time": "2021-01-27T10:01:46+00:00" }, { "name": "symfony/framework-bundle", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "0663407ca5ad12e2e3fe657b32266904b3dc1e3f" + "reference": "ff455b2afd3f98237d4131ffebe190e59cc0f011" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/0663407ca5ad12e2e3fe657b32266904b3dc1e3f", - "reference": "0663407ca5ad12e2e3fe657b32266904b3dc1e3f", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/ff455b2afd3f98237d4131ffebe190e59cc0f011", + "reference": "ff455b2afd3f98237d4131ffebe190e59cc0f011", "shasum": "" }, "require": { @@ -6407,8 +6408,8 @@ }, "conflict": { "doctrine/persistence": "<1.3", - "phpdocumentor/reflection-docblock": "<3.0", - "phpdocumentor/type-resolver": "<0.2.1", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", "phpunit/phpunit": "<5.4.3", "symfony/asset": "<5.1", "symfony/browser-kit": "<4.4", @@ -6433,8 +6434,9 @@ "symfony/workflow": "<5.2" }, "require-dev": { - "doctrine/annotations": "~1.7", + "doctrine/annotations": "^1.10.4", "doctrine/cache": "~1.0", + "doctrine/persistence": "^1.3|^2.0", "paragonie/sodium_compat": "^1.8", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/asset": "^5.1", @@ -6500,10 +6502,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony FrameworkBundle", + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v5.2.1" + "source": "https://github.com/symfony/framework-bundle/tree/v5.2.2" }, "funding": [ { @@ -6519,20 +6521,20 @@ "type": "tidelift" } ], - "time": "2020-12-18T11:40:59+00:00" + "time": "2021-01-27T11:19:04+00:00" }, { "name": "symfony/messenger", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/messenger.git", - "reference": "3fc7766f5fa6c21096fa962a01684868b68f1f3c" + "reference": "ce658034cd7884428a8c6f50c2d4f8cf66348c40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/messenger/zipball/3fc7766f5fa6c21096fa962a01684868b68f1f3c", - "reference": "3fc7766f5fa6c21096fa962a01684868b68f1f3c", + "url": "https://api.github.com/repos/symfony/messenger/zipball/ce658034cd7884428a8c6f50c2d4f8cf66348c40", + "reference": "ce658034cd7884428a8c6f50c2d4f8cf66348c40", "shasum": "" }, "require": { @@ -6588,10 +6590,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Messenger Component", + "description": "Helps applications send and receive messages to/from other applications or via message queues", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/messenger/tree/v5.2.1" + "source": "https://github.com/symfony/messenger/tree/v5.2.2" }, "funding": [ { @@ -6607,20 +6609,20 @@ "type": "tidelift" } ], - "time": "2020-12-18T07:27:35+00:00" + "time": "2021-01-27T11:24:50+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "c024671adcac903b142dd952306a243d35843963" + "reference": "aca99c4135001224b917eed17cc846e8c0ba981c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/c024671adcac903b142dd952306a243d35843963", - "reference": "c024671adcac903b142dd952306a243d35843963", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/aca99c4135001224b917eed17cc846e8c0ba981c", + "reference": "aca99c4135001224b917eed17cc846e8c0ba981c", "shasum": "" }, "require": { @@ -6670,10 +6672,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Monolog Bridge", + "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v5.2.1" + "source": "https://github.com/symfony/monolog-bridge/tree/v5.2.2" }, "funding": [ { @@ -6689,7 +6691,7 @@ "type": "tidelift" } ], - "time": "2020-12-10T19:16:15+00:00" + "time": "2021-01-27T11:24:50+00:00" }, { "name": "symfony/monolog-bundle", @@ -6774,16 +6776,16 @@ }, { "name": "symfony/options-resolver", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "87a2a4a766244e796dd9cb9d6f58c123358cd986" + "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/87a2a4a766244e796dd9cb9d6f58c123358cd986", - "reference": "87a2a4a766244e796dd9cb9d6f58c123358cd986", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", + "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", "shasum": "" }, "require": { @@ -6815,7 +6817,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony OptionsResolver Component", + "description": "Provides an improved replacement for the array_replace PHP function", "homepage": "https://symfony.com", "keywords": [ "config", @@ -6823,7 +6825,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.2.1" + "source": "https://github.com/symfony/options-resolver/tree/v5.2.2" }, "funding": [ { @@ -6839,7 +6841,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:08:07+00:00" + "time": "2021-01-27T12:56:27+00:00" }, { "name": "symfony/polyfill-php70", @@ -6911,16 +6913,16 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.20.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930" + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cede45fcdfabdd6043b3592e83678e42ec69e930", - "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", "shasum": "" }, "require": { @@ -6929,7 +6931,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6967,7 +6969,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.0" }, "funding": [ { @@ -6983,7 +6985,7 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/profiler-pack", @@ -7032,16 +7034,16 @@ }, { "name": "symfony/redis-messenger", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/redis-messenger.git", - "reference": "c9ab1c7467657661554e7010a59f47f723f69c93" + "reference": "7e68914bf35cda948ee4d9081b8eaed9fd783fe5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/redis-messenger/zipball/c9ab1c7467657661554e7010a59f47f723f69c93", - "reference": "c9ab1c7467657661554e7010a59f47f723f69c93", + "url": "https://api.github.com/repos/symfony/redis-messenger/zipball/7e68914bf35cda948ee4d9081b8eaed9fd783fe5", + "reference": "7e68914bf35cda948ee4d9081b8eaed9fd783fe5", "shasum": "" }, "require": { @@ -7079,7 +7081,7 @@ "description": "Symfony Redis extension Messenger Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/redis-messenger/tree/v5.2.1" + "source": "https://github.com/symfony/redis-messenger/tree/v5.2.2" }, "funding": [ { @@ -7095,20 +7097,20 @@ "type": "tidelift" } ], - "time": "2020-12-15T11:52:46+00:00" + "time": "2021-01-27T11:24:50+00:00" }, { "name": "symfony/routing", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "934ac2720dcc878a47a45c986b483a7ee7193620" + "reference": "348b5917e56546c6d96adbf21d7f92c9ef563661" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/934ac2720dcc878a47a45c986b483a7ee7193620", - "reference": "934ac2720dcc878a47a45c986b483a7ee7193620", + "url": "https://api.github.com/repos/symfony/routing/zipball/348b5917e56546c6d96adbf21d7f92c9ef563661", + "reference": "348b5917e56546c6d96adbf21d7f92c9ef563661", "shasum": "" }, "require": { @@ -7122,7 +7124,7 @@ "symfony/yaml": "<4.4" }, "require-dev": { - "doctrine/annotations": "^1.7", + "doctrine/annotations": "^1.10.4", "psr/log": "~1.0", "symfony/config": "^5.0", "symfony/dependency-injection": "^4.4|^5.0", @@ -7160,7 +7162,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Routing Component", + "description": "Maps an HTTP request to a set of configuration variables", "homepage": "https://symfony.com", "keywords": [ "router", @@ -7169,7 +7171,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.2.1" + "source": "https://github.com/symfony/routing/tree/v5.2.2" }, "funding": [ { @@ -7185,20 +7187,20 @@ "type": "tidelift" } ], - "time": "2020-12-08T17:03:37+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "2b105c0354f39a63038a1d8bf776ee92852813af" + "reference": "b12274acfab9d9850c52583d136a24398cdf1a0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/2b105c0354f39a63038a1d8bf776ee92852813af", - "reference": "2b105c0354f39a63038a1d8bf776ee92852813af", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b12274acfab9d9850c52583d136a24398cdf1a0c", + "reference": "b12274acfab9d9850c52583d136a24398cdf1a0c", "shasum": "" }, "require": { @@ -7228,10 +7230,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Stopwatch Component", + "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.2.1" + "source": "https://github.com/symfony/stopwatch/tree/v5.2.2" }, "funding": [ { @@ -7247,7 +7249,7 @@ "type": "tidelift" } ], - "time": "2020-11-01T16:14:45+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/translation-contracts", @@ -7329,25 +7331,27 @@ }, { "name": "symfony/twig-bridge", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "378a136a41c07b5f2086f753d9756fb018921f86" + "reference": "5618cadebf28dff5c375f6c3c8e6f1d52df397e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/378a136a41c07b5f2086f753d9756fb018921f86", - "reference": "378a136a41c07b5f2086f753d9756fb018921f86", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/5618cadebf28dff5c375f6c3c8e6f1d52df397e1", + "reference": "5618cadebf28dff5c375f6c3c8e6f1d52df397e1", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/polyfill-php80": "^1.15", "symfony/translation-contracts": "^1.1|^2", - "twig/twig": "^2.10|^3.0" + "twig/twig": "^2.13|^3.0.4" }, "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", "symfony/console": "<4.4", "symfony/form": "<5.1", "symfony/http-foundation": "<4.4", @@ -7423,10 +7427,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Twig Bridge", + "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v5.2.1" + "source": "https://github.com/symfony/twig-bridge/tree/v5.2.2" }, "funding": [ { @@ -7442,20 +7446,20 @@ "type": "tidelift" } ], - "time": "2020-12-11T23:40:07+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/twig-bundle", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "8cb3208aec4655ae1495afad7ef3c032a236dfa7" + "reference": "5ebbb5f0e8bfaa0b4b37cb25ff97f83b18caf221" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/8cb3208aec4655ae1495afad7ef3c032a236dfa7", - "reference": "8cb3208aec4655ae1495afad7ef3c032a236dfa7", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/5ebbb5f0e8bfaa0b4b37cb25ff97f83b18caf221", + "reference": "5ebbb5f0e8bfaa0b4b37cb25ff97f83b18caf221", "shasum": "" }, "require": { @@ -7465,7 +7469,7 @@ "symfony/http-kernel": "^5.0", "symfony/polyfill-ctype": "~1.8", "symfony/twig-bridge": "^5.0", - "twig/twig": "^2.10|^3.0" + "twig/twig": "^2.13|^3.0.4" }, "conflict": { "symfony/dependency-injection": "<5.2", @@ -7473,7 +7477,7 @@ "symfony/translation": "<5.0" }, "require-dev": { - "doctrine/annotations": "~1.7", + "doctrine/annotations": "^1.10.4", "doctrine/cache": "~1.0", "symfony/asset": "^4.4|^5.0", "symfony/dependency-injection": "^5.2", @@ -7510,10 +7514,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony TwigBundle", + "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v5.2.1" + "source": "https://github.com/symfony/twig-bundle/tree/v5.2.2" }, "funding": [ { @@ -7529,20 +7533,20 @@ "type": "tidelift" } ], - "time": "2020-12-08T16:43:38+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/var-exporter", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "fbc3507f23d263d75417e09a12d77c009f39676c" + "reference": "5aed4875ab514c8cb9b6ff4772baa25fa4c10307" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/fbc3507f23d263d75417e09a12d77c009f39676c", - "reference": "fbc3507f23d263d75417e09a12d77c009f39676c", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/5aed4875ab514c8cb9b6ff4772baa25fa4c10307", + "reference": "5aed4875ab514c8cb9b6ff4772baa25fa4c10307", "shasum": "" }, "require": { @@ -7575,7 +7579,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "A blend of var_export() + serialize() to turn any serializable data structure to plain PHP code", + "description": "Allows exporting any serializable PHP data structure to plain PHP code", "homepage": "https://symfony.com", "keywords": [ "clone", @@ -7586,7 +7590,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v5.2.1" + "source": "https://github.com/symfony/var-exporter/tree/v5.2.2" }, "funding": [ { @@ -7602,20 +7606,20 @@ "type": "tidelift" } ], - "time": "2020-10-28T21:31:18+00:00" + "time": "2021-01-27T10:01:46+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "6cd2f3d01faf1d77125ec14150a6fbd062dbe211" + "reference": "d9ce6aa8abdb84fc0db8a6f47962a949e1c652c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/6cd2f3d01faf1d77125ec14150a6fbd062dbe211", - "reference": "6cd2f3d01faf1d77125ec14150a6fbd062dbe211", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/d9ce6aa8abdb84fc0db8a6f47962a949e1c652c2", + "reference": "d9ce6aa8abdb84fc0db8a6f47962a949e1c652c2", "shasum": "" }, "require": { @@ -7625,7 +7629,7 @@ "symfony/http-kernel": "^5.2", "symfony/routing": "^4.4|^5.0", "symfony/twig-bundle": "^4.4|^5.0", - "twig/twig": "^2.10|^3.0" + "twig/twig": "^2.13|^3.0.4" }, "conflict": { "symfony/dependency-injection": "<5.2", @@ -7661,10 +7665,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony WebProfilerBundle", + "description": "Provides a development tool that gives detailed information about the execution of any request", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v5.2.1" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v5.2.2" }, "funding": [ { @@ -7680,20 +7684,20 @@ "type": "tidelift" } ], - "time": "2020-12-08T17:03:37+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/yaml", - "version": "v5.2.1", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "290ea5e03b8cf9b42c783163123f54441fb06939" + "reference": "6bb8b36c6dea8100268512bf46e858c8eb5c545e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/290ea5e03b8cf9b42c783163123f54441fb06939", - "reference": "290ea5e03b8cf9b42c783163123f54441fb06939", + "url": "https://api.github.com/repos/symfony/yaml/zipball/6bb8b36c6dea8100268512bf46e858c8eb5c545e", + "reference": "6bb8b36c6dea8100268512bf46e858c8eb5c545e", "shasum": "" }, "require": { @@ -7736,10 +7740,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Yaml Component", + "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.2.1" + "source": "https://github.com/symfony/yaml/tree/v5.2.2" }, "funding": [ { @@ -7755,7 +7759,7 @@ "type": "tidelift" } ], - "time": "2020-12-08T17:02:38+00:00" + "time": "2021-01-27T10:01:46+00:00" }, { "name": "theseer/tokenizer", @@ -7998,12 +8002,12 @@ "version": "1.9.1", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", + "url": "https://github.com/webmozarts/assert.git", "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", "shasum": "" }, @@ -8041,8 +8045,8 @@ "validate" ], "support": { - "issues": "https://github.com/webmozart/assert/issues", - "source": "https://github.com/webmozart/assert/tree/master" + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.9.1" }, "time": "2020-07-08T17:02:28+00:00" } diff --git a/src/Bridge/Symfony/Bundle/Command/AbstractServerStartCommand.php b/src/Bridge/Symfony/Bundle/Command/AbstractServerStartCommand.php index 658b9fa8..5063a6b5 100644 --- a/src/Bridge/Symfony/Bundle/Command/AbstractServerStartCommand.php +++ b/src/Bridge/Symfony/Bundle/Command/AbstractServerStartCommand.php @@ -9,6 +9,8 @@ use function K911\Swoole\decode_string_as_set; use function K911\Swoole\format_bytes; use function K911\Swoole\get_max_memory; +use K911\Swoole\Process\Signal\PcntlSignalHandler; +use K911\Swoole\Process\Signal\Signal; use K911\Swoole\Server\Config\Socket; use K911\Swoole\Server\Configurator\ConfiguratorInterface; use K911\Swoole\Server\HttpServer; @@ -25,33 +27,28 @@ abstract class AbstractServerStartCommand extends Command { - /** - * @var ParameterBagInterface - */ - protected $parameterBag; - - private $server; - private $bootManager; - private $serverConfiguration; - private $serverConfigurator; - - /** - * @var bool - */ - private $testing = false; + protected ParameterBagInterface $parameterBag; + private HttpServer $server; + private BootableInterface $bootManager; + private HttpServerConfiguration $serverConfiguration; + private ConfiguratorInterface $serverConfigurator; + private ?PcntlSignalHandler $pcntlSignalHandler; + private bool $testing = false; public function __construct( HttpServer $server, HttpServerConfiguration $serverConfiguration, ConfiguratorInterface $serverConfigurator, ParameterBagInterface $parameterBag, - BootableInterface $bootManager + BootableInterface $bootManager, + ?PcntlSignalHandler $pcntlSignalHandler ) { $this->server = $server; $this->bootManager = $bootManager; $this->parameterBag = $parameterBag; $this->serverConfigurator = $serverConfigurator; $this->serverConfiguration = $serverConfiguration; + $this->pcntlSignalHandler = $pcntlSignalHandler; parent::__construct(); } @@ -160,7 +157,7 @@ protected function prepareServerConfiguration(HttpServerConfiguration $serverCon $sockets->changeApiSocket(new Socket('0.0.0.0', (int) $apiPort)); } - if (\filter_var($input->getOption('serve-static'), FILTER_VALIDATE_BOOLEAN)) { + if (\filter_var($input->getOption('serve-static'), \FILTER_VALIDATE_BOOLEAN)) { $publicDir = $input->getOption('public-dir'); Assertion::string($publicDir, 'Public dir must be a valid path'); $serverConfiguration->enableServingStaticFiles($publicDir); @@ -201,7 +198,7 @@ protected function prepareConfigurationRowsToPrint(HttpServerConfiguration $serv ['worker_count', $serverConfiguration->getWorkerCount()], ['reactor_count', $serverConfiguration->getReactorCount()], ['worker_max_request', $serverConfiguration->getMaxRequest()], - ['worker_max_request_grace', $serverConfiguration->getMaxRequestGrace()], + ['worker_max_request_grace', $serverConfiguration->getMaxRequestGrace() ?? '~'], ['memory_limit', format_bytes(get_max_memory())], ['trusted_hosts', \implode(', ', $runtimeConfiguration['trustedHosts'])], ]; @@ -226,6 +223,15 @@ protected function startServer(HttpServerConfiguration $serverConfiguration, Htt { $io->comment('Quit the server with CONTROL-C.'); + if ($this->pcntlSignalHandler instanceof PcntlSignalHandler && $serverConfiguration->isReactorRunningMode()) { + // Register dummy SIGINT handler to make sure process doesn't exit to early when CONTROL-C is hit + $this->pcntlSignalHandler->register(function () use ($server): void { + if (\getmypid() !== $server->getMasterPid()) { + $server->shutdown(); + } + }, Signal::int()); + } + if ($server->start()) { $io->newLine(); $io->success('Swoole HTTP Server has been successfully shutdown.'); diff --git a/src/Bridge/Symfony/Bundle/Command/ServerStartCommand.php b/src/Bridge/Symfony/Bundle/Command/ServerStartCommand.php index a5015e08..442c8713 100644 --- a/src/Bridge/Symfony/Bundle/Command/ServerStartCommand.php +++ b/src/Bridge/Symfony/Bundle/Command/ServerStartCommand.php @@ -87,7 +87,7 @@ private function closeConsoleOutput(ConsoleOutput $output): void private function closeStreamOutput(StreamOutput $output): void { - $output->setVerbosity(PHP_INT_MIN); + $output->setVerbosity(\PHP_INT_MIN); \fclose($output->getStream()); } } diff --git a/src/Bridge/Symfony/Bundle/Command/ServerStatusCommand.php b/src/Bridge/Symfony/Bundle/Command/ServerStatusCommand.php index d9e47cee..070001c2 100644 --- a/src/Bridge/Symfony/Bundle/Command/ServerStatusCommand.php +++ b/src/Bridge/Symfony/Bundle/Command/ServerStatusCommand.php @@ -126,7 +126,7 @@ private function showStatus(SymfonyStyle $io, array $status): void private function showMetrics(SymfonyStyle $io, array $metrics): void { - $date = \DateTimeImmutable::createFromFormat(DATE_ATOM, $metrics['date']); + $date = \DateTimeImmutable::createFromFormat(\DATE_ATOM, $metrics['date']); Assertion::isInstanceOf($date, \DateTimeImmutable::class); $server = $metrics['server']; $runningSeconds = $date->getTimestamp() - $server['start_time']; diff --git a/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php b/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php index 6a65a19c..0b4752a1 100644 --- a/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php +++ b/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php @@ -206,6 +206,18 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->end() ->end() // drivers + ->arrayNode('coroutine') + ->addDefaultsIfNotSet() + ->canBeDisabled() + ->children() + ->arrayNode('hooks') + ->defaultValue(['all']) + ->prototype('enum') + ->values(['off', 'all']) + ->end() + ->end() + ->end() + ->end() ->arrayNode('settings') ->addDefaultsIfNotSet() ->children() @@ -240,6 +252,13 @@ public function getConfigTreeBuilder(): TreeBuilder ->min(0) ->defaultValue(0) ->end() + ->booleanNode('worker_reload_async') + ->defaultTrue() + ->end() + ->integerNode('worker_exit_timeout_seconds') + ->min(0) + ->defaultValue(5) + ->end() ->scalarNode('worker_max_request_grace') ->defaultNull() ->end() diff --git a/src/Bridge/Symfony/Bundle/DependencyInjection/SwooleExtension.php b/src/Bridge/Symfony/Bundle/DependencyInjection/SwooleExtension.php index e373fea2..414d774e 100644 --- a/src/Bridge/Symfony/Bundle/DependencyInjection/SwooleExtension.php +++ b/src/Bridge/Symfony/Bundle/DependencyInjection/SwooleExtension.php @@ -18,9 +18,11 @@ use K911\Swoole\Bridge\Symfony\Messenger\SwooleServerTaskTransportFactory; use K911\Swoole\Bridge\Symfony\Messenger\SwooleServerTaskTransportHandler; use K911\Swoole\Bridge\Upscale\Blackfire\WithProfiler; +use K911\Swoole\Process\Signal\PcntlSignalHandler; use K911\Swoole\Server\Config\Socket; use K911\Swoole\Server\Config\Sockets; use K911\Swoole\Server\Configurator\ConfiguratorInterface; +use K911\Swoole\Server\Configurator\WithProcess; use K911\Swoole\Server\HttpServer; use K911\Swoole\Server\HttpServerConfiguration; use K911\Swoole\Server\RequestHandler\AdvancedStaticFilesServer; @@ -32,10 +34,13 @@ use K911\Swoole\Server\Runtime\HMR\HotModuleReloaderInterface; use K911\Swoole\Server\Runtime\HMR\InotifyHMR; use K911\Swoole\Server\TaskHandler\TaskHandlerInterface; +use K911\Swoole\Server\WorkerHandler\ClearAllTimersWorkerExitHandler; use K911\Swoole\Server\WorkerHandler\HMRWorkerStartHandler; +use K911\Swoole\Server\WorkerHandler\WorkerExitHandlerInterface; use K911\Swoole\Server\WorkerHandler\WorkerStartHandlerInterface; use ReflectionMethod; use RuntimeException; +use Swoole\Process; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; @@ -192,6 +197,7 @@ private function registerHttpServerConfiguration(array $config, ContainerBuilder 'socket_type' => $socketType, 'ssl_enabled' => $sslEnabled, 'settings' => $settings, + 'coroutine' => $coroutine, ] = $config; if ('auto' === $static['strategy']) { @@ -211,6 +217,8 @@ private function registerHttpServerConfiguration(array $config, ContainerBuilder $settings['serve_static'] = $static['strategy']; $settings['public_dir'] = $static['public_dir']; + $settings['coroutine_enabled'] = $coroutine['enabled']; + $settings['coroutine_hooks'] = $coroutine['hooks']; if ('auto' === $settings['log_level']) { $settings['log_level'] = $this->isDebug($container) ? 'debug' : 'notice'; @@ -234,9 +242,32 @@ private function registerHttpServerConfiguration(array $config, ContainerBuilder ->addArgument($settings) ; + $this->registerSignalHandlers($runningMode, $container); $this->registerHttpServerHMR($hmr, $container); } + private function registerSignalHandlers(string $runningMode, ContainerBuilder $container): void + { + if ('reactor' !== $runningMode) { + return; + } + + if (\extension_loaded('pcntl') && \extension_loaded('posix')) { + $container->register(PcntlSignalHandler::class); + } + + $container->register('swoole_bundle.server.http_server.configurator.with_process_signal_shutdown_handler') + ->setClass(WithProcess::class) + ->setAutowired(false) + ->setAutoconfigured(false) + ->setPublic(false) + ->setArguments([Process::class => new Reference('swoole_bundle.http_server.runtime.server_shutdown.signal_handler_swoole_process')]) + ; + + $def = $container->getDefinition('swoole_bundle.server.http_server.configurator.for_server_run_command'); + $def->addArgument(new Reference('swoole_bundle.server.http_server.configurator.with_process_signal_shutdown_handler')); + } + private function registerHttpServerHMR(string $hmr, ContainerBuilder $container): void { if ('off' === $hmr || !$this->isDebug($container)) { @@ -255,6 +286,13 @@ private function registerHttpServerHMR(string $hmr, ContainerBuilder $container) ->setArgument('$decorated', new Reference(HMRWorkerStartHandler::class.'.inner')) ->setDecoratedService(WorkerStartHandlerInterface::class) ; + + $container->autowire(ClearAllTimersWorkerExitHandler::class) + ->setPublic(false) + ->setAutoconfigured(true) + ->setArgument('$decorated', new Reference(ClearAllTimersWorkerExitHandler::class.'.inner')) + ->setDecoratedService(WorkerExitHandlerInterface::class) + ; } private function resolveAutoHMR(): string diff --git a/src/Bridge/Symfony/Bundle/Resources/config/services.yaml b/src/Bridge/Symfony/Bundle/Resources/config/services.yaml index 19b48c56..d35ce281 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/services.yaml +++ b/src/Bridge/Symfony/Bundle/Resources/config/services.yaml @@ -32,7 +32,31 @@ services: K911\Swoole\Server\RequestHandler\LimitedRequestHandler: - K911\Swoole\Server\LifecycleHandler\SigIntHandler: + K911\Swoole\Server\Runtime\ServerShutdown\SignalServerShutdownHandlerOnServerStart: + + K911\Swoole\Component\Clock\ClockInterface: + class: K911\Swoole\Component\Clock\CoroutineFriendlyClock + + K911\Swoole\Process\Signal\SwooleProcessSignalHandler: + + K911\Swoole\Process\ProcessFactory: + + K911\Swoole\Process\ProcessManagerInterface: + class: K911\Swoole\Process\ProcessManager + + K911\Swoole\Process\Signal\SignalHandlerInterface: + alias: K911\Swoole\Process\Signal\SwooleProcessSignalHandler + + swoole_bundle.http_server.runtime.server_shutdown.signal_handler_process: + class: K911\Swoole\Server\Runtime\ServerShutdown\SignalServerShutdownHandlerAsServerProcess + + swoole_bundle.http_server.runtime.server_shutdown.signal_handler_swoole_process: + class: Swoole\Process + factory: ['@K911\Swoole\Process\ProcessFactory', make] + autowire: false + autoconfigure: false + arguments: + $process: '@swoole_bundle.http_server.runtime.server_shutdown.signal_handler_process' K911\Swoole\Server\Runtime\CallableBootManagerFactory: @@ -55,6 +79,9 @@ services: K911\Swoole\Server\WorkerHandler\WorkerStartHandlerInterface: class: K911\Swoole\Server\WorkerHandler\NoOpWorkerStartHandler + K911\Swoole\Server\WorkerHandler\WorkerExitHandlerInterface: + class: K911\Swoole\Server\WorkerHandler\NoOpWorkerExitHandler + K911\Swoole\Server\LifecycleHandler\ServerStartHandlerInterface: class: K911\Swoole\Server\LifecycleHandler\NoOpServerStartHandler @@ -102,6 +129,8 @@ services: K911\Swoole\Server\Configurator\WithWorkerStartHandler: + K911\Swoole\Server\Configurator\WithWorkerExitHandler: + K911\Swoole\Server\Configurator\WithTaskHandler: K911\Swoole\Server\Configurator\WithTaskFinishedHandler: @@ -143,4 +172,4 @@ services: class: K911\Swoole\Server\Configurator\WithServerStartHandler autoconfigure: false arguments: - $handler: '@K911\Swoole\Server\LifecycleHandler\SigIntHandler' + $handler: '@K911\Swoole\Server\Runtime\ServerShutdown\SignalServerShutdownHandlerOnServerStart' diff --git a/src/Bridge/Symfony/ErrorHandler/ExceptionHandlerFactory.php b/src/Bridge/Symfony/ErrorHandler/ExceptionHandlerFactory.php index 0b349577..f79313f1 100644 --- a/src/Bridge/Symfony/ErrorHandler/ExceptionHandlerFactory.php +++ b/src/Bridge/Symfony/ErrorHandler/ExceptionHandlerFactory.php @@ -45,7 +45,7 @@ public function newExceptionHandler(Request $request): callable $e = new ErrorException( $e->getMessage(), $e->getCode(), - E_ERROR, + \E_ERROR, $e->getFile(), $e->getLine(), $e->getPrevious() diff --git a/src/Bridge/Symfony/HttpFoundation/RequestFactory.php b/src/Bridge/Symfony/HttpFoundation/RequestFactory.php index f604eecf..e93b9a27 100644 --- a/src/Bridge/Symfony/HttpFoundation/RequestFactory.php +++ b/src/Bridge/Symfony/HttpFoundation/RequestFactory.php @@ -14,7 +14,7 @@ final class RequestFactory implements RequestFactoryInterface */ public function make(SwooleRequest $request): HttpFoundationRequest { - $server = \array_change_key_case($request->server, CASE_UPPER); + $server = \array_change_key_case($request->server, \CASE_UPPER); // Add formatted headers to server foreach ($request->header as $key => $value) { diff --git a/src/Bridge/Symfony/HttpFoundation/Session/SwooleSessionStorage.php b/src/Bridge/Symfony/HttpFoundation/Session/SwooleSessionStorage.php index 2402ab2d..001794b0 100644 --- a/src/Bridge/Symfony/HttpFoundation/Session/SwooleSessionStorage.php +++ b/src/Bridge/Symfony/HttpFoundation/Session/SwooleSessionStorage.php @@ -121,7 +121,7 @@ public function save(): void $this->storage->set( $this->currentId, - \json_encode($this->data, JSON_THROW_ON_ERROR), + \json_encode($this->data, \JSON_THROW_ON_ERROR), $this->sessionLifetimeSeconds ); } @@ -251,7 +251,7 @@ private function obtainSessionData(string $sessionId): array Assertion::string($sessionData); - return \json_decode($sessionData, true, 512, JSON_THROW_ON_ERROR); + return \json_decode($sessionData, true, 512, \JSON_THROW_ON_ERROR); } /** diff --git a/src/Client/HttpClient.php b/src/Client/HttpClient.php index cbc649ec..2d24702a 100644 --- a/src/Client/HttpClient.php +++ b/src/Client/HttpClient.php @@ -126,7 +126,7 @@ public function serialize(): string 'port' => $this->client->port, 'ssl' => $this->client->ssl, 'options' => $this->client->setting, - ], JSON_THROW_ON_ERROR); + ], \JSON_THROW_ON_ERROR); } /** @@ -136,7 +136,7 @@ public function serialize(): string */ public function unserialize($serialized): void { - $spec = \json_decode($serialized, true, 512, JSON_THROW_ON_ERROR); + $spec = \json_decode($serialized, true, 512, \JSON_THROW_ON_ERROR); $this->client = self::makeSwooleClient($spec['host'], $spec['port'], $spec['ssl'], $spec['options']); } @@ -167,7 +167,7 @@ private function assertHttpMethodSupported(string $method): void */ private function serializeRequestData(Client $client, $data): void { - $json = \json_encode($data, JSON_THROW_ON_ERROR); + $json = \json_encode($data, \JSON_THROW_ON_ERROR); $client->requestHeaders[Http::HEADER_CONTENT_TYPE] = Http::CONTENT_TYPE_APPLICATION_JSON; $client->setData($json); } @@ -229,7 +229,7 @@ private function resolveResponseBody(Client $client) switch ($contentType) { case Http::CONTENT_TYPE_APPLICATION_JSON: - return \json_decode($client->body, true, 512, JSON_THROW_ON_ERROR); + return \json_decode($client->body, true, 512, \JSON_THROW_ON_ERROR); case Http::CONTENT_TYPE_TEXT_PLAIN: case Http::CONTENT_TYPE_TEXT_HTML: return $client->body; diff --git a/src/Common/XdebugHandler/XdebugHandler.php b/src/Common/XdebugHandler/XdebugHandler.php index 4ac719be..2c8c1a9d 100644 --- a/src/Common/XdebugHandler/XdebugHandler.php +++ b/src/Common/XdebugHandler/XdebugHandler.php @@ -46,7 +46,7 @@ public function allowXdebugEnvName(): string public function prepareRestartedProcess(): Process { - $command = [PHP_BINARY, '-n', '-c', $this->createPreparedTempIniFile()]; + $command = [\PHP_BINARY, '-n', '-c', $this->createPreparedTempIniFile()]; $currentCommand = $_SERVER['argv']; $command = \array_merge($command, $currentCommand); @@ -139,7 +139,7 @@ private function parsePhpIniContent(iterable $iniFiles): string } $data = \preg_replace($regex, ';$1', $iniContent); - $content .= $data.PHP_EOL; + $content .= $data.\PHP_EOL; } // Merge loaded settings into our ini content, if it is valid @@ -152,7 +152,7 @@ private function parsePhpIniContent(iterable $iniFiles): string } // Work-around for https://bugs.php.net/bug.php?id=75932 - $content .= 'opcache.enable_cli=0'.PHP_EOL; + $content .= 'opcache.enable_cli=0'.\PHP_EOL; return $content; } @@ -175,7 +175,7 @@ private function mergeLoadedConfig(array $loadedConfig, array $iniConfig): strin if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) { // Double-quote escape each value - $content .= $name.'="'.\addcslashes($value, '\\"').'"'.PHP_EOL; + $content .= $name.'="'.\addcslashes($value, '\\"').'"'.\PHP_EOL; } } diff --git a/src/Component/Clock/ClockInterface.php b/src/Component/Clock/ClockInterface.php new file mode 100644 index 00000000..6e73e95b --- /dev/null +++ b/src/Component/Clock/ClockInterface.php @@ -0,0 +1,24 @@ +coroutineSleepHookEnabled = $coroutineSleepHookEnabled; + } + + public function timeout(callable $condition, float $timeoutSeconds = 10, int $stepMicroseconds = 1000): bool + { + $now = $this->currentTime(); + $start = $now; + $max = $start + $timeoutSeconds; + + do { + if ($condition()) { + return true; + } + + $now = $this->currentTime(); + $this->microSleep($stepMicroseconds); + } while ($now < $max); + + return false; + } + + public function currentTime(): float + { + return \microtime(true); + } + + public function microSleep(int $microseconds): void + { + $this->sleepCoroutineHookCheck(); + \usleep($microseconds); + } + + private function sleepCoroutineHookCheck(): void + { + if ($this->coroutineSleepHookEnabled) { + return; + } + + $this->coroutineSleepHookEnabled = (Runtime::getHookFlags() & \SWOOLE_HOOK_SLEEP) === \SWOOLE_HOOK_SLEEP; + Assertion::true($this->coroutineSleepHookEnabled, 'Swoole Coroutine hook "SWOOLE_HOOK_SLEEP" must be enabled'); + } +} diff --git a/src/Process/ProcessFactory.php b/src/Process/ProcessFactory.php new file mode 100644 index 00000000..3666bed6 --- /dev/null +++ b/src/Process/ProcessFactory.php @@ -0,0 +1,15 @@ +signalHandler = $signalHandler; + $this->clock = $clock; + } + + /** + * {@inheritDoc} + */ + public function gracefullyTerminate(int $processId, int $timeoutSeconds = 10): void + { + if (!$this->runningStatus($processId)) { + throw new SignalException(\sprintf('Process with id "%d" is not running.', $processId)); + } + + $this->signalHandler->kill($processId, Signal::term()); + + if (!$this->clock->timeout(fn () => $this->runningStatus($processId), $timeoutSeconds, 1000)) { + $this->signalHandler->kill($processId, Signal::kill()); + } + } + + /** + * {@inheritDoc} + */ + public function runningStatus(int $processId): bool + { + try { + $this->signalHandler->kill($processId, Signal::zero()); + } catch (SignalException $exception) { + return false; + } + + return true; + } +} diff --git a/src/Process/ProcessManagerInterface.php b/src/Process/ProcessManagerInterface.php new file mode 100644 index 00000000..6b314062 --- /dev/null +++ b/src/Process/ProcessManagerInterface.php @@ -0,0 +1,19 @@ +getMessage(), $exception->getCode(), $exception); + } + + public static function fromKillCommand(int $processId, Signal $signal): self + { + return new self(\sprintf('Unable to kill process having id "%d" using signal "%s (%d)"', $processId, $signal->name(), $signal->number())); + } +} diff --git a/src/Process/Signal/PcntlSignalHandler.php b/src/Process/Signal/PcntlSignalHandler.php new file mode 100644 index 00000000..6b1ee6ef --- /dev/null +++ b/src/Process/Signal/PcntlSignalHandler.php @@ -0,0 +1,66 @@ +restartSysCalls = $restartSysCalls; + + if ($asyncSignals) { + $this->enableAsyncSignals(); + } + } + + /** + * {@inheritDoc} + */ + public function register(callable $handler, Signal $signal, Signal ...$moreSignals): void + { + /** @var Signal $signalObj */ + foreach ([$signal, ...$moreSignals] as $signalObj) { + if (!\pcntl_signal($signalObj->number(), $handler, $this->restartSysCalls)) { + $errorNumber = \posix_get_last_error(); + $errorMessage = \pcntl_strerror($errorNumber); + + throw new SignalException(\sprintf('Unable to register PCNTL signal handler on signal "%s (%d)". Error (%d): %s', $signal->name(), $signal->number(), $errorNumber, $errorMessage)); + } + } + } + + /** + * {@inheritDoc} + */ + public function kill(int $processId, Signal $signal): void + { + if (!\posix_kill($processId, $signal->number())) { + $errorNumber = \posix_get_last_error(); + $errorMessage = \posix_strerror($errorNumber); + + throw new SignalException(\sprintf('Killing process id "%d" with signal "%s (%d)" failed. Error (%d): %s', $processId, $signal->name(), $signal->number(), $errorNumber, $errorMessage)); + } + } + + private function enableAsyncSignals(): void + { + if (!\pcntl_async_signals()) { + \pcntl_async_signals(true); + } + } +} diff --git a/src/Process/Signal/Signal.php b/src/Process/Signal/Signal.php new file mode 100644 index 00000000..94867784 --- /dev/null +++ b/src/Process/Signal/Signal.php @@ -0,0 +1,86 @@ + 0, + self::SIGINT => 2, + self::SIGKILL => 9, + self::SIGTERM => 15, + ]; + + private string $name; + private int $number; + + public function __construct(string $name) + { + $this->name = \mb_strtoupper($name); + $this->number = $this->resolveNumber($this->name); + } + + public function name(): string + { + return $this->name; + } + + public function number(): int + { + return $this->number; + } + + public static function kill(): self + { + return new self(self::SIGKILL); + } + + public static function term(): self + { + return new self(self::SIGTERM); + } + + public static function int(): self + { + return new self(self::SIGINT); + } + + public static function zero(): self + { + return new self(self::ZERO); + } + + private function resolveNumber(string $name): int + { + if (\array_key_exists($name, self::PORTABLE_SIGNALS)) { + return self::PORTABLE_SIGNALS[$name]; + } + + if (\defined($name)) { + $signalConstant = \constant($name); + Assertion::integer($signalConstant, 'Signal number must be an integer. Value "%s" is not an integer.'); + Assertion::greaterOrEqualThan($signalConstant, 0, 'Provided signal number "%s" is not greater or equal than "%s".'); + + return $signalConstant; + } + + throw new SignalException(\sprintf('Signal constant "%s" is not defined. Signal number unknown', $name)); + } +} diff --git a/src/Process/Signal/SignalHandlerInterface.php b/src/Process/Signal/SignalHandlerInterface.php new file mode 100644 index 00000000..999f557b --- /dev/null +++ b/src/Process/Signal/SignalHandlerInterface.php @@ -0,0 +1,18 @@ +number(), $handler); + } + } catch (\Throwable $exception) { + throw SignalException::fromThrowable($exception); + } + } + + /** + * {@inheritDoc} + */ + public function kill(int $processId, Signal $signal): void + { + try { + if (!Process::kill($processId, $signal->number())) { + throw SignalException::fromKillCommand($processId, $signal); + } + } catch (\Throwable $exception) { + throw SignalException::fromThrowable($exception); + } + } +} diff --git a/src/Server/Api/ApiServer.php b/src/Server/Api/ApiServer.php index a0827043..0e94cdfa 100644 --- a/src/Server/Api/ApiServer.php +++ b/src/Server/Api/ApiServer.php @@ -29,7 +29,7 @@ public function __construct(HttpServer $server, HttpServerConfiguration $serverC public function metrics(): array { return [ - 'date' => (new \DateTimeImmutable('now'))->format(DATE_ATOM), + 'date' => (new \DateTimeImmutable('now'))->format(\DATE_ATOM), 'server' => $this->server->metrics(), ]; } @@ -58,7 +58,7 @@ public function status(): array $swooleServer = $this->server->getServer(); return [ - 'date' => \date(DATE_ATOM), + 'date' => \date(\DATE_ATOM), 'server' => [ 'host' => $swooleServer->host, 'port' => $swooleServer->port, diff --git a/src/Server/Api/ApiServerRequestHandler.php b/src/Server/Api/ApiServerRequestHandler.php index 2779a83c..a1cb3180 100644 --- a/src/Server/Api/ApiServerRequestHandler.php +++ b/src/Server/Api/ApiServerRequestHandler.php @@ -143,6 +143,6 @@ private function sendResponse(Response $response, int $statusCode = 200, ?array $response->header(Http::HEADER_CONTENT_TYPE, Http::CONTENT_TYPE_APPLICATION_JSON); $response->status($statusCode); - $response->end(\json_encode($data, JSON_THROW_ON_ERROR)); + $response->end(\json_encode($data, \JSON_THROW_ON_ERROR)); } } diff --git a/src/Server/Config/Socket.php b/src/Server/Config/Socket.php index ae303c63..b6838375 100644 --- a/src/Server/Config/Socket.php +++ b/src/Server/Config/Socket.php @@ -11,12 +11,12 @@ final class Socket { private const CONSTANT_SWOOLE_SSL_IS_NOT_DEFINED_ERROR_MESSAGE = 'Constant SWOOLE_SSL is not defined. Please compile swoole extension with SSL support enabled.'; private const SWOOLE_SOCKET_TYPE = [ - 'tcp' => SWOOLE_SOCK_TCP, - 'tcp_ipv6' => SWOOLE_SOCK_TCP6, - 'udp' => SWOOLE_SOCK_UDP, - 'udp_ipv6' => SWOOLE_SOCK_UDP6, - 'unix_dgram' => SWOOLE_SOCK_UNIX_DGRAM, - 'unix_stream' => SWOOLE_SOCK_UNIX_STREAM, + 'tcp' => \SWOOLE_SOCK_TCP, + 'tcp_ipv6' => \SWOOLE_SOCK_TCP6, + 'udp' => \SWOOLE_SOCK_UDP, + 'udp_ipv6' => \SWOOLE_SOCK_UDP6, + 'unix_dgram' => \SWOOLE_SOCK_UNIX_DGRAM, + 'unix_stream' => \SWOOLE_SOCK_UNIX_STREAM, ]; /** @@ -90,7 +90,7 @@ public function type(): int if (!\defined('SWOOLE_SSL')) { throw new InvalidArgumentException(self::CONSTANT_SWOOLE_SSL_IS_NOT_DEFINED_ERROR_MESSAGE); } - $resolvedSocketType |= SWOOLE_SSL; + $resolvedSocketType |= \SWOOLE_SSL; } return $resolvedSocketType; diff --git a/src/Server/Configurator/WithProcess.php b/src/Server/Configurator/WithProcess.php new file mode 100644 index 00000000..26f0fd01 --- /dev/null +++ b/src/Server/Configurator/WithProcess.php @@ -0,0 +1,23 @@ +process = $process; + } + + public function configure(Server $server): void + { + $server->addProcess($this->process); + } +} diff --git a/src/Server/Configurator/WithWorkerExitHandler.php b/src/Server/Configurator/WithWorkerExitHandler.php new file mode 100644 index 00000000..ffe386e1 --- /dev/null +++ b/src/Server/Configurator/WithWorkerExitHandler.php @@ -0,0 +1,26 @@ +handler = $handler; + } + + /** + * {@inheritdoc} + */ + public function configure(Server $server): void + { + $server->on('WorkerExit', [$this->handler, 'handle']); + } +} diff --git a/src/Server/HttpServer.php b/src/Server/HttpServer.php index f47c674e..b80ff0f7 100644 --- a/src/Server/HttpServer.php +++ b/src/Server/HttpServer.php @@ -136,6 +136,11 @@ public function getListeners(): array return $this->listeners; } + public function getMasterPid(): int + { + return $this->getServer()->master_pid; + } + private function isRunningInBackground(): bool { try { diff --git a/src/Server/HttpServerConfiguration.php b/src/Server/HttpServerConfiguration.php index 84434d3a..78856b77 100644 --- a/src/Server/HttpServerConfiguration.php +++ b/src/Server/HttpServerConfiguration.php @@ -27,12 +27,18 @@ class HttpServerConfiguration private const SWOOLE_HTTP_SERVER_CONFIG_PACKAGE_MAX_LENGTH = 'package_max_length'; private const SWOOLE_HTTP_SERVER_CONFIG_WORKER_MAX_REQUEST = 'worker_max_request'; private const SWOOLE_HTTP_SERVER_CONFIG_WORKER_MAX_REQUEST_GRACE = 'worker_max_request_grace'; + private const SWOOLE_HTTP_SERVER_CONFIG_WORKER_RELOAD_ASYNC = 'worker_reload_async'; + private const SWOOLE_HTTP_SERVER_CONFIG_WORKER_EXIT_TIMEOUT_SECONDS = 'worker_exit_timeout_seconds'; + private const SWOOLE_HTTP_SERVER_CONFIG_COROUTINE_ENABLED = 'coroutine_enabled'; + private const SWOOLE_HTTP_SERVER_CONFIG_COROUTINE_HOOKS = 'coroutine_hooks'; /** * @todo add more * * @see https://github.com/swoole/swoole-docs/blob/master/modules/swoole-server/configuration.md * @see https://github.com/swoole/swoole-docs/blob/master/modules/swoole-http-server/configuration.md + * @see https://wiki.swoole.com/#/server/setting + * @see https://wiki.swoole.com/#/http_server?id=%e9%85%8d%e7%bd%ae%e9%80%89%e9%a1%b9 */ private const SWOOLE_HTTP_SERVER_CONFIGURATION = [ self::SWOOLE_HTTP_SERVER_CONFIG_REACTOR_COUNT => 'reactor_num', @@ -48,6 +54,10 @@ class HttpServerConfiguration self::SWOOLE_HTTP_SERVER_CONFIG_TASK_WORKER_COUNT => 'task_worker_num', self::SWOOLE_HTTP_SERVER_CONFIG_WORKER_MAX_REQUEST => 'max_request', self::SWOOLE_HTTP_SERVER_CONFIG_WORKER_MAX_REQUEST_GRACE => 'max_request_grace', + self::SWOOLE_HTTP_SERVER_CONFIG_WORKER_RELOAD_ASYNC => 'reload_async', + self::SWOOLE_HTTP_SERVER_CONFIG_WORKER_EXIT_TIMEOUT_SECONDS => 'max_wait_time', + self::SWOOLE_HTTP_SERVER_CONFIG_COROUTINE_ENABLED => 'enable_coroutine', + self::SWOOLE_HTTP_SERVER_CONFIG_COROUTINE_HOOKS => 'hook_flags', ]; private const SWOOLE_SERVE_STATIC = [ @@ -57,12 +67,34 @@ class HttpServerConfiguration ]; private const SWOOLE_LOG_LEVELS = [ - 'debug' => SWOOLE_LOG_DEBUG, - 'trace' => SWOOLE_LOG_TRACE, - 'info' => SWOOLE_LOG_INFO, - 'notice' => SWOOLE_LOG_NOTICE, - 'warning' => SWOOLE_LOG_WARNING, - 'error' => SWOOLE_LOG_ERROR, + 'debug' => \SWOOLE_LOG_DEBUG, + 'trace' => \SWOOLE_LOG_TRACE, + 'info' => \SWOOLE_LOG_INFO, + 'notice' => \SWOOLE_LOG_NOTICE, + 'warning' => \SWOOLE_LOG_WARNING, + 'error' => \SWOOLE_LOG_ERROR, + ]; + + /** + * @see https://wiki.swoole.com/#/runtime?id=%e9%80%89%e9%a1%b9 + */ + private const SWOOLE_COROUTINE_HOOKS = [ + 'off' => 0, + 'all' => \SWOOLE_HOOK_ALL, + 'tcp' => \SWOOLE_HOOK_TCP, + 'unix' => \SWOOLE_HOOK_UNIX, + 'udp' => \SWOOLE_HOOK_UDP, + 'udg' => \SWOOLE_HOOK_UDG, + 'ssl' => \SWOOLE_HOOK_SSL, + 'tls' => \SWOOLE_HOOK_TLS, + 'sleep' => \SWOOLE_HOOK_SLEEP, + 'file' => \SWOOLE_HOOK_FILE, + 'stream_function' => \SWOOLE_HOOK_STREAM_FUNCTION, + 'blocking_function' => \SWOOLE_HOOK_BLOCKING_FUNCTION, + 'proc' => \SWOOLE_HOOK_PROC, + 'curl' => \SWOOLE_HOOK_CURL, + // 'native_curl' => SWOOLE_HOOK_NATIVE_CURL, // TODO: Swoole >= 4.6.0 + // 'sockets' => SWOOLE_HOOK_SOCKETS, // TODO: Swoole >= 4.6.0 ]; private $sockets; @@ -280,6 +312,19 @@ public function getSwooleDocumentRoot(): ?string return 'default' === $this->settings[self::SWOOLE_HTTP_SERVER_CONFIG_SERVE_STATIC] ? $this->settings[self::SWOOLE_HTTP_SERVER_CONFIG_PUBLIC_DIR] : null; } + /** + * @see getSwooleSettings() + */ + public function getSwooleHookFlags(): int + { + $flags = 0; + foreach ($this->settings[self::SWOOLE_HTTP_SERVER_CONFIG_COROUTINE_HOOKS] as $hookName) { + $flags |= self::SWOOLE_COROUTINE_HOOKS[$hookName]; + } + + return $flags; + } + /** * @see getSwooleSettings() */ @@ -371,7 +416,9 @@ private function validateSetting(string $key, $value): void break; case self::SWOOLE_HTTP_SERVER_CONFIG_DAEMONIZE: - Assertion::boolean($value); + case self::SWOOLE_HTTP_SERVER_CONFIG_COROUTINE_ENABLED: + case self::SWOOLE_HTTP_SERVER_CONFIG_WORKER_RELOAD_ASYNC: + Assertion::boolean($value, \sprintf('Setting "%s" must be a boolean.', $key)); break; case self::SWOOLE_HTTP_SERVER_CONFIG_PUBLIC_DIR: @@ -395,6 +442,7 @@ private function validateSetting(string $key, $value): void case self::SWOOLE_HTTP_SERVER_CONFIG_TASK_WORKER_COUNT: case self::SWOOLE_HTTP_SERVER_CONFIG_REACTOR_COUNT: case self::SWOOLE_HTTP_SERVER_CONFIG_WORKER_COUNT: + case self::SWOOLE_HTTP_SERVER_CONFIG_WORKER_EXIT_TIMEOUT_SECONDS: Assertion::integer($value, \sprintf('Setting "%s" must be an integer.', $key)); Assertion::greaterThan($value, 0, 'Count value cannot be negative, "%s" provided.'); @@ -409,6 +457,10 @@ private function validateSetting(string $key, $value): void Assertion::nullOrGreaterOrEqualThan($value, 0, 'Value cannot be negative, "%s" provided.'); break; + case self::SWOOLE_HTTP_SERVER_CONFIG_COROUTINE_HOOKS: + Assertion::allChoice($value, \array_keys(self::SWOOLE_COROUTINE_HOOKS), \sprintf('Setting "%s" encountered value "%%s" which is not among expected values: %%s', $key)); + + // no break default: return; } diff --git a/src/Server/HttpServerFactory.php b/src/Server/HttpServerFactory.php index c9b017f6..19a7e398 100644 --- a/src/Server/HttpServerFactory.php +++ b/src/Server/HttpServerFactory.php @@ -11,8 +11,8 @@ final class HttpServerFactory { private const SWOOLE_RUNNING_MODE = [ - 'process' => SWOOLE_PROCESS, - 'reactor' => SWOOLE_BASE, + 'process' => \SWOOLE_PROCESS, + 'reactor' => \SWOOLE_BASE, // 'thread' => SWOOLE_THREAD, ]; diff --git a/src/Server/LifecycleHandler/ServerStartHandlerInterface.php b/src/Server/LifecycleHandler/ServerStartHandlerInterface.php index e92a33d3..340e3b0d 100644 --- a/src/Server/LifecycleHandler/ServerStartHandlerInterface.php +++ b/src/Server/LifecycleHandler/ServerStartHandlerInterface.php @@ -9,7 +9,7 @@ interface ServerStartHandlerInterface { /** - * Handle "OnStart" event. + * Handle "OnStart" event. (Process Mode only!). */ public function handle(Server $server): void; } diff --git a/src/Server/LifecycleHandler/SigIntHandler.php b/src/Server/LifecycleHandler/SigIntHandler.php deleted file mode 100644 index 9424f53d..00000000 --- a/src/Server/LifecycleHandler/SigIntHandler.php +++ /dev/null @@ -1,33 +0,0 @@ -decorated = $decorated; - $this->signalInterrupt = \defined('SIGINT') ? (int) \constant('SIGINT') : 2; - } - - /** - * {@inheritdoc} - */ - public function handle(Server $server): void - { - // 2 => SIGINT - Process::signal($this->signalInterrupt, [$server, 'shutdown']); - - if ($this->decorated instanceof ServerStartHandlerInterface) { - $this->decorated->handle($server); - } - } -} diff --git a/src/Server/RequestHandler/AdvancedStaticFilesServer.php b/src/Server/RequestHandler/AdvancedStaticFilesServer.php index c4cfb34b..800d4fdc 100644 --- a/src/Server/RequestHandler/AdvancedStaticFilesServer.php +++ b/src/Server/RequestHandler/AdvancedStaticFilesServer.php @@ -155,11 +155,11 @@ public function handle(Request $request, Response $response): void private function checkPath(string $path): bool { - $extension = \pathinfo($path, PATHINFO_EXTENSION); + $extension = \pathinfo($path, \PATHINFO_EXTENSION); // eg. "file.js.map" if ('map' === $extension) { - $extension = \pathinfo(\pathinfo($path, PATHINFO_FILENAME), PATHINFO_EXTENSION); + $extension = \pathinfo(\pathinfo($path, \PATHINFO_FILENAME), \PATHINFO_EXTENSION); } if (!\file_exists($path) || \is_dir($path)) { diff --git a/src/Server/RequestHandler/ExceptionHandler/JsonExceptionHandler.php b/src/Server/RequestHandler/ExceptionHandler/JsonExceptionHandler.php index f0b9f27a..0ba70279 100644 --- a/src/Server/RequestHandler/ExceptionHandler/JsonExceptionHandler.php +++ b/src/Server/RequestHandler/ExceptionHandler/JsonExceptionHandler.php @@ -27,6 +27,6 @@ public function handle(Request $request, Throwable $exception, Response $respons $response->header(Http::HEADER_CONTENT_TYPE, Http::CONTENT_TYPE_APPLICATION_JSON); $response->status(500); - $response->end(\json_encode($data, JSON_THROW_ON_ERROR)); + $response->end(\json_encode($data, \JSON_THROW_ON_ERROR)); } } diff --git a/src/Server/Runtime/ServerShutdown/SignalServerShutdownHandlerAsServerProcess.php b/src/Server/Runtime/ServerShutdown/SignalServerShutdownHandlerAsServerProcess.php new file mode 100644 index 00000000..42142183 --- /dev/null +++ b/src/Server/Runtime/ServerShutdown/SignalServerShutdownHandlerAsServerProcess.php @@ -0,0 +1,49 @@ +server = $server; + $this->signalHandler = $signalHandler; + $this->processManager = $processManager; + } + + public function run(Process $self): void + { + $run = true; + $this->signalHandler->register(function () use (&$run): void { + $run = false; + $this->server->shutdown(); + }, Signal::int(), Signal::term()); + + $sleepTimes = 0; + while ($run) { + ++$sleepTimes; + \sleep(1); + if (0 === $sleepTimes % 5 && !$this->processManager->runningStatus($this->server->getMasterPid())) { + break; + } + } + } +} diff --git a/src/Server/Runtime/ServerShutdown/SignalServerShutdownHandlerOnServerStart.php b/src/Server/Runtime/ServerShutdown/SignalServerShutdownHandlerOnServerStart.php new file mode 100644 index 00000000..7bd4d7ed --- /dev/null +++ b/src/Server/Runtime/ServerShutdown/SignalServerShutdownHandlerOnServerStart.php @@ -0,0 +1,38 @@ +decorated = $decorated; + $this->signalHandler = $signalHandler; + } + + /** + * {@inheritdoc} + */ + public function handle(Server $server): void + { + // Note: SIGTERM is already registered by Swoole itself + $this->signalHandler->register([$server, 'shutdown'], Signal::int()); + + if ($this->decorated instanceof ServerStartHandlerInterface) { + $this->decorated->handle($server); + } + } +} diff --git a/src/Server/WorkerHandler/ClearAllTimersWorkerExitHandler.php b/src/Server/WorkerHandler/ClearAllTimersWorkerExitHandler.php new file mode 100644 index 00000000..52196c32 --- /dev/null +++ b/src/Server/WorkerHandler/ClearAllTimersWorkerExitHandler.php @@ -0,0 +1,30 @@ +decorated = $decorated; + } + + /** + * {@inheritDoc} + */ + public function handle(Server $worker, int $workerId): void + { + if ($this->decorated instanceof WorkerExitHandlerInterface) { + $this->decorated->handle($worker, $workerId); + } + + Timer::clearAll(); + } +} diff --git a/src/Server/WorkerHandler/NoOpWorkerExitHandler.php b/src/Server/WorkerHandler/NoOpWorkerExitHandler.php new file mode 100644 index 00000000..238977c8 --- /dev/null +++ b/src/Server/WorkerHandler/NoOpWorkerExitHandler.php @@ -0,0 +1,18 @@ +assertNotEmpty($response['headers']['x-debug-token']); $debugToken = $response['headers']['x-debug-token']; - $profilerResponse = $client->send('/_wdt/'.$debugToken)['response']; - - $this->assertStringContainsString('sf-toolbar-block-logger sf-toolbar-status-red', $profilerResponse['body']); + $profilerResponse = $client->send('/_profiler/'.$debugToken)['response']; + $this->assertSame(200, $profilerResponse['statusCode']); + $this->assertStringContainsString('Profiler', $profilerResponse['body']); }); $serverRun->stop(); diff --git a/tests/Fixtures/Symfony/TestBundle/Controller/TaskController.php b/tests/Fixtures/Symfony/TestBundle/Controller/TaskController.php index d2ede069..6a19444a 100644 --- a/tests/Fixtures/Symfony/TestBundle/Controller/TaskController.php +++ b/tests/Fixtures/Symfony/TestBundle/Controller/TaskController.php @@ -23,7 +23,7 @@ final class TaskController public function dispatchMessage(MessageBusInterface $bus, Request $request): Response { $fileName = $request->get('fileName', 'test-default-file.txt'); - $content = $request->get('content', (new \DateTimeImmutable())->format(DATE_ATOM)); + $content = $request->get('content', (new \DateTimeImmutable())->format(\DATE_ATOM)); $message = new CreateFileMessage($fileName, $content); $bus->dispatch($message); diff --git a/tests/Fixtures/Symfony/TestBundle/Test/ServerTestCase.php b/tests/Fixtures/Symfony/TestBundle/Test/ServerTestCase.php index 822f996f..8e459972 100644 --- a/tests/Fixtures/Symfony/TestBundle/Test/ServerTestCase.php +++ b/tests/Fixtures/Symfony/TestBundle/Test/ServerTestCase.php @@ -71,7 +71,7 @@ public function killAllProcessesListeningOnPort(int $port, int $timeout = 1): vo $listProcessesOnPort->run(); if ($listProcessesOnPort->isSuccessful()) { - foreach (\array_filter(\explode(PHP_EOL, $listProcessesOnPort->getOutput())) as $processId) { + foreach (\array_filter(\explode(\PHP_EOL, $listProcessesOnPort->getOutput())) as $processId) { $kill = new Process(['kill', '-9', $processId]); $kill->setTimeout($timeout); $kill->disableOutput(); @@ -94,7 +94,7 @@ public function assertCommandTesterDisplayContainsString(string $expected, Comma { self::assertStringContainsString( $expected, - \preg_replace('!\s+!', ' ', \str_replace(PHP_EOL, '', $commandTester->getDisplay())) + \preg_replace('!\s+!', ' ', \str_replace(\PHP_EOL, '', $commandTester->getDisplay())) ); } diff --git a/tests/Unit/Client/HttpClientTest.php b/tests/Unit/Client/HttpClientTest.php index 872b0a30..980cf8cd 100644 --- a/tests/Unit/Client/HttpClientTest.php +++ b/tests/Unit/Client/HttpClientTest.php @@ -25,7 +25,7 @@ public function testThatClientSerializesProperly(): void 'options' => $options, ]; - self::assertSame(\json_encode($expected, JSON_THROW_ON_ERROR), $client->serialize()); + self::assertSame(\json_encode($expected, \JSON_THROW_ON_ERROR), $client->serialize()); $serializedClient = \serialize($client); $unserializedClient = \unserialize($serializedClient, ['allowed_classes' => [HttpClient::class]]); diff --git a/tests/Unit/Functions/FormatBytesTest.php b/tests/Unit/Functions/FormatBytesTest.php index 3c331c0e..0436c879 100644 --- a/tests/Unit/Functions/FormatBytesTest.php +++ b/tests/Unit/Functions/FormatBytesTest.php @@ -37,7 +37,7 @@ public function bytesFormattedProvider(): array '2 GiB', ], 'PHP_INT_MAX bytes' => [ - PHP_INT_MAX, + \PHP_INT_MAX, '8192 PiB', ], ]; diff --git a/tests/Unit/Process/SwooleProcessSignalHandlerTest.php b/tests/Unit/Process/SwooleProcessSignalHandlerTest.php new file mode 100644 index 00000000..c9fe2d97 --- /dev/null +++ b/tests/Unit/Process/SwooleProcessSignalHandlerTest.php @@ -0,0 +1,47 @@ +swooleProcesSignalHandler = new SwooleProcessSignalHandler(); + } + + public function testSignalRegisteredAndExecuted(): void + { + Runtime::enableCoroutine(true, \SWOOLE_HOOK_ALL); + \go(function (): void { + $signal = new Signal('SIGUSR2'); + $signaled = false; + $this->swooleProcesSignalHandler->register(function () use (&$signaled): void { + $signaled = true; + }, $signal); + + self::assertFalse($signaled); + $this->swooleProcesSignalHandler->kill(\getmypid(), $signal); + \sleep(1); + self::assertTrue($signaled); + }); + Event::wait(); + } + + public function testKillNotExistingProcessExpectSignalException(): void + { + $this->expectException(SignalException::class); + $this->expectExceptionMessage('Unable to kill process having id "9999" using signal "ZERO (0)"'); + $this->swooleProcesSignalHandler->kill(9999, new Signal('ZERO')); + } +} diff --git a/tests/Unit/Server/Configurator/WithWorkerExitHandlerTest.php b/tests/Unit/Server/Configurator/WithWorkerExitHandlerTest.php new file mode 100644 index 00000000..cad1a2e2 --- /dev/null +++ b/tests/Unit/Server/Configurator/WithWorkerExitHandlerTest.php @@ -0,0 +1,36 @@ +noOpWorkerExitHandler = new NoOpWorkerExitHandler(); + + $this->configurator = new WithWorkerExitHandler($this->noOpWorkerExitHandler); + } + + public function testConfigure(): void + { + $swooleServerOnEventSpy = SwooleHttpServerMock::make(); + + $this->configurator->configure($swooleServerOnEventSpy); + + self::assertTrue($swooleServerOnEventSpy->registeredEvent); + self::assertSame(['WorkerExit', [$this->noOpWorkerExitHandler, 'handle']], $swooleServerOnEventSpy->registeredEventPair); + } +} diff --git a/tests/Unit/Server/SwooleHttpServerDummy.php b/tests/Unit/Server/SwooleHttpServerDummy.php index f2e5385a..b092b613 100644 --- a/tests/Unit/Server/SwooleHttpServerDummy.php +++ b/tests/Unit/Server/SwooleHttpServerDummy.php @@ -84,7 +84,7 @@ public function shutdown(): void { } - public function addListener($host, $port, $type = SWOOLE_SOCK_TCP): void + public function addListener($host, $port, $type = \SWOOLE_SOCK_TCP): void { } @@ -96,7 +96,7 @@ public function after($after_time_ms, $callback_function, $param = null): void { } - public function listen($host, $port, $type = SWOOLE_SOCK_TCP): void + public function listen($host, $port, $type = \SWOOLE_SOCK_TCP): void { } diff --git a/tests/Unit/Server/WorkerHandler/ClearAllTimersWorkerExitHandlerTest.php b/tests/Unit/Server/WorkerHandler/ClearAllTimersWorkerExitHandlerTest.php new file mode 100644 index 00000000..9a410eb4 --- /dev/null +++ b/tests/Unit/Server/WorkerHandler/ClearAllTimersWorkerExitHandlerTest.php @@ -0,0 +1,51 @@ +workerExitHandlerProphecy = $this->prophesize(WorkerExitHandlerInterface::class); + + $this->clearAllTimersWorkerExitHandler = new ClearAllTimersWorkerExitHandler($this->workerExitHandlerProphecy->reveal()); + } + + public function testClearAllTimersAfterHandle(): void + { + $timerId = Timer::tick(1000, function (): void {}); + self::assertFalse(Timer::info($timerId)['removed']); + + $serverMock = SwooleServerMock::make(); + $workerId = IntMother::random(); + + $this->workerExitHandlerProphecy->handle($serverMock, $workerId) + ->shouldBeCalled() + ; + + $this->clearAllTimersWorkerExitHandler->handle($serverMock, $workerId); + + self::assertNull(Timer::info($timerId)); + } +}