diff --git a/composer.lock b/composer.lock index 0c8514b945ace5ebb9e720450585f7d3023e946a..464fd3d9ead5c9eb45c4d675936d88954e6960b4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c3bebdab1f5cd01e6c038f6defc7bdbe", + "content-hash": "b5ae8ece34266c0c406aaf2c5765e2a2", "packages": [ { "name": "composer/ca-bundle", - "version": "1.3.2", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "fd5dd441932a7e10ca6e5b490e272d34c8430640" + "reference": "30897edbfb15e784fe55587b4f73ceefd3c4d98c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/fd5dd441932a7e10ca6e5b490e272d34c8430640", - "reference": "fd5dd441932a7e10ca6e5b490e272d34c8430640", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/30897edbfb15e784fe55587b4f73ceefd3c4d98c", + "reference": "30897edbfb15e784fe55587b4f73ceefd3c4d98c", "shasum": "" }, "require": { @@ -64,7 +64,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.3.2" + "source": "https://github.com/composer/ca-bundle/tree/1.3.3" }, "funding": [ { @@ -80,28 +80,102 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:56:16+00:00" + "time": "2022-07-20T07:14:26+00:00" + }, + { + "name": "composer/class-map-generator", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/composer/class-map-generator.git", + "reference": "1e1cb2b791facb2dfe32932a7718cf2571187513" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/1e1cb2b791facb2dfe32932a7718cf2571187513", + "reference": "1e1cb2b791facb2dfe32932a7718cf2571187513", + "shasum": "" + }, + "require": { + "composer/pcre": "^2 || ^3", + "php": "^7.2 || ^8.0", + "symfony/finder": "^4.4 || ^5.3 || ^6" + }, + "require-dev": { + "phpstan/phpstan": "^1.6", + "phpstan/phpstan-deprecation-rules": "^1", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/filesystem": "^5.4 || ^6", + "symfony/phpunit-bridge": "^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\ClassMapGenerator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Utilities to scan PHP code and generate class maps.", + "keywords": [ + "classmap" + ], + "support": { + "issues": "https://github.com/composer/class-map-generator/issues", + "source": "https://github.com/composer/class-map-generator/tree/1.0.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-06-19T11:31:27+00:00" }, { "name": "composer/composer", - "version": "2.3.7", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "10cd375cf85dede2ff417ceab517ef9a0dc55407" + "reference": "026d6de6ea2c913974a7756661a3faac135cb36e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/10cd375cf85dede2ff417ceab517ef9a0dc55407", - "reference": "10cd375cf85dede2ff417ceab517ef9a0dc55407", + "url": "https://api.github.com/repos/composer/composer/zipball/026d6de6ea2c913974a7756661a3faac135cb36e", + "reference": "026d6de6ea2c913974a7756661a3faac135cb36e", "shasum": "" }, "require": { "composer/ca-bundle": "^1.0", + "composer/class-map-generator": "^1.0", "composer/metadata-minifier": "^1.0", "composer/pcre": "^2 || ^3", "composer/semver": "^3.0", - "composer/spdx-licenses": "^1.2", + "composer/spdx-licenses": "^1.5.7", "composer/xdebug-handler": "^2.0.2 || ^3.0.3", "justinrainbow/json-schema": "^5.2.11", "php": "^7.2.5 || ^8.0", @@ -109,7 +183,8 @@ "react/promise": "^2.8", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.2", - "symfony/console": "^5.4.7 || ^6.0.7", + "seld/signal-handler": "^2.0", + "symfony/console": "^5.4.11 || ^6.0.11", "symfony/filesystem": "^5.4 || ^6.0", "symfony/finder": "^5.4 || ^6.0", "symfony/polyfill-php73": "^1.24", @@ -135,7 +210,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.3-dev" + "dev-main": "2.4-dev" }, "phpstan": { "includes": [ @@ -174,7 +249,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/2.3.7" + "source": "https://github.com/composer/composer/tree/2.4.0" }, "funding": [ { @@ -190,7 +265,7 @@ "type": "tidelift" } ], - "time": "2022-06-06T14:43:28+00:00" + "time": "2022-08-16T14:10:48+00:00" }, { "name": "composer/metadata-minifier", @@ -654,16 +729,16 @@ }, { "name": "doctrine/dbal", - "version": "3.3.6", + "version": "3.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "9e7f76dd1cde81c62574fdffa5a9c655c847ad21" + "reference": "94e016428884227245fb1219e0de7d8b86ca16d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/9e7f76dd1cde81c62574fdffa5a9c655c847ad21", - "reference": "9e7f76dd1cde81c62574fdffa5a9c655c847ad21", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/94e016428884227245fb1219e0de7d8b86ca16d7", + "reference": "94e016428884227245fb1219e0de7d8b86ca16d7", "shasum": "" }, "require": { @@ -671,21 +746,21 @@ "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3|^1", "doctrine/event-manager": "^1.0", - "php": "^7.3 || ^8.0", + "php": "^7.4 || ^8.0", "psr/cache": "^1|^2|^3", "psr/log": "^1|^2|^3" }, "require-dev": { "doctrine/coding-standard": "9.0.0", "jetbrains/phpstorm-stubs": "2022.1", - "phpstan/phpstan": "1.6.3", - "phpstan/phpstan-strict-rules": "^1.2", - "phpunit/phpunit": "9.5.20", - "psalm/plugin-phpunit": "0.16.1", - "squizlabs/php_codesniffer": "3.6.2", - "symfony/cache": "^5.2|^6.0", - "symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0", - "vimeo/psalm": "4.23.0" + "phpstan/phpstan": "1.8.2", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "9.5.21", + "psalm/plugin-phpunit": "0.17.0", + "squizlabs/php_codesniffer": "3.7.1", + "symfony/cache": "^5.4|^6.0", + "symfony/console": "^4.4|^5.4|^6.0", + "vimeo/psalm": "4.24.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -745,7 +820,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.3.6" + "source": "https://github.com/doctrine/dbal/tree/3.4.1" }, "funding": [ { @@ -761,7 +836,7 @@ "type": "tidelift" } ], - "time": "2022-05-02T17:21:01+00:00" + "time": "2022-08-16T18:37:46+00:00" }, { "name": "doctrine/deprecations", @@ -808,34 +883,31 @@ }, { "name": "doctrine/event-manager", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f" + "reference": "eb2ecf80e3093e8f3c2769ac838e27d8ede8e683" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/41370af6a30faa9dc0368c4a6814d596e81aba7f", - "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/eb2ecf80e3093e8f3c2769ac838e27d8ede8e683", + "reference": "eb2ecf80e3093e8f3c2769ac838e27d8ede8e683", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "conflict": { - "doctrine/common": "<2.9@dev" + "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpunit/phpunit": "^7.0" + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "~1.4.10 || ^1.5.4", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.22" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\": "lib/Doctrine/Common" @@ -882,7 +954,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/1.1.x" + "source": "https://github.com/doctrine/event-manager/tree/1.1.2" }, "funding": [ { @@ -898,20 +970,20 @@ "type": "tidelift" } ], - "time": "2020-05-29T18:28:51+00:00" + "time": "2022-07-27T22:18:11+00:00" }, { "name": "gettext/gettext", - "version": "v5.6.1", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/php-gettext/Gettext.git", - "reference": "017e249601d32b9a88c2eb4c10eac89bf582a7d3" + "reference": "8657e580747bb3baacccdcebe69cac094661e404" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-gettext/Gettext/zipball/017e249601d32b9a88c2eb4c10eac89bf582a7d3", - "reference": "017e249601d32b9a88c2eb4c10eac89bf582a7d3", + "url": "https://api.github.com/repos/php-gettext/Gettext/zipball/8657e580747bb3baacccdcebe69cac094661e404", + "reference": "8657e580747bb3baacccdcebe69cac094661e404", "shasum": "" }, "require": { @@ -956,7 +1028,7 @@ "support": { "email": "oom@oscarotero.com", "issues": "https://github.com/php-gettext/Gettext/issues", - "source": "https://github.com/php-gettext/Gettext/tree/v5.6.1" + "source": "https://github.com/php-gettext/Gettext/tree/v5.7.0" }, "funding": [ { @@ -972,7 +1044,7 @@ "type": "patreon" } ], - "time": "2021-12-04T11:33:21+00:00" + "time": "2022-07-27T19:54:55+00:00" }, { "name": "gettext/languages", @@ -1194,16 +1266,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.6.2", + "version": "v6.6.3", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "b52ed06864fdda81b82ec8bf564cf15d45ed4f95" + "reference": "9400f305a898f194caff5521f64e5dfa926626f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/b52ed06864fdda81b82ec8bf564cf15d45ed4f95", - "reference": "b52ed06864fdda81b82ec8bf564cf15d45ed4f95", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/9400f305a898f194caff5521f64e5dfa926626f3", + "reference": "9400f305a898f194caff5521f64e5dfa926626f3", "shasum": "" }, "require": { @@ -1260,7 +1332,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.2" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.3" }, "funding": [ { @@ -1268,7 +1340,7 @@ "type": "github" } ], - "time": "2022-06-14T09:27:21+00:00" + "time": "2022-06-20T09:21:02+00:00" }, { "name": "psr/cache", @@ -1697,32 +1769,93 @@ }, "time": "2021-12-10T11:20:11+00:00" }, + { + "name": "seld/signal-handler", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/signal-handler.git", + "reference": "f69d119511dc0360440cdbdaa71829c149b7be75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/signal-handler/zipball/f69d119511dc0360440cdbdaa71829c149b7be75", + "reference": "f69d119511dc0360440cdbdaa71829c149b7be75", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "phpstan/phpstan": "^1", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^7.5.20 || ^8.5.23", + "psr/log": "^1 || ^2 || ^3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\Signal\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Simple unix signal handler that silently fails where signals are not supported for easy cross-platform development", + "keywords": [ + "posix", + "sigint", + "signal", + "sigterm", + "unix" + ], + "support": { + "issues": "https://github.com/Seldaek/signal-handler/issues", + "source": "https://github.com/Seldaek/signal-handler/tree/2.0.1" + }, + "time": "2022-07-20T18:31:45+00:00" + }, { "name": "simplesamlphp/assert", - "version": "v0.2.13", + "version": "v0.3.3", "source": { "type": "git", "url": "https://github.com/simplesamlphp/assert.git", - "reference": "72a16329cf95b148717aadd258fbe36ac96cf004" + "reference": "9af4fe36e7b2a9c4d0695a8e8ad118c39b9e3564" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/simplesamlphp/assert/zipball/72a16329cf95b148717aadd258fbe36ac96cf004", - "reference": "72a16329cf95b148717aadd258fbe36ac96cf004", + "url": "https://api.github.com/repos/simplesamlphp/assert/zipball/9af4fe36e7b2a9c4d0695a8e8ad118c39b9e3564", + "reference": "9af4fe36e7b2a9c4d0695a8e8ad118c39b9e3564", "shasum": "" }, "require": { "ext-spl": "*", "php": "^7.4 || ^8.0", - "webmozart/assert": "^1.10" + "webmozart/assert": "^1.11" }, "require-dev": { - "simplesamlphp/simplesamlphp-test-framework": "^1.0.5" + "simplesamlphp/simplesamlphp-test-framework": "^1.2.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "v0.1.x-dev" + "dev-master": "v0.2.x-dev" } }, "autoload": { @@ -1747,9 +1880,9 @@ "description": "A wrapper around webmozart/assert to make it useful beyond checking method arguments", "support": { "issues": "https://github.com/simplesamlphp/assert/issues", - "source": "https://github.com/simplesamlphp/assert/tree/v0.2.13" + "source": "https://github.com/simplesamlphp/assert/tree/v0.3.3" }, - "time": "2022-02-17T21:38:59+00:00" + "time": "2022-08-02T21:14:39+00:00" }, { "name": "simplesamlphp/composer-module-installer", @@ -1849,16 +1982,16 @@ }, { "name": "simplesamlphp/simplesamlphp", - "version": "v2.0.0-beta.11", + "version": "v2.0.0-rc1", "source": { "type": "git", "url": "https://github.com/simplesamlphp/simplesamlphp.git", - "reference": "9c2ee532a78fecf67d1b985cd79d61a705fb0d9f" + "reference": "cf68e6ef7aaecf75d434023adfe30913d993f015" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp/zipball/9c2ee532a78fecf67d1b985cd79d61a705fb0d9f", - "reference": "9c2ee532a78fecf67d1b985cd79d61a705fb0d9f", + "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp/zipball/cf68e6ef7aaecf75d434023adfe30913d993f015", + "reference": "cf68e6ef7aaecf75d434023adfe30913d993f015", "shasum": "" }, "require": { @@ -1877,8 +2010,8 @@ "gettext/translator": "^1.0.1", "php": ">=7.4 || ^8.0", "phpmailer/phpmailer": "^6.5", - "simplesamlphp/assert": "^0.2.11", - "simplesamlphp/saml2": "^4.5", + "simplesamlphp/assert": "^0.3.0", + "simplesamlphp/saml2": "^4.6", "symfony/cache": "^5.4", "symfony/config": "^5.4", "symfony/console": "^5.4", @@ -1901,9 +2034,9 @@ "ext-curl": "*", "ext-pdo_sqlite": "*", "mikey179/vfsstream": "~1.6", - "simplesamlphp/simplesamlphp-module-adfs": ">=2.0.0-rc1", - "simplesamlphp/simplesamlphp-test-framework": "^1.2.0", - "simplesamlphp/xml-security": "^0.4.1" + "simplesamlphp/simplesamlphp-module-adfs": ">=2.0.0-rc2", + "simplesamlphp/simplesamlphp-test-framework": "^1.2.1", + "simplesamlphp/xml-security": "^0.4.5" }, "suggest": { "ext-curl": "Needed in order to check for updates automatically", @@ -1961,20 +2094,20 @@ "issues": "https://github.com/simplesamlphp/simplesamlphp/issues", "source": "https://github.com/simplesamlphp/simplesamlphp" }, - "time": "2022-06-04T09:48:27+00:00" + "time": "2022-07-01T19:47:50+00:00" }, { "name": "symfony/cache", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "a50b7249bea81ddd6d3b799ce40c5521c2f72f0b" + "reference": "5a0fff46df349f0db3fe242263451fddf5277362" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/a50b7249bea81ddd6d3b799ce40c5521c2f72f0b", - "reference": "a50b7249bea81ddd6d3b799ce40c5521c2f72f0b", + "url": "https://api.github.com/repos/symfony/cache/zipball/5a0fff46df349f0db3fe242263451fddf5277362", + "reference": "5a0fff46df349f0db3fe242263451fddf5277362", "shasum": "" }, "require": { @@ -2042,7 +2175,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v5.4.9" + "source": "https://github.com/symfony/cache/tree/v5.4.11" }, "funding": [ { @@ -2058,11 +2191,11 @@ "type": "tidelift" } ], - "time": "2022-05-21T10:24:18+00:00" + "time": "2022-07-28T15:25:17+00:00" }, { "name": "symfony/cache-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", @@ -2121,7 +2254,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" }, "funding": [ { @@ -2141,16 +2274,16 @@ }, { "name": "symfony/config", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "8f551fe22672ac7ab2c95fe46d899f960ed4d979" + "reference": "ec79e03125c1d2477e43dde8528535d90cc78379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/8f551fe22672ac7ab2c95fe46d899f960ed4d979", - "reference": "8f551fe22672ac7ab2c95fe46d899f960ed4d979", + "url": "https://api.github.com/repos/symfony/config/zipball/ec79e03125c1d2477e43dde8528535d90cc78379", + "reference": "ec79e03125c1d2477e43dde8528535d90cc78379", "shasum": "" }, "require": { @@ -2200,7 +2333,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.9" + "source": "https://github.com/symfony/config/tree/v5.4.11" }, "funding": [ { @@ -2216,20 +2349,20 @@ "type": "tidelift" } ], - "time": "2022-05-17T10:39:36+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/console", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb" + "reference": "535846c7ee6bc4dd027ca0d93220601456734b10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb", - "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb", + "url": "https://api.github.com/repos/symfony/console/zipball/535846c7ee6bc4dd027ca0d93220601456734b10", + "reference": "535846c7ee6bc4dd027ca0d93220601456734b10", "shasum": "" }, "require": { @@ -2299,7 +2432,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.9" + "source": "https://github.com/symfony/console/tree/v5.4.11" }, "funding": [ { @@ -2315,20 +2448,20 @@ "type": "tidelift" } ], - "time": "2022-05-18T06:17:34+00:00" + "time": "2022-07-22T10:42:43+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "beecae161577305926ec078c4ed973f2b98880b3" + "reference": "a8b9251016e9476db73e25fa836904bc0bf74c62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/beecae161577305926ec078c4ed973f2b98880b3", - "reference": "beecae161577305926ec078c4ed973f2b98880b3", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a8b9251016e9476db73e25fa836904bc0bf74c62", + "reference": "a8b9251016e9476db73e25fa836904bc0bf74c62", "shasum": "" }, "require": { @@ -2388,7 +2521,7 @@ "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.4.9" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.11" }, "funding": [ { @@ -2404,11 +2537,11 @@ "type": "tidelift" } ], - "time": "2022-05-27T06:40:03+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -2455,7 +2588,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -2475,16 +2608,16 @@ }, { "name": "symfony/error-handler", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "c116cda1f51c678782768dce89a45f13c949455d" + "reference": "f75d17cb4769eb38cd5fccbda95cd80a054d35c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/c116cda1f51c678782768dce89a45f13c949455d", - "reference": "c116cda1f51c678782768dce89a45f13c949455d", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/f75d17cb4769eb38cd5fccbda95cd80a054d35c8", + "reference": "f75d17cb4769eb38cd5fccbda95cd80a054d35c8", "shasum": "" }, "require": { @@ -2526,7 +2659,7 @@ "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.4.9" + "source": "https://github.com/symfony/error-handler/tree/v5.4.11" }, "funding": [ { @@ -2542,7 +2675,7 @@ "type": "tidelift" } ], - "time": "2022-05-21T13:57:48+00:00" + "time": "2022-07-29T07:37:50+00:00" }, { "name": "symfony/event-dispatcher", @@ -2631,7 +2764,7 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", @@ -2690,7 +2823,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" }, "funding": [ { @@ -2710,16 +2843,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba" + "reference": "6699fb0228d1bc35b12aed6dd5e7455457609ddd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/36a017fa4cce1eff1b8e8129ff53513abcef05ba", - "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/6699fb0228d1bc35b12aed6dd5e7455457609ddd", + "reference": "6699fb0228d1bc35b12aed6dd5e7455457609ddd", "shasum": "" }, "require": { @@ -2754,7 +2887,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.9" + "source": "https://github.com/symfony/filesystem/tree/v5.4.11" }, "funding": [ { @@ -2770,20 +2903,20 @@ "type": "tidelift" } ], - "time": "2022-05-20T13:55:35+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/finder", - "version": "v5.4.8", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9" + "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9b630f3427f3ebe7cd346c277a1408b00249dad9", - "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9", + "url": "https://api.github.com/repos/symfony/finder/zipball/7872a66f57caffa2916a584db1aa7f12adc76f8c", + "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c", "shasum": "" }, "require": { @@ -2817,7 +2950,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.8" + "source": "https://github.com/symfony/finder/tree/v5.4.11" }, "funding": [ { @@ -2833,20 +2966,20 @@ "type": "tidelift" } ], - "time": "2022-04-15T08:07:45+00:00" + "time": "2022-07-29T07:37:50+00:00" }, { "name": "symfony/framework-bundle", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "1cb89cd3e36d5060545d0f223f00a774fa6430ef" + "reference": "a0660b602357d5c2ceaac1c9f80c5820bbff803d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/1cb89cd3e36d5060545d0f223f00a774fa6430ef", - "reference": "1cb89cd3e36d5060545d0f223f00a774fa6430ef", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/a0660b602357d5c2ceaac1c9f80c5820bbff803d", + "reference": "a0660b602357d5c2ceaac1c9f80c5820bbff803d", "shasum": "" }, "require": { @@ -2968,7 +3101,7 @@ "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.4.9" + "source": "https://github.com/symfony/framework-bundle/tree/v5.4.11" }, "funding": [ { @@ -2984,20 +3117,20 @@ "type": "tidelift" } ], - "time": "2022-05-27T06:29:07+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "6b0d0e4aca38d57605dcd11e2416994b38774522" + "reference": "0a5868e0999e9d47859ba3d918548ff6943e6389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6b0d0e4aca38d57605dcd11e2416994b38774522", - "reference": "6b0d0e4aca38d57605dcd11e2416994b38774522", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0a5868e0999e9d47859ba3d918548ff6943e6389", + "reference": "0a5868e0999e9d47859ba3d918548ff6943e6389", "shasum": "" }, "require": { @@ -3041,7 +3174,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.9" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.11" }, "funding": [ { @@ -3057,20 +3190,20 @@ "type": "tidelift" } ], - "time": "2022-05-17T15:07:29+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "34b121ad3dc761f35fe1346d2f15618f8cbf77f8" + "reference": "4fd590a2ef3f62560dbbf6cea511995dd77321ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/34b121ad3dc761f35fe1346d2f15618f8cbf77f8", - "reference": "34b121ad3dc761f35fe1346d2f15618f8cbf77f8", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4fd590a2ef3f62560dbbf6cea511995dd77321ee", + "reference": "4fd590a2ef3f62560dbbf6cea511995dd77321ee", "shasum": "" }, "require": { @@ -3153,7 +3286,7 @@ "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.4.9" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.11" }, "funding": [ { @@ -3169,20 +3302,20 @@ "type": "tidelift" } ], - "time": "2022-05-27T07:09:08+00:00" + "time": "2022-07-29T12:30:22+00:00" }, { "name": "symfony/intl", - "version": "v5.4.8", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "b9e17d7ab867ce99f89950ebced0fa91076ba12b" + "reference": "d305c0c1d31b30b3876e041804c35e49e5f8a96e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/b9e17d7ab867ce99f89950ebced0fa91076ba12b", - "reference": "b9e17d7ab867ce99f89950ebced0fa91076ba12b", + "url": "https://api.github.com/repos/symfony/intl/zipball/d305c0c1d31b30b3876e041804c35e49e5f8a96e", + "reference": "d305c0c1d31b30b3876e041804c35e49e5f8a96e", "shasum": "" }, "require": { @@ -3241,7 +3374,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v5.4.8" + "source": "https://github.com/symfony/intl/tree/v5.4.11" }, "funding": [ { @@ -3257,7 +3390,7 @@ "type": "tidelift" } ], - "time": "2022-04-07T09:39:59+00:00" + "time": "2022-07-20T11:34:24+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3832,16 +3965,16 @@ }, { "name": "symfony/process", - "version": "v5.4.8", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3" + "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", - "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", + "url": "https://api.github.com/repos/symfony/process/zipball/6e75fe6874cbc7e4773d049616ab450eff537bf1", + "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1", "shasum": "" }, "require": { @@ -3874,7 +4007,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.8" + "source": "https://github.com/symfony/process/tree/v5.4.11" }, "funding": [ { @@ -3890,20 +4023,20 @@ "type": "tidelift" } ], - "time": "2022-04-08T05:07:18+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "symfony/routing", - "version": "v5.4.8", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "e07817bb6244ea33ef5ad31abc4a9288bef3f2f7" + "reference": "3e01ccd9b2a3a4167ba2b3c53612762300300226" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/e07817bb6244ea33ef5ad31abc4a9288bef3f2f7", - "reference": "e07817bb6244ea33ef5ad31abc4a9288bef3f2f7", + "url": "https://api.github.com/repos/symfony/routing/zipball/3e01ccd9b2a3a4167ba2b3c53612762300300226", + "reference": "3e01ccd9b2a3a4167ba2b3c53612762300300226", "shasum": "" }, "require": { @@ -3964,7 +4097,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.8" + "source": "https://github.com/symfony/routing/tree/v5.4.11" }, "funding": [ { @@ -3980,20 +4113,20 @@ "type": "tidelift" } ], - "time": "2022-04-18T21:45:37+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", "shasum": "" }, "require": { @@ -4047,7 +4180,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" }, "funding": [ { @@ -4063,20 +4196,20 @@ "type": "tidelift" } ], - "time": "2022-03-13T20:07:29+00:00" + "time": "2022-05-30T19:17:29+00:00" }, { "name": "symfony/string", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99" + "reference": "5eb661e49ad389e4ae2b6e4df8d783a8a6548322" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/985e6a9703ef5ce32ba617c9c7d97873bb7b2a99", - "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99", + "url": "https://api.github.com/repos/symfony/string/zipball/5eb661e49ad389e4ae2b6e4df8d783a8a6548322", + "reference": "5eb661e49ad389e4ae2b6e4df8d783a8a6548322", "shasum": "" }, "require": { @@ -4133,7 +4266,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.9" + "source": "https://github.com/symfony/string/tree/v5.4.11" }, "funding": [ { @@ -4149,20 +4282,20 @@ "type": "tidelift" } ], - "time": "2022-04-19T10:40:37+00:00" + "time": "2022-07-24T16:15:25+00:00" }, { "name": "symfony/translation-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "1211df0afa701e45a04253110e959d4af4ef0f07" + "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/1211df0afa701e45a04253110e959d4af4ef0f07", - "reference": "1211df0afa701e45a04253110e959d4af4ef0f07", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/136b19dd05cdf0709db6537d058bcab6dd6e2dbe", + "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe", "shasum": "" }, "require": { @@ -4211,7 +4344,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/translation-contracts/tree/v2.5.2" }, "funding": [ { @@ -4227,20 +4360,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "symfony/twig-bridge", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "fd13c89a1abdbaa7ee2e655d9a11405adcb7a6cf" + "reference": "63b8a50d48c9fe3d04e77307d4f1771dd848baa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/fd13c89a1abdbaa7ee2e655d9a11405adcb7a6cf", - "reference": "fd13c89a1abdbaa7ee2e655d9a11405adcb7a6cf", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/63b8a50d48c9fe3d04e77307d4f1771dd848baa8", + "reference": "63b8a50d48c9fe3d04e77307d4f1771dd848baa8", "shasum": "" }, "require": { @@ -4332,7 +4465,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v5.4.9" + "source": "https://github.com/symfony/twig-bridge/tree/v5.4.11" }, "funding": [ { @@ -4348,20 +4481,20 @@ "type": "tidelift" } ], - "time": "2022-05-21T10:24:18+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.9", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "af52239a330fafd192c773795520dc2dd62b5657" + "reference": "b8f306d7b8ef34fb3db3305be97ba8e088fb4861" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/af52239a330fafd192c773795520dc2dd62b5657", - "reference": "af52239a330fafd192c773795520dc2dd62b5657", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8f306d7b8ef34fb3db3305be97ba8e088fb4861", + "reference": "b8f306d7b8ef34fb3db3305be97ba8e088fb4861", "shasum": "" }, "require": { @@ -4421,7 +4554,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.9" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.11" }, "funding": [ { @@ -4437,20 +4570,20 @@ "type": "tidelift" } ], - "time": "2022-05-21T10:24:18+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/var-exporter", - "version": "v5.4.9", + "version": "v5.4.10", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "63249ebfca4e75a357679fa7ba2089cfb898aa67" + "reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/63249ebfca4e75a357679fa7ba2089cfb898aa67", - "reference": "63249ebfca4e75a357679fa7ba2089cfb898aa67", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/8fc03ee75eeece3d9be1ef47d26d79bea1afb340", + "reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340", "shasum": "" }, "require": { @@ -4494,7 +4627,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v5.4.9" + "source": "https://github.com/symfony/var-exporter/tree/v5.4.10" }, "funding": [ { @@ -4510,20 +4643,20 @@ "type": "tidelift" } ], - "time": "2022-05-21T10:24:18+00:00" + "time": "2022-05-27T12:56:18+00:00" }, { "name": "symfony/yaml", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e80f87d2c9495966768310fc531b487ce64237a2" + "reference": "05d4ea560f3402c6c116afd99fdc66e60eda227e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e80f87d2c9495966768310fc531b487ce64237a2", - "reference": "e80f87d2c9495966768310fc531b487ce64237a2", + "url": "https://api.github.com/repos/symfony/yaml/zipball/05d4ea560f3402c6c116afd99fdc66e60eda227e", + "reference": "05d4ea560f3402c6c116afd99fdc66e60eda227e", "shasum": "" }, "require": { @@ -4569,7 +4702,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.3" + "source": "https://github.com/symfony/yaml/tree/v5.4.11" }, "funding": [ { @@ -4585,20 +4718,20 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:32:32+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "twig/intl-extra", - "version": "v3.4.0", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/twigphp/intl-extra.git", - "reference": "8dca6f4c5a00cdd3c43b6bd080f50d32aca33a84" + "reference": "151e50fad9c7915bd56f0adf3f0cb3c47e6ed28a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/8dca6f4c5a00cdd3c43b6bd080f50d32aca33a84", - "reference": "8dca6f4c5a00cdd3c43b6bd080f50d32aca33a84", + "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/151e50fad9c7915bd56f0adf3f0cb3c47e6ed28a", + "reference": "151e50fad9c7915bd56f0adf3f0cb3c47e6ed28a", "shasum": "" }, "require": { @@ -4642,7 +4775,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/intl-extra/tree/v3.4.0" + "source": "https://github.com/twigphp/intl-extra/tree/v3.4.2" }, "funding": [ { @@ -4654,20 +4787,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T10:02:25+00:00" + "time": "2022-06-10T08:33:05+00:00" }, { "name": "twig/twig", - "version": "v3.4.1", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "e939eae92386b69b49cfa4599dd9bead6bf4a342" + "reference": "e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/e939eae92386b69b49cfa4599dd9bead6bf4a342", - "reference": "e939eae92386b69b49cfa4599dd9bead6bf4a342", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077", + "reference": "e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077", "shasum": "" }, "require": { @@ -4718,7 +4851,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.4.1" + "source": "https://github.com/twigphp/Twig/tree/v3.4.2" }, "funding": [ { @@ -4730,7 +4863,7 @@ "type": "tidelift" } ], - "time": "2022-05-17T05:48:52+00:00" + "time": "2022-08-12T06:47:24+00:00" }, { "name": "webmozart/assert", @@ -6116,16 +6249,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.20", + "version": "9.5.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba" + "reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/12bc8879fb65aef2138b26fc633cb1e3620cffba", - "reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0e32b76be457de00e83213528f6bb37e2a38fcb1", + "reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1", "shasum": "" }, "require": { @@ -6159,7 +6292,6 @@ "sebastian/version": "^3.0.2" }, "require-dev": { - "ext-pdo": "*", "phpspec/prophecy-phpunit": "^2.0.1" }, "suggest": { @@ -6203,7 +6335,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.21" }, "funding": [ { @@ -6215,7 +6347,7 @@ "type": "github" } ], - "time": "2022-04-01T12:37:26+00:00" + "time": "2022-06-19T12:14:25+00:00" }, { "name": "sebastian/cli-parser", @@ -7240,16 +7372,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.0", + "version": "3.7.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "a2cd51b45bcaef9c1f2a4bda48f2dd2fa2b95563" + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/a2cd51b45bcaef9c1f2a4bda48f2dd2fa2b95563", - "reference": "a2cd51b45bcaef9c1f2a4bda48f2dd2fa2b95563", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", "shasum": "" }, "require": { @@ -7292,20 +7424,20 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2022-06-13T06:31:38+00:00" + "time": "2022-06-18T07:21:10+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v6.1.0", + "version": "v6.1.3", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "092ccc3b364925cd8ed6046bc31dcf3a022bd5a4" + "reference": "75c2fa71d049c1f48e39d208c0cefba97e66335a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/092ccc3b364925cd8ed6046bc31dcf3a022bd5a4", - "reference": "092ccc3b364925cd8ed6046bc31dcf3a022bd5a4", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/75c2fa71d049c1f48e39d208c0cefba97e66335a", + "reference": "75c2fa71d049c1f48e39d208c0cefba97e66335a", "shasum": "" }, "require": { @@ -7359,7 +7491,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v6.1.0" + "source": "https://github.com/symfony/phpunit-bridge/tree/v6.1.3" }, "funding": [ { @@ -7375,7 +7507,7 @@ "type": "tidelift" } ], - "time": "2022-04-12T16:22:53+00:00" + "time": "2022-07-28T13:40:41+00:00" }, { "name": "theseer/tokenizer", @@ -7429,16 +7561,16 @@ }, { "name": "vimeo/psalm", - "version": "4.23.0", + "version": "4.26.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88" + "reference": "6998fabb2bf528b65777bf9941920888d23c03ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/f1fe6ff483bf325c803df9f510d09a03fd796f88", - "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/6998fabb2bf528b65777bf9941920888d23c03ac", + "reference": "6998fabb2bf528b65777bf9941920888d23c03ac", "shasum": "" }, "require": { @@ -7530,9 +7662,9 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/4.23.0" + "source": "https://github.com/vimeo/psalm/tree/4.26.0" }, - "time": "2022-04-28T17:35:49+00:00" + "time": "2022-07-31T13:10:26+00:00" }, { "name": "webmozart/path-util", diff --git a/src/Entities/AuthenticationEvent/Job.php b/src/Entities/AuthenticationEvent/Job.php index 51308d6fbba4657e453e3b7b4d80240897d91036..eaa66aba53624337e61f73e3417e25f7e0bac2fa 100644 --- a/src/Entities/AuthenticationEvent/Job.php +++ b/src/Entities/AuthenticationEvent/Job.php @@ -5,11 +5,11 @@ declare(strict_types=1); namespace SimpleSAML\Module\accounting\Entities\AuthenticationEvent; use SimpleSAML\Module\accounting\Entities\AuthenticationEvent; +use SimpleSAML\Module\accounting\Entities\Bases\AbstractJob; use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload; -use SimpleSAML\Module\accounting\Entities\GenericJob; use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException; -class Job extends GenericJob +class Job extends AbstractJob { public function getPayload(): AuthenticationEvent { @@ -24,9 +24,14 @@ class Job extends GenericJob protected function validatePayload(AbstractPayload $payload): AuthenticationEvent { if (! ($payload instanceof AuthenticationEvent)) { - throw new UnexpectedValueException('Job payload must be of type AuthenticationEvent.'); + throw new UnexpectedValueException('AuthenticationEvent Job payload must be of type AuthenticationEvent.'); } return $payload; } + + public function getType(): string + { + return self::class; + } } diff --git a/src/Entities/Bases/AbstractJob.php b/src/Entities/Bases/AbstractJob.php index b2f1f73968f4d3adcf622f5e06406e6e230aae25..a41f3450c2dde05e438296ccd487cc83fd710e12 100644 --- a/src/Entities/Bases/AbstractJob.php +++ b/src/Entities/Bases/AbstractJob.php @@ -9,10 +9,22 @@ use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface; abstract class AbstractJob implements JobInterface { protected AbstractPayload $payload; + protected ?int $id; + protected \DateTimeImmutable $createdAt; - public function __construct(AbstractPayload $payload) - { + public function __construct( + AbstractPayload $payload, + int $id = null, + \DateTimeImmutable $createdAt = null + ) { $this->setPayload($payload); + $this->id = $id; + $this->createdAt = $createdAt ?? new \DateTimeImmutable(); + } + + public function getId(): ?int + { + return $this->id; } public function getPayload(): AbstractPayload @@ -24,4 +36,11 @@ abstract class AbstractJob implements JobInterface { $this->payload = $payload; } + + public function getCreatedAt(): \DateTimeImmutable + { + return $this->createdAt; + } + + abstract public function getType(): string; } diff --git a/src/Entities/GenericJob.php b/src/Entities/GenericJob.php index 03aa70051f005bde1e63e11b062d61c9449702f8..6577929bb3a978eae43619ace4a6aa1a69fb14bb 100644 --- a/src/Entities/GenericJob.php +++ b/src/Entities/GenericJob.php @@ -4,4 +4,8 @@ namespace SimpleSAML\Module\accounting\Entities; class GenericJob extends Bases\AbstractJob { + public function getType(): string + { + return self::class; + } } diff --git a/src/Entities/Interfaces/JobInterface.php b/src/Entities/Interfaces/JobInterface.php index c4622c3b09ced9fa1547a945759d6f9bfb7aba6a..7ebc01969c8676a6e51cad6aba7f87dc71d47e03 100644 --- a/src/Entities/Interfaces/JobInterface.php +++ b/src/Entities/Interfaces/JobInterface.php @@ -8,7 +8,12 @@ use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload; interface JobInterface { - public function getPayload(): AbstractPayload; + public function getId(): ?int; + public function getPayload(): AbstractPayload; public function setPayload(AbstractPayload $payload): void; + + public function getType(): string; + + public function getCreatedAt(): \DateTimeImmutable; } diff --git a/src/Stores/Interfaces/JobsStoreInterface.php b/src/Stores/Interfaces/JobsStoreInterface.php index 52d973bb7f08d768cc9650553059148e63f7010f..0ea21d761bcea526fd3e73859b28e1725284cdd3 100644 --- a/src/Stores/Interfaces/JobsStoreInterface.php +++ b/src/Stores/Interfaces/JobsStoreInterface.php @@ -11,10 +11,9 @@ interface JobsStoreInterface extends StoreInterface /** * Add job to queue * @param JobInterface $job - * @param string|null $type Optional job type designation. If not null, payload class FQN will be used. * @return void */ - public function enqueue(JobInterface $job, string $type = null): void; + public function enqueue(JobInterface $job): void; /** * Get job from queue diff --git a/src/Stores/Jobs/DoctrineDbal/JobsStore.php b/src/Stores/Jobs/DoctrineDbal/JobsStore.php index 30f760d5bf4f352a6925c02a5d4881276f262dcf..5507ab339391a7b488eb5328f6303c01f9884e43 100644 --- a/src/Stores/Jobs/DoctrineDbal/JobsStore.php +++ b/src/Stores/Jobs/DoctrineDbal/JobsStore.php @@ -4,21 +4,19 @@ declare(strict_types=1); namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal; -use DateTimeImmutable; -use Doctrine\DBAL\Result; -use Doctrine\DBAL\Types\Types; use Psr\Log\LoggerInterface; use ReflectionClass; -use SimpleSAML\Module\accounting\Entities\GenericJob; use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface; use SimpleSAML\Module\accounting\Exceptions\StoreException; use SimpleSAML\Module\accounting\Exceptions\StoreException\MigrationException; +use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException; use SimpleSAML\Module\accounting\ModuleConfiguration; use SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator; use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection; use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory; use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator; use SimpleSAML\Module\accounting\Stores\Interfaces\JobsStoreInterface; +use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\Repository; use Throwable; class JobsStore implements JobsStoreInterface @@ -39,11 +37,13 @@ class JobsStore implements JobsStoreInterface protected string $prefixedTableNameFailedJobs; protected Migrator $migrator; protected LoggerInterface $logger; + protected Repository $jobsRepository; public function __construct( ModuleConfiguration $moduleConfiguration, Factory $factory, - LoggerInterface $logger + LoggerInterface $logger, + Repository $jobsRepository = null ) { $this->moduleConfiguration = $moduleConfiguration; $this->connection = $factory->buildConnection($moduleConfiguration->getStoreConnection(self::class)); @@ -52,59 +52,17 @@ class JobsStore implements JobsStoreInterface $this->prefixedTableNameJobs = $this->connection->preparePrefixedTableName(self::TABLE_NAME_JOBS); $this->prefixedTableNameFailedJobs = $this->connection->preparePrefixedTableName(self::TABLE_NAME_FAILED_JOBS); - } - - /** - * @throws StoreException - */ - public function enqueue(JobInterface $job, string $type = null): void - { - $queryBuilder = $this->connection->dbal()->createQueryBuilder(); - - $payload = $job->getPayload(); - $type = $this->validateType($type ?? get_class($job)); - $queryBuilder->insert($this->prefixedTableNameJobs) - ->values( - [ - self::COLUMN_NAME_PAYLOAD => ':' . self::COLUMN_NAME_PAYLOAD, - self::COLUMN_NAME_TYPE => ':' . self::COLUMN_NAME_TYPE, - self::COLUMN_NAME_CREATED_AT => ':' . self::COLUMN_NAME_CREATED_AT, - ] - ) - ->setParameters( - [ - self::COLUMN_NAME_PAYLOAD => serialize($payload), - self::COLUMN_NAME_TYPE => $type, - self::COLUMN_NAME_CREATED_AT => new DateTimeImmutable(), - ], - [ - self::COLUMN_NAME_PAYLOAD => Types::TEXT, - self::COLUMN_NAME_TYPE => Types::STRING, - self::COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE - ] - ); - - try { - $queryBuilder->executeStatement(); - } catch (Throwable $exception) { - $message = sprintf('Could not enqueue job (%s)', $exception->getMessage()); - throw new StoreException($message, (int)$exception->getCode(), $exception); - } + $this->jobsRepository = $jobsRepository ?? + new Repository($this->connection, $this->prefixedTableNameJobs, $this->logger); } /** * @throws StoreException */ - protected function validateType(string $type): string + public function enqueue(JobInterface $job): void { - if (mb_strlen($type) > self::COLUMN_LENGTH_TYPE) { - throw new StoreException( - sprintf('String length for type column exceeds %s limit.', self::COLUMN_LENGTH_TYPE) - ); - } - - return $type; + $this->jobsRepository->insert($job); } /** @@ -112,28 +70,35 @@ class JobsStore implements JobsStoreInterface */ public function dequeue(string $type = null): ?JobInterface { + /** @noinspection PhpUnusedLocalVariableInspection - psalm reports possibly undefined variable */ $job = null; + $attempts = 0; + $maxDeleteAttempts = 3; try { // Check if there are any jobs in the store... - while ($row = $this->getNext($type)->fetchAssociative()) { - // We have a row. Let's create a row job instance, which will take care of validation and make it easier - // to work with instead of array. - $rawJob = new RawJob($row, $this->connection->dbal()->getDatabasePlatform()); + while (($job = $this->jobsRepository->getNext($type)) !== null) { + // We have job instance. + $jobId = $job->getId(); + + if ($jobId === null) { + throw new UnexpectedValueException('Retrieved job does not contain ID.'); + } + + $attempts++; + // Let's try to delete this job from the store, so it can't be fetched again. - $numberOfAffectedRows = $this->delete($rawJob->getId()); - if ($numberOfAffectedRows === 0) { - // It seems that this job has already been dequeued in the meantime. Try to get next job again. + if ($this->jobsRepository->delete($jobId) === false) { + // It seems that this job has already been deleted in the meantime. + // Check if this happened before. If threshold is reached, throw. + // Otherwise, try to get next job again. + if ($attempts > $maxDeleteAttempts) { + $message = 'Job retrieval was successful, however it was deleted in the meantime.'; + throw new StoreException($message); + } + continue; } - // Job is deleted, meaning it is now dequeued and we can return a new job instance. - // If a valid type is declared, let's try to instantiate a job of that specific type. - if ($type !== null && class_exists($type) && is_subclass_of($type, JobInterface::class)) { - $job = (new ReflectionClass($type))->newInstance($rawJob->getPayload()); - } else { - // No (valid) job type, so generic job will do... - $job = new GenericJob($rawJob->getPayload()); - } // We have found and dequeued a job, so finish with the search. break; @@ -141,7 +106,7 @@ class JobsStore implements JobsStoreInterface } catch (Throwable $exception) { throw new StoreException( 'Error while trying to dequeue a job.', - (int) $exception->getCode(), + (int)$exception->getCode(), $exception ); } @@ -149,50 +114,6 @@ class JobsStore implements JobsStoreInterface return $job; } - /** - * @throws StoreException - */ - public function getNext(string $type = null): Result - { - $queryBuilder = $this->connection->dbal()->createQueryBuilder(); - - /** - * @psalm-suppress TooManyArguments - providing array or null is deprecated - */ - $queryBuilder->select( - self::COLUMN_NAME_ID, - self::COLUMN_NAME_PAYLOAD, - self::COLUMN_NAME_TYPE, - self::COLUMN_NAME_CREATED_AT - ) - ->from($this->prefixedTableNameJobs) - ->orderBy(self::COLUMN_NAME_ID) - ->setMaxResults(1); - - if ($type !== null) { - $queryBuilder->where(self::COLUMN_NAME_TYPE . ' = ' . $queryBuilder->createNamedParameter($type)); - } - - try { - $result = $queryBuilder->executeQuery(); - } catch (Throwable $exception) { - $message = 'Error while trying to execute query to get next available job.'; - throw new StoreException($message, (int)$exception->getCode(), $exception); - } - - return $result; - } - - protected function delete(int $id): int - { - return (int)$this->connection->dbal() - ->delete( - $this->prefixedTableNameJobs, - [self::COLUMN_NAME_ID => $id], - [self::COLUMN_NAME_ID => Types::BIGINT] - ); - } - /** * @throws StoreException * @throws MigrationException diff --git a/src/Stores/Jobs/DoctrineDbal/RawJob.php b/src/Stores/Jobs/DoctrineDbal/JobsStore/RawJob.php similarity index 96% rename from src/Stores/Jobs/DoctrineDbal/RawJob.php rename to src/Stores/Jobs/DoctrineDbal/JobsStore/RawJob.php index e66eb263925311c1331a20894cf8e331d6f18542..f22a73f66182fd9d20df945ac527a9c01104d145 100644 --- a/src/Stores/Jobs/DoctrineDbal/RawJob.php +++ b/src/Stores/Jobs/DoctrineDbal/JobsStore/RawJob.php @@ -2,13 +2,14 @@ declare(strict_types=1); -namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal; +namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload; use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException; +use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore; class RawJob { diff --git a/src/Stores/Jobs/DoctrineDbal/JobsStore/Repository.php b/src/Stores/Jobs/DoctrineDbal/JobsStore/Repository.php new file mode 100644 index 0000000000000000000000000000000000000000..2c06c20276f208a18e250cf63404944f8ad59f80 --- /dev/null +++ b/src/Stores/Jobs/DoctrineDbal/JobsStore/Repository.php @@ -0,0 +1,190 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore; + +use Doctrine\DBAL\Types\Types; +use Psr\Log\LoggerInterface; +use ReflectionClass; +use SimpleSAML\Module\accounting\Entities\GenericJob; +use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface; +use SimpleSAML\Module\accounting\Exceptions\StoreException; +use SimpleSAML\Module\accounting\Services\LoggerService; +use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection; +use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore; +use Throwable; + +class Repository +{ + protected Connection $connection; + + protected array $validJobsTableNames = []; + + protected string $tableName; + protected LoggerInterface $logger; + + public function __construct(Connection $connection, string $tableName, LoggerInterface $logger) + { + $this->connection = $connection; + + $this->prepareValidJobsTableNames(); + + $this->validateTableName($tableName); + + $this->tableName = $tableName; + $this->logger = $logger; + } + + protected function prepareValidJobsTableNames(): void + { + $this->validJobsTableNames[] = $this->connection + ->preparePrefixedTableName(JobsStore::TABLE_NAME_JOBS); + $this->validJobsTableNames[] = $this->connection + ->preparePrefixedTableName(JobsStore::TABLE_NAME_FAILED_JOBS); + } + + /** + * @throws StoreException + */ + public function insert(JobInterface $job): void + { + $this->validateType($job->getType()); + + $queryBuilder = $this->connection->dbal()->createQueryBuilder(); + + $queryBuilder->insert($this->tableName) + ->values( + [ + JobsStore::COLUMN_NAME_PAYLOAD => ':' . JobsStore::COLUMN_NAME_PAYLOAD, + JobsStore::COLUMN_NAME_TYPE => ':' . JobsStore::COLUMN_NAME_TYPE, + JobsStore::COLUMN_NAME_CREATED_AT => ':' . JobsStore::COLUMN_NAME_CREATED_AT, + ] + ) + ->setParameters( + [ + JobsStore::COLUMN_NAME_PAYLOAD => serialize($job->getPayload()), + JobsStore::COLUMN_NAME_TYPE => $job->getType(), + JobsStore::COLUMN_NAME_CREATED_AT => $job->getCreatedAt(), + ], + [ + JobsStore::COLUMN_NAME_PAYLOAD => Types::TEXT, + JobsStore::COLUMN_NAME_TYPE => Types::STRING, + JobsStore::COLUMN_NAME_CREATED_AT => Types::DATETIMETZ_IMMUTABLE + ] + ); + + try { + $queryBuilder->executeStatement(); + } catch (Throwable $exception) { + $message = sprintf('Could not insert job (%s)', $exception->getMessage()); + throw new StoreException($message, (int)$exception->getCode(), $exception); + } + } + + /** + * @param string|null $type + * @return ?JobInterface + * @throws StoreException + */ + public function getNext(string $type = null): ?JobInterface + { + $queryBuilder = $this->connection->dbal()->createQueryBuilder(); + + /** + * @psalm-suppress TooManyArguments - providing array or null is deprecated + */ + $queryBuilder->select( + JobsStore::COLUMN_NAME_ID, + JobsStore::COLUMN_NAME_PAYLOAD, + JobsStore::COLUMN_NAME_TYPE, + JobsStore::COLUMN_NAME_CREATED_AT + ) + ->from($this->tableName) + ->orderBy(JobsStore::COLUMN_NAME_ID) + ->setMaxResults(1); + + if ($type !== null) { + $queryBuilder->where(JobsStore::COLUMN_NAME_TYPE . ' = ' . $queryBuilder->createNamedParameter($type)); + } + + try { + $result = $queryBuilder->executeQuery(); + $row = $result->fetchAssociative(); + } catch (Throwable $exception) { + $message = 'Error while trying to execute query to get next available job.'; + throw new StoreException($message, (int)$exception->getCode(), $exception); + } + + if ($row === false) { + return null; + } + + try { + $rawJob = new RawJob($row, $this->connection->dbal()->getDatabasePlatform()); + $rawJobType = $rawJob->getType(); + + // Try to create a specific job type. Otherwise, create a generic one. + if (class_exists($rawJobType) && is_subclass_of($rawJobType, JobInterface::class)) { + $job = (new ReflectionClass($rawJobType)) + ->newInstance($rawJob->getPayload(), $rawJob->getId(), $rawJob->getCreatedAt()); + } else { + // No (valid) job type, so generic one will do... + $job = new GenericJob($rawJob->getPayload(), $rawJob->getId(), $rawJob->getCreatedAt()); + } + } catch (Throwable $exception) { + $message = 'Could not create a job instance.'; + throw new StoreException($message, (int)$exception->getCode(), $exception); + } + + return $job; + } + + /** + * @throws StoreException + */ + public function delete(int $id): bool + { + try { + $numberOfAffectedRows = (int)$this->connection->dbal() + ->delete( + $this->tableName, + [JobsStore::COLUMN_NAME_ID => $id], + [JobsStore::COLUMN_NAME_ID => Types::BIGINT] + ); + } catch (Throwable $exception) { + $message = sprintf('Error while trying to delete a job with ID %s.', $id); + throw new StoreException($message, (int)$exception->getCode(), $exception); + } + + if ($numberOfAffectedRows === 0) { + return false; + } + + return true; + } + + /** + * @throws StoreException + */ + protected function validateTableName(string $tableName): void + { + if (!in_array($tableName, $this->validJobsTableNames)) { + throw new StoreException( + sprintf('Table %s is not valid table for storing jobs.', $tableName) + ); + } + } + + /** + * @throws StoreException + */ + protected function validateType(string $type): void + { + if (mb_strlen($type) > JobsStore::COLUMN_LENGTH_TYPE) { + throw new StoreException( + sprintf('String length for type column exceeds %s limit.', JobsStore::COLUMN_LENGTH_TYPE) + ); + } + } +} diff --git a/tests/src/Entities/AuthenticationEvent/JobTest.php b/tests/src/Entities/AuthenticationEvent/JobTest.php index 16824118e8d757a34b08f6e4c8502fa52e12e82f..cbe5e8bf5d3da071d54d62a1af4d3ed2abeeb22a 100644 --- a/tests/src/Entities/AuthenticationEvent/JobTest.php +++ b/tests/src/Entities/AuthenticationEvent/JobTest.php @@ -31,4 +31,11 @@ class JobTest extends TestCase (new Job($payload)); } + + public function testCanGetProperType(): void + { + $job = new Job(new AuthenticationEvent(['sample' => 'state'])); + + $this->assertSame(Job::class, $job->getType()); + } } diff --git a/tests/src/Entities/Bases/AbstractJobTest.php b/tests/src/Entities/Bases/AbstractJobTest.php index 86fa21be640475adb53764e39f71e74f8c8f6cf0..88d265716e59a622069ab65aa2ef27488b51a7b9 100644 --- a/tests/src/Entities/Bases/AbstractJobTest.php +++ b/tests/src/Entities/Bases/AbstractJobTest.php @@ -23,14 +23,20 @@ class AbstractJobTest extends TestCase }; } - public function testCanSetAndGetPayload(): void + public function testCanInitializeProperties(): void { - $job = new class ($this->payload) extends AbstractJob { - public function run(): void + $id = 1; + $createdAt = new \DateTimeImmutable(); + $job = new class ($this->payload, $id, $createdAt) extends AbstractJob { + public function getType(): string { + return self::class; } }; + $this->assertSame($id, $job->getId()); + $this->assertSame($createdAt, $job->getCreatedAt()); + $this->assertSame(get_class($job), $job->getType()); $this->assertInstanceOf(AbstractPayload::class, $job->getPayload()); } } diff --git a/tests/src/Entities/GenericJobTest.php b/tests/src/Entities/GenericJobTest.php new file mode 100644 index 0000000000000000000000000000000000000000..11aed48d0183f49e9204d63d734caa07a193322a --- /dev/null +++ b/tests/src/Entities/GenericJobTest.php @@ -0,0 +1,21 @@ +<?php + +namespace SimpleSAML\Test\Module\accounting\Entities; + +use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload; +use SimpleSAML\Module\accounting\Entities\GenericJob; +use PHPUnit\Framework\TestCase; + +/** + * @covers \SimpleSAML\Module\accounting\Entities\GenericJob + * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob + */ +class GenericJobTest extends TestCase +{ + public function testCanGetProperType(): void + { + $job = new GenericJob($this->createStub(AbstractPayload::class)); + + $this->assertSame(GenericJob::class, $job->getType()); + } +} diff --git a/tests/src/Stores/Jobs/DoctrineDbal/RawJobTest.php b/tests/src/Stores/Jobs/DoctrineDbal/JobsStore/RawJobTest.php similarity index 90% rename from tests/src/Stores/Jobs/DoctrineDbal/RawJobTest.php rename to tests/src/Stores/Jobs/DoctrineDbal/JobsStore/RawJobTest.php index 6d9fe229e710b367db088a8e3aa071d77b56ee9b..7615243deec2246d0de11e98973c8ff355ae8bff 100644 --- a/tests/src/Stores/Jobs/DoctrineDbal/RawJobTest.php +++ b/tests/src/Stores/Jobs/DoctrineDbal/JobsStore/RawJobTest.php @@ -1,17 +1,17 @@ <?php -namespace SimpleSAML\Test\Module\accounting\Stores\Jobs\DoctrineDbal; +namespace SimpleSAML\Test\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\SqlitePlatform; +use PHPUnit\Framework\TestCase; use SimpleSAML\Module\accounting\Entities\AuthenticationEvent; use SimpleSAML\Module\accounting\Exceptions\UnexpectedValueException; use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore; -use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\RawJob; -use PHPUnit\Framework\TestCase; +use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\RawJob; /** - * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\RawJob + * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\RawJob * @uses \SimpleSAML\Module\accounting\Entities\AuthenticationEvent */ class RawJobTest extends TestCase @@ -35,7 +35,7 @@ class RawJobTest extends TestCase public function testCanInstantiateValidRawJob(): void { $abstractPlatform = new SqlitePlatform(); - $rawJob = new RawJob($this->validRawRow, $abstractPlatform); + $rawJob = new JobsStore\RawJob($this->validRawRow, $abstractPlatform); $this->assertSame($rawJob->getId(), $this->validRawRow[JobsStore::COLUMN_NAME_ID]); $this->assertEquals($rawJob->getPayload(), $this->authenticationEvent); $this->assertSame($rawJob->getType(), $this->validRawRow[JobsStore::COLUMN_NAME_TYPE]); @@ -83,7 +83,7 @@ class RawJobTest extends TestCase $this->expectException(UnexpectedValueException::class); /** @psalm-suppress InvalidArgument */ - new RawJob($invalidRawRow, $this->abstractPlatformStub); + new JobsStore\RawJob($invalidRawRow, $this->abstractPlatformStub); } public function testThrowsOnNonStringType(): void @@ -94,7 +94,7 @@ class RawJobTest extends TestCase $this->expectException(UnexpectedValueException::class); /** @psalm-suppress InvalidArgument */ - new RawJob($invalidRawRow, $this->abstractPlatformStub); + new JobsStore\RawJob($invalidRawRow, $this->abstractPlatformStub); } public function testThrowsOnNonStringCreatedAt(): void @@ -116,6 +116,6 @@ class RawJobTest extends TestCase $this->expectException(UnexpectedValueException::class); /** @psalm-suppress InvalidArgument */ - new RawJob($invalidRawRow, $this->abstractPlatformStub); + new JobsStore\RawJob($invalidRawRow, $this->abstractPlatformStub); } } diff --git a/tests/src/Stores/Jobs/DoctrineDbal/JobsStore/RepositoryTest.php b/tests/src/Stores/Jobs/DoctrineDbal/JobsStore/RepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..11c09baa0fce5395a128a5e439977df5890926ad --- /dev/null +++ b/tests/src/Stores/Jobs/DoctrineDbal/JobsStore/RepositoryTest.php @@ -0,0 +1,216 @@ +<?php + +namespace SimpleSAML\Test\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore; + +use SimpleSAML\Module\accounting\Entities\AuthenticationEvent; +use SimpleSAML\Module\accounting\Entities\Bases\AbstractJob; +use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload; +use SimpleSAML\Module\accounting\Entities\GenericJob; +use SimpleSAML\Module\accounting\Exceptions\StoreException; +use SimpleSAML\Module\accounting\ModuleConfiguration; +use SimpleSAML\Module\accounting\Services\LoggerService; +use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection; +use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory; +use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator; +use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore; +use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\Repository; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpKernel\HttpCache\Store; + +/** + * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\Repository + * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection + * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob + * @uses \SimpleSAML\Module\accounting\Helpers\FilesystemHelper + * @uses \SimpleSAML\Module\accounting\ModuleConfiguration + * @uses \SimpleSAML\Module\accounting\Stores\Connections\Bases\AbstractMigrator + * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Bases\AbstractMigration + * @uses \SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator + * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore + * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\Migrations\Version20220601000000CreateJobsTable + * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\Migrations\Version20220601000100CreateFailedJobsTable + * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\RawJob + * @uses \SimpleSAML\Module\accounting\Entities\AuthenticationEvent + * @uses \SimpleSAML\Module\accounting\Entities\AuthenticationEvent\Job + */ +class RepositoryTest extends TestCase +{ + protected ModuleConfiguration $moduleConfiguration; + protected Connection $connection; + protected \PHPUnit\Framework\MockObject\Stub $loggerServiceStub; + protected Migrator $migrator; + protected \PHPUnit\Framework\MockObject\Stub $factoryStub; + protected \PHPUnit\Framework\MockObject\Stub $payloadStub; + protected \PHPUnit\Framework\MockObject\Stub $jobStub; + protected JobsStore $jobsStore; + protected string $jobsTableName; + + protected function setUp(): void + { + // Configuration directory is set by phpunit using php ENV setting feature (check phpunit.xml). + $this->moduleConfiguration = new ModuleConfiguration('module_accounting.php'); + $this->connection = new Connection(['driver' => 'pdo_sqlite', 'memory' => true,]); + + $this->loggerServiceStub = $this->createStub(LoggerService::class); + + /** @psalm-suppress InvalidArgument */ + $this->migrator = new Migrator($this->connection, $this->loggerServiceStub); + + $this->factoryStub = $this->createStub(Factory::class); + $this->factoryStub->method('buildConnection')->willReturn($this->connection); + $this->factoryStub->method('buildMigrator')->willReturn($this->migrator); + + $this->payloadStub = $this->createStub(AbstractPayload::class); + $this->jobStub = $this->createStub(GenericJob::class); + $this->jobStub->method('getPayload')->willReturn($this->payloadStub); + $this->jobStub->method('getType')->willReturn(GenericJob::class); + $this->jobStub->method('getCreatedAt')->willReturn(new \DateTimeImmutable()); + + /** @psalm-suppress InvalidArgument */ + $this->jobsStore = new JobsStore($this->moduleConfiguration, $this->factoryStub, $this->loggerServiceStub); + + $this->jobsTableName = $this->connection->preparePrefixedTableName(JobsStore::TABLE_NAME_JOBS); + } + + public function testCanInsertAndGetJob(): void + { + /** @psalm-suppress InvalidArgument */ + $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub); + // Running setup will ensure that all migrations are ran. + $this->jobsStore->runSetup(); + + $this->assertNull($repository->getNext()); + + /** @psalm-suppress InvalidArgument */ + $repository->insert($this->jobStub); + + $this->assertNotNull($repository->getNext()); + } + + public function testInsertThrowsIfJobsStoreSetupNotRan(): void + { + /** @psalm-suppress InvalidArgument */ + $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub); + // Running setup will ensure that all migrations are ran. + //$this->jobsStore->runSetup(); + + $this->expectException(StoreException::class); + + /** @psalm-suppress InvalidArgument */ + $repository->insert($this->jobStub); + } + + public function testInsertThrowsForInvalidJobType(): void + { + /** @psalm-suppress InvalidArgument */ + $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub); + // Running setup will ensure that all migrations are ran. + $this->jobsStore->runSetup(); + + $this->expectException(StoreException::class); + + $invalidType = str_pad('abc', JobsStore::COLUMN_LENGTH_TYPE + 1); + $jobStub = $this->createStub(GenericJob::class); + $jobStub->method('getPayload')->willReturn($this->payloadStub); + $jobStub->method('getType')->willReturn($invalidType); + $jobStub->method('getCreatedAt')->willReturn(new \DateTimeImmutable()); + + /** @psalm-suppress InvalidArgument */ + $repository->insert($jobStub); + } + + public function testGetNextThrowsIfJobsStoreSetupNotRan(): void + { + /** @psalm-suppress InvalidArgument */ + $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub); + // Running setup will ensure that all migrations are ran. + //$this->jobsStore->runSetup(); + + $this->expectException(StoreException::class); + + $repository->getNext(); + } + + public function testGetNextThrowsForInvalidJobType(): void + { + /** @psalm-suppress InvalidArgument */ + $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub); + // Running setup will ensure that all migrations are ran. + $this->jobsStore->runSetup(); + + $payloadStub = $this->createStub(AbstractPayload::class); + $jobStub = $this->createStub(AbstractJob::class); // Abstract classes can't be initialized.. + $jobStub->method('getPayload')->willReturn($payloadStub); + $jobStub->method('getType')->willReturn(AbstractJob::class); + $jobStub->method('getCreatedAt')->willReturn(new \DateTimeImmutable()); + + /** @psalm-suppress InvalidArgument */ + $repository->insert($jobStub); + + $this->expectException(StoreException::class); + + $repository->getNext(); + } + + public function testCanDeleteJob(): void + { + /** @psalm-suppress InvalidArgument */ + $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub); + // Running setup will ensure that all migrations are ran. + $this->jobsStore->runSetup(); + + $this->assertFalse($repository->delete(1)); + /** @psalm-suppress InvalidArgument */ + $repository->insert($this->jobStub); + $job = $repository->getNext(); + if ($job === null) { + throw new \Exception('Invalid job.'); + } + $jobId = $job->getId(); + if ($jobId === null) { + throw new \Exception('Invalid job ID.'); + } + $this->assertTrue($repository->delete($jobId)); + $this->assertFalse($repository->delete($jobId)); + } + + public function testDeleteThrowsWhenJobsStoreSetupNotRan(): void + { + /** @psalm-suppress InvalidArgument */ + $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub); + // Running setup will ensure that all migrations are ran. + //$this->jobsStore->runSetup(); + + $this->expectException(StoreException::class); + + $repository->delete(1); + } + + public function testCanGetSpecificJobType(): void + { + /** @psalm-suppress InvalidArgument */ + $repository = new Repository($this->connection, $this->jobsTableName, $this->loggerServiceStub); + // Running setup will ensure that all migrations are ran. + $this->jobsStore->runSetup(); + + $this->assertNull($repository->getNext()); + + /** @psalm-suppress InvalidArgument */ + $repository->insert($this->jobStub); + + $authenticationEvent = new AuthenticationEvent(['sample-state']); + $authenticationEventJob = new AuthenticationEvent\Job($authenticationEvent); + + $repository->insert($authenticationEventJob); + + $this->assertInstanceOf(AuthenticationEvent\Job::class, $repository->getNext(AuthenticationEvent\Job::class)); + } + + public function testInitializationThrowsForInvalidJobsTableName(): void + { + $this->expectException(StoreException::class); + + /** @psalm-suppress InvalidArgument */ + new Repository($this->connection, 'invalid-table-name', $this->loggerServiceStub); + } +} diff --git a/tests/src/Stores/Jobs/DoctrineDbal/JobsStoreTest.php b/tests/src/Stores/Jobs/DoctrineDbal/JobsStoreTest.php index 3686a6f4acf623a132a381dcec22247e86dc9caa..d7c5a7db520e571d5a50f93de12e1e02f8540377 100644 --- a/tests/src/Stores/Jobs/DoctrineDbal/JobsStoreTest.php +++ b/tests/src/Stores/Jobs/DoctrineDbal/JobsStoreTest.php @@ -2,10 +2,11 @@ namespace SimpleSAML\Test\Module\accounting\Stores\Jobs\DoctrineDbal; +use PHPUnit\Framework\TestCase; use SimpleSAML\Module\accounting\Entities\AuthenticationEvent; use SimpleSAML\Module\accounting\Entities\Bases\AbstractJob; use SimpleSAML\Module\accounting\Entities\Bases\AbstractPayload; -use SimpleSAML\Module\accounting\Entities\Interfaces\JobInterface; +use SimpleSAML\Module\accounting\Entities\GenericJob; use SimpleSAML\Module\accounting\Exceptions\StoreException; use SimpleSAML\Module\accounting\ModuleConfiguration; use SimpleSAML\Module\accounting\Services\LoggerService; @@ -13,7 +14,6 @@ use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Connection; use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Factory; use SimpleSAML\Module\accounting\Stores\Connections\DoctrineDbal\Migrator; use SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore; -use PHPUnit\Framework\TestCase; /** * @covers \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore @@ -27,9 +27,10 @@ use PHPUnit\Framework\TestCase; * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\Migrations\Version20220601000000CreateJobsTable * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\Migrations\Version20220601000100CreateFailedJobsTable * @uses \SimpleSAML\Module\accounting\Entities\Bases\AbstractJob - * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\RawJob + * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\RawJob * @uses \SimpleSAML\Module\accounting\Entities\AuthenticationEvent * @uses \SimpleSAML\Module\accounting\Entities\AuthenticationEvent\Job + * @uses \SimpleSAML\Module\accounting\Stores\Jobs\DoctrineDbal\JobsStore\Repository */ class JobsStoreTest extends TestCase { @@ -38,6 +39,8 @@ class JobsStoreTest extends TestCase protected Connection $connection; protected \PHPUnit\Framework\MockObject\Stub $loggerServiceStub; protected Migrator $migrator; + protected \PHPUnit\Framework\MockObject\Stub $payloadStub; + protected \PHPUnit\Framework\MockObject\Stub $jobStub; protected function setUp(): void { @@ -53,6 +56,13 @@ class JobsStoreTest extends TestCase $this->factoryStub = $this->createStub(Factory::class); $this->factoryStub->method('buildConnection')->willReturn($this->connection); $this->factoryStub->method('buildMigrator')->willReturn($this->migrator); + + $this->payloadStub = $this->createStub(AbstractPayload::class); + $this->jobStub = $this->createStub(GenericJob::class); + $this->jobStub->method('getPayload')->willReturn($this->payloadStub); + $this->jobStub->method('getType')->willReturn(GenericJob::class); + $this->jobStub->method('getCreatedAt')->willReturn(new \DateTimeImmutable()); + $this->jobStub->method('getId')->willReturn(1); } public function testSetupDependsOnMigratorSetup(): void @@ -101,21 +111,20 @@ class JobsStoreTest extends TestCase $jobsStore = new JobsStore($this->moduleConfiguration, $this->factoryStub, $this->loggerServiceStub); $jobsStore->runSetup(); - $payloadStub = $this->createStub(AbstractPayload::class); - $jobStub = $this->createStub(AbstractJob::class); - $jobStub->method('getPayload')->willReturn($payloadStub); - $queryBuilder = $this->connection->dbal()->createQueryBuilder(); $queryBuilder->select('COUNT(id) as jobsCount')->from($jobsStore->getPrefixedTableNameJobs())->fetchOne(); $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne()); - $jobsStore->enqueue($jobStub); + /** @psalm-suppress InvalidArgument */ + $jobsStore->enqueue($this->jobStub); $this->assertSame(1, (int) $queryBuilder->executeQuery()->fetchOne()); - $jobsStore->enqueue($jobStub); - $jobsStore->enqueue($jobStub); + /** @psalm-suppress InvalidArgument */ + $jobsStore->enqueue($this->jobStub); + /** @psalm-suppress InvalidArgument */ + $jobsStore->enqueue($this->jobStub); $this->assertSame(3, (int) $queryBuilder->executeQuery()->fetchOne()); } @@ -136,81 +145,21 @@ class JobsStoreTest extends TestCase $jobsStore->enqueue($jobStub); } - public function testEnqueueThrowsStoreExceptionOnInvalidType(): void - { - /** @psalm-suppress InvalidArgument */ - $jobsStore = new JobsStore($this->moduleConfiguration, $this->factoryStub, $this->loggerServiceStub); - // Don't run setup, so we get exception - $jobsStore->runSetup(); - - $payloadStub = $this->createStub(AbstractPayload::class); - $jobStub = $this->createStub(AbstractJob::class); - $jobStub->method('getPayload')->willReturn($payloadStub); - $invalidType = str_pad('invalid-type', JobsStore::COLUMN_LENGTH_TYPE + 1); - - $this->expectException(StoreException::class); - - $jobsStore->enqueue($jobStub, $invalidType); - } - - public function testCanGetNextJob(): void + public function testCanDequeueJob(): void { /** @psalm-suppress InvalidArgument */ $jobsStore = new JobsStore($this->moduleConfiguration, $this->factoryStub, $this->loggerServiceStub); $jobsStore->runSetup(); - $payloadStub = $this->createStub(AbstractPayload::class); - $jobStub = $this->createStub(AbstractJob::class); - $jobStub->method('getPayload')->willReturn($payloadStub); - $queryBuilder = $this->connection->dbal()->createQueryBuilder(); $queryBuilder->select('COUNT(id) as jobsCount')->from($jobsStore->getPrefixedTableNameJobs())->fetchOne(); $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne()); - $jobsStore->enqueue($jobStub); - - $this->assertNotEmpty($jobsStore->getNext()->fetchOne()); - $this->assertNotEmpty($jobsStore->getNext(get_class($jobStub))->fetchOne()); - - - $jobsStore->enqueue($jobStub, 'sample-type'); - $this->assertNotEmpty($jobsStore->getNext('sample-type')->fetchOne()); - } - - public function testGetNextThrowsOnNonSetupRun(): void - { /** @psalm-suppress InvalidArgument */ - $jobsStore = new JobsStore($this->moduleConfiguration, $this->factoryStub, $this->loggerServiceStub); - // Don't run setup, so we get exception - //$jobsStore->runSetup(); - - $payloadStub = $this->createStub(AbstractPayload::class); - $jobStub = $this->createStub(AbstractJob::class); - $jobStub->method('getPayload')->willReturn($payloadStub); - - $this->expectException(StoreException::class); - - $jobsStore->getNext(); - } - - public function testCanDequeueJob(): void - { + $jobsStore->enqueue($this->jobStub); /** @psalm-suppress InvalidArgument */ - $jobsStore = new JobsStore($this->moduleConfiguration, $this->factoryStub, $this->loggerServiceStub); - $jobsStore->runSetup(); - - $payloadStub = $this->createStub(AbstractPayload::class); - $jobStub = $this->createStub(AbstractJob::class); - $jobStub->method('getPayload')->willReturn($payloadStub); - - $queryBuilder = $this->connection->dbal()->createQueryBuilder(); - $queryBuilder->select('COUNT(id) as jobsCount')->from($jobsStore->getPrefixedTableNameJobs())->fetchOne(); - - $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne()); - - $jobsStore->enqueue($jobStub); - $jobsStore->enqueue($jobStub); + $jobsStore->enqueue($this->jobStub); $this->assertSame(2, (int) $queryBuilder->executeQuery()->fetchOne()); @@ -225,10 +174,6 @@ class JobsStoreTest extends TestCase $jobsStore = new JobsStore($this->moduleConfiguration, $this->factoryStub, $this->loggerServiceStub); $jobsStore->runSetup(); - $payloadStub = $this->createStub(AbstractPayload::class); - $jobStub = $this->createStub(AbstractJob::class); - $jobStub->method('getPayload')->willReturn($payloadStub); - $authenticationEvent = new AuthenticationEvent(['sample-state']); $authenticationEventJob = new AuthenticationEvent\Job($authenticationEvent); @@ -237,7 +182,8 @@ class JobsStoreTest extends TestCase $this->assertSame(0, (int) $queryBuilder->executeQuery()->fetchOne()); - $jobsStore->enqueue($jobStub, 'test-type'); + /** @psalm-suppress InvalidArgument */ + $jobsStore->enqueue($this->jobStub); $jobsStore->enqueue($authenticationEventJob); $this->assertSame(2, (int) $queryBuilder->executeQuery()->fetchOne()); @@ -266,9 +212,66 @@ class JobsStoreTest extends TestCase $jobsStore->dequeue('test-type'); } + public function testDequeueThrowsForJobWithInvalidId(): void + { + $repositoryStub = $this->createStub(JobsStore\Repository::class); + $jobStub = $this->createStub(GenericJob::class); + $jobStub->method('getPayload')->willReturn($this->payloadStub); + $jobStub->method('getCreatedAt')->willReturn(new \DateTimeImmutable()); + $jobStub->method('getType')->willReturn(GenericJob::class); + $jobStub->method('getId')->willReturn(null); // Invalid ID value... + + $repositoryStub->method('getNext')->willReturn($jobStub); + + /** @psalm-suppress InvalidArgument */ + $jobsStore = new JobsStore( + $this->moduleConfiguration, + $this->factoryStub, + $this->loggerServiceStub, + $repositoryStub + ); + $jobsStore->runSetup(); + + $this->expectException(StoreException::class); + + $jobsStore->dequeue(); + } + + public function testDequeThrowsAfterMaxDeleteAttempts(): void + { + $repositoryStub = $this->createStub(JobsStore\Repository::class); + $repositoryStub->method('getNext')->willReturn($this->jobStub); + $repositoryStub->method('delete')->willReturn(false); + + /** @psalm-suppress InvalidArgument */ + $jobsStore = new JobsStore( + $this->moduleConfiguration, + $this->factoryStub, + $this->loggerServiceStub, + $repositoryStub + ); + $jobsStore->runSetup(); + + $this->expectException(StoreException::class); + + $jobsStore->dequeue(); + } + public function testCanContinueSearchingInCaseOfJobDeletion(): void { - // TODO try to simulate job deletion - $this->markTestIncomplete(); + $repositoryStub = $this->createStub(JobsStore\Repository::class); + $repositoryStub->method('getNext')->willReturn($this->jobStub); + $repositoryStub->method('delete')->willReturnOnConsecutiveCalls(false, true); + + /** @psalm-suppress InvalidArgument */ + $jobsStore = new JobsStore( + $this->moduleConfiguration, + $this->factoryStub, + $this->loggerServiceStub, + $repositoryStub + ); + $jobsStore->runSetup(); + + $this->assertNotNull($jobsStore->dequeue()); } }