diff --git a/composer.lock b/composer.lock index 5c48ff41..387c24f2 100644 --- a/composer.lock +++ b/composer.lock @@ -1463,16 +1463,16 @@ }, { "name": "doctrine/orm", - "version": "2.20.2", + "version": "2.20.3", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "19912de9270fa6abb3d25a1a37784af6b818d534" + "reference": "17d28b5c4cac212ca92730d9a26e32a0b1516126" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/19912de9270fa6abb3d25a1a37784af6b818d534", - "reference": "19912de9270fa6abb3d25a1a37784af6b818d534", + "url": "https://api.github.com/repos/doctrine/orm/zipball/17d28b5c4cac212ca92730d9a26e32a0b1516126", + "reference": "17d28b5c4cac212ca92730d9a26e32a0b1516126", "shasum": "" }, "require": { @@ -1499,14 +1499,14 @@ }, "require-dev": { "doctrine/annotations": "^1.13 || ^2", - "doctrine/coding-standard": "^9.0.2 || ^12.0", + "doctrine/coding-standard": "^9.0.2 || ^13.0", "phpbench/phpbench": "^0.16.10 || ^1.0", "phpstan/extension-installer": "~1.1.0 || ^1.4", "phpstan/phpstan": "~1.4.10 || 2.0.3", "phpstan/phpstan-deprecation-rules": "^1 || ^2", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", "psr/log": "^1 || ^2 || ^3", - "squizlabs/php_codesniffer": "3.7.2", + "squizlabs/php_codesniffer": "3.12.0", "symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0", "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0", "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0" @@ -1559,9 +1559,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.20.2" + "source": "https://github.com/doctrine/orm/tree/2.20.3" }, - "time": "2025-02-04T19:17:01+00:00" + "time": "2025-05-02T17:07:53+00:00" }, { "name": "doctrine/persistence", @@ -3142,16 +3142,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.13.0", + "version": "1.13.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", "shasum": "" }, "require": { @@ -3190,7 +3190,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" }, "funding": [ { @@ -3198,7 +3198,7 @@ "type": "tidelift" } ], - "time": "2025-02-12T12:17:51+00:00" + "time": "2025-04-29T12:36:36+00:00" }, { "name": "nelmio/api-doc-bundle", @@ -5203,16 +5203,16 @@ }, { "name": "symfony/cache", - "version": "v6.4.20", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "95af448bb7c3d8db02f7b4f5cbf3cb7a6ff1e432" + "reference": "d1abcf763a7414f2e572f676f22da7a06c8cd9ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/95af448bb7c3d8db02f7b4f5cbf3cb7a6ff1e432", - "reference": "95af448bb7c3d8db02f7b4f5cbf3cb7a6ff1e432", + "url": "https://api.github.com/repos/symfony/cache/zipball/d1abcf763a7414f2e572f676f22da7a06c8cd9ee", + "reference": "d1abcf763a7414f2e572f676f22da7a06c8cd9ee", "shasum": "" }, "require": { @@ -5279,7 +5279,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.20" + "source": "https://github.com/symfony/cache/tree/v6.4.21" }, "funding": [ { @@ -5295,7 +5295,7 @@ "type": "tidelift" } ], - "time": "2025-03-08T15:51:34+00:00" + "time": "2025-04-08T08:21:20+00:00" }, { "name": "symfony/cache-contracts", @@ -5524,16 +5524,16 @@ }, { "name": "symfony/console", - "version": "v6.4.20", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "2e4af9c952617cc3f9559ff706aee420a8464c36" + "reference": "a3011c7b7adb58d89f6c0d822abb641d7a5f9719" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2e4af9c952617cc3f9559ff706aee420a8464c36", - "reference": "2e4af9c952617cc3f9559ff706aee420a8464c36", + "url": "https://api.github.com/repos/symfony/console/zipball/a3011c7b7adb58d89f6c0d822abb641d7a5f9719", + "reference": "a3011c7b7adb58d89f6c0d822abb641d7a5f9719", "shasum": "" }, "require": { @@ -5598,7 +5598,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.20" + "source": "https://github.com/symfony/console/tree/v6.4.21" }, "funding": [ { @@ -5614,7 +5614,7 @@ "type": "tidelift" } ], - "time": "2025-03-03T17:16:38+00:00" + "time": "2025-04-07T15:42:41+00:00" }, { "name": "symfony/css-selector", @@ -5831,16 +5831,16 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v6.4.20", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "7205dbc642bac2ecbf108fadbf9a04aa08290a2a" + "reference": "fcce66ede41ca56100b91fd4a00131ba6cf89aba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/7205dbc642bac2ecbf108fadbf9a04aa08290a2a", - "reference": "7205dbc642bac2ecbf108fadbf9a04aa08290a2a", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/fcce66ede41ca56100b91fd4a00131ba6cf89aba", + "reference": "fcce66ede41ca56100b91fd4a00131ba6cf89aba", "shasum": "" }, "require": { @@ -5919,7 +5919,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v6.4.20" + "source": "https://github.com/symfony/doctrine-bridge/tree/v6.4.21" }, "funding": [ { @@ -5935,7 +5935,7 @@ "type": "tidelift" } ], - "time": "2025-02-28T20:55:44+00:00" + "time": "2025-04-27T15:22:02+00:00" }, { "name": "symfony/dotenv", @@ -6506,16 +6506,16 @@ }, { "name": "symfony/form", - "version": "v6.4.20", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "3929e2a60a828f39df6765fb49d224cc629fa529" + "reference": "44a0e253c16a3187299f07b8f80e23ecb000d360" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/3929e2a60a828f39df6765fb49d224cc629fa529", - "reference": "3929e2a60a828f39df6765fb49d224cc629fa529", + "url": "https://api.github.com/repos/symfony/form/zipball/44a0e253c16a3187299f07b8f80e23ecb000d360", + "reference": "44a0e253c16a3187299f07b8f80e23ecb000d360", "shasum": "" }, "require": { @@ -6583,7 +6583,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v6.4.20" + "source": "https://github.com/symfony/form/tree/v6.4.21" }, "funding": [ { @@ -6599,20 +6599,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T10:21:45+00:00" + "time": "2025-04-27T15:22:02+00:00" }, { "name": "symfony/framework-bundle", - "version": "v6.4.20", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "51418a20079cb25af3fcb8fa8ae1ed82f7fdd1ce" + "reference": "d0b06133b00e4dd3df7f47a3188fb7baabcc6b2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/51418a20079cb25af3fcb8fa8ae1ed82f7fdd1ce", - "reference": "51418a20079cb25af3fcb8fa8ae1ed82f7fdd1ce", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/d0b06133b00e4dd3df7f47a3188fb7baabcc6b2a", + "reference": "d0b06133b00e4dd3df7f47a3188fb7baabcc6b2a", "shasum": "" }, "require": { @@ -6732,7 +6732,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/v6.4.20" + "source": "https://github.com/symfony/framework-bundle/tree/v6.4.21" }, "funding": [ { @@ -6748,7 +6748,7 @@ "type": "tidelift" } ], - "time": "2025-03-23T16:46:24+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/http-client", @@ -6923,16 +6923,16 @@ }, { "name": "symfony/http-foundation", - "version": "v6.4.18", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "d0492d6217e5ab48f51fca76f64cf8e78919d0db" + "reference": "3f0c7ea41db479383b81d436b836d37168fd5b99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d0492d6217e5ab48f51fca76f64cf8e78919d0db", - "reference": "d0492d6217e5ab48f51fca76f64cf8e78919d0db", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3f0c7ea41db479383b81d436b836d37168fd5b99", + "reference": "3f0c7ea41db479383b81d436b836d37168fd5b99", "shasum": "" }, "require": { @@ -6980,7 +6980,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.18" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.21" }, "funding": [ { @@ -6996,20 +6996,20 @@ "type": "tidelift" } ], - "time": "2025-01-09T15:48:56+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.20", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "6be6db31bc74693ce5516e1fd5e5ff1171005e37" + "reference": "983ca05eec6623920d24ec0f1005f487d3734a0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6be6db31bc74693ce5516e1fd5e5ff1171005e37", - "reference": "6be6db31bc74693ce5516e1fd5e5ff1171005e37", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/983ca05eec6623920d24ec0f1005f487d3734a0c", + "reference": "983ca05eec6623920d24ec0f1005f487d3734a0c", "shasum": "" }, "require": { @@ -7094,7 +7094,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/v6.4.20" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.21" }, "funding": [ { @@ -7110,20 +7110,20 @@ "type": "tidelift" } ], - "time": "2025-03-28T13:27:10+00:00" + "time": "2025-05-02T08:46:38+00:00" }, { "name": "symfony/intl", - "version": "v6.4.15", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "b1d5e8d82615b60f229216edfee0b59e2ef66da6" + "reference": "b248d227fa10fd6345efd4c1c74efaa1c1de6f76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/b1d5e8d82615b60f229216edfee0b59e2ef66da6", - "reference": "b1d5e8d82615b60f229216edfee0b59e2ef66da6", + "url": "https://api.github.com/repos/symfony/intl/zipball/b248d227fa10fd6345efd4c1c74efaa1c1de6f76", + "reference": "b248d227fa10fd6345efd4c1c74efaa1c1de6f76", "shasum": "" }, "require": { @@ -7177,7 +7177,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v6.4.15" + "source": "https://github.com/symfony/intl/tree/v6.4.21" }, "funding": [ { @@ -7193,20 +7193,20 @@ "type": "tidelift" } ], - "time": "2024-11-08T15:28:48+00:00" + "time": "2025-04-07T19:02:30+00:00" }, { "name": "symfony/mailer", - "version": "v6.4.18", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "e93a6ae2767d7f7578c2b7961d9d8e27580b2b11" + "reference": "ada2809ccd4ec27aba9fc344e3efdaec624c6438" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/e93a6ae2767d7f7578c2b7961d9d8e27580b2b11", - "reference": "e93a6ae2767d7f7578c2b7961d9d8e27580b2b11", + "url": "https://api.github.com/repos/symfony/mailer/zipball/ada2809ccd4ec27aba9fc344e3efdaec624c6438", + "reference": "ada2809ccd4ec27aba9fc344e3efdaec624c6438", "shasum": "" }, "require": { @@ -7257,7 +7257,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.4.18" + "source": "https://github.com/symfony/mailer/tree/v6.4.21" }, "funding": [ { @@ -7273,20 +7273,20 @@ "type": "tidelift" } ], - "time": "2025-01-24T15:27:15+00:00" + "time": "2025-04-26T23:47:35+00:00" }, { "name": "symfony/mime", - "version": "v6.4.19", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "ac537b6c55ccc2c749f3c979edfa9ec14aaed4f3" + "reference": "fec8aa5231f3904754955fad33c2db50594d22d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/ac537b6c55ccc2c749f3c979edfa9ec14aaed4f3", - "reference": "ac537b6c55ccc2c749f3c979edfa9ec14aaed4f3", + "url": "https://api.github.com/repos/symfony/mime/zipball/fec8aa5231f3904754955fad33c2db50594d22d1", + "reference": "fec8aa5231f3904754955fad33c2db50594d22d1", "shasum": "" }, "require": { @@ -7342,7 +7342,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.19" + "source": "https://github.com/symfony/mime/tree/v6.4.21" }, "funding": [ { @@ -7358,7 +7358,7 @@ "type": "tidelift" } ], - "time": "2025-02-17T21:23:52+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/monolog-bridge", @@ -7661,7 +7661,7 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", @@ -7717,7 +7717,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" }, "funding": [ { @@ -7737,16 +7737,16 @@ }, { "name": "symfony/polyfill-php84", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "e5493eb51311ab0b1cc2243416613f06ed8f18bd" + "reference": "000df7860439609837bbe28670b0be15783b7fbf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/e5493eb51311ab0b1cc2243416613f06ed8f18bd", - "reference": "e5493eb51311ab0b1cc2243416613f06ed8f18bd", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/000df7860439609837bbe28670b0be15783b7fbf", + "reference": "000df7860439609837bbe28670b0be15783b7fbf", "shasum": "" }, "require": { @@ -7793,7 +7793,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.32.0" }, "funding": [ { @@ -7809,7 +7809,7 @@ "type": "tidelift" } ], - "time": "2024-09-09T12:04:04+00:00" + "time": "2025-02-20T12:04:08+00:00" }, { "name": "symfony/process", @@ -8270,16 +8270,16 @@ }, { "name": "symfony/security-bundle", - "version": "v6.4.13", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "181d1fcf5f88ef8212ed7f6434e5ff51c9d7dff3" + "reference": "99b656ff6046ef217d4e3f852940de7e22489849" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/181d1fcf5f88ef8212ed7f6434e5ff51c9d7dff3", - "reference": "181d1fcf5f88ef8212ed7f6434e5ff51c9d7dff3", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/99b656ff6046ef217d4e3f852940de7e22489849", + "reference": "99b656ff6046ef217d4e3f852940de7e22489849", "shasum": "" }, "require": { @@ -8362,7 +8362,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v6.4.13" + "source": "https://github.com/symfony/security-bundle/tree/v6.4.21" }, "funding": [ { @@ -8378,20 +8378,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:18:03+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/security-core", - "version": "v6.4.18", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "0ae7ae716968e00287ab9b7768405e0dc9cad109" + "reference": "c6e70da38436a9a49ed39d9cbead1ecf760f0fbd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/0ae7ae716968e00287ab9b7768405e0dc9cad109", - "reference": "0ae7ae716968e00287ab9b7768405e0dc9cad109", + "url": "https://api.github.com/repos/symfony/security-core/zipball/c6e70da38436a9a49ed39d9cbead1ecf760f0fbd", + "reference": "c6e70da38436a9a49ed39d9cbead1ecf760f0fbd", "shasum": "" }, "require": { @@ -8448,7 +8448,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.4.18" + "source": "https://github.com/symfony/security-core/tree/v6.4.21" }, "funding": [ { @@ -8464,7 +8464,7 @@ "type": "tidelift" } ], - "time": "2025-01-22T20:59:03+00:00" + "time": "2025-04-17T07:43:34+00:00" }, { "name": "symfony/security-csrf", @@ -8536,16 +8536,16 @@ }, { "name": "symfony/security-http", - "version": "v6.4.19", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "a57bb00b01036865e6c08d0c8540df429534df19" + "reference": "67d0edaf6702c3192f27ad483df9a875c9a1f1a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/a57bb00b01036865e6c08d0c8540df429534df19", - "reference": "a57bb00b01036865e6c08d0c8540df429534df19", + "url": "https://api.github.com/repos/symfony/security-http/zipball/67d0edaf6702c3192f27ad483df9a875c9a1f1a2", + "reference": "67d0edaf6702c3192f27ad483df9a875c9a1f1a2", "shasum": "" }, "require": { @@ -8604,7 +8604,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v6.4.19" + "source": "https://github.com/symfony/security-http/tree/v6.4.21" }, "funding": [ { @@ -8620,20 +8620,20 @@ "type": "tidelift" } ], - "time": "2025-01-28T19:24:43+00:00" + "time": "2025-04-27T13:58:34+00:00" }, { "name": "symfony/serializer", - "version": "v6.4.19", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "a221b2f6066af304d760cff7a26f201b4fab4aef" + "reference": "c45f8f7763afb11e85772c0c1debb8f272c17f51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/a221b2f6066af304d760cff7a26f201b4fab4aef", - "reference": "a221b2f6066af304d760cff7a26f201b4fab4aef", + "url": "https://api.github.com/repos/symfony/serializer/zipball/c45f8f7763afb11e85772c0c1debb8f272c17f51", + "reference": "c45f8f7763afb11e85772c0c1debb8f272c17f51", "shasum": "" }, "require": { @@ -8702,7 +8702,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v6.4.19" + "source": "https://github.com/symfony/serializer/tree/v6.4.21" }, "funding": [ { @@ -8718,7 +8718,7 @@ "type": "tidelift" } ], - "time": "2025-02-24T08:42:36+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/service-contracts", @@ -8867,16 +8867,16 @@ }, { "name": "symfony/string", - "version": "v6.4.15", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f" + "reference": "73e2c6966a5aef1d4892873ed5322245295370c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", - "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", + "url": "https://api.github.com/repos/symfony/string/zipball/73e2c6966a5aef1d4892873ed5322245295370c6", + "reference": "73e2c6966a5aef1d4892873ed5322245295370c6", "shasum": "" }, "require": { @@ -8933,7 +8933,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.15" + "source": "https://github.com/symfony/string/tree/v6.4.21" }, "funding": [ { @@ -8949,20 +8949,20 @@ "type": "tidelift" } ], - "time": "2024-11-13T13:31:12+00:00" + "time": "2025-04-18T15:23:29+00:00" }, { "name": "symfony/translation", - "version": "v6.4.19", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "3b9bf9f33997c064885a7bfc126c14b9daa0e00e" + "reference": "bb92ea5588396b319ba43283a5a3087a034cb29c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/3b9bf9f33997c064885a7bfc126c14b9daa0e00e", - "reference": "3b9bf9f33997c064885a7bfc126c14b9daa0e00e", + "url": "https://api.github.com/repos/symfony/translation/zipball/bb92ea5588396b319ba43283a5a3087a034cb29c", + "reference": "bb92ea5588396b319ba43283a5a3087a034cb29c", "shasum": "" }, "require": { @@ -9028,7 +9028,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.4.19" + "source": "https://github.com/symfony/translation/tree/v6.4.21" }, "funding": [ { @@ -9044,7 +9044,7 @@ "type": "tidelift" } ], - "time": "2025-02-13T10:18:43+00:00" + "time": "2025-04-07T19:02:30+00:00" }, { "name": "symfony/translation-contracts", @@ -9126,16 +9126,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v6.4.20", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "bb423dfaa51b6d88b1d64197ae695a0c8ac73778" + "reference": "0457b7944bf1cc9c846c98d4923b5379ec6afc09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/bb423dfaa51b6d88b1d64197ae695a0c8ac73778", - "reference": "bb423dfaa51b6d88b1d64197ae695a0c8ac73778", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/0457b7944bf1cc9c846c98d4923b5379ec6afc09", + "reference": "0457b7944bf1cc9c846c98d4923b5379ec6afc09", "shasum": "" }, "require": { @@ -9215,7 +9215,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.20" + "source": "https://github.com/symfony/twig-bridge/tree/v6.4.21" }, "funding": [ { @@ -9231,7 +9231,7 @@ "type": "tidelift" } ], - "time": "2025-03-28T13:08:36+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/twig-bundle", @@ -9319,16 +9319,16 @@ }, { "name": "symfony/validator", - "version": "v6.4.20", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "9314555aceb8d8ce8abda81e1e47e439258d9309" + "reference": "47610116f476595b90c368ff2a22514050712785" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/9314555aceb8d8ce8abda81e1e47e439258d9309", - "reference": "9314555aceb8d8ce8abda81e1e47e439258d9309", + "url": "https://api.github.com/repos/symfony/validator/zipball/47610116f476595b90c368ff2a22514050712785", + "reference": "47610116f476595b90c368ff2a22514050712785", "shasum": "" }, "require": { @@ -9396,7 +9396,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.4.20" + "source": "https://github.com/symfony/validator/tree/v6.4.21" }, "funding": [ { @@ -9412,20 +9412,20 @@ "type": "tidelift" } ], - "time": "2025-03-14T14:22:58+00:00" + "time": "2025-04-30T18:50:04+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.18", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "4ad10cf8b020e77ba665305bb7804389884b4837" + "reference": "22560f80c0c5cd58cc0bcaf73455ffd81eb380d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/4ad10cf8b020e77ba665305bb7804389884b4837", - "reference": "4ad10cf8b020e77ba665305bb7804389884b4837", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/22560f80c0c5cd58cc0bcaf73455ffd81eb380d5", + "reference": "22560f80c0c5cd58cc0bcaf73455ffd81eb380d5", "shasum": "" }, "require": { @@ -9481,7 +9481,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.18" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.21" }, "funding": [ { @@ -9497,20 +9497,20 @@ "type": "tidelift" } ], - "time": "2025-01-17T11:26:11+00:00" + "time": "2025-04-09T07:34:50+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.20", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "998df255e9e6a15a36ae35e9c6cd818c17cf92a2" + "reference": "717e7544aa99752c54ecba5c0e17459c48317472" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/998df255e9e6a15a36ae35e9c6cd818c17cf92a2", - "reference": "998df255e9e6a15a36ae35e9c6cd818c17cf92a2", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/717e7544aa99752c54ecba5c0e17459c48317472", + "reference": "717e7544aa99752c54ecba5c0e17459c48317472", "shasum": "" }, "require": { @@ -9558,7 +9558,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.20" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.21" }, "funding": [ { @@ -9574,7 +9574,7 @@ "type": "tidelift" } ], - "time": "2025-03-13T09:55:08+00:00" + "time": "2025-04-27T21:06:26+00:00" }, { "name": "symfony/webpack-encore-bundle", @@ -9650,16 +9650,16 @@ }, { "name": "symfony/yaml", - "version": "v6.4.20", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "28ee818fce4a73ac1474346b94e4b966f665c53f" + "reference": "f01987f45676778b474468aa266fe2eda1f2bc7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/28ee818fce4a73ac1474346b94e4b966f665c53f", - "reference": "28ee818fce4a73ac1474346b94e4b966f665c53f", + "url": "https://api.github.com/repos/symfony/yaml/zipball/f01987f45676778b474468aa266fe2eda1f2bc7e", + "reference": "f01987f45676778b474468aa266fe2eda1f2bc7e", "shasum": "" }, "require": { @@ -9702,7 +9702,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.20" + "source": "https://github.com/symfony/yaml/tree/v6.4.21" }, "funding": [ { @@ -9718,7 +9718,7 @@ "type": "tidelift" } ], - "time": "2025-02-27T20:15:30+00:00" + "time": "2025-04-04T09:48:44+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -9777,7 +9777,7 @@ }, { "name": "twig/cssinliner-extra", - "version": "v3.20.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/cssinliner-extra.git", @@ -9830,7 +9830,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/cssinliner-extra/tree/v3.20.0" + "source": "https://github.com/twigphp/cssinliner-extra/tree/v3.21.0" }, "funding": [ { @@ -9846,16 +9846,16 @@ }, { "name": "twig/extra-bundle", - "version": "v3.20.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/twig-extra-bundle.git", - "reference": "9df5e1dbb6a68c0665ae5603f6f2c20815647876" + "reference": "62d1cf47a1aa009cbd07b21045b97d3d5cb79896" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/9df5e1dbb6a68c0665ae5603f6f2c20815647876", - "reference": "9df5e1dbb6a68c0665ae5603f6f2c20815647876", + "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/62d1cf47a1aa009cbd07b21045b97d3d5cb79896", + "reference": "62d1cf47a1aa009cbd07b21045b97d3d5cb79896", "shasum": "" }, "require": { @@ -9904,7 +9904,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.20.0" + "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.21.0" }, "funding": [ { @@ -9916,11 +9916,11 @@ "type": "tidelift" } ], - "time": "2025-02-08T09:47:15+00:00" + "time": "2025-02-19T14:29:33+00:00" }, { "name": "twig/inky-extra", - "version": "v3.20.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/inky-extra.git", @@ -9974,7 +9974,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/inky-extra/tree/v3.20.0" + "source": "https://github.com/twigphp/inky-extra/tree/v3.21.0" }, "funding": [ { @@ -9990,7 +9990,7 @@ }, { "name": "twig/intl-extra", - "version": "v3.20.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/intl-extra.git", @@ -10038,7 +10038,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/intl-extra/tree/v3.20.0" + "source": "https://github.com/twigphp/intl-extra/tree/v3.21.0" }, "funding": [ { @@ -10054,7 +10054,7 @@ }, { "name": "twig/string-extra", - "version": "v3.20.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/string-extra.git", @@ -10105,7 +10105,7 @@ "unicode" ], "support": { - "source": "https://github.com/twigphp/string-extra/tree/v3.20.0" + "source": "https://github.com/twigphp/string-extra/tree/v3.21.0" }, "funding": [ { @@ -10121,16 +10121,16 @@ }, { "name": "twig/twig", - "version": "v3.20.0", + "version": "v3.21.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "3468920399451a384bef53cf7996965f7cd40183" + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183", - "reference": "3468920399451a384bef53cf7996965f7cd40183", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", "shasum": "" }, "require": { @@ -10184,7 +10184,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.20.0" + "source": "https://github.com/twigphp/Twig/tree/v3.21.1" }, "funding": [ { @@ -10196,7 +10196,7 @@ "type": "tidelift" } ], - "time": "2025-02-13T08:34:43+00:00" + "time": "2025-05-03T07:21:55+00:00" }, { "name": "webmozart/assert", @@ -10357,16 +10357,16 @@ }, { "name": "zircote/swagger-php", - "version": "5.1.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "a9b953c25f5bd11ea0542636936de04504496bd9" + "reference": "7a6544c60441ddb5959b91266b3a290dc28537ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/a9b953c25f5bd11ea0542636936de04504496bd9", - "reference": "a9b953c25f5bd11ea0542636936de04504496bd9", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/7a6544c60441ddb5959b91266b3a290dc28537ba", + "reference": "7a6544c60441ddb5959b91266b3a290dc28537ba", "shasum": "" }, "require": { @@ -10437,9 +10437,9 @@ ], "support": { "issues": "https://github.com/zircote/swagger-php/issues", - "source": "https://github.com/zircote/swagger-php/tree/5.1.0" + "source": "https://github.com/zircote/swagger-php/tree/5.1.1" }, - "time": "2025-04-18T00:35:12+00:00" + "time": "2025-04-27T10:02:08+00:00" } ], "packages-dev": [ @@ -11274,16 +11274,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.12", + "version": "2.1.14", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "96dde49e967c0c22812bcfa7bda4ff82c09f3b0c" + "reference": "8f2e03099cac24ff3b379864d171c5acbfc6b9a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/96dde49e967c0c22812bcfa7bda4ff82c09f3b0c", - "reference": "96dde49e967c0c22812bcfa7bda4ff82c09f3b0c", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f2e03099cac24ff3b379864d171c5acbfc6b9a2", + "reference": "8f2e03099cac24ff3b379864d171c5acbfc6b9a2", "shasum": "" }, "require": { @@ -11328,25 +11328,25 @@ "type": "github" } ], - "time": "2025-04-16T13:19:18+00:00" + "time": "2025-05-02T15:32:28+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", - "reference": "1cc1259cb91ee4cfbb5c39bca9f635f067c910b4" + "reference": "9d8e7d4e32711715ad78a1fb6ec368df9af01fdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/1cc1259cb91ee4cfbb5c39bca9f635f067c910b4", - "reference": "1cc1259cb91ee4cfbb5c39bca9f635f067c910b4", + "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/9d8e7d4e32711715ad78a1fb6ec368df9af01fdf", + "reference": "9d8e7d4e32711715ad78a1fb6ec368df9af01fdf", "shasum": "" }, "require": { "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.0" + "phpstan/phpstan": "^2.1.13" }, "require-dev": { "php-parallel-lint/php-parallel-lint": "^1.2", @@ -11373,27 +11373,27 @@ "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", "support": { "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", - "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/2.0.1" + "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/2.0.2" }, - "time": "2024-11-28T21:56:36+00:00" + "time": "2025-04-26T19:59:57+00:00" }, { "name": "phpstan/phpstan-doctrine", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-doctrine.git", - "reference": "a61a04a361b60014ec04881ccb87252d3bf02e94" + "reference": "4497663eb17b9d29211830df5aceaa3a4d256a35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/a61a04a361b60014ec04881ccb87252d3bf02e94", - "reference": "a61a04a361b60014ec04881ccb87252d3bf02e94", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/4497663eb17b9d29211830df5aceaa3a4d256a35", + "reference": "4497663eb17b9d29211830df5aceaa3a4d256a35", "shasum": "" }, "require": { "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.0.3" + "phpstan/phpstan": "^2.1.13" }, "conflict": { "doctrine/collections": "<1.0", @@ -11417,6 +11417,7 @@ "gedmo/doctrine-extensions": "^3.8", "nesbot/carbon": "^2.49", "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0.2", "phpstan/phpstan-phpunit": "^2.0", "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^9.6.20", @@ -11444,9 +11445,9 @@ "description": "Doctrine extensions for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-doctrine/issues", - "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.2" + "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.3" }, - "time": "2025-03-03T09:29:16+00:00" + "time": "2025-05-05T15:28:52+00:00" }, { "name": "phpstan/phpstan-phpunit", @@ -11943,16 +11944,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.45", + "version": "10.5.46", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "bd68a781d8e30348bc297449f5234b3458267ae8" + "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8", - "reference": "bd68a781d8e30348bc297449f5234b3458267ae8", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8080be387a5be380dda48c6f41cee4a13aadab3d", + "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d", "shasum": "" }, "require": { @@ -11962,7 +11963,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.1", + "myclabs/deep-copy": "^1.13.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.1", @@ -12024,7 +12025,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.46" }, "funding": [ { @@ -12035,12 +12036,20 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2025-02-06T16:08:12+00:00" + "time": "2025-05-02T06:46:24+00:00" }, { "name": "react/cache", diff --git a/phpstan.neon b/phpstan.neon index f12fd6bf..fd43dfba 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1907,46 +1907,16 @@ parameters: count: 1 path: src/Form/Extension/SelectWithApiDataExtension.php - - - message: "#^Parameter \\#1 \\$haystack of function stripos expects string, bool\\|float\\|int\\|string given\\.$#" - count: 2 - path: src/Form/Helper/ActivityHelper.php - - - - message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\\\|string, bool\\|float\\|int\\|string given\\.$#" - count: 1 - path: src/Form/Helper/ActivityHelper.php - - message: "#^Property App\\\\Form\\\\Helper\\\\ActivityHelper\\:\\:\\$pattern \\(string\\|null\\) does not accept bool\\|float\\|int\\|string\\|null\\.$#" count: 1 path: src/Form/Helper/ActivityHelper.php - - - message: "#^Parameter \\#1 \\$haystack of function stripos expects string, bool\\|float\\|int\\|string given\\.$#" - count: 2 - path: src/Form/Helper/CustomerHelper.php - - - - message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\\\|string, bool\\|float\\|int\\|string given\\.$#" - count: 1 - path: src/Form/Helper/CustomerHelper.php - - message: "#^Property App\\\\Form\\\\Helper\\\\CustomerHelper\\:\\:\\$pattern \\(string\\|null\\) does not accept bool\\|float\\|int\\|string\\|null\\.$#" count: 1 path: src/Form/Helper/CustomerHelper.php - - - message: "#^Parameter \\#1 \\$haystack of function stripos expects string, bool\\|float\\|int\\|string given\\.$#" - count: 2 - path: src/Form/Helper/ProjectHelper.php - - - - message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\\\|string, bool\\|float\\|int\\|string given\\.$#" - count: 1 - path: src/Form/Helper/ProjectHelper.php - - message: "#^Property App\\\\Form\\\\Helper\\\\ProjectHelper\\:\\:\\$pattern \\(string\\|null\\) does not accept bool\\|float\\|int\\|string\\|null\\.$#" count: 1 @@ -3262,11 +3232,6 @@ parameters: count: 1 path: src/Ldap/LdapAuthenticator.php - - - message: "#^Instanceof between Symfony\\\\Component\\\\Security\\\\Http\\\\Authenticator\\\\Passport\\\\Passport and Symfony\\\\Component\\\\Security\\\\Http\\\\Authenticator\\\\Passport\\\\Passport will always evaluate to true\\.$#" - count: 1 - path: src/Ldap/LdapCredentialsSubscriber.php - - message: "#^Method App\\\\Ldap\\\\LdapCredentialsSubscriber\\:\\:onCheckPassport\\(\\) has no return type specified\\.$#" count: 1 @@ -3912,26 +3877,6 @@ parameters: count: 1 path: src/Timesheet/TimesheetStatisticService.php - - - message: "#^Method App\\\\Timesheet\\\\TrackingMode\\\\AbstractTrackingMode\\:\\:setBeginEndFromRequest\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Timesheet/TrackingMode/AbstractTrackingMode.php - - - - message: "#^Method App\\\\Timesheet\\\\TrackingMode\\\\AbstractTrackingMode\\:\\:setFromToFromRequest\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Timesheet/TrackingMode/AbstractTrackingMode.php - - - - message: "#^Parameter \\#1 \\$datetime of class DateTime constructor expects string, mixed given\\.$#" - count: 2 - path: src/Timesheet/TrackingMode/AbstractTrackingMode.php - - - - message: "#^Parameter \\#2 \\$datetime of static method DateTime\\:\\:createFromFormat\\(\\) expects string, mixed given\\.$#" - count: 2 - path: src/Timesheet/TrackingMode/AbstractTrackingMode.php - - message: "#^Method App\\\\Twig\\\\Configuration\\:\\:__call\\(\\) has no return type specified\\.$#" count: 1 diff --git a/src/API/Serializer/ValidationFailedExceptionErrorHandler.php b/src/API/Serializer/ValidationFailedExceptionErrorHandler.php index b0530434..d2c9868b 100644 --- a/src/API/Serializer/ValidationFailedExceptionErrorHandler.php +++ b/src/API/Serializer/ValidationFailedExceptionErrorHandler.php @@ -23,7 +23,11 @@ use Symfony\Contracts\Translation\TranslatorInterface; final class ValidationFailedExceptionErrorHandler implements SubscribingHandlerInterface { - public function __construct(private TranslatorInterface $translator, private FlattenExceptionHandler $exceptionHandler, private Security $security) + public function __construct( + private readonly TranslatorInterface $translator, + private readonly FlattenExceptionHandler $exceptionHandler, // @phpstan-ignore-line + private readonly Security $security + ) { } @@ -47,7 +51,7 @@ final class ValidationFailedExceptionErrorHandler implements SubscribingHandlerI public function serializeExceptionToJson(JsonSerializationVisitor $visitor, FlattenException $exception, array $type, Context $context) { if ($exception->getClass() !== ValidationFailedException::class) { - return $this->exceptionHandler->serializeToJson($visitor, $exception, $type, $context); + return $this->exceptionHandler->serializeToJson($visitor, $exception, $type, $context); // @phpstan-ignore method.internalClass } $original = $context->getAttribute('exception'); @@ -55,7 +59,7 @@ final class ValidationFailedExceptionErrorHandler implements SubscribingHandlerI return $this->serializeValidationExceptionToJson($visitor, $original, $type, $context); } - return $this->exceptionHandler->serializeToJson($visitor, $exception, $type, $context); + return $this->exceptionHandler->serializeToJson($visitor, $exception, $type, $context); // @phpstan-ignore method.internalClass } public function serializeValidationExceptionToJson(JsonSerializationVisitor $visitor, ValidationFailedException $exception, array $type, Context $context) diff --git a/src/Configuration/SystemConfiguration.php b/src/Configuration/SystemConfiguration.php index 0c172fd1..5be0a947 100644 --- a/src/Configuration/SystemConfiguration.php +++ b/src/Configuration/SystemConfiguration.php @@ -483,25 +483,17 @@ final class SystemConfiguration return (bool) $this->find('theme.avatar_url'); } - /** - * @internal will be made private soon after 2.18.0 - do not access this method directly, but through getThemeColors() - */ - public function getThemeColorChoices(): string - { - $config = $this->find('theme.color_choices'); - if (\is_string($config) && $config !== '') { - return $config; - } - - return 'Silver|#c0c0c0'; - } - /** * @return array */ public function getThemeColors(): array { - $config = explode(',', $this->getThemeColorChoices()); + $config = $this->find('theme.color_choices'); + if (!\is_string($config) || $config === '') { + return ['Silver' => '#c0c0c0']; + } + + $config = explode(',', $config); $colors = []; foreach ($config as $item) { diff --git a/src/Constants.php b/src/Constants.php index 862094f2..40b8dc6b 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -17,11 +17,11 @@ final class Constants /** * The current release version */ - public const VERSION = '2.33.0'; + public const VERSION = '2.34.0'; /** * The current release: major * 10000 + minor * 100 + patch */ - public const VERSION_ID = 23300; + public const VERSION_ID = 23400; /** * The software name */ diff --git a/src/Controller/InvoiceController.php b/src/Controller/InvoiceController.php index bfc0682f..45f13687 100644 --- a/src/Controller/InvoiceController.php +++ b/src/Controller/InvoiceController.php @@ -60,10 +60,10 @@ use Twig\Environment; final class InvoiceController extends AbstractController { public function __construct( - private ServiceInvoice $service, - private InvoiceTemplateRepository $templateRepository, - private InvoiceRepository $invoiceRepository, - private EventDispatcherInterface $dispatcher + private readonly ServiceInvoice $service, + private readonly InvoiceTemplateRepository $templateRepository, + private readonly InvoiceRepository $invoiceRepository, + private readonly EventDispatcherInterface $dispatcher ) { } @@ -333,7 +333,7 @@ final class InvoiceController extends AbstractController { $invoice = null; - if (null !== ($id = $request->get('id'))) { + if (null !== ($id = $request->query->get('id'))) { $invoice = $this->invoiceRepository->find($id); } diff --git a/src/Controller/PluginController.php b/src/Controller/PluginController.php index ace5ea10..70745f99 100644 --- a/src/Controller/PluginController.php +++ b/src/Controller/PluginController.php @@ -28,7 +28,7 @@ final class PluginController extends AbstractController $installed = []; $plugins = $manager->getPlugins(); foreach ($plugins as $plugin) { - $installed[] = $plugin->getId(); + $installed[$plugin->getId()] = $plugin; } $page = new PageSetup('menu.plugin'); @@ -36,18 +36,23 @@ final class PluginController extends AbstractController $all = $this->getPluginInformation($client, $cache); $bundles = []; + $updates = []; foreach ($all as $item) { if ($item['bundle'] !== null) { $bundles[$item['bundle']] = $item; + if (\array_key_exists($item['bundle'], $installed)) { + $updates[$item['bundle']] = version_compare($installed[$item['bundle']]->getMetadata()->getVersion(), $item['latest_release']) === -1; + } } } return $this->render('plugin/index.html.twig', [ 'page_setup' => $page, 'plugins' => $plugins, - 'installed' => $installed, + 'installed' => array_keys($installed), 'extensions' => $all, 'bundles' => $bundles, + 'updates' => $updates, ]); } diff --git a/src/Controller/QuickEntryController.php b/src/Controller/QuickEntryController.php index 384cb032..ed344406 100644 --- a/src/Controller/QuickEntryController.php +++ b/src/Controller/QuickEntryController.php @@ -10,6 +10,7 @@ namespace App\Controller; use App\Configuration\SystemConfiguration; +use App\Event\QuickEntryMetaDisplayEvent; use App\Form\QuickEntryForm; use App\Form\WeekByUserForm; use App\Model\QuickEntryWeek; @@ -19,6 +20,7 @@ use App\Repository\TimesheetRepository; use App\Timesheet\FavoriteRecordService; use App\Timesheet\TimesheetService; use App\Utils\PageSetup; +use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -34,7 +36,8 @@ final class QuickEntryController extends AbstractController private readonly SystemConfiguration $configuration, private readonly TimesheetService $timesheetService, private readonly TimesheetRepository $repository, - private readonly FavoriteRecordService $favoriteRecordService + private readonly FavoriteRecordService $favoriteRecordService, + private readonly EventDispatcherInterface $dispatcher, ) { } @@ -149,6 +152,11 @@ final class QuickEntryController extends AbstractController $defaultHour = (int) $defaultBegin->format('H'); $defaultMinute = (int) $defaultBegin->format('i'); + // find additional meta-fields exclusively for QuickEntry view + $event = new QuickEntryMetaDisplayEvent($query); + $this->dispatcher->dispatch($event); + $metaFields = $event->getFields(); + $formModel = new QuickEntryWeek($startWeek); foreach ($rows as $id => $row) { @@ -168,10 +176,12 @@ final class QuickEntryController extends AbstractController $model->addTimesheet($day['entry']); } } + $model->setMetaFields($metaFields); } // create prototype model $empty = $formModel->createRow($user); + $empty->setMetaFields($metaFields); $empty->markAsPrototype(); foreach ($week as $dayId => $day) { $tmp = $this->timesheetService->createNewTimesheet($user); @@ -219,7 +229,11 @@ final class QuickEntryController extends AbstractController foreach ($tmpModel->getTimesheets() as $timesheet) { if ($timesheet->getId() !== null) { $duration = $timesheet->getDuration(false); - if ($duration === null || $timesheet->isRunning()) { + // previously running timesheets were deleted, which was wrong + // so now we distinguish between running timesheets and null duration + if ($timesheet->isRunning()) { + $saveTimesheets[] = $timesheet; + } elseif ($duration === null) { $deleteTimesheets[] = $timesheet; } else { $saveTimesheets[] = $timesheet; @@ -263,6 +277,7 @@ final class QuickEntryController extends AbstractController 'page_setup' => $page, 'days' => $week, 'form' => $form->createView(), + 'metaColumns' => $metaFields, ]); } } diff --git a/src/Controller/TimesheetAbstractController.php b/src/Controller/TimesheetAbstractController.php index 09244565..0568c0bc 100644 --- a/src/Controller/TimesheetAbstractController.php +++ b/src/Controller/TimesheetAbstractController.php @@ -147,9 +147,7 @@ abstract class TimesheetAbstractController extends AbstractController $event = new TimesheetMetaDefinitionEvent($entry); $this->dispatcher->dispatch($event); - $page = $request->get('page'); - $page = is_numeric($page) ? (int) $page : 1; - $editForm = $this->getEditForm($entry, $page); + $editForm = $this->getEditForm($entry); $editForm->handleRequest($request); if ($editForm->isSubmitted() && $editForm->isValid()) { @@ -157,7 +155,7 @@ abstract class TimesheetAbstractController extends AbstractController $this->service->updateTimesheet($entry); $this->flashSuccess('action.update.success'); - return $this->redirectToRoute($this->getTimesheetRoute(), ['page' => $request->get('page', 1)]); + return $this->redirectToRoute($this->getTimesheetRoute()); } catch (\Exception $ex) { $this->flashUpdateException($ex); } @@ -494,14 +492,13 @@ abstract class TimesheetAbstractController extends AbstractController ]); } - private function getEditForm(Timesheet $entry, int $page): FormInterface + private function getEditForm(Timesheet $entry): FormInterface { $mode = $this->getTrackingMode(); return $this->createForm($this->getEditFormClassName(), $entry, [ 'action' => $this->generateUrl($this->getEditRoute(), [ 'id' => $entry->getId(), - 'page' => $page, ]), 'include_rate' => $this->isGranted('edit_rate', $entry), 'include_exported' => $this->isGranted('edit_export', $entry), diff --git a/src/Doctrine/Behavior/CreatedAt.php b/src/Doctrine/Behavior/CreatedAt.php index 46e0f636..af4476db 100644 --- a/src/Doctrine/Behavior/CreatedAt.php +++ b/src/Doctrine/Behavior/CreatedAt.php @@ -9,9 +9,6 @@ namespace App\Doctrine\Behavior; -/** - * @internal - */ interface CreatedAt { public function getCreatedAt(): ?\DateTimeImmutable; diff --git a/src/Doctrine/Behavior/ModifiedTrait.php b/src/Doctrine/Behavior/ModifiedTrait.php index 4d3b4d86..91605ffd 100644 --- a/src/Doctrine/Behavior/ModifiedTrait.php +++ b/src/Doctrine/Behavior/ModifiedTrait.php @@ -25,4 +25,9 @@ trait ModifiedTrait { $this->modifiedAt = $dateTime; } + + public function markAsModified(): void + { + $this->setModifiedAt(new \DateTimeImmutable('now', new \DateTimeZone('UTC'))); + } } diff --git a/src/Entity/Timesheet.php b/src/Entity/Timesheet.php index b85d0eb1..06642ac6 100644 --- a/src/Entity/Timesheet.php +++ b/src/Entity/Timesheet.php @@ -224,7 +224,7 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt { $this->tags = new ArrayCollection(); $this->meta = new ArrayCollection(); - $this->setModifiedAt(new \DateTimeImmutable('now', new \DateTimeZone('UTC'))); + $this->markAsModified(); } /** @@ -611,7 +611,7 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt { // this needs to be done, otherwise doctrine will not see the item as changed // and the calculators will not run - $this->setModifiedAt(new \DateTimeImmutable('now', new \DateTimeZone('UTC'))); + $this->markAsModified(); if (null === ($current = $this->getMetaField($meta->getName()))) { $meta->setEntity($this); @@ -659,7 +659,7 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt $this->id = null; } - $this->setModifiedAt(new \DateTimeImmutable('now', new \DateTimeZone('UTC'))); + $this->markAsModified(); $this->exported = false; $currentMeta = $this->meta; diff --git a/src/Event/QuickEntryMetaDisplayEvent.php b/src/Event/QuickEntryMetaDisplayEvent.php new file mode 100644 index 00000000..ff50f989 --- /dev/null +++ b/src/Event/QuickEntryMetaDisplayEvent.php @@ -0,0 +1,25 @@ +addItem($menuEvent->getSystemMenu()); } - $route = $event->getRequest()->get('_route'); + $route = $event->getRequest()->attributes->get('_route'); if (!\is_string($route)) { return; } diff --git a/src/Form/QuickEntryForm.php b/src/Form/QuickEntryForm.php index fc67d6b4..5a416090 100644 --- a/src/Form/QuickEntryForm.php +++ b/src/Form/QuickEntryForm.php @@ -33,6 +33,18 @@ final class QuickEntryForm extends AbstractType $builder->addModelTransformer(new CallbackTransformer( function ($value) { // page is loaded, nothing to do + if (!$value instanceof QuickEntryWeek) { + return $value; + } + + foreach ($value->getRows() as $row) { + foreach ($row->getTimesheets() as $timesheet) { + foreach ($timesheet->getMetaFields() as $metaField) { + $row->setMetaFieldValue($metaField); + } + } + } + return $value; }, function (?QuickEntryWeek $value) { @@ -49,6 +61,24 @@ final class QuickEntryForm extends AbstractType foreach ($row->getTimesheets() as $timesheet) { $timesheet->setProject($project); $timesheet->setActivity($activity); + foreach ($row->getMetaFields() as $metaField) { + if (null === ($name = $metaField->getName())) { + continue; + } + + if (null === $timesheet->getMetaField($name)) { + $timesheet->setMetaField($metaField); + } + + if (null === ($tmpField = $timesheet->getMetaField($name))) { + continue; + } + + if ($tmpField->getValue() !== $metaField->getValue()) { + $tmpField->setValue($metaField->getValue()); + $timesheet->markAsModified(); + } + } } } diff --git a/src/Form/TimesheetEditForm.php b/src/Form/TimesheetEditForm.php index 5d3b4681..4c28507b 100644 --- a/src/Form/TimesheetEditForm.php +++ b/src/Form/TimesheetEditForm.php @@ -214,9 +214,9 @@ class TimesheetEditForm extends AbstractType return; } - // if the user did not change the time, make sure to keep the seconds $seconds = 0; - if ($data->getBegin()?->format('H:i') === $time->format('H:i')) { + // if the user did not change the time, make sure to keep the seconds (ONLY if the timesheet is already existing) + if ($data->getBegin()?->format('H:i') === $time->format('H:i') && $data->getId() !== null) { $seconds = $data->getBegin()->format('s') ?? 0; } @@ -276,9 +276,9 @@ class TimesheetEditForm extends AbstractType throw new \Exception('Cannot work with timesheets without start time'); } - // if the user did not change the time, make sure to keep the seconds $seconds = 0; - if ($oldEnd !== null && $oldEnd->format('H:i') === $end->format('H:i')) { + // if the user did not change the time, make sure to keep the seconds (ONLY if the timesheet is already existing) + if ($oldEnd !== null && $oldEnd->format('H:i') === $end->format('H:i') && $timesheet->getId() !== null) { $seconds = $oldEnd->format('s') ?? 0; } diff --git a/src/Form/Type/QuickEntryWeekType.php b/src/Form/Type/QuickEntryWeekType.php index 5704cef6..cb249456 100644 --- a/src/Form/Type/QuickEntryWeekType.php +++ b/src/Form/Type/QuickEntryWeekType.php @@ -92,6 +92,8 @@ final class QuickEntryWeekType extends AbstractType }; $builder->addEventListener(FormEvents::PRE_SUBMIT, $activityPreSubmitFunction); + $builder->add('metaFields', MetaFieldsCollectionType::class); + $builder->add('timesheets', CollectionType::class, [ 'entry_type' => QuickEntryTimesheetType::class, 'label' => false, diff --git a/src/Ldap/LdapCredentialsSubscriber.php b/src/Ldap/LdapCredentialsSubscriber.php index c3d8576d..ad78febc 100644 --- a/src/Ldap/LdapCredentialsSubscriber.php +++ b/src/Ldap/LdapCredentialsSubscriber.php @@ -13,12 +13,11 @@ use App\Entity\User; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials; -use Symfony\Component\Security\Http\Authenticator\Passport\Passport; use Symfony\Component\Security\Http\Event\CheckPassportEvent; final class LdapCredentialsSubscriber implements EventSubscriberInterface { - public function __construct(private LdapManager $ldapManager) + public function __construct(private readonly LdapManager $ldapManager) { } @@ -40,7 +39,7 @@ final class LdapCredentialsSubscriber implements EventSubscriberInterface return; } - if (!$passport instanceof Passport || !$passport->hasBadge(PasswordCredentials::class)) { + if (!$passport->hasBadge(PasswordCredentials::class)) { throw new \LogicException(\sprintf('LDAP authentication requires a passport containing a user and password credentials, authenticator "%s" does not fulfill these requirements.', \get_class($event->getAuthenticator()))); } @@ -78,6 +77,6 @@ final class LdapCredentialsSubscriber implements EventSubscriberInterface } // make sure that the normal auth process is not triggered - $passwordCredentials->markResolved(); + $passwordCredentials->markResolved(); // @phpstan-ignore method.internal } } diff --git a/src/Model/QuickEntryModel.php b/src/Model/QuickEntryModel.php index 5455e828..3f312a03 100644 --- a/src/Model/QuickEntryModel.php +++ b/src/Model/QuickEntryModel.php @@ -10,9 +10,12 @@ namespace App\Model; use App\Entity\Activity; +use App\Entity\MetaTableTypeInterface; use App\Entity\Project; use App\Entity\Timesheet; use App\Entity\User; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; /** * @internal @@ -24,9 +27,18 @@ class QuickEntryModel * @var Timesheet[] */ private array $timesheets = []; + /** + * @var Collection + */ + private Collection $metaFields; - public function __construct(private User $user, private ?Project $project = null, private ?Activity $activity = null) + public function __construct( + private readonly User $user, + private ?Project $project = null, + private ?Activity $activity = null + ) { + $this->metaFields = new ArrayCollection(); } public function markAsPrototype(): void @@ -184,4 +196,36 @@ class QuickEntryModel $this->timesheets[] = clone $record; } } + + /** + * @return Collection + */ + public function getMetaFields(): Collection + { + return $this->metaFields; + } + + public function setMetaFieldValue(MetaTableTypeInterface $metaField): void + { + // we only update the value for fields which were previously registered + // as we do NOT want new fields to show up by accident + foreach ($this->metaFields as $field) { + if ($field->getName() === $metaField->getName() && $metaField->getValue() !== null) { + $field->setValue($metaField->getValue()); + break; + } + } + } + + /** + * @param array $metaFields + */ + public function setMetaFields(array $metaFields): void + { + $collection = new ArrayCollection(); + foreach($metaFields as $field) { + $collection->add(clone $field); + } + $this->metaFields = $collection; + } } diff --git a/src/Model/QuickEntryWeek.php b/src/Model/QuickEntryWeek.php index 5b99ca8e..c4de20f6 100644 --- a/src/Model/QuickEntryWeek.php +++ b/src/Model/QuickEntryWeek.php @@ -23,7 +23,7 @@ class QuickEntryWeek */ private array $rows = []; - public function __construct(private \DateTime $startDate) + public function __construct(private readonly \DateTime $startDate) { } @@ -79,7 +79,7 @@ class QuickEntryWeek $result = strcmp((string) $aName, (string) $bName); } - return $result < 0 ? -1 : 1; + return $result < 0 ? -1 : 1; } /** diff --git a/src/Model/TimesheetCountedStatistic.php b/src/Model/TimesheetCountedStatistic.php index 920bf6d4..1f89c71a 100644 --- a/src/Model/TimesheetCountedStatistic.php +++ b/src/Model/TimesheetCountedStatistic.php @@ -9,9 +9,6 @@ namespace App\Model; -/** - * @internal - */ class TimesheetCountedStatistic implements \JsonSerializable { private int $counter = 0; @@ -34,8 +31,6 @@ class TimesheetCountedStatistic implements \JsonSerializable /** * For unified access, used in frontend. - * - * @return int */ public function getCounter(): int { @@ -84,8 +79,6 @@ class TimesheetCountedStatistic implements \JsonSerializable /** * For unified access, used in frontend. - * - * @return int */ public function getValue(): int { @@ -104,8 +97,6 @@ class TimesheetCountedStatistic implements \JsonSerializable /** * For unified access, used in frontend. - * - * @return int */ public function getDuration(): int { @@ -114,8 +105,6 @@ class TimesheetCountedStatistic implements \JsonSerializable /** * For unified access, used in frontend. - * - * @return float */ public function getRate(): float { @@ -134,8 +123,6 @@ class TimesheetCountedStatistic implements \JsonSerializable /** * Returns the total internal rate of all included timesheet records. - * - * @return float */ public function getInternalRate(): float { diff --git a/src/Repository/Query/BaseQuery.php b/src/Repository/Query/BaseQuery.php index 3cad20cd..09b6d665 100644 --- a/src/Repository/Query/BaseQuery.php +++ b/src/Repository/Query/BaseQuery.php @@ -324,7 +324,6 @@ class BaseQuery * @template T of BaseQuery * @param T $query * @return T - * @internal */ final public function copyTo(BaseQuery $query): BaseQuery { diff --git a/src/Saml/Security/SamlAuthenticationSuccessHandler.php b/src/Saml/Security/SamlAuthenticationSuccessHandler.php index 0874a211..4cd6101c 100644 --- a/src/Saml/Security/SamlAuthenticationSuccessHandler.php +++ b/src/Saml/Security/SamlAuthenticationSuccessHandler.php @@ -24,7 +24,7 @@ final class SamlAuthenticationSuccessHandler extends DefaultAuthenticationSucces protected function determineTargetUrl(Request $request): string { - $relayState = $request->get('RelayState'); + $relayState = $request->request->get('RelayState', $request->query->get('RelayState')); if (\is_scalar($relayState)) { $relayState = (string) $relayState; if ($relayState !== $this->httpUtils->generateUri($request, (string) $this->options['login_path'])) { diff --git a/src/Timesheet/TrackingMode/AbstractTrackingMode.php b/src/Timesheet/TrackingMode/AbstractTrackingMode.php index a2ae3a6e..f29864bf 100644 --- a/src/Timesheet/TrackingMode/AbstractTrackingMode.php +++ b/src/Timesheet/TrackingMode/AbstractTrackingMode.php @@ -27,9 +27,9 @@ abstract class AbstractTrackingMode implements TrackingModeInterface $this->setFromToFromRequest($timesheet, $request); } - protected function setBeginEndFromRequest(Timesheet $entry, Request $request) + protected function setBeginEndFromRequest(Timesheet $entry, Request $request): void { - $start = $request->get('begin'); + $start = $request->query->get('begin'); if (null === $start) { return; } @@ -42,7 +42,7 @@ abstract class AbstractTrackingMode implements TrackingModeInterface $entry->setBegin($start); // only check for an end date if a begin date was given - $end = $request->get('end'); + $end = $request->query->get('end'); if (null === $end) { return; } @@ -59,33 +59,33 @@ abstract class AbstractTrackingMode implements TrackingModeInterface $entry->setDuration($end->getTimestamp() - $start->getTimestamp()); } - protected function setFromToFromRequest(Timesheet $entry, Request $request) + protected function setFromToFromRequest(Timesheet $entry, Request $request): void { - $from = $request->get('from'); - if (null === $from) { + $from = $request->query->get('from'); + if (!\is_string($from)) { return; } try { $from = new DateTime($from, $this->getTimezone($entry)); + $entry->setBegin($from); } catch (\Exception $ex) { return; } - $entry->setBegin($from); - - $to = $request->get('to'); - if (null === $to) { + // only check for an end date if a valid begin date was given + $to = $request->query->get('to'); + if (!\is_string($to)) { return; } try { $to = new DateTime($to, $this->getTimezone($entry)); + $entry->setEnd($to); } catch (\Exception $ex) { return; } - $entry->setEnd($to); $entry->setDuration($to->getTimestamp() - $from->getTimestamp()); } } diff --git a/src/Twig/Runtime/ThemeExtension.php b/src/Twig/Runtime/ThemeExtension.php index 10dcbb55..87d2db55 100644 --- a/src/Twig/Runtime/ThemeExtension.php +++ b/src/Twig/Runtime/ThemeExtension.php @@ -63,12 +63,12 @@ final class ThemeExtension implements RuntimeExtensionInterface public function getJavascriptTranslations(): array { - $event = new ThemeJavascriptTranslationsEvent(); // @phpstan-ignore new.deprecated + $event = new ThemeJavascriptTranslationsEvent(); // @phpstan-ignore new.deprecatedClass $this->eventDispatcher->dispatch($event); $all = []; - foreach ($event->getTranslations() as $key => $translation) { + foreach ($event->getTranslations() as $key => $translation) { // @phpstan-ignore method.deprecatedClass $all[$key] = $this->translator->trans($translation[0], [], $translation[1]); } diff --git a/src/Twig/SecurityPolicy/ForbiddenPolicy.php b/src/Twig/SecurityPolicy/ForbiddenPolicy.php index cab45ce9..b5199d63 100644 --- a/src/Twig/SecurityPolicy/ForbiddenPolicy.php +++ b/src/Twig/SecurityPolicy/ForbiddenPolicy.php @@ -34,11 +34,11 @@ final class ForbiddenPolicy implements SecurityPolicyInterface * @param array $forbiddenFunctions */ public function __construct( - private array $forbiddenTags = [], - private array $forbiddenFilters = [], + private readonly array $forbiddenTags = [], + private readonly array $forbiddenFilters = [], array $forbiddenMethods = [], - private array $forbiddenProperties = [], - private array $forbiddenFunctions = [] + private readonly array $forbiddenProperties = [], + private readonly array $forbiddenFunctions = [] ) { $this->forbiddenMethods = []; @@ -70,7 +70,7 @@ final class ForbiddenPolicy implements SecurityPolicyInterface public function checkMethodAllowed($obj, $method): void { - if ($obj instanceof Template || $obj instanceof Markup) { + if ($obj instanceof Template || $obj instanceof Markup) { // @phpstan-ignore instanceof.internalClass return; } diff --git a/src/Twig/SecurityPolicy/InvoicePolicy.php b/src/Twig/SecurityPolicy/InvoicePolicy.php index 46507ce9..8db0fa96 100644 --- a/src/Twig/SecurityPolicy/InvoicePolicy.php +++ b/src/Twig/SecurityPolicy/InvoicePolicy.php @@ -204,7 +204,7 @@ final class InvoicePolicy implements SecurityPolicyInterface public function checkMethodAllowed($obj, $method): void { - if ($obj instanceof Template || $obj instanceof Markup || $obj instanceof UnicodeString) { + if ($obj instanceof Template || $obj instanceof Markup || $obj instanceof UnicodeString) { // @phpstan-ignore instanceof.internalClass return; } diff --git a/src/WorkingTime/WorkingTimeService.php b/src/WorkingTime/WorkingTimeService.php index 831f5972..8d2f6dba 100644 --- a/src/WorkingTime/WorkingTimeService.php +++ b/src/WorkingTime/WorkingTimeService.php @@ -27,9 +27,6 @@ use App\WorkingTime\Model\Year; use App\WorkingTime\Model\YearPerUserSummary; use Psr\EventDispatcher\EventDispatcherInterface; -/** - * @internal this API and the entire namespace is experimental: expect changes! - */ final class WorkingTimeService { private const LATEST_APPROVAL_PREF = '_latest_approval'; diff --git a/templates/form/blocks.html.twig b/templates/form/blocks.html.twig index 176e1063..cf02ba63 100644 --- a/templates/form/blocks.html.twig +++ b/templates/form/blocks.html.twig @@ -35,6 +35,10 @@ {{ form_row(form.duration, {row_attr: {class: 'p-0'}}) }} {%- endblock %} +{% block _quick_entry_form_rows_entry_metaFields_entry_widget %} + {{ form_row(form, {row_attr: {class: 'p-0'}}) }} +{%- endblock %} + {% block quick_entry_week_row %} @@ -43,6 +47,11 @@ {{ form_row(form.activity, {row_attr: {class: 'p-0'}}) }} + {% for meta in form.metaFields|sort((a, b) => a.vars.data.order <=> b.vars.data.order) %} + + {{ form_row(meta.value, {label: false}) }} + + {% endfor %} {% for timesheet in form.timesheets %} {{ form_widget(timesheet) }} diff --git a/templates/plugin/index.html.twig b/templates/plugin/index.html.twig index 989bf02e..ebde9694 100644 --- a/templates/plugin/index.html.twig +++ b/templates/plugin/index.html.twig @@ -29,7 +29,7 @@ {{ plugin.metadata.description }} - {% if bundles[plugin.id] is defined and bundles[plugin.id]['latest_release'] is defined and bundles[plugin.id]['latest_release'] != plugin.metadata.version %} + {% if updates[plugin.id] is defined and updates[plugin.id] == true %} {{ widgets.alert('warning', 'update_available'|trans({'%version%': bundles[plugin.id]['latest_release']}, 'plugins')) }} {% endif %} diff --git a/templates/quick-entry/index.html.twig b/templates/quick-entry/index.html.twig index 959bf1c9..9ee323f8 100644 --- a/templates/quick-entry/index.html.twig +++ b/templates/quick-entry/index.html.twig @@ -28,6 +28,9 @@ {{ 'project'|trans }} {{ 'activity'|trans }} + {% for field in metaColumns|sort((a, b) => a.order <=> b.order) %} + {{ field.label }} + {% endfor %} {% for id, week in days %} {{ week.day|date_weekday }} @@ -43,6 +46,9 @@ {{ 'stats.durationTotal'|trans }} + {% for field in metaColumns %} + + {% endfor %} {% for id, week in days %} {% endfor %} diff --git a/tests/Configuration/SystemConfigurationTest.php b/tests/Configuration/SystemConfigurationTest.php index fb038615..618990e9 100644 --- a/tests/Configuration/SystemConfigurationTest.php +++ b/tests/Configuration/SystemConfigurationTest.php @@ -136,7 +136,6 @@ class SystemConfigurationTest extends TestCase self::assertEquals('GBP', $sut->find('defaults.customer.currency')); self::assertFalse($sut->find('timesheet.rules.allow_future_times')); self::assertEquals(99, $sut->find('timesheet.active_entries.hard_limit')); - self::assertEquals('Maroon|#800000,Brown|#a52a2a,Red|#ff0000,Orange|#ffa500,#ffffff,,|#000000', $sut->getThemeColorChoices()); self::assertEquals(['Maroon' => '#800000', 'Brown' => '#a52a2a', 'Red' => '#ff0000', 'Orange' => '#ffa500', '#ffffff' => '#ffffff', '#000000' => '#000000'], $sut->getThemeColors()); } @@ -160,7 +159,6 @@ class SystemConfigurationTest extends TestCase ]); self::assertFalse($sut->find('timesheet.rules.allow_future_times')); self::assertTrue($sut->isSamlActive()); - self::assertEquals('Silver|#c0c0c0', $sut->getThemeColorChoices()); self::assertEquals(['Silver' => '#c0c0c0'], $sut->getThemeColors()); self::assertEquals('2020-03-27', $sut->getFinancialYearStart()); } diff --git a/tests/Event/ThemeJavascriptTranslationsEventTest.php b/tests/Event/ThemeJavascriptTranslationsEventTest.php index 02d63156..c8f80f24 100644 --- a/tests/Event/ThemeJavascriptTranslationsEventTest.php +++ b/tests/Event/ThemeJavascriptTranslationsEventTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; /** * @covers \App\Event\ThemeJavascriptTranslationsEvent + * @group legacy */ class ThemeJavascriptTranslationsEventTest extends TestCase { @@ -21,18 +22,18 @@ class ThemeJavascriptTranslationsEventTest extends TestCase public function testDefaultValues(): void { - $sut = new ThemeJavascriptTranslationsEvent(); // @phpstan-ignore new.deprecated + $sut = new ThemeJavascriptTranslationsEvent(); // @phpstan-ignore new.deprecatedClass - self::assertCount(self::COUNTER, $sut->getTranslations()); + self::assertCount(self::COUNTER, $sut->getTranslations()); // @phpstan-ignore method.deprecatedClass } public function testGetterAndSetter(): void { - $sut = new ThemeJavascriptTranslationsEvent(); // @phpstan-ignore new.deprecated - $sut->setTranslation('foo', 'bar'); - $sut->setTranslation('hello', 'world', 'testing'); + $sut = new ThemeJavascriptTranslationsEvent(); // @phpstan-ignore new.deprecatedClass + $sut->setTranslation('foo', 'bar'); // @phpstan-ignore method.deprecatedClass + $sut->setTranslation('hello', 'world', 'testing'); // @phpstan-ignore method.deprecatedClass - $result = $sut->getTranslations(); + $result = $sut->getTranslations(); // @phpstan-ignore method.deprecatedClass self::assertCount(self::COUNTER + 2, $result); self::assertArrayHasKey('foo', $result); self::assertEquals(['bar', 'messages'], $result['foo']); diff --git a/translations/system-configuration.de.xlf b/translations/system-configuration.de.xlf index 77e9d8a8..b91ec28f 100644 --- a/translations/system-configuration.de.xlf +++ b/translations/system-configuration.de.xlf @@ -180,19 +180,19 @@ Ceil - Ceil: Start, Ende und Dauer werden nach oben gerundet + Start, Ende und Dauer werden nach oben gerundet Closest - Closest: Mathematische Rundung zum nächsten Wert + Mathematische Rundung zum nächsten Wert Default - Standard: Start wird nach unten, Ende und Dauer nach oben gerundet + Start wird nach unten, Ende und Dauer nach oben gerundet Floor - Floor: Start, Ende und Dauer werden nach unten gerundet + Start, Ende und Dauer werden nach unten gerundet timesheet.default_begin diff --git a/translations/system-configuration.en.xlf b/translations/system-configuration.en.xlf index 61494e3f..e6331254 100644 --- a/translations/system-configuration.en.xlf +++ b/translations/system-configuration.en.xlf @@ -180,19 +180,19 @@ Ceil - Ceil: begin, end and duration will be rounded up + Begin, end and duration will be rounded up Closest - Closest: mathematical rounding to the nearest value + Mathematical rounding to the nearest value Default - Standard: begin will be rounded down, end and duration up + Begin will be rounded down, end and duration up Floor - Floor: begin, end and duration will be rounded down + Begin, end and duration will be rounded down timesheet.default_begin